Ruby.学習その9

#### 投稿目的
- 個人の学習目的で投稿していきます。
- Rubyの入門を読みながら自分なりの思考で記述しています。

#### 参考資料

[ゼロからわかる Ruby 超入門 (かんたんIT基礎講座)](https://www.amazon.co.jp/ゼロからわかる-Ruby-超入門-かんたんIT基礎講座-五十嵐/dp/4297101238/ref=sr_1_3?ie=UTF8&qid=1549614126&sr=8-3&keywords=ruby+入門)

## クラスの高度な話

### インスタンス変数を簡略的に定義
- 下記が簡略的ではない書き方になります。

```ruby
class Greeting # Greetingクラス定義
    def morning # morningメソッド定義
        @morning # morningインスタンス変数定義
    end
    def morning=(text) # morning=メソッドに引数1つ定義
        @morning = text # 受け取った引数をインスタンス変数に代入
    end
end

greeting = Greeting.new # インスタンス作成
greeting.morning = "おはようございます" # morning=メソッドを呼び出し
puts greeting.morning # morningメソッドを呼び出し 
# 結果: おはようございます
```

- 下記のように記述することでインスタンス変数を簡略的にすることが可能です。

```ruby
attr_reader :インスタンス変数名
```

#### attr_readerメソッド
- 上記のGreetingクラスに追加すると下記のようになります。
- attr_readerメソッドは同名のインスランス変数を戻り値とするメソッドを定義します。
    - @を記述せずに:に繋げて記述します。

```ruby
class Greeting
    attr_reader :morning # 戻り値が同名のインスタンス変数のメソッドを定義
    def morning=(text)
        @morning = text
    end
end

greeting = Greeting.new
greeting.morning = "おはよう"
puts greeting.morning
# 結果: おはよう
```

#### attr_writerメソッド
- attr_writerメソッドを利用することで引数を受け取って同名のインスタンス変数に代入するメソッドを簡略的に定義することができます。

```ruby
class Greeting
    attr_reader :morning 
    attr_writer :morning # 同名のインスタンス変数に引数を受け取り代入するメソッドを定義
end

greeting = Greeting.new
greeting.morning = "おはよう！！"
puts greeting.morning
# 結果: おはよう！！
```

#### attr_accessorメソッド
- さらに上記の2つはセットで利用することが多いのでその2つの機能を持つメソッドがattr_accessorメソッドです。

```ruby
class Greeting
    # 同名のインスタンス変数に代入、戻り値が同名のインスタンス変数
    attr_accessor :morning 
end

greeting = Greeting.new
greeting.morning = "Good morning"
puts greeting.morning
# 結果: Good morning
```

## self
- selfは自分自身(レシーバ)を指している。
    - レシーバとはメソッドを呼び出せるオブジェクト.
- メソッド内でselfを指定すると返ってくるオブジェクトはインスタンスメソッドならクラスのインスタンス、クラスメソッドならクラスのように自分自身を指している。

##### インスタンスメソッド

```ruby
class Greeting
    def me # インスタンスメソッドを定義
        self.morning # インスタンスメソッドなのでクラスのインスタンスを指している
    end
    def morning # インスタンスメソッドを定義
        puts "おはよう"
    end
end

greeting = Greeting.new
greeting.me # 結果: おはよう
```

##### クラスメソッド
- クラスメソッドの場合はメソッド名の前にselfを付ける必要がある。

```ruby
class Greeting
    def self.me # クラスメソッドを定義
        self.morning # クラスメソッドなのでクラス自身を指している
    end
    def self.morning #クラスメソッドを定義
        puts "おはよう"
    end
end

Greeting.me # 結果: おはよう
```

- 自分自身のメソッドを呼び出すのにself(レシーバ)と付けるのは手間なのでself(レシーバ)指定を省略することができる。

```ruby
class Greeting
    def me
        morning 
    end
    def morning 
        puts "おはよう"
    end
end

greeting = Greeting.new
greeting.me # 結果: おはよう
```

## インスタンスメソッドとクラスメソッドが持つインスタンス変数は別物
- インスタンス変数の持ち主はselfが指すオブジェクトです。
    - クラスにインスタンスとクラスはオブジェクトが違うのでインスタンス変数の持ち主も別々になります。

```ruby
class Greeting
    def morning # インスタンスメソッドを定義
        @morning = "おはよう" #　インスタンスメソッドのインスタンス変数に代入
    end
    def self.morning # クラスメソッドを定義
        @morning # クラスメソッドのインスタンス変数が戻り値で返る
    end
end
        
greeting = Greeting.new
greeting.morning # インスタンスメソッドのmorningを呼び出し
p Greeting.morning # クラスメソッドのmorningを呼び出し 
# 結果: nil
```

## クラス変数
- インスタンス変数、ローカル変数の他にクラス変数が存在します。
    - クラス変数は変数名の前に@@を付けることで定義できます。
    - クラス変数はクラスを継承した先でも利用することができる。

```ruby
class GreetingA
    @@morning = "おはよう" # クラス変数に代入
    def morning
        @@morning 
    end
end

greetingA = GreetingA.new
puts greetingA.morning # 結果: おはよう

class GreetingB < GreetingA # GreetingAのクラスをGreetingBに継承
    def morning
        @@morning # greetingAのクラス変数を利用
    end
end

greetingB = GreetingB.new
puts greetingB.morning # 結果: おはよう
```

## 文字列を調べる正規表現

### 文字列を含むかを判定
- match?メソッドを利用することで特定の文字列を含んでいるかが判定できます。
- match?の引数にパターンを渡すことで含むかを判定できます。

```ruby
"文字列".match?(/正規表現パターン/)
```

- /で囲むことで正規表現(Regexp)オブジェクトとなりこれをパターンと呼びます。 

```ruby
/正規表現パターン/
```

- 下記はフルーツと文字が含むものがtrueとなります。

```ruby
p "グレープフルーツ".match?(/フルーツ/) # true
p "りんご".match?(/フルーツ/) # false
p "ドラゴンフルーツ".match?(/フルーツ/) # true
```

#### その他の正規表現 

- \zを加えることで末尾に指定された文字が含まれているかを判定します。
- \Aを加えることで先頭に指定された文字が含まれているかを判定します。

```ruby
p "グレープフルーツ".match?(/フルーツ\z/) # true
p "フルーツレモン".match?(/\Aフルーツ/) # true
```

- よく使われる正規表現.
- []で囲むと中の１文字どれかが含まれているかを判定します。

```ruby
/[abc]/　# aかbかcが含まれていればtrue
```

- []の中に範囲指定で記述して判定することもできます。
- アルファベットの大文字か小文字、数字のいずれか１文字が含まれているかを判定します。

```ruby
p "りんごv".match?(/[A-Za-z0-9]/) # true
p "りんご5".match?(/[A-Za-z0-9]/) # true
```
- .は任意の１文字。

```ruby
p "a0b".match?(/a.b/) # true
p "agb".match?(/a.b/) # true
```

- *は前の文字が0回以上繰り返すかどうかを判定します。

```ruby
p "abc".match?(/ab*c/) # true
p "c".match?(/ab*c/) # false
p "aaac".match?(/ab*c/) # true
```

- +は前の文字が1回以上繰り返すかを判定します。

```ruby
p "ac".match?(/ab+c/) # false
p "abc".match?(/ab+c/) # true
p "bbc".match?(/ab+c/) # false
```

#### 条件と一致する文字を置換
- gsubメソッドを利用することで文字の置換をすることができます。
- 第1引数が置換元で第2引数が置換先になります。

```ruby
p "フルーツオレ".gsub("フルーツ", "カフェ") # カフェオレ
p "グレープフルーツサワー".gsub("サワー", "ジュース") # グレープフルーツジュース
p "フルーツフルーツ".gsub(/\Aフルーツ/, "ミックス") # フルーツミックス
```

#### 正規表現とif文
- 正規表現を利用してif文で分岐することができます。
- 下記のプログラムはフルーツと含まれているものだけを表示する条件です。

```ruby
["バナナジュース", "グレープフルーツサワー", "フルーツオレ"].each do |drink|
    puts drink if drink.match?(/フルーツ/) 
end
# 結果: グレープフルーツサワー フルーツオレ 
```

## ブロックの高度な話
- eachメソッドなどを使用する際にdoからendをブロックと呼びます。
    - ブロックとはプログラムのかたまりをメソッドへと渡すことができる仕組みです。
    - ブロックは引数と似ています引数はオブジェクトを渡してブロックは処理のかたまりを渡すイメージです。
    - ブロックは1つしか渡すことができません。
     
#### 渡されたブロックを実行 
- block_given?メソッドを利用することでブロックが渡されたどうかを判別してくれます。

```ruby
def foo
    p block_given
end

foo #=> false

foo do
end #=> true
```

- 渡されたブロックを実行するにはyieldを利用します。

```ruby
def dice
    if block_given? # ブロックの有無を判別
        puts "run block" 
        yield # 渡されたブロックを実行
    else    # ブロックが渡されていない場合の処理
        puts "normal dice" 
        puts [1, 2, 3 , 4, 5, 6].sample 
    end
end

dice # 結果: ブロックを渡していないので1~6をランラムで表示

dice do # ブロックが渡されたのでブロックの処理を実行
    puts [4, 5, 6].sample # 結果: 4~6をランダムに表示
end
```

#### 渡されたブロックを引数で受け取る
- 引数にブロックを渡す際は変数名の前に&を付けることで受け取ることができます。
- callメソッドで変数に代入されたブロックを実行することができる。
- 変数に代入されているブロックをprocオブジェクトと呼びます、プログラムの処理もオブジェクトとして扱うことができます。

```ruby
def foo(&greeting) # &でブロックを受け取る
    greeting.call #  代入されたブロックを実行
end

foo do
    puts "おはようございます！" 
end
# 結果: おはようございます！
```

## ゼロからわかるRuby超入門の教本は終了です。