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では制御構造もオブジェクト的なのです
しかしこれらの制御構造は真のオブジェクトではありません
したがってこのような制御構造を
メソッドの引数として渡すことはできません
LispやSchemeなどの異次元言語では
これらの制御構造を何の苦もなく関数の引数として渡せるそうです
このような関数は高階関数などとブルジョワジーに呼ばれます
しかしハンカチを噛む必要はありません
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:メソッド定義の外でも使えます