глюки method_missing в Ruby

49
задан undur_gongor 29 April 2013 в 10:54
поделиться

3 ответа

Несколько очевидный: всегда переопределяйте respond_to?, если Вы переопределяете method_missing. Если method_missing(:sym) работы, respond_to?(:sym) должны всегда возвращать true. Существуют многие библиотеки, которые полагаются на это.

Позже:

пример:

# Wrap a Foo; don't expose the internal guts.
# Pass any method that starts with 'a' on to the
# Foo.
class FooWrapper
  def initialize(foo)
    @foo = foo
  end
  def some_method_that_doesnt_start_with_a
    'bar'
  end
  def a_method_that_does_start_with_a
    'baz'
  end
  def respond_to?(sym, include_private = false)
    pass_sym_to_foo?(sym) || super(sym, include_private)
  end
  def method_missing(sym, *args, &block)
    return foo.call(sym, *args, &block) if pass_sym_to_foo?(sym)
    super(sym, *args, &block)
  end
  private
  def pass_sym_to_foo?(sym)
    sym.to_s =~ /^a/ && @foo.respond_to?(sym)
  end
end

class Foo
  def argh
    'argh'
  end
  def blech
    'blech'
  end
end

w = FooWrapper.new(Foo.new)

w.respond_to?(:some_method_that_doesnt_start_with_a)
# => true
w.some_method_that_doesnt_start_with_a
# => 'bar'

w.respond_to?(:a_method_that_does_start_with_a)
# => true
w.a_method_that_does_start_with_a
# => 'baz'

w.respond_to?(:argh)
# => true
w.argh
# => 'argh'

w.respond_to?(:blech)
# => false
w.blech
# NoMethodError

w.respond_to?(:glem!)
# => false
w.glem!
# NoMethodError

w.respond_to?(:apples?)
w.apples?
# NoMethodError
60
ответ дан James A. Rosen 7 November 2019 в 11:42
поделиться

Если можно ожидать имена методов, лучше динамично объявить их, чем полагаться на method_missing, потому что method_missing подвергается потере производительности. Например, предположите, что Вы хотели расширить дескриптор базы данных, чтобы быть в состоянии получить доступ к представлениям базы данных с этим синтаксисом:

selected_view_rows = @dbh.viewname( :column => value, ... )

Вместо того, чтобы полагаться на method_missing на дескрипторе базы данных и отправить имя метода базе данных как название представления, Вы могли определить все представления в базе данных загодя, затем выполнить итерации по ним для создания "viewname" методов на @dbh.

11
ответ дан Pistos 7 November 2019 в 11:42
поделиться

Построение точка Pistos : method_missing, по крайней мере, порядок величины медленнее, чем обычный метод, обращающийся ко всем реализациям Ruby, которые я попробовал. Он прав ожидать, если это возможно, для предотвращения вызовов к method_missing.

, Если Вы чувствуете себя предприимчивыми, проверьте Ruby, малоизвестный класс Delegator .

5
ответ дан Community 7 November 2019 в 11:42
поделиться