Являются ли доработки в 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 учебный класс. Эта функциональность называется "открытым классом", и это именно то, чего стоит избегать Уточнения.

Другие вопросы по тегам