Project

General

Profile

Actions

Feature #19432

closed

Introduce a wrapping operator (&) to Proc

Added by joel@drapper.me (Joel Drapper) almost 2 years ago. Updated over 1 year ago.

Status:
Feedback
Assignee:
-
Target version:
-
[ruby-core:112333]

Description

I don't know if this concept exists under another name, or whether there’s a technical term for it. I often find myself wanting to wrap a proc in another proc.

Here's a snippet from a recent example where a visitor class renders a TipTap AST. Given a text node, we want to output the text by calling the text method with the value. But if the text has marks, we want to iterate through each mark, wrapping the output for each mark. It's possible to do this using the >>= operator if each proc explicitly returns another proc.

when "text"
  result = -> { -> { text node["text"] } }

  node["marks"]&.each do |mark|
    case mark["type"]
    when "bold"
      result >>= -> (r) { -> { strong { r.call } } }
    when "italic"
      result >>= -> (r) { -> { em { r.call } } }
    end
  end

  result.call.call
end

This is quite difficult to follow and the result.call.call feels wrong. I think the concept of wrapping one proc in another proc would make for a great addition to Proc itself. I prototyped this using the & operator.

class Proc
  def &(other)
    -> { other.call(self) }
  end
end

With this definition, we can call & on the original proc with our other proc to return a new proc that calls the other proc with the original proc as an argument. It also works with &=, so the above code can be refactored to this:

when "text"
  result = -> { text node["text"] }

  node["marks"]&.each do |mark|
    case mark["type"]
    when "bold"
      result &= -> (r) { strong { r.call } }
    when "italic"
      result &= -> (r) { em { r.call } }
    end
  end

  result.call
end
Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0