【Ruby】初学者向け－メソッドの基本について②

本記事ではメソッド周辺・オブジェクト周辺の文法についてまとめていきます。

まずメソッドについておさらいをします。

**メソッド**
…Rubyにおけるメソッドとは、特定の動作や処理を定義した一連のコードをまとめたもの。
　メソッドを使用することで、コードの再利用ができ、可読性・保守性を向上させることができる。
 （→使いたい処理を部品化して簡単に使いまわしができるようにするよ。）

**メソッドの特徴**
・定義
　…defを使用してメソッドを定義する
 
・呼び出し
　…定義したメソッド名をコード内で記載して呼び出す

・引数
　…メソッドとその呼び出し元の間でやり取りされる、処理に必要な値
     　　　　　　仮引数：メソッド内で定義する仮の引数
           　　　　　　　　　　（→数学でいうところのx、yとかのイメージ）
     　　　　　　実引数：メソッドの呼び出しもとで設定する引数
           　　　　　　　　　　（→数学でいうところの「代入する値」のイメージ）
                     
・戻り値
…メソッド内の最後の処理によって導き出された結果の値
　（→数学でいうところの「=」の右側の値のイメージ）

目次
・Procオブジェクトについて
・yieldについて
・クラス定義について（イニシャライザ・アクセサリ）


<h1>Procオブジェクトについて</h1>

**Procオブジェクト**
…do ~ endや中括弧「{}」を用いて処理のブロックを作成したオブジェクトのこと
  Procクラスのコンストラクタに、ブロックを指定することで作成できる

**コンストラクタ**
…クラスのインスタンス（オブジェクト）を生成する際に自動的に呼び出される特別なメソッドのこと
　Rubyではコンストラクタはinitializeという名前のメソッドで定義される
 　コンストラクタは、オブジェクトが生成された際に必要な初期設定や初期化処理を行う


```ruby:example_1.rb
    proc = Proc.new{|x| p x}
    proc.call(1)
    =>1
```

（例）数値をカウントする際、初期値をプログラムの最初に決定しておいて、後で値を操作したいとき

```ruby:example_2.rb
    def get_counter start
        # Procオブジェクト作成。引数startには現在の値を設定する
        Proc.new{|up| start += up}
    end

    # 初期値として1を設定。count_upはProcオブジェクトを参照する
    count_up = get_counter(1)

    # ~~~~~~その他たくさんの長い処理~~~~~~

    # count_upの参照するブロックを実行
    # procで作成した処理はcallメソッドで呼び出すことができる
    count_up.call(1)
    => 2

    # ~~~~~~その他たくさんの長い処理~~~~~~
    
    count_up.call(3)
    => 5
    
```

また、procを用いるとprocの外にある変数を参照することができるので便利
```ruby:example_3.rb
    test = :test1
    => :test1

    proc = Proc.new {puts test1}
    => #<Proc:~~~~~~~~~~~~~~~(pry):~>

    proc.call
    => test1

    # 変数の中身をtest2に変更
    test = :test2
    =>:test2

    # 変更後の変数の中身が表示される
    proc.call
    test2
    =>nil
```

**注意事項**
Procオブジェクトの外で指定した変数を、Procで呼び出す場合は
先に変数を定義しておかなければエラーが発生する

<h1>yieldについて</h1>

yieldを用いるためにまずスコープという概念から説明します。

**スコープ**
…変数やメソッドが有効でアクセスできる範囲のこと。
　スコープによって、変数やメソッドがどこから参照・どこで使用できるかが決まる。
　for文、if文、while文ではスコープは作成されない。

**ブロックの基本**
…ブロックはメソッドを呼び出すときのみ記述でき、
　メソッドの内部でyieldという式を使用することで　ブロックの内部で記述した処理を
 　呼び出すことができる。
 
**yield**
…メソッド内でブロックを実行するためのもの。
　メソッドを呼び出す際にブロックが渡されていると、そのブロックをyieldで呼び出せる。
 　また、スコープを作成することができる。繰り返し処理を簡潔に記載するのに適している。

```ruby:example_4.rb
    def test x
        x + yield # ブロックの実行結果を取得（ここでは２）
    end
    p test(1){ 2 }
    => 3 # ブロック付きメソッドtestの呼び出し
```


また、下記コードでスコープ作成の流れを確認すると
yieldとは別のブロック内で代入された値は参照できないため、NameErrorが発生している

```ruby:example_5.rb
    # スコープが作成されている
    def test y 
        y + yield
    end

    # ブロック内で代入された値なので、変数xはブロックの外から参照できない
    # ブロック内で初期化された変数はブロックの処理が終了すると消滅する
    test(1) do
        x = 2
    end

    p x # NameErrorになる
```

<h1>クラス定義について（イニシャライザ・アクセサリ）</h1>

**クラス定義**
…オブジェクト指向プログラミングの基本概念。
　クラスを使用して関連するデータ（属性）や動作（メソッド）をまとめ、
 　オブジェクトを生成するための設計を行うこと

**クラス定義の決まり**
…クラス名の頭文字は大文字(→小文字から始めると構文エラーになる)

**クラス定義の例**
```ruby:example_6.rb
    class <クラス名>
    end
```

```ruby:example_7.rb
    class Test
        # initializeメソッドは初期化のときに実行されるメソッド
        def initialize(a)
            # インスタンス変数を使用することで、値がインスタンスに保持される
            @a = a
        end
        def method1
            @a
        end
    end
    # newメソッドの引数はそのまま初期化（initialize）メソッドに渡されるため、
    # @aは異なる値で出力される
    test1 = Test.new(1)
    test2 = Test.new(2)
    p foo1.method1 => 1
    p foo2.method1 => 2
```

クラスはオブジェクトであるため、メソッドの実行や変数への再代入が可能
```ruby:example_8.rb
    a = Test # Fooの参照先を変数aに代入
    a.new(1) # Fooを扱うのと同じように操作できる
    Foo = 1  # 定数なので警告が出る
```

**アクセッサ**
…クラス内で定義されたインスタンス変数に対して、
　ゲッター（読み取り）やセッター（書き込み）のメソッドを簡単に作成するための仕組み。
 　これを利用することで、インスタンス変数の値を外部から、参照・変更できる

（例）アクセッサを都度定義する例
```ruby:example_9.rb
    class Test2
        def example
            return @example
        end
        def example=(value) @exampleに対するsetter
            @example = value
        end
        def method; @v3: end
    end

    test2 = Test2.new
    test2.example = 3
    p test2.example
    => 3
    p test2.method
    => 3
```

上記ではアクセッサを都度定義していますが、
アクセッサの生成を行うクラスメソッドにより、より簡潔に記載することができます。
```ruby:example_10.rb
    attr_reader     # getterメソッドの生成を行う
    attr_writer     # setterメソッドの生成を行う
    attr_accessor   # getterとsetterメソッドの生成を行う
```

アクセッサの生成を行うクラスメソッドを使用した場合、コードは以下のようになります。
```ruby:example_11.rb
    class Test2
        # getterとsetterメソッドの生成を行う
        attr_accesser :example
        def method; @example; end
    end
    test2 = Test2.new
    test2.example = 3
    
    # 下記はレシーバとなる。インスタンス変数を操作するためmethodから参照が行うことができる
    p test2.example
    => 3
    p test2.method
    => 3
```

インスタンス変数は継承されないが、メソッドは継承されるため
サブクラスからメソッドを経由してスーパークラスのインスタンス変数にアクセスすることができます。
```ruby:example_12.rb
    class TestSub < Test2
    end
    
    testsub = TestSub.new
    testsub.example = 4
    testsub.example
    => 4
```