Help us understand the problem. What is going on with this article?

Ruby のブロック付きメソッドを実装する

More than 1 year has passed since last update.

シンプルな例

メソッド呼び出し(super・ブロック付き・yield) (Ruby 2.4.0) https://docs.ruby-lang.org/ja/latest/doc/spec=2fcall.html

ブロック付きメソッドとは制御構造の抽象化のために用いられる メソッドです。最初はループの抽象化のために用いられていたため、 特にイテレータと呼ばれることもあります。 do ... end または { ... } で囲まれたコードの断片 (ブロックと呼ばれる)を後ろに付けてメソッドを呼び出すと、その メソッドの内部からブロックを評価できます。 ブロック付きメソッドを自分で定義するには yield 式を使います。

ソースコード

# ブロック付きメソッド
def add(x, y)
  puts "begin: #{x}, #{y}"
  yield(x + y) # 足した結果をブロックに渡す
  puts "end: #{x}, #{y}"
end

# ブロック付きメソッドを呼び出す
add 2, 3 do |result|
  puts "answer: #{result}"
end

実行結果

begin: 2, 3
answer: 5
end: 2, 3

Proc オブジェクトを使う

class Proc (Ruby 2.4.0) https://docs.ruby-lang.org/ja/latest/class/Proc.html

ブロックをコンテキスト(ローカル変数のスコープやスタックフ レーム)とともにオブジェクト化した手続きオブジェクトです。
Proc は ローカル変数のスコープを導入しないことを除いて 名前のない関数のように使えます。ダイナミックローカル変数は Proc ローカルの変数として使えます。

ソースコード

# ブロック付きメソッド
def add(x, y)
  puts "begin: #{x}, #{y}"
  yield(x + y) # 足した結果をブロックに渡す
  puts "end: #{x}, #{y}"
end

# Procオブジェクトを生成
header = ''
p = Proc.new{|result|
  puts "#{header}: #{result}"
}
header = 'answer' # ブロック内で使う変数に値を代入

# ブロック付きメソッドを呼び出す
add 2, 3, &p

実行結果

begin: 2, 3
answer: 5
end: 2, 3

ループ処理

ソースコード

# ブロック付きメソッド
def double(array)
  array.each do |e|
    # 元の値と2倍した値をブロックに渡す
    yield(e, e * 2)
  end
end

# ブロック付きメソッドを呼び出す
double [2, 3, 5] do |src, dst|
  puts "#{src} -> #{dst}"
end

実行結果

2 -> 4
3 -> 6
5 -> 10

ブロックをコールバックする

ソースコード

class Slots

  def initialize()
    @slots = {}
  end

  # マッチしたときに実行するブロックを登録する
  def add(regexp, &block)
    @slots[regexp] = block
  end

  # 文字列にマッチしたら対応するブロックを実行する
  def match(str)
    @slots.each do |regexp, block|
      if matchdata = str.match(regexp)
        puts "[match] #{block.yield(matchdata)}"
      end
    end
  end
end

slots = Slots.new
slots.add(/hell/i) {|m| "'#{m.string}' has 'hell'."}
slots.add(/hello/i){|m| "'#{m.string}' has 'hello'."}

slots.match('He')
slots.match('HELL')
slots.match('Hello, Goodbye')

実行結果

[match] 'HELL' has 'hell'.
[match] 'Hello, Goodbye' has 'hell'.
[match] 'Hello, Goodbye' has 'hello'.

参考資料

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした