Являются ли доработки в Ruby 2.0 совершенно бесполезными?
В Ruby 2.0 были представлены так называемые доработки. Я играл с ними, и теперь я полностью одурачен:
- главное заявленное преимущество refine
в том, что они не являются глобальными. Ба.
module MyModule
class ::String
def my_locally_needed_func
# do smth
end
end
end
# here I need it
require 'mymodule'
"".my_locally_needed_func
изолирован не хуже.
- Уточнения не поддерживают методы класса. Ба. Конечно они через хак (помните, все это объект):
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
Последнее даже не приводит к снижению производительности, так как никто не будет звонить Fixnum.substr
нарочно.
- уточнения выполняются через eval
, refine
это не ключевое слово. Ба. (хорошо, снова "ба!")
Итак, мой вопрос: я что-то упускаю или все не видят никаких преимуществ во вновь представленной функции?
1 ответ
Вы полностью отвергаете тот факт, что уточнения не имеют глобальных масштабов, но это и есть причина их введения. Конечно, если вы просто игнорируете причину существования чего-либо, вы, очевидно, не увидите в этом никакой ценности.
Но посмотрите на изоляцию в действии. Вот ваш пример, модифицированный для использования уточнений:
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
Вот ваш пример для сравнения:
module MyModule
class ::String
def my_locally_needed_func
# do smth
end
end
end
# here I need it
"".my_locally_needed_func
Примечание: я удалил звонок using
что не имело смысла, так как вы все равно не использовали уточнения.
В вашем случае monkeypatch доступен во всем мире, потому что вы просто изменили String
учебный класс. Эта функциональность называется "открытым классом", и это именно то, чего стоит избегать Уточнения.