Rubyチュートリアル 〜英文小説の最頻出ワードを見つけよう!(その3)

Rubyのブロックは仮装オブジェクトです

次にRubyのブロックを説明します


手続き型言語同様
Rubyもifやwhileなどの制御構造をサポートしており
メソッド定義式の中でこれらを使うことができます*1

 def hello(name)
   if name.length > 10
     name.squeeze!
   else
     name += name.reverse
   end
   "Hello, #{name}."
 end
 
 hello('mississippi-hippopotamus') # => "Hello, misisipi-hipopotamus."
 hello('donkey') # => "Hello, donkeyyeknod."


case式というユニークな制御構造もあります

 def good_bye(name)
   new_name = case name.length
   when 1..8
     name.next.capitalize
   when 9..15
     name.upcase.chop
   else
     name.replace("too-long-name")
   end
   "Good-bye, #{new_name}!!"
 end
 
 good_bye('donkey') # => "Good-bye, Donkez!!"
 good_bye('alligator') # => "Good-bye, ALLIGATO!!"
 good_bye('mississppi-hippopotamus') # => "Good-bye, too-long-name!!"

コードをよく見て頂ければわかると思いますが
caseはcase式であり値を返します
Rubyでは多くの制御構造や構文が式であり値を返します
つまりRubyでは制御構造もオブジェクト的なのです


しかしこれらの制御構造は真のオブジェクトではありません
したがってこのような制御構造を
メソッドの引数として渡すことはできません
LispSchemeなどの異次元言語では
これらの制御構造を何の苦もなく関数の引数として渡せるそうです
このような関数は高階関数などとブルジョワジーに呼ばれます


しかしハンカチを噛む必要はありません
Rubyにはブロックがあります
制御構造をdo endまたは{ }のブロックに入れると
メソッドに引数のように渡せるようになります

 ['donkey', 'alligator', 'hippopotamus'].each do |name|
   salute = if name.start_with?('hip')
     'ばか!'
   else
     'やあ!'
   end
   puts salute + name
 end
 # >> やあ!donkey
 # >> やあ!alligator
 # >> ばか!hippopotamus

例では配列オブジェクトにeachメソッドを送る際に
ブロックを渡しています
これを受け取った配列オブジェクトは
各要素をブロック引数nameに順番に渡して
ブロックの制御構造を起動するのです
eachに渡すブロックの中身を変えれば
eachメソッドの働きは大幅に変更できます


この項の表題における「仮装」はtypoではありません
そう制御構造はブロックでオブジェクトに仮装して
他のオブジェクトに入り込むのです!


制御構造をメソッドに付けてオブジェクトに
渡せるようにする方法はまだあります
勘のいい人は気が付いたかもしれません
そう制御構造をオブジェクト化すればいいのです
手続きオブジェクト メソッドオブジェクト スレッドオブジェクト
ファイバーオブジェクト 継続オブジェクト
などがこれを可能にします
先を急がれるでしょうからこの話題はこれで終わりにします


興味のある方は以下が参考になるかもしれません
Rubyのブロックはメソッドに対するメソッドのMix-inだ! - hp12c


(次回に続く

*1:メソッド定義の外でも使えます