как работает метод делегата рельсов?
После прочтения ответа от jvans ниже и просмотра исходного кода еще несколько раз я получаю его сейчас :). И если кому-то все еще интересно, как именно работают делегаты рельсов. Все, что делает rails - это создает новый метод с (module_eval) в файле / классе, из которого вы запускали метод делегата.
Так, например:
class A
delegate :hello, :to => :b
end
class B
def hello
p hello
end
end
В тот момент, когда делегат вызывается, rails создаст метод hello с (* args, &block) в классе A (технически в файле, в котором написан класс A), и в этом методе все, что делает rails, использует ": К» value (который должен быть объектом или классом, который уже определен в классе A) и назначить его локальной переменной _, а затем просто вызывает метод для этого объекта или класса, передавая параметры.
Таким образом, чтобы делегат работал, не вызывая исключения ... с нашим предыдущим примером. Экземпляр A должен уже иметь переменную экземпляра, ссылающуюся на экземпляр класса B.
class A
attr_accessor :b
def b
@b ||= B.new
end
delegate :hello, :to => :b
end
class B
def hello
p hello
end
end
Это не вопрос "как использовать метод делегата в рельсах ", который я уже знаю. Я'мне интересно как именноделегировать» методы делегатов: D. В Rails 4 делегат исходного кода определяется в базовом классе Ruby Module, что делает его доступным в качестве метода класса во всех приложениях rails.
На самом деле мой первый вопрос будет как РубиМодуль включен в класс? Я имею в виду, что у каждого класса Ruby есть предки> Объект> Ядро> BasicObject и любой модуль в ruby имеют одинаковых предков. Итак, как именно ruby добавляет методы ко всем классам / модулям ruby, когда кто-то открывает класс Module?
Мой второй вопрос .. Я понимаю, что метод делегата в rails использует module_eval для фактического делегирования, но я неЯ действительно не понимаю, как работает module_eval.
def delegate(*methods)
options = methods.pop
unless options.is_a?(Hash) && to = options[:to]
raise ArgumentError, 'Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter).'
end
prefix, allow_nil = options.values_at(:prefix, :allow_nil)
if prefix == true && to =~ /^[^a-z_]/
raise ArgumentError, 'Can only automatically set the delegation prefix when delegating to a method.'
end
method_prefix = \
if prefix
"#{prefix == true ? to : prefix}_"
else
''
end
file, line = caller.first.split(':', 2)
line = line.to_i
to = to.to_s
to = 'self.class' if to == 'class'
methods.each do |method|
# Attribute writer methods only accept one argument. Makes sure []=
# methods still accept two arguments.
definition = (method =~ /[^\]]=$/) ? 'arg' : '*args, &block'
# The following generated methods call the target exactly once, storing
# the returned value in a dummy variable.
#
# Reason is twofold: On one hand doing less calls is in general better.
# On the other hand it could be that the target has side-effects,
# whereas conceptually, from the user point of view, the delegator should
# be doing one call.
if allow_nil
module_eval(