Ruby | 暗黙の to_proc で遊ぶ #ruby
概要
暗黙の to_proc で遊びます。
暗黙の to_proc って何?
Ruby のメソッド呼び出し時に、 &をつけるとブロックをオブジェクトとして扱うことができます。
しかし、 &を付けた対象がブロックでは無かった場合、どうなるか?
この際に暗黙の to_proc が呼び出されます。
よく見る利用例が、 Enumerbale の各種メソッドとの併用です。
例えば、文字列配列を大文字に変換する場合、オーソドックスに書くと下記のようになります。
print ('a'..'e').map { |e|e.upcase }, "\n"
# => ["A", "B", "C", "D", "E"]
ここで、暗黙の to_proc を利用すると
print ('a'..'e').map(&:upcase), "\n"
# => ["A", "B", "C", "D", "E"]
このように簡潔に記述することができます。
補足すると、& を付けて呼び出した際に、メソッドがブロックではなかったため、
Symbol#to_proc が呼び出されています。
実処理のイメージをコードにするとこんな感じでしょうか。
print ('a'..'e').map { |e|:upcase.to_proc.call(e) }, "\n"
# => ["A", "B", "C", "D", "E"]
遊んでみる
Filter を作成
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]
Converter を作成
※ module_function についてはるりま参照 Module#module_function
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"
- 結果
[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]
Filter と Converter を併用
# 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"]