🔥

[Feature #21160] next の別名を追加する提案

に公開

[Feature #21160] Local return from proc

  • 次のような DSL ライクな fulfills_promise なメソッドのブロック内から抜けるときに next を使うことがある
class Example
  def self.fulfills_promise(promise_name, &block)
    @@promise_callbacks ||= {}
    @@promise_callbacks[promise_name] = block
  end

  def self.fulfill_promise(promise_name, data)
    puts "Fulfilling promise: #{promise_name}"

    callback = @@promise_callbacks[promise_name]

    if callback.call(data)
      puts 'Complete!'
    else
      puts 'Failed!'
    end
  end

  fulfills_promise :generate_large_image do |image_data|
    # 特定の条件の場合はなにもせずに処理を終わらせる
    next false if image_data.nil?

    puts 'Saving image..'
    # etc.

    true
  end
end


Example.fulfill_promise(:generate_large_image, 'image data')
# => Complete!

Example.fulfill_promise(:generate_large_image, nil)
# => Failed!
  • この next がわかりづらいので別の名前でエイリアスしたいという提案
    • チケットだと passcontinua が提示されている
  • これなんですが next の変わりに break を使うことがコメントされていますね
  • ただし、上記のコードの next をそのまま break に変えた場合には LocalJumpError が発生します
fulfills_promise :generate_large_image do |image_data|
  # error: 'block in <class:Example>': break from proc-closure (LocalJumpError)
  break false if image_data.nil?

  puts 'Saving image..'
  # etc.

  true
end
class Example
  def self.fulfills_promise(promise_name, &block)
    @@promise_callbacks ||= {}
    @@promise_callbacks[promise_name] = block
  end

  def self.fulfill_promise(promise_name, data)
    puts "Fulfilling promise: #{promise_name}"

    callback = @@promise_callbacks[promise_name]

    begin
      complete = callback.call(data)
    rescue LocalJumpError => e
      complete = e.exit_value
    end

    if complete
      puts 'Complete!'
    else
      puts 'Failed!'
    end
  end

  fulfills_promise :generate_large_image do |image_data|
    # 特定の条件の場合はなにもせずに処理を終わらせる
    break false if image_data.nil?

    puts 'Saving image..'
    # etc.

    true
  end
end


Example.fulfill_promise(:generate_large_image, 'image data')
# => Complete!

Example.fulfill_promise(:generate_large_image, nil)
# => Failed!
  • この発想はなかった
  • これだと return にも対応できるみたいですね
  • こういうのってあんまり書いたことないけど Rails とかでも多用されてたりするんですかね?
GitHubで編集を提案

Discussion