Issue #4085 has been updated by Jedediah Smith.


It would be great to finally have scoped monkey patching for Ruby, but I am finding some problems with this approach.

There are many ways for refinements to leak out of the lexical scope that uses them:

1. Inheritance (which is used in many APIs e.g. ActiveRecord::Base)
2. DSLs that use instance_eval
3. Re-opening a class
4. When a class that uses refinements is itself refined (or does it not work that way?)

Classes that are to be used in any of these ways can't use refinements internally, I guess. For 1 and 4, that could be any class at all. So we still have to be paranoid about using refinements in library code, which kind of defeats the purpose.


Also, if "using" and "include" both operate on modules, the difference between them is going to be confusing, particularly for those unfamiliar with the history of the language. It seems arbitrary to overload modules with a use unrelated to their existing purpose. And having to group refinements in modules seems overly complicated for many cases. I would like to be able to do something like this:

  refinement StringExt < String
    def pig_latin
      "#{self[1..-1]}#{self[0]}ay"
    end
  end

  ...

  using StringExt
  "woot".pig_latin    # ==> "ootway"

But there does need to be a way to group refinements, and there should probably be a way to combine groups as well. Perhaps this:

  refinement CoreExt          # empty refinement bound to constant CoreExt
    using ArrayExt            # import other refinement(s)
  
    refinement < String       # anonymous refinement of String
      ...
    end
  end

This keeps refinements and modules separate and makes their usage clear: modules are "included" dynamically, refinements are "used" lexically. Mix them up and you get a TypeError. It also keeps definition of refinements separate from their use, and lets you use an anonymous refinement inside a module without exporting it. Refinements can still be nested members of modules. The above syntax may not be quite right, but I think the semantics are: refinements are composable sets of lexically scoped monkey patches.

----------------------------------------
http://redmine.ruby-lang.org/issues/show/4085

----------------------------------------
http://redmine.ruby-lang.org