LoginSignup
9
10

More than 5 years have passed since last update.

Ruby | 暗黙の to_proc で遊ぶ #ruby

Posted at

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"]

参照

9
10
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
9
10