Road to Ruby Silver (Part 4)

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)

[Part 3](https://qiita.com/ThuBM/items/af4fbe91f4db3ec5e286)

# Chapter 4: Object orientation (continue)
### 4.5. Class Method
#### 4.5.1. Class `Class`

① Example about using `class` method

```
class Foo; end
foo_class = Foo.class
→ Class
```


② Create an instance of class `Class`

```
2.1.
Foo = Class.new

Foo.new.class
→ Foo

2.2.
FooExt = Class.new(Foo) do      # → Foo is super class
  def initialize b              # → Init method of FooExt class
    super()
    @b = b
  end

  def method_2 c                # → Instance method method_2
    @b + c
  end
end
```

#### 4.5.2. Define a class method

①

```
class Class
  def new_method
    puts "This method will be applied as a class method of any class"
  end
end

class Foo; end
Foo.new_method
→ This method will be applied as a class method of any class
String.new_method
→ This method will be applied as a class method of any class
```

②

```
class Foo
  def Foo.new_method
    puts "This is Foo.new_method"
  end
end

Foo.new_method
→ This is Foo.new_method
```

③

```
class Foo
  def self.new_method
    puts "New method of Foo"
  end
end

Foo.new_method
→ "New method of Foo"
```

④

```
class Foo
  class << self
    def new_method
      puts "new_method"
    end
  end
end

Foo.new_method
→ "new_method"
```

#### 4.5.3. `include` and `extend`

```
2.3.0 :005 >   class C4
2.3.0 :006?>     include M4
2.3.0 :007?>     extend M4
2.3.0 :008?>   end
 => C4
2.3.0 :009 > C4.method1
 => 1
2.3.0 :010 > C4.new.method1
 => 1
```

### 4.6. Scope of methods, attributes
#### Definition
- public: can called in every where   → this is default
- protected: can called only inside object, instance of sub class
- private: can called only inside object

```
class Bar1
  def public_method1; 1; end
  public
  def public_method2; 2; end

  protected
  def protected_method1; 1; end
  def protected_method2; 2; end

  private
  def private_method1; 1; end
end

Bar1.new.public_method1  → 1
Bar1.new.public_method2  → 2
Bar1.new.protected_method1 → NoMethodError
Bar1.new.protected_method2 → NoMethodError
Bar1.new.private_method1 → NoMethodError
```

- We can change the scope of method or attributes by using key word: `public, private, protected` like below:

```
class Bar1
  def public_method1; 1; end
  public
  def public_method2; 2; end

  protected
  def protected_method1; 1; end
  def protected_method2; 2; end

  private
  def private_method1; 1; end
end

class Bar2 < Bar1
  public :private_method1
end

Bar2.new.private_method1 → 1
```

★ NOTE: Can not use `self` for calling a private method inside object

```
class Bar2
  def public_method1
    private_method1
  end

  def public_method2
    self.private_method1
  end

  private
  def private_method1; 1; end
end

b = Bar2.new
b.public_method1 → 1
b.public_method2 → NoMethodError: private method `private_method1' called for #<Bar2:0x007fc3ca806a70>
```

#### 4.6.2. `Kernel` module and function
- `Object` class is including `Kernel` module

```
2.3.0 :052 > Object.included_modules
 => [Kernel]
```
- In `Kernel`, there are some methods are defined, sample: `p, puts`. You can check all methods of `Kernel` module by run: `Kernel.methods`
- Almost methods of `Kernel` module are private, so we can not call them with `self`

```
puts "a" → this is ok
self.puts "a" → NoMethodError
```

NOTE: When you defined a method inside `irb`, that method will be a method of `Object` class.
This means all other classes (what are an instance of `Object`) can use this method.

```
2.3.0 :056 > self
 => main
2.3.0 :057 > def my_func; 1; end
 => :my_func
2.3.0 :058 > Integer.my_func
 => 1
2.3.0 :059 > String.my_func
 => 1
2.3.0 :060 > "a".my_func
 => 1
```

### 4.7. Variables and Constants
#### 4.7.1. Local variables and global variables

- Local variables

```
2.3.0 :061 > v1 = 1
 => 1
2.3.0 :062 > class Bar
2.3.0 :063?>     p v1
2.3.0 :064?>   end
NameError: undefined local variable or method `v1' for Bar:Class
```

→ In above sample, we can not define class `Bar` because when defining it, we call variable `v1`.
`v1` is defined in main but it can not be used inside other scope.

Other sample:

```
v1 = 1
class Bar2
  v2 = 2
  def method1; v1; end
  def method2; v2; end
end
b = Bar2.new
b.method1 → NoMethodError: undefined local variable or method `v1' for #<Bar2:0x007fc3ca1ea268>
b.method2 → NoMethodError: undefined local variable or method `v2' for #<Bar2:0x007fc3ca1ea268>
```

- Global variables: add `$` as the first character when define variable name

```
$v1 = 1
class Bar2
  $v2 = 2
  def method1; $v1; end
  def method2; $v2; end
end
b = Bar2.new
b.method1 → 1
b.method2 → 2
```

#### 4.7.2. Instance variable
- Use prefix `@` when define variable name
- Default is `nil` when variable is not initialized

```
@v1 = 1
class Bar
  @v2 = 2
  def method1; @v1; end
  def method2; @v2; end
end
b = Bar.new
b.method1 → nil
b.method2 → nil


class Bar2
  def initialize; @v3 = 3; end

  def method3; @v3; end
end
Bar2.new.method3 → 3
```

- Auto generate `getter`, `setter` methods for instance variable by using `attr_reader, attr_writer, attr_accessor, attr`

| Keyword        | Meaning           |
| ------------- |:-------------:|
| attr_reader      | Generate only setter method |
| attr_writer      | Generate only getter method |
| attr_accessor | Generate both setter and getter  |
| attr | Generate only getter  |


```
class B
  attr :var

  def initialize
    @var = 2
  end
end

b = B.new
b.var = 2
b.var
```

#### 4.7.3. Class variables
- Use prefix `@@` when define variable name
- Raise error when called uninitizalized variable

```
class Bar
  @@v1 = 1
  def v1; @@v1; end
  def v2; @@v2; end
end
b = Bar.new
b.v1 → 1
b.v2 → NameError

class Bar2 < Bar
  def new_v1; @@v1; end
end
b2 = Bar2.new
b2.new_v1 → 1
```

### 4.7.4. Nested scope of constants

- In previous part, we investigated about `Constant`.

```
A = 1
p A → 1
A = 2 → warning
p A → 2
```

- Constant can be not defined inside method

```
def func
  B = 1
end
→ SyntaxError: dynamic constant assignment
```

- Nested scope of constants
  - Normaly

```
module B; end
B::A = 1 → Ok
B::A::A = 1 → TypeError
```
  - Modulized

```
module M
  A = 1
  class B
    A = 2
  end
  class C
  end
end

M::A → 1
M::B::A → 2
M.constants
→ [:A, :B, :C]
M::B.constants
→ [:A]
```

- `const_missing`

```
module M
  def self.const_missing(id)
    id
  end
end

M::UNEXISTED_CONSTANT
→ :UNEXISTED_CONSTANT
```