问题
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?
回答1:
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.
来源:https://stackoverflow.com/questions/15220526/are-refinements-in-ruby-2-0-totally-useless