Project

General

Profile

Actions

Feature #17336

closed

using refined: do ... end

Added by k0kubun (Takashi Kokubun) almost 4 years ago. Updated almost 4 years ago.

Status:
Closed
Assignee:
-
Target version:
-
[ruby-core:100962]

Description

Problem

When we need a monkey patch which is used only in a single file, we'd like to define a refinement and use it in the same place. The problem is that it needs deep indentation and Module.new { ... } which feels redundant.

class Foo
  using Module.new {
    refine Array do
      def flat_map!(&block)
        replace(flat_map(&block))
      end
    end
  }
  
  # ...
end

@tagomoris (Satoshi Tagomori) proposed an idea to reduce indentation and remove Module.new { ... }. This looks pretty convenient, but I want to write do ... end, which would make it a block of using here, because we almost always use ... end for defining methods or modules.

module Kernel
  def refined(mod, &block)
    Module.new do
      refine(mod, &block)
    end
  end
end

class Foo
  using refined(Array) {
    def flat_map!(&block)
      replace(flat_map(&block))
    end
  }

  # ...
end

Proposal

How about supporting this? Because using currently doesn't take a block, it doesn't conflict with the existing syntax.

class Foo
  using refined: Array do
    def flat_map!(&block)
      replace(flat_map(&block))
    end
  end

  # ...
end

This syntax is based on ideas of @tagomoris (Satoshi Tagomori) and @znz (Kazuhiro NISHIYAMA) .


Related issues 1 (1 open0 closed)

Is duplicate of Ruby master - Feature #16241: Shorter syntax for anonymous refinementsOpenActions
Actions #1

Updated by k0kubun (Takashi Kokubun) almost 4 years ago

  • Description updated (diff)
Actions #2

Updated by k0kubun (Takashi Kokubun) almost 4 years ago

  • Description updated (diff)
Actions #3

Updated by k0kubun (Takashi Kokubun) almost 4 years ago

  • Description updated (diff)
Actions #4

Updated by k0kubun (Takashi Kokubun) almost 4 years ago

  • Description updated (diff)

Updated by zverok (Victor Shepelev) almost 4 years ago

Why not #16241?.. using refined: Array do seems redundant to me, as both significant words (using and refined) are related to the same fact: "We are dealing with refinement here".

Updated by Eregon (Benoit Daloze) almost 4 years ago

How about:

class Foo
  using do
    refine Array do
      def flat_map!(&block)
        replace(flat_map(&block))
      end
    end

    refine String do
      ...
    end
  end

So let using take a block instead of a positional argument.

That way, it's also possible to refine multiple classes/modules at once, which is often better than multiple using calls (notably, such methods can use the refinements of each other and it's more concise)

Updated by k0kubun (Takashi Kokubun) almost 4 years ago

  • Status changed from Open to Closed

Why not #16241?

Works for me :) Honestly whatever Array do ... end sounds fine. When I tried to implement a quick version, I picked using Array do .. end, and it was changed to this proposal because some others said it should be keeping the word "refine". I also thought, "well, it's also using in place", but it's not a big deal. If refining is there, I'd be happy to use it. Plus, the ticket mentions using_refined too. I'm closing this as a duplicate.

How about:
So let using take a block instead of a positional argument.

It might be helpful anyway, but a part of the ticket's motivation was to eliminate the deep indentation.

Actions #8

Updated by k0kubun (Takashi Kokubun) almost 4 years ago

  • Is duplicate of Feature #16241: Shorter syntax for anonymous refinements added

Updated by Eregon (Benoit Daloze) almost 4 years ago

k0kubun (Takashi Kokubun) wrote in #note-7:

It might be helpful anyway, but a part of the ticket's motivation was to eliminate the deep indentation.

Is it annoying in practice?
It kind of seems nice to have the outer using do ... end which is saying "below are local monkey patches for this file".
Instead of having to check if there are further using refined: Array/refining calls one after another.

And if those refinements are not trivial and the implementation needs quite some indentation, maybe the refinements should be defined in their own file under some module, that also solves the indentation.

I guess an example of real code where the deep indentation is problematic might help to convince me and maybe others.

Updated by k0kubun (Takashi Kokubun) almost 4 years ago

Is it annoying in practice?

In practice? Nah, maybe not for many people, at least you. I admit I'm a bit extreme about indentation, and for sure it annoys me.

It kind of seems nice to have the outer using do ... end which is saying "below are local monkey patches for this file".

For me, a word refine is enough to expect a monkey patch.

I guess an example of real code where the deep indentation is problematic might help to convince me and maybe others.

While I would say it's not a problem for many people but me, here's the deepest indentation of def I've ever seen: https://github.com/rails/rails/blob/v6.0.3.4/activejob/lib/active_job/arguments.rb#L73-L96

Updated by zverok (Victor Shepelev) almost 4 years ago

It kind of seems nice to have the outer using do ... end which is saying "below are local monkey patches for this file".

I'd say that one of the important usage of refinements (as for me) is small adjustments to core/third-party classes, that make sense in the current context. And the whole point of this ticket, as well as #16241, is to make them as lightweight-feeling as possible. This is what feels "intuitively enough" to refine something:

refine Something do
  def foo
  #...

Everything that tries to be more formalistic, just raises the bar of "shouldn't I do a small refinement here?.." (well, somebody might argue that this bar should be high, but then what's the point of refinements?)

So, for me "let's nest it in one more using for better organization" seems annoyingly redundant and un-Ruby-ish (like, there are many things that can be nested in more blocks for "better organization", like attributes do ... end or private_methods do ... end, or constants do ... end, but we don't do this, right? And if somebody wants to logically structure stuff, they do it with comments/order/non-code means)

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0