Feature #17336
closedusing refined: do ... end
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) .
Updated by k0kubun (Takashi Kokubun) almost 4 years ago
- Description updated (diff)
Updated by k0kubun (Takashi Kokubun) almost 4 years ago
- Description updated (diff)
Updated by k0kubun (Takashi Kokubun) almost 4 years ago
- Description updated (diff)
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.
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)