как работает метод делегата рельсов?

После прочтения ответа от 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(

Ответы на вопрос(2)

Ваш ответ на вопрос