Ruby | 暗黙の to_proc で遊ぶ #ruby

# Ruby | 暗黙の to_proc で遊ぶ #ruby
## <i class="fa fa-cubes" style="font-size:1em;"></i> 概要
暗黙の to_proc で遊びます。

## <i class="fa fa-question-circle" style="font-size:1em;"></i> 暗黙の to_proc って何？
Ruby のメソッド呼び出し時に、 &をつけるとブロックをオブジェクトとして扱うことができます。
しかし、 &を付けた対象がブロックでは無かった場合、どうなるか？
この際に暗黙の to_proc が呼び出されます。

よく見る利用例が、 Enumerbale の各種メソッドとの併用です。
例えば、文字列配列を大文字に変換する場合、オーソドックスに書くと下記のようになります。

~~~ruby
print ('a'..'e').map { |e|e.upcase }, "\n"
# => ["A", "B", "C", "D", "E"]
~~~

ここで、暗黙の to_proc を利用すると

~~~ruby
print ('a'..'e').map(&:upcase), "\n"
# => ["A", "B", "C", "D", "E"]
~~~

このように簡潔に記述することができます。

補足すると、& を付けて呼び出した際に、メソッドがブロックではなかったため、
<i class="fa fa-external-link-square" style="font-size:1em;"></i> [Symbol#to_proc](http://docs.ruby-lang.org/ja/2.1.0/method/Symbol/i/to_proc.html) が呼び出されています。
実処理のイメージをコードにするとこんな感じでしょうか。

~~~ruby
print ('a'..'e').map { |e|:upcase.to_proc.call(e) }, "\n"
# => ["A", "B", "C", "D", "E"]
~~~

## <i class="fa fa-child" style="font-size:1em;"></i> 遊んでみる

### <i class="fa fa-filter" style="font-size:1em;"></i> Filter を作成

~~~ruby
require 'prime'

module OddFilter
  module_function
  def to_proc
    -> (x) { x.odd? }
  end
end

module EvenFilter
  module_function
  def to_proc
    -> (x) { x.even? }
  end
end

module PrimeFilter
  module_function
  def to_proc
    -> (x) { x.prime? }
  end
end

print [*1..15].select(&OddFilter), "\n"
print [*1..15].select(&EvenFilter), "\n"
print [*1..15].select(&PrimeFilter), "\n"
~~~

* 結果

~~~
[1, 3, 5, 7, 9, 11, 13, 15]
[2, 4, 6, 8, 10, 12, 14]
[2, 3, 5, 7, 11, 13]
~~~

### <i class="fa fa-refresh" style="font-size:1em;"></i> Converter を作成
※ module_function についてはるりま参照 <i class="fa fa-external-link-square" style="font-size:1em;"></i> [Module#module_function](http://docs.ruby-lang.org/ja/2.1.0/method/Module/i/module_function.html)

~~~ruby
require 'prime'

module FizzBuzzConverter
  module_function
  def to_proc
    -> (x) {
      case
      when x % 15 == 0 then 'FizzBuzz'
      when x % 5 == 0 then 'Buzz'
      when x % 3 == 0 then 'Fizz'
      else x
      end
    }
  end
end

module PrimeConverter
  module_function
  def to_proc
    -> (x) {
      x.prime? ? "#{x} is prime number" : "#{x} is composite number"
    }
  end
end

module DoubleConverter
  module_function
  def to_proc
    -> (x) { x * 2 }
  end
end

print [*1..15].map(&FizzBuzzConverter), "\n"
print [*1..15].map(&PrimeConverter), "\n"
print [*1..15].map(&DoubleConverter), "\n"
~~~

* 結果

~~~ruby
[1, 2, "Fizz", 4, "Buzz", "Fizz", 7, 8, "Fizz", "Buzz", 11, "Fizz", 13, 14, "FizzBuzz"]
["1 is composite number", "2 is prime number", "3 is prime number", "4 is composite number", "5 is prime number", "6 is composite number", "7 is prime number", "8 is composite number", "9 is composite number", "10 is composite number", "11 is prime number", "12 is composite number", "13 is prime number", "14 is composite number", "15 is composite number"]
[2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30]
~~~

### <i class="fa fa-filter" style="font-size:1em;"></i><i class="fa fa-refresh" style="font-size:1em;"></i>  Filter と Converter を併用

~~~ruby
# Converter と Filter の定義部分は前述の定義をそのまま利用

print [*1..15].select(&OddFilter).map(&FizzBuzzConverter), "\n"
print [*1..15].select(&OddFilter).map(&DoubleConverter), "\n"
print [*1..15].select(&EvenFilter).map(&FizzBuzzConverter), "\n"
print [*1..15].select(&PrimeFilter).map(&PrimeConverter), "\n"
~~~

* 結果

~~~
[1, "Fizz", "Buzz", 7, "Fizz", 11, 13, "FizzBuzz"]
[2, 6, 10, 14, 18, 22, 26, 30]
[2, 4, "Fizz", 8, "Buzz", "Fizz", 14]
["2 is prime number", "3 is prime number", "5 is prime number", "7 is prime number", "11 is prime number", "13 is prime number"]
~~~

## 参照
* <i class="fa fa-external-link-square" style="font-size:1em;"></i> [るりま | Symbol#to_proc](http://docs.ruby-lang.org/ja/2.1.0/method/Symbol/i/to_proc.html)