Je travaille sur un projet où, dans la suite de tests, nous appelons un tas de méthodes au sein d'une classe Nous devons les conserver, mais ils arrêtent le programme lorsqu'ils sont appelés, donc pour contourner le problème, j'essaie de trouver un moyen de pousser les appels de méthode dans un tableau, afin que je puisse les traiter plus tard.
Le problème est un peu similaire à ceci à ce stade:
class Dog assert 1 + 1 =2 end
La question est: y a-t-il un moyen de STOCKER ces appels de méthode dans un tableau, à exécuter plus tard? p>
Edit:
def hello(greeting) puts greeting end class Dog hello "Cat" hello "Bear" hello "Snake" hello "Pig" hello "Cow" hello "Wolf" hello "Lion" end
c'est plus proche du code avec lequel je travaille, les classes contiennent des assertions qui arrêtent le programme en cas d'échec. Je dois garder la même classe dans la suite de tests, donc je ne peux pas supprimer ces assertions - mais si je veux tester la même chose dans la suite de tests, je ne peux pas les déclencher. C'est pourquoi je veux trouver un moyen d'itérer dans la classe et de pousser les appels de méthode vers un tableau - pour les exécuter après l'exécution de la suite de tests. J'espère que c'est un peu plus clair
Je pense qu'il y a un malentendu. La CLASSE ne peut pas changer. J'essaie de parcourir une classe pour parcourir dynamiquement les instances d'une méthode qui est déjà appelée.
Puis-je parcourir la classe Dog et écrire une méthode pour chaque bonjour?
p>
3 Réponses :
Pourquoi ne pas simplement créer une autre méthode qui effectue les appels souhaités et appeler cette méthode lorsque cela est nécessaire? Quelque chose comme ceci:
def hello(greeting)
puts greeting
end
class Dog
def self.sayHello()
hello "Cat"
hello "Bear"
hello "Snake"
hello "Pig"
hello "Cow"
hello "Wolf"
hello "Lion"
end
end
# later
Dog.sayHello()
SyntaxError , et lorsque vous corrigez cela, NoMethodError .
Parce que, comme le mentionne l'OP, il n'est pas autorisé à modifier la classe Dog : "Je dois garder la même classe dans la suite de tests."
La réponse à la question que vous avez posée est:
hello_targets = %w[Cat Bear Snake Pig Cow Wolf Lion]
# later, whenever you want
hello(args[4]) # puts 'Cow'
hello_targets.each { |target| hello(target) }
Cependant, j'ai l'impression que ce que vous voulez vraiment n'est pas encapsulé dans la question que vous avez posée .
Par exemple, étant donné l'exemple que vous avez publié, il n'y a pas de bonne raison de le faire comme je l'ai publié ci-dessus. Le code ci-dessous est plus simple et fait la même chose.
def hello(greeting)
puts greeting
end
hello_targets = %w[Cat Bear Snake Pig Cow Wolf Lion]
lazy_greetings = hello_targets.map do |target|
-> { hello(target) }
end
# later, whenever you want
lazy_greetings[4].call # puts 'Cow'
lazy_greetings.each(&:call)
# Cat
# Bear
# Snake
# Pig
# Cow
# Wolf
# Lion
Je veux trouver un moyen d'itérer dans la classe et de pousser les appels de méthode vers un tableau - pour les exécuter après l'exécution de la suite de tests.
Si vous souhaitez différer un appel de méthode, vous pouvez en effet le stocker dans un tableau. Vous pouvez ensuite utiliser
#sendpour l'appeler quand vous le souhaitez. Voici un exemple:require 'singleton' def hello(method) DogWalker.instance.add_method(method) end class DogWalker include Singleton def initialize @methods = [] end def add_method(method) @methods << method.downcase.to_sym end def call_methods @methods.each do |m| self.respond_to?(m) ? send(m) : send(:etc) end end def cat puts 'called Cat' end def bear puts 'called Bear' end def snake puts 'called Snake' end def pig puts 'called Pig' end def etc puts 'called one of the others' end end class Dog hello "Cat" hello "Bear" hello "Snake" hello "Pig" hello "Cow" hello "Wolf" hello "Lion" end Dog DogWalker.instance.call_methodsUn point important est que les noms de méthodes sont stockés en interne dans Ruby sous forme de symboles, donc à chaque fois que vous
définissezune méthode, le Le nom de la méthode est stocké sous forme de symbole. Ensuite, vous pouvez utiliser le symbole avec#sendpour appeler la méthode. Si vous bricolez un peu cette idée, vous devriez obtenir ce que vous voulez.Edit: Take Two
J'ai jeté un autre regard sur votre problème, et je pense avoir une meilleure prise en main. il. Vous devez toujours utiliser
#send, mais il y a plus.Vous avez un certain nombre d'appels directs à la méthode
hellodans votre classe, ce qui rend certaines choses difficiles. Si vous ajoutez cette ligne:Dogà votre code, vous obtiendrez une liste de tous les animaux, un par un.
Si, à la place, vous voulez stocker les appels de méthode à un tableau à appeler plus tard, vous devez trouver un endroit pour placer le tableau. C'est difficile:
- Vous ne pouvez pas modifier la classe
Dog, vous ne pouvez donc pas la placer ici.- Vous ne pouvez pas le mettre dans la méthode
hello, car il ne conservera pas ses valeurs entre les appels.- Vous ne pouvez pas le mettre dans une autre classe puis l'instancier, car vous ne pouvez pas ensuite passer l'instance dans
hello; puisquehelloest appelé par la classe et que vous n'êtes pas autorisé à changer de classe, vous ne pouvez pas modifier ces appels pour passer dans l'instance.Après un peu de bricolage, j'ai trouvé une solution. Ce dont vous avez besoin est une classe qui fait le travail pour vous (nommée de manière appropriée
DogWalkerici), instanciée en tant qu'instance singleton:def a puts 'Called a' end def b puts 'Called b' end def c puts 'Called c' end def d puts 'Called d' end def my_test methods = [] # assert this, assert that, and # if I need to call method a, then methods << :a # and so on... methods << :b methods << :c methods << :d end # Now, to call the methods in the array: my_test.each { |method| send method }Pour ce faire , vous devez avoir besoin du module
singleton. Ce module expose une méthode:: instance, qui dit essentiellement "S'il existe déjà une instance de cette classe, renvoyez-la. Sinon, créez-en une nouvelle."La classe
DogWalkerest exposée comme une instance singleton, en appelantDogWalker :: instancepartout où nous la référencons. De cette façon, nous travaillons toujours avec la même instance deDogWalker.Nous exécutons d'abord
Dog, qui appelle lehello code> dans votre classeDogplusieurs fois.bonjourappelleDogWalker.instance.add_method, qui (crée une instance deDogWalkerla première et seulement la première fois que#instance est appelé, et) pousse le symbole de méthode sur le tableau@methods.Cette variable est conservée entre les appels de méthode à
hello; puisque nous utilisons la méthodeinstance, nous continuons à travailler avec la même instance deDogWalker. (De cette façon, nous n'avons pas besoin de mettreDogWalker.newdans la méthodehello, ou de le mettre en dehors de la méthodehelloet de le passer dans. Le premier continuerait à réinitialiser@methods, et nous ne sommes pas autorisés à faire le second.)Quand nous aurons terminé, appelons le
La méthodeexécute toutes les méthodes une par une (j'ai juste abrégé aveccall_methodsde l'instance DogWalkeretcdans l'exemple).Donc, ceci vous permet d'exécuter votre classe
Doget de différer l'appel de toutes ces méthodes jusqu'à ce que la classeDogsoit terminée.Les appels de méthode directs dans une classe sont un joli horrible façon de concevoir les choses, mais comme vous le dites, vos mains sont liées et vous devriez pouvoir modifier cela pour faire votre travail.
Merci, c'est assez utile, le problème que j'ai cependant est que j'essaie d'itérer dans la classe telle quelle et de stocker les appels de méthode, donc si la méthode est appelée 4 fois, elle est poussée 4 fois, si 5 fois , puis 5 méthodes sont stockées.
@LouisRaymond En lisant un peu entre les lignes, je pense avoir compris quel est votre problème et proposer ce que je pense être une solution pour vous.
C'est bien! Merci beaucoup :-)
@LouisRaymond De rien. Je n'ai jamais trouvé d'occasions d'utiliser 'singleton' auparavant, alors j'ai aussi appris quelque chose. Un code bizarre a ses objectifs, je suppose. :)
"mais ils arrêtent le programme lorsqu'ils sont appelés" Pouvez-vous expliquer plus à ce sujet? Arrêtez comment? une erreur?
Vous pouvez utiliser Procs ou lambdas pour stocker des fermetures dans un tableau, mais votre exemple de code publié ne semble pas justifier la complexité de cette opération. Il serait probablement préférable de stocker les résultats ou les entrées.
La classe est dans notre suite de tests, et la méthode "hello" est en fait une assertion, donc la difficulté à laquelle je suis confronté est d'utiliser l'assert, mais en essayant de la retarder lors de l'écriture des tests. Je suis obligé de conserver les affirmations dans le corps de la classe