There were so-called refinements introduced in Ruby 2.0. I was playing with them and now I’m totally cajoled:

— The main declared advantage of refine is that they are not global scoped. Bah.

module MyModule
  class ::String
    def my_locally_needed_func
      # do smth 
    end
  end
end

# here I need it
require 'mymodule'
"".my_locally_needed_func

is isolated not worse.

— Refinements do not support class methods. Bah. Of course they are through a hack (remember, everything is an object):

module VoidRefinements
  refine String do
    def self.singleton_method_for_string_class
      puts "inside singleton_method_for_string_class"
    end 
  end 
end

module VoidRefinementsOK
  refine Class do
    def singleton_method_for_string_class
      err_msg = "NoMethodError: undefined method ‘#{__method__}’ for ‘#{self}:#{self.class}’"
      raise NoMethodError.new(err_msg) unless String == self
      puts "inside proper singleton_method_for_string_class"
    end 
  end 
end

using VoidRefinements
String.singleton_method_for_string_class rescue puts $!

using VoidRefinementsOK
String.singleton_method_for_string_class rescue puts $!

# undefined method `singleton_method_for_string_class' for String:Class
# inside proper singleton_method_for_string_class

The latter is not even resulting in performance penalties, since nobody would call Fixnum.substr on purpose.

— Refinements are executed through eval. refine is not a keyword. Bah. (well, “bah!” again.)

So, my question is: am I missing smth or everybody sees no advantages in the newly introduced feature?

有帮助吗?

解决方案

You completely dismiss the fact that Refinements aren't globally scoped, but that's the very reason for their introduction. Of course, if you simply ignore the reason for something's existence, then you obviously won't see any value in it.

But, see the isolation in action. Here is your example modified to use Refinements:

module MyModule
  refine String do
    def my_locally_needed_func
      # do smth 
    end
  end
end

module MyOtherModule
  # The monkeypatch is invisible:
  "".my_locally_needed_func
  # NoMethodError: undefined method `my_locally_needed_func' for "":String

  # I first have to use the Refinement:
  using MyModule
  "".my_locally_needed_func
end

# The monkeypatch is scoped. Even though we were able to use 
# it in MyOtherModule, we still cannot use it at the top-level:
"".my_locally_needed_func
# NoMethodError: undefined method `my_locally_needed_func' for "":String

# We have to call `using` again, for the top-level:
using MyModule
"".my_locally_needed_func

Here is your example for comparison:

module MyModule
  class ::String
    def my_locally_needed_func
      # do smth 
    end
  end
end

# here I need it
"".my_locally_needed_func

Note: I removed the call to using which didn't make sense since you didn't use Refinements anyway.

In your case, the monkeypatch is available globally, because you simply modified the String class. This functionality is called an "open class", and it is precisely what Refinements are there to avoid.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top