(みかん) accessorを定義してみよう

せっかく書いたけど、途中で秋田。

はじめに言っておくけど、特別な理由がない限りはRuby標準の`attr_xxxxx`メソッドを使った方が良い。

## ゴール

`attr_reader`, `attr_writer`, `attr_accessor`を自分で実装してみる。

つまり、次のようなコードが動作するようになる。

```rb
class Car < MyObject
  my_attr_reader :name
  my_attr_writer :color
  my_attr_accessor :driver

  def initialize (name, color, driver)
    @name   = name
    @color  = color
    @driver = driver
  end

  def ColoR
    @color
  end
end

my_car = Car.new('TwinDrill', :red, 'Teto')
p my_car.name   # "TwinDrill"
p my_car.ColoR  # :red
p my_car.driver # "Teto"

puts

my_car.driver = "Miku"
my_car.color  = :blue

p my_car.driver # "Miku"
p my_car.ColoR  # :blue
```
## attrよ、唐突に出てくるお前は何者だ

ふつうのクラス定義はこんな感じ。メソッド定義がある。

```rb
class Counter
  def initialize
    @v = 0
  end

  def count (n)
    @v += n
  end
end
```

しかし、`attr_reader`,`attr_writer`,`attr_accessor`、メソッド定義の外に出てくるお前らは何者だ。

```rb
class Counter
  attr_reader :v
```

### クラス定義の中には

任意の式が書ける。つまり、

```rb
class Hoge
  p 1 + 2 + 3
end
```

↑この式は合法だ。クラスを定義したときに、一度だけ`6`と出力される。ただ、意味がないので普通は書かない。

せっかくなので次のコードも試してみよう。

```rb
class Hoge
  p self
end
```

すると、`Hoge`と出力されるだろう。どうやら`class Hoge 〜 end`で囲まれた間の主役(= `self`)は`Hoge`クラス本人のようだ。

> #### 補充課題
>
> 以下のコードの実行結果はどうなるか。
>
> ```rb
> class Hoge
>   fuga = "Fuga!"
> end
>
> puts Hoge.fuga
> ```

## 特異クラスの世界に入門してきたといふわけだ

Rubyの世界ではメソッドはクラスに定義するものだと思ってないだろうか。否、そうとも限らない。

```rb
class Dog
  def sound; "Bow"; end
end

dog = Dog.new
inu = Dog.new

# inuオブジェクトにメソッドを定義する
class << inu
  def 鳴き声; "わん"; end
end

puts dog.sound #=> Bow
puts inu.鳴き声 #=> わん


puts dog.鳴き声
# NoMethodError: undefined method `鳴き声' for #<Dog:0x007fab2b69b210>
```

`鳴き声`はれっきとしたメソッドだが、`dog`オブジェクトにはなく、`inu`オブジェクトだけが持つ特異な性質だ。

ここで心に留めておきたい。`Dog`の`sound`メソッドを呼び出すには`Dog.sound`ではなく`Dog.new.sound`と書く必要がある。

## クラスメソッドって何だ

クラスのメソッドのことですよ(核心)

ふつうのメソッドは、クラスをインスタンス化したあとに呼び出される。

```rb
class Dog
  def sound; "Bow"; end
end

dog = Dog.new
puts dog.sound # Bow
```

では、`Dog.sound`と書くことで呼び出されるメソッドを定義するにはどうすれば良いか? そのひとつに特異クラスを利用することができる。


> #### 課題
>
> 特異クラスを利用してクラスメソッドを定義せよ。

## メソッドってなんだ

はじめに用語について整理しておきたい。

```rb
Dog           # ← これはクラスだ。実はオブジェクトでもある
dog = Dog.new # ← インスタンスの初期化
# ↑ これがインスタンスオブジェクト


# オブジェクトとメソッド名をつなげて書くことでメソッド呼び出しになる

  dog.sound # ←メソッド名 ()はつけなくてもいい
#  ↑ 
# レシーバ (受取人)
```

ほかのプログラミング言語ではメソッドのことを「メッセージ」と呼ぶことがある。つまり、犬に「鳴け」とメッセージを送りつけることで犬は **Bow** と返答するといった具合だ。

ここで心に留めてほしいのは、メソッド(メッセージ)には**かならず**受取人が存在することだ。

### 俺だよ、オレオレ

```rb
class Dog
  def sound; "Bow" ; end
  def 鳴く;  sound ; end
  #          ↑ 唐突に出てきたお前は誰だよ
end
```

この`sound`は変数などではない。れっきとしたメソッド呼び出しだ。コード中にメソッド名を書くと、それはメソッド呼び出しになる。

しかし、これは「オブジェクトとメソッド名をつなげて書くことでメソッド呼び出しになる」に反してるではないか。受取人は誰だよ。

…

俺だよ、オレオレ。主役なんだから名乗るまでもないだろ?

### privateは大事、コソコソと隠れて生きたい

## インスタンスの世界

### instance_eval

### instance_variable_get, instance_variable_set

# 書くの飽きた

## 解答

```rb
class MyObject
  class << self
    private def my_attr_writer (name)
      self.instance_eval do
        define_method("#{name}=") do |value|
          instance_variable_set "@#{name}", value
        end
      end
    end

    private def my_attr_reader (name)
      self.instance_eval do
        define_method(name) do
          instance_variable_get "@#{name}"
        end
      end
    end

    private def my_attr_accessor (name)
      self.instance_eval do
        my_attr_reader name
        my_attr_writer name
      end
    end
  end
end
```