From: "joel@... (Joel Drapper) via ruby-core" Date: 2023-03-08T12:14:35+00:00 Subject: [ruby-core:112742] [Ruby master Feature#19432] Introduce a wrapping operator (&) to Proc Issue #19432 has been updated by joel@drapper.me (Joel Drapper). Your examples of, `strong` and `em` return a string but they don't buffer it anywhere. In order to use them like this, they would need to buffer the opening tag, yield, and then buffer the closing tag. ```ruby strong { em { text("Hello") } } ``` **Implementation** ```ruby def strong = @buffer << ""; yield; @buffer << "" def em = @buffer << ""; yield; @buffer << "" def text(value) = @buffer << ERB::Escape.html_escape(value) ``` Given this interface, if you were visiting an AST (from Markdown or an editor like TipTap), it would be useful to have an operator for Proc that wraps one proc in another, as I showed in the original post. ---------------------------------------- Feature #19432: Introduce a wrapping operator (&) to Proc https://bugs.ruby-lang.org/issues/19432#change-102201 * Author: joel@drapper.me (Joel Drapper) * Status: Feedback * Priority: Normal ---------------------------------------- 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. ```ruby 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. ```ruby 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: ```ruby 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 ``` -- https://bugs.ruby-lang.org/ ______________________________________________ ruby-core mailing list -- ruby-core@ml.ruby-lang.org To unsubscribe send an email to ruby-core-leave@ml.ruby-lang.org ruby-core info -- https://ml.ruby-lang.org/mailman3/postorius/lists/ruby-core.ml.ruby-lang.org/