Project

General

Profile

Actions

Feature #12737

closed

Module#defined_refinements

Added by shugo (Shugo Maeda) almost 6 years ago. Updated 6 months ago.

Status:
Closed
Priority:
Normal
Target version:
-
[ruby-core:77215]

Description

How about to provide Module#defined_refinements, which returns the refinements defined in the receiver as a Hash, as follows:

module M
  refine String do
    $M_String = self
  end

  refine Integer do
    $M_Integer = self
  end
end

p M.defined_refinements #=> {String => $M_String, Integer => $M_Integer}

By Module#defined_refinements, you can activate refinements globally:

for klass, refinement in M.defined_refinements
  klass.prepend(refinement)
end

Related issues 2 (1 open1 closed)

Related to Ruby master - Feature #9704: Refinements as files instead of modulesOpenmatz (Yukihiro Matsumoto)Actions
Related to Ruby master - Feature #14332: Module.used_refinements to list refinement modulesClosedshugo (Shugo Maeda)Actions
Actions #1

Updated by shugo (Shugo Maeda) almost 6 years ago

  • Related to Feature #9704: Refinements as files instead of modules added

Updated by shugo (Shugo Maeda) 8 months ago

  • Status changed from Open to Assigned

Matz, can I add Module#defined_refinements?

Actions #3

Updated by Eregon (Benoit Daloze) 8 months ago

  • Related to Feature #14332: Module.used_refinements to list refinement modules added

Updated by Eregon (Benoit Daloze) 8 months ago

Should the code in the description be p M.defined_refinements?

I'm not sure to understand the use case, isn't using M doing the same as that for?

Updated by shugo (Shugo Maeda) 7 months ago

Eregon (Benoit Daloze) wrote in #note-4:

Should the code in the description be p M.defined_refinements?

Yes.

I'm not sure to understand the use case, isn't using M doing the same as that for?

Forget the following example. It was not a good idea.

for klass, refinement in Module.defined_refinements
  klass.prepend(refinement)
end

Module#defined_refinements is a reflection API for debugging purposes.
You can get a similar result of Module.used_refinements using Module.use_modules and Module#defined_refinements except that Module.used_refinements only returns refinements defined at the time when modules are used.

Updated by Eregon (Benoit Daloze) 7 months ago

Ah, so it's to list the refinements (instance of Refinement) under a "namespace module" like M, without needing using.
I'm unsure of use cases besides debugging, but I think it's useful to add.

Actions #7

Updated by mame (Yusuke Endoh) 7 months ago

  • Description updated (diff)
Actions #8

Updated by mame (Yusuke Endoh) 7 months ago

  • Description updated (diff)

Updated by shugo (Shugo Maeda) 7 months ago

Considerations raised by Matz at the developers meeting on 2021-11-18:

  1. Is the name defined_refinements appropriate?

    other proposals:

    • configured_refinements (by tenderlove)
    • refinements
      • consistent with Module#constants
    • contained_refinements
  2. Should the return value be an Array instead of a Hash?

    pros:

    • consistent with Module.used_refinements

    cons:

    • A new API like Refinement#refined_class (or target_class) is needed to know the refined class.
    • M.defined_refinements.find { |r| r.refined_class == Integer } is longer than M.defined_refinements[Integer].

Updated by Eregon (Benoit Daloze) 7 months ago

Module#refinements seems nice and straightforward.

I think Refinement#refined_class is useful in any case, +1 to add that.

I slightly prefer the array variant.
Since this would be mostly used for debugging, there might not be any need to filter in many cases, i.e., the Refinement#inspect output already shows the refined_class's name, so p M.refinements seems typical usage (and the Hash for that case would just be more verbose).

Updated by shugo (Shugo Maeda) 7 months ago

Eregon (Benoit Daloze) wrote in #note-10:

Module#refinements seems nice and straightforward.

I prefer Module#refinements too.

I slightly prefer the array variant.
Since this would be mostly used for debugging, there might not be any need to filter in many cases, i.e., the Refinement#inspect output already shows the refined_class's name, so p M.refinements seems typical usage (and the Hash for that case would just be more verbose).

The array variant is OK for me if Refinement#refined_class will be introduced.

Another use case is testing of Refinements themselves:

m = Module.new {
  refine Integer do
    ....
  end

  refine String do
    ...
  end
}
refinements = m.refinements
assert_something ..., refinements[Integer]
assert_something ..., refinements[String]

However, I may be the only user, so it's not so important.
If there are more use cases, Module#refinement_get can be added in the future.

Updated by matz (Yukihiro Matsumoto) 7 months ago

OK, accepted. After 3.1, you can introduce:

  • Module#refinements
  • Refinment#refined_class

Matz.

Updated by shugo (Shugo Maeda) 7 months ago

  • Assignee set to shugo (Shugo Maeda)
Actions #14

Updated by shugo (Shugo Maeda) 6 months ago

  • Status changed from Assigned to Closed

Applied in changeset git|54198c7b97d3d353f7ac233e0360034b6e7b6cb6.


Add Module#refinements and Refinement#refined_class [Feature #12737]

Actions

Also available in: Atom PDF