[Ruby]Procを使うべき場面、メリットとは

# はじめに
*Proc*は他言語を学んできた者でも*Ruby*ではじめてでてきた概念であるため、理解するのに苦労する。
「Procとは何か？」については大体理解できたが、それを使用すべき場面や使用することによるメリットというのを実感するために、**Procで実装してあるものをProc無しでの実装**を試みてみる。
# Procとは
Rubyで頻繁に使用するブロックは色んな場面で持ち出して利用していきたいが、ブロックはオブジェクトではない。
オブジェクト指向であるRubyはオブジェクトとして捉えられると何かと便利であるので、ブロックもオブジェクト化したい。

そこで登場するのがProcであり、**Procは「ブロックをオブジェクト化」したもの**である。
このProcの機能を活かした、Procを用いた実装例から深く学んでいく。
#Procを使用した実装例
文字列をエフェクトをする仕組みをProcを使用して実装する。

今回実装する文字のエフェクトは３種類。
・リバース...逆順　例）'apple',reverse=>'elppa'
・エコー...残響化　例）'apple',echo(2)=>'aappppllee'
・ラウド...大声　　例）'apple',loud(3)=>'APPLE!!!'

そして、これらのエフェクトを混合させる。
(以下、このことをWordSynthと表記する)
echo(2)→loud(3)→reverse => '!!!EELLPPPPAA'

この仕組をまずはProcを使用して作成する。
#Procを使用して実装
まずはEffectsに関しての実装。
メソッドの中でProcを作成している。

```ruby:./lib/effects.rb
module Effects
  # reverseエフェクトについて関してのメソッド
  def self.reverse
    proc do |words|
      words.split(' ').map(&:reverse).join(' ')
    end
  end
  # echoエフェクトについて関してのメソッド
  def self.echo(rate)
    proc do |words|
      words.chars.map{|c| c==' ' ?  c:c*rate}.join
    end
  end
  # loudエフェクトについて関してのメソッド
  def self.loud(level)
    proc do |words|
      words.split(' ').map {|word| word.upcase + '!'*level }.join(' ')
    end
  end
end
```

WordSynthに関しての実装。
Effectsで実装したProcをcall()で呼び出す。

```ruby:./lib/word_synth.rb
class WordSynth
  def initialize
    @effects =[]
  end
#effectを配列に加える
  def add_effect(effect)
    @effects << effect
  end
#配列に格納されたeffectを順々に実施
  def play(original_words)
    @effects.inject(original_words) do |words,effect|
      effect.call(words)
    end
  end
end
```
Effects,WordSynthに関して実行させる

```ruby:./list/word_synth_execute.rb
require './lib/effects'
require './lib/word_synth'

# Effectsに関して
effect1 = Effects.reverse
effect2 = Effects.echo(2)
effect3 = Effects.loud(3)
puts effect1.call('Ruby is fun!')
puts effect2.call('Ruby is fun!')
puts effect3.call('Ruby is fun!')

# WordSynthに関して
synth = WordSynth.new
synth.add_effect(Effects.echo(2))
synth.add_effect(Effects.loud(3))
synth.add_effect(Effects.reverse)
puts synth.play('Ruby is fun!')
```

実行結果

```
ybuR si !nuf
RRuubbyy iiss ffuunn!!
RUBY!!! IS!!! FUN!!!!
!!!YYBBUURR !!!SSII !!!!!NNUUFF
```
Procを使用することによって、WordSynthを作成することはできた。
なんとなくProcを使用すると都合良く作成できた感触はある。
しかし、イマイチその威力がわかっていない。
Procを使わずに突き進もうとしたらどうなっていたのか検証してみた。
#Procを使用せずに実装を試みる
まずはEffecsの実装。
Procの引数で与えていた(words)をどうするか、、

```ruby:effects_test.rb
module Effects
  def self.reverse(words)
    words.split(' ').map(&:reverse).join(' ')
  end
  def self.echo(words,rate)
    words.chars.map{|c| c==' ' ?  c:c*rate}.join
  end
  def self.loud(words,level)
    words.split(' ').map {|word| word.upcase + '!'*level }.join(' ')
  end
end
```
とりあえず、メソッドに第一引数,第二引数という形で引数wordsを与えた。
Procを使用せずとも問題ないのでは？？

続いて、WordSynthの実装。

```ruby:word_synth_test.rb
class WordSynth
  def initialize
    @effects =[]
  end

  def add_effect(effect)
    @effects << effect
  end

#  Procを使用していないとplay(original_words)を使用できない

  # def play(original_words)
  #   @effects.inject(original_words) do |words,effect|
  #     effect.call(words)
  #   end
  # end

end
```
Effectsの時点で引数に（words）を与えてしまうため、先程のplay(original_words)をうまく作ることができない。

そもそもこれでは@ effects =[]に格納するものがeffect機能ではなくて、既に与えられた文字を変換した文字列にしかならない。

何か工夫すればProcを使用せずとも同じ機能をもちあわせるメソッドを作成できそうではあるが、Procを使用すると簡単に上記の機能を作成することができるというのはわかった。

#Procを使用するメリットについて
検証からProcの強みを２つ実感した。
・**メソッドが受け取れるブロックの数は最大で１つであるが、Procを利用すれば複数のブロックを使用できる**ということ。
・**callのタイミングで引数を与えることができる**ということ。

play(original_words)ではcallを使用することで、メソッドの中で２つのブロックが機能していていることがわかる。
また、引数(words)をcallのタイミングで入れることができるという点も特徴的である。

反対にProcを使用していない方は、**１つのメソッドにブロックは１つ**であり、**引数(words)を与えるタイミングも他の引数と同時**でなくてはいけなくなる。
#まとめ
Procを使用するメリットは他にもたくさんあると思うが、あくまで今回の検証からは２つのメリットを実感できる。

プログラミングの学習の際、どういった機能であるかを理解することも大事であるが、それをどの場面に使用すべきかを自分なりにイメージできるようになることも大切である。

#参考文献

この記事は以下の情報を参考にして執筆しました。
- プロを目指す人のためのRuby入門　伊藤 淳一[著]