comment la méthode de délégation de rails fonctionne?

Après la lecture de la réponse par jvans ci-dessous et en regardant le code source un peu plus de temps, je comprends maintenant :). Et dans le cas où quelqu'un se demande encore comment exactement rails délégués des œuvres. Tous les rails est en train de faire est de créer une nouvelle méthode (module_eval) dans le fichier/classe l'exécution de la méthode du délégué de.

Ainsi, par exemple:

  class A
    delegate :hello, :to => :b
  end

  class B
    def hello
     p hello
    end
  end

Au point lorsque le délégué est appelé rails de créer une méthode hello (*args, &bloc) dans la classe A (techniquement dans le fichier de classe A) et en ce que la méthode de tous les rails n'est utilise le ":" la valeur(qui doit être un objet ou une Classe qui est déjà défini dans la classe A) et de l'affecter à une variable locale _, puis appelle simplement la méthode sur un objet ou une Classe de passage dans les params.

Donc, pour délégué à travailler sans lever une exception... avec notre exemple précédent. Une instance d'Un devez déjà disposer d'une instance de variable fait référence à une instance de la classe 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

Ce n'est pas une question sur "comment utiliser la méthode du délégué dans les rails", qui je le sais déjà. Je me demande comment exactement "délégué" délégués méthodes :D. Dans les Rails 4 code source délégué est défini dans le cœur de Ruby Module de classe, qui le rend disponible comme une méthode de classe dans toutes les application rails.

En fait, ma première question serait de savoir comment est Ruby Module de classe inclus? Je veux dire que chaque classe Ruby a des ancêtres de > Object > Noyau > BasicObject et un module de ruby a les mêmes ancêtres. Alors, comment exactement comment ruby ajouter des méthodes à toutes les classe ruby/modules quand quelqu'un ouvre de nouveau le Module de classe?

Ma deuxième question est.. je comprends que le délégué de la méthode dans les rails utilise module_eval de faire le même délégation, mais je ne comprends pas vraiment comment module_eval œuvres.

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(<<-EOS, file, line - 3)
def #{method_prefix}#{method}(#{definition})        # def customer_name(*args, &block)
_ = #{to}                                         #   _ = client
if !_.nil? || nil.respond_to?(:#{method})         #   if !_.nil? || nil.respond_to?(:name)
_.#{method}(#{definition})                      #     _.name(*args, &block)
end                                               #   end
end                                                 # end
EOS
else
exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
module_eval(<<-EOS, file, line - 2)
def #{method_prefix}#{method}(#{definition})                                          # def customer_name(*args, &block)
_ = #{to}                                                                           #   _ = client
_.#{method}(#{definition})                                                          #   _.name(*args, &block)
rescue NoMethodError => e                                                             # rescue NoMethodError => e
if _.nil? && e.name == :#{method}                                                   #   if _.nil? && e.name == :name
#{exception}                                                                      #     # add helpful message to the exception
else                                                                                #   else
raise                                                                             #     raise
end                                                                                 #   end
end                                                                                   # end
EOS
end
end

fin

source d'informationauteur Steve007