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
Vous devez vous connecter pour publier un commentaire.
Ruby n'est pas la réouverture de la classe de module ici. En ruby, le Module de classe et la classe de la Classe sont presque identiques.
La principale différence est que vous ne pouvez pas "nouveau " module".
Du Module sont de ruby version de l'héritage multiple, donc quand vous n':
derrière les coulisses ruby est de réellement créer quelque chose qui s'appelle une classe anonyme. ainsi, le ci-dessus est en fait équivalent à:
module_eval ici est un peu trompeur. Rien dans le code que vous êtes en train de regarder est de traiter avec les modules. class_eval et module_eval sont la même chose et ils viennent juste de rouvrir la classe à laquelle ils sont appelés sur donc, si vous voulez ajouter des méthodes à une classe C, vous pouvez le faire:
ou
les deux sont équivalentes manuellement la réouverture de la classe et de la définition de la méthode
donc quand ils appellent module_eval dans la source ci-dessus, ils sont juste à la réouverture de la classe courante, c'est d'être appelé et dynamique, en définissant les méthodes que vous êtes en déléguant
Je pense que cela va répondre à votre question mieux:
depuis tout en ruby, c'est une classe, la méthode de recherche de la chaîne va passer par tous ces objets jusqu'à ce qu'il trouve ce qu'il cherche. Par reoping module vous ajouter un comportement à tout. L'ancêtre de la chaîne ici est un peu trompeur, car BasicObject.class #=> Classe et le Module est dans la Classe de recherche de la hiérarchie, même BasicObject hérite comportement de repening module. L'avantage de la réouverture de Module ici plus de Classe, c'est que vous pouvez maintenant appeler cette méthode à partir d'un module ainsi que dans une classe! Très cool, appris quelque chose ici moi-même.
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:
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.