Ruby を書いていると必ず出てくる「ブロック」と「yield」。 難しく見えますが、要は 「処理を渡す」「渡された処理を実行する」 だけです。 ブロックとは メソッドに渡す「処理のかたまり(コードの切れ端)」 のこと。 { } か do...end で囲みます。 [1, 2, 3].each { |n| puts n } # └──────────┘ これがブロック .each に「各要素で puts n してね」という指示書を渡しています。 1 2 3 { } と do...end は同じもの。長いときは do...end を使うだけです。 [1, 2, 3].each do |n| puts n end yield とは メソッドの中の「yield と書いた場所」で、渡されたブロックを実行する命令。 def あいさつ puts "こんにちは" yield # ← ここで渡されたブロックを実行 puts "さようなら" end あいさつ { puts "元気ですか?" } こんにちは 元気ですか? ← yield の場所にブロックが差し込まれる さようなら yield は好きな場所に置け、何回でも呼べ、値も渡せます。 def 数える yield 1 yield 2 end 数える { |n| puts "#{n}番目" } # 1番目 # 2番目 2つの関係 ブロック = 渡す「やることメモ」(呼ぶ側が書く) yield = そのメモを実行する命令(メソッド側が書く) 差し込む場所を決めるのがメソッド、差し込む中身を決めるのが呼ぶ側。 実践編:yield で処理を「挟み込む」 yield の本当に便利な使い方が、共通の前処理と後始末で、渡された処理を挟むパターンです。 def with_debug old = Rails.logger.level Rails.logger.level = :debug # 前処理:ログを debug に yield # 呼び出し側の処理を実行 ensure # エラーが起きても起きなくても、最後に必ず実行される(=finally) Rails.logger.level = old # 後始末:必ず元に戻す end 使い方: with_debug do # この中だけログが debug になる user.save! end # ここを抜けると自動で元のログレベルに戻る なぜ便利か 共通部分(ログ切替と復元)を1か所にまとめられる。使う側は「何をしたいか」だけ書けばよい。 ensure で後始末が保証される。ブロックの中でエラーが起きても、ログレベルは必ず元に戻る。 もし yield を使わなければ、使う場所ごとに「切替 → 処理 → 復元」を毎回コピペする羽目になります。yield なら枠(前後処理)はメソッド側、中身は呼ぶ側、ときれいに分けられます。 もう一つの例:処理時間を測る 同じパターンで「実行時間の計測」も書けます。 def measure(label) start = Time.now yield ensure puts "#{label}: #{Time.now - start}秒" end measure("重い処理") do heavy_task end # => 重い処理: 1.23秒 「共通の前後処理でブロックを挟む」 ——これは Ruby で頻出の設計パターンです。 File.open { |f| ... }(開いて必ず閉じる)なども、この仲間です。