52 votes

définir une méthode pour une instance de classe

Soyez-en class Example défini comme:

class Example
  def initialize(test='hey')
    self.class.send(:define_method, :say_hello, lambda { test })
  end
end

Sur l'appel de Example.new; Example.new - je obtenir un warning: method redefined; discarding old say_hello. Cela, je conclus, doit être parce qu'il définit une méthode dans la classe réelle (ce qui est logique, à partir de la syntaxe). Et que, bien sûr, serait désastreuse devrait-il y avoir plusieurs instances d' Example avec des valeurs différentes dans leurs méthodes.

Est-il possible de créer des méthodes juste pour l'exemple d'une classe de l'intérieur de cette instance?

Merci beaucoup.

81voto

thorncp Points 1812

Vous devez saisir une référence à la classe singleton de l'instance, la classe qui contient tous les éléments spécifiques à l'instance, et définir la méthode correspondante. En ruby 1.8, ça a l'air un peu brouillon. (si vous trouvez une solution plus propre, faites le moi savoir!)

Ruby 1.8

 class Example
  def initialize(test='hey')
    singleton = class << self; self end
    singleton.send :define_method, :say_hello, lambda { test }
  end
end
 

Ruby 1.9 fournit cependant un moyen beaucoup plus facile à l’intérieur.

Ruby 1.9

 class Example
  def initialize(test='hey')
    define_singleton_method :say_hello, lambda { test }
  end
end
 

40voto

Jörg W Mittag Points 153275

Tout d'abord, une petite pointe de style:

self.class.send(:define_method, :say_hello, lambda { test })

Vous pouvez le rendre un peu plus agréable en utilisant le nouveau proc littérale de Ruby 1.9:

self.class.send(:define_method, :say_hello, -> { test })

Mais vous n'en avez pas besoin. Ruby a quelque chose qui s'appelle des blocs, qui sont fondamentalement un morceau de code que vous pouvez passer en argument à une méthode. En fait, vous avez déjà utilisé des blocs, depuis lambda est juste une méthode qui prend un bloc en argument et renvoie un Proc. Toutefois, define_method déjà prend un bloc de toute façon, il n'est pas nécessaire de passer d'un bloc à l' lambda qui la convertit en Proc qu'il transmet à la define_method qui reconvertit en un bloc:

self.class.send(:define_method, :say_hello) { test }

Comme vous l'avez déjà remarqué, vous êtes à la définition de la méthode sur la mauvaise classe. Vous définissez sur l' Example classe, depuis l'intérieur d'une méthode d'instance comme initialize, self est l'objet courant (c'est à dire ex1 ou ex2 dans @mikej exemple), ce qui signifie qu' self.class est ex1's de la classe, qui est - Example. Donc, vous l'écrasez la même méthode, encore et encore.

Ceci conduit à considérer un comportement non désiré:

ex1 = Example.new('ex1')
ex2 = Example.new('ex2') # warning: method redefined; discarding old say_hello
ex1.say_hello            # => ex2 # Huh?!?

Au lieu de cela, si vous voulez un singleton méthode, vous devez définir dans la classe singleton:

(class << self; self end).send(:define_method, :say_hello) { test }

Cela fonctionne comme prévu:

ex1 = Example.new('ex1')
ex2 = Example.new('ex2')
ex1.say_hello            # => ex1
ex2.say_hello            # => ex2

En Ruby 1.9, il y a une méthode qui fait que:

define_singleton_method(:say_hello) { test }

Maintenant, cela fonctionne de la façon dont vous le souhaitez, mais il y a un niveau plus élevé problème ici: ce n'est pas du code Ruby. Il est Ruby syntaxe, mais ce n'est pas du code Ruby, c'est Régime.

Maintenant, est un brillant de la langue et de l'écriture Régime de code dans la syntaxe Ruby est certainement pas une mauvaise chose à faire. Il bat l'enfer hors de l'écriture, du Java ou du code PHP dans la syntaxe Ruby, ou, comme ce fut le cas dans un StackOverflow question hier, Fortran-57 du code de syntaxe Ruby. Mais ce n'est pas aussi bonne que l'écriture de Ruby code dans la syntaxe Ruby.

Scheme est un langage fonctionnel. Les langages fonctionnels utilisation des fonctions (plus précisément, les fermetures de fonction) pour l'encapsulation et de l'état. Mais Ruby n'est pas un langage fonctionnel, c'est un langage orienté objet et les langages à objets utiliser des objets pour l'encapsulation et de l'état.

Ainsi, la fonction de fermetures de devenir des objets et capturé variables deviennent des variables d'instance.

Nous pouvons également venir à ce à partir d'un angle complètement différent: ce que vous faites, c'est que vous êtes à la définition d'un singleton méthode, qui est une méthode dont le but est de définir un comportement qui est spécifique à un objet. Mais la définition que singleton méthode pour chaque instance de la classe, et de la définition de la même singleton méthode pour chaque instance de la classe. Nous avons déjà un mécanisme pour définir le comportement de chaque instance d'une classe: les méthodes d'instance.

Deux de ces arguments proviennent des directions complètement opposées, mais ils arrivent à la même destination:

class Example
  def initialize(test='hey')
    @test = test
  end

  def say_hello
    @test
  end
end

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X