Road to ruby silver (Part 3)

This is just some note for who want to get Ruby Silver certification. :)

[Part 1](https://qiita.com/ThuBM/items/072ab020633ef1d3e818)
[Part 2](https://qiita.com/ThuBM/items/d38ca87f8d5747e207d9)

# Chapter 4: Object orientation

### 4.1. Define a class

#### 4.1.1. Syntax

```
class <<ClassName>>
end
```

Sample:

```
class Foo
  def initialize a = 0
    @a = a
  end

  def method1
    @a
  end
end

foo1 = Foo.new(1)
foo1.method1 ⇛ 1
foo2 = Foo.new
foo2.method1 ⇛ 0
```

★ All commands is not contained in any method will be ran when class is loaded

```
puts 1
class Hoge
  puts 2
end
puts 3

⇛
1
2
3
```

#### 4.1.2. Instance method and initialization method

```
class Foo
  def initialize a = 0
    @a = a
  end

  def method1
    @a
  end
end

⇛ method1 is an instance method of class Foo

foo1 = Foo.new
foo1.class == Foo ⇛ true
```

#### 4.1.3. Inheritance class (クラス継承)

```
class FooExt < Foo
  def initialize a, b
    @b = b
    super a
  end

  def method2
    @a + @b
  end
end

fooExt = FooExt.new(3, 4)
fooExt.method1 ⇛ 3
fooExt.method2 ⇛ 7

FooExt.superclass ⇛ Foo
```

#### 4.1.4. `super`

For calling the nearest parent class

### 4.2. Instance method
#### 4.2.1. Class object (クラスオブジェクト)

- Create new instance of class `Foo`

```
instance1 = Foo.new(1)
instance2 = Foo.new(1)

instance1.object_id ⇛ 70323462947500
instance2.object_id ⇛ 70323462930480
Foo.object_id ⇛ 70323462538720
```

#### 4.2.2. What method will be called?

```
class Foo
  def initialize a
    @a = a
  end

  def get_a
    @a
  end
end

class FooExt
  def initialize a, b
    super a
    @b = b
  end

  def get_a
    puts "FooExt get_a: #{@a}"
  end

  def get_b
    puts "FooExt get_b: #{@b}"
  end
end

foo = Foo.new 3
foo.get_a
⇛ 3
foo.get_b
⇛ NameError
foo_ext = FooExt.new 3, 4
foo_ext.get_a
⇛ "FooExt get_a: 3"
foo_ext.get_b
⇛ 4
```

#### 4.2.3. Inheritance chain and `method_missing`

- For above example:

```
FooExt => Foo => Object => Kernel => BasicObject
```

- Get all ancestors of a class

```
Foo.ancestors
⇛ [Foo, Object, Kernel, BasicObject]
FooExt.ancestors
⇛ [FooExt, Foo, Object, Kernel, BasicObject]
```

- Check a class is interiting an other class

```
Foo < BasicObject
⇛ true
Foo < FooExt
⇛ false
```

- `instance_methods` and `instance_variables`

```
Foo.instance_methods(false)
⇛ [:method1]
FooExt.instance_methods(false)
⇛ [:method2]
Foo.instance_variables
⇛ []
FooExt.instance_variables
⇛ []
foo1.instance_variables
⇛ [:@a]
fooExt.instance_variables
⇛ [:@b, :@a]
```

- `alias`

```
alias new_method_name old_method_name
alias new_global_var_name old_global_var_name
```

- `undef`

```
undef method_name
undef method1_name, method2_name
```

Sample:

```
class Test
  def method1; end

  def method2; end

  alias :method3 :method2
  undef :method2
end

Test.instance_methods(false)
⇛ [:method1, :method3]

class Test2
  def method1; end

  def method2; end

  alias :method3 :method2
  undef :method3
end

Test2.instance_methods(false)
⇛ [:method1, :method2]
```

- Override `method_missing` method

```
class Test
  def method_missing m, *args
    puts "called: Test##{m}"
    super
  end
end

Test.new.do_not_existed_method
⇛ called: Test#do_not_existed_method
NoMethodError: undefined method `do_not_existed_method' for #<Test:0x007feaea84dc08>
```

#### 4.2.4. Open class

- All classes in Ruby are open. This means you can define new method for any other class.

```
class Test
  def method1
    "method1"
  end
end

Test.object_id
⇛ 70119510391780

t1 = Test.new
t1.method1
⇛ "method1"
t1.method2
⇛ NameError

class Test
  def method2
    "method2"
  end
end

Test.object_id
⇛ 70119510391780

t2 = Test.new
t2.method1
⇛ "method1"
t2.method2
⇛ "method2"
t1.method2
⇛ "method2"
```

★ Attention: There is attention when you reopen a class that is extending an other class.

```
class A; end
class B; end
class C < B
end

①
class C < A
end
⇛ TypeError
②
class C < B
end
⇛ OK
③
class C
end
⇛ OK
```

### 4.3. Mix-in (Modules)
#### 4.3.1. Module definition and include

- Some attentions about module:
  - Can not create instance for module
  - Can not inherit
  - Can be included in class or other module

```
module A; end
A.new ⇛ NoMethodError

module B < A
end
⇛ SyntaxError
```

- Module definition syntax

```
module <<module_name>>
  def method_name
  end
end
```

- Module is not inheritable
⇛ Ancestor of it contains only it.

```
module TestModule
  def method1
    "method1"
  end
end

TestModule.ancestors
⇛ [TestModule]

TestModule.instance_methods
⇛ [:method1]
```

- Include module to a class

```
class B
  include TestModule
end

b = B.new
b.method1
⇛ "method1"
B.instance_methods(false)
⇛ [] # :method1 is not defined inside of B ⇛ do not appear in here
```

- Check all modules a class is including

```
module A; end
module B; end

class Test1
  include A
end

class Test2 < Test1
  include B
end

Test1.included_modules
⇛ [A, Kernel]
Test2.included_modules
⇛ [A, B, Kernel]
```

#### 4.3.2. Load flow when include module

```
module TestModule
  def method1
    "TestModule#method1"
  end
end

class A
  include TestModule

  def method1
    "A#method1"
  end
end

class B
  def method1
    "B#method1"
  end

  include TestModule
end

A.new.method1 ⇛ "A#method1"
B.new.method1 ⇛ "B#method1"
```

### 4.4. Singleton class
#### 4.4.1. Class method

- Definition

```
class A; end
def A.class_method_1
  "class_method_1"
end

A.class_method_1
⇛ "class_method_1"

A.new.class_method_1
⇛ NoMethodError
```

- Define method for only 1 instance

```
class Foo; end

foo1 = Foo.new
foo2 = Foo.new

foo1.object_id ⇛ 70175903036120
foo1.class ⇛ Foo

def foo1.method_1
  "method_1"
end

foo1.object_id ⇛ 70175903036120
foo1.class ⇛ Foo
foo1.class.instance_methods　⇛ []

foo1.method_1
⇛ "method_1"
foo2.method_1
⇛ NoMethodError
```

When define method for only instance `foo1`,
system will create an singleton class like:

```
class #foo1 < Foo
  def method_1
  end
end
```

and `foo1` is setted as the instance of class `#foo1`

#### 4.4.2. Singleton class
- Definition sample

```
①
class Foo; end

foo1 = Foo.new
singleton_class = class << foo1
  self
end

singleton_class
⇛ #<Class:#<Foo:0x007ff2fd810c48>>

②
class Foo; end

foo2 = Foo.new
class << foo2
  def method1
    "method1"
  end
end

foo2.method1 ⇛ "method1"
```

- Define new method inside an other method

```
class A
  def method1
    def method2
    end
  end
end

A.instance_methods ⇛ [:method1]
A.new.method1
A.instance_methods ⇛ [:method1, :method2]
```

#### 4.4.3. `extend`

- Sample of using mix-in in singleton class

```
module TestModule
  def method1; "method1"; end
end
class Foo; end
foo1 = Foo.new
class << foo1
  include TestModule
end

foo1.method1 ⇛ "method1"
```

- Use `extend`

```
module TestModule
  def method1; "method1"; end
end

class Foo; end
foo1 = Foo.new
foo1.extend(TestModule)
foo1.method1 ⇛ "method1"
```