Je dois autoriser la définition et l'appel de blocs dans le cadre d'une classe, en utilisant instance_exec
(via Rails 2.3.2). Cependant, certains de ces blocs doivent revenir tôt dans certaines situations, ce qui me cause un problème.Retour anticipé d'un bloc donné à instance_exec
Mon application a été compilée en utilisant ruby 1.8.6, mais je dois la faire tourner sur 1.8.7 aussi. Il semble que, entre les deux versions, la possibilité de revenir de l'intérieur d'un lambda a été supprimée. Les travaux suivants en 1.8.6, mais jette un LocalJumpError
(retour inattendu) dans 1.8.7:
class Foo
def square(n)
n ** 2
end
def cube(n)
n ** 3
end
def call_block(*args, &block)
instance_exec *args, &block
end
end
block = lambda { |n|
return square(n) if n < 5
cube(n)
}
f = Foo.new
f.call_block(5, &block) # returns 125
f.call_block(3, &block) # returns 9 in 1.8.6, throws a LocalJumpError in 1.8.7
Je déterminé que je pouvais le faire fonctionner en 1.8.7 si je l'ai remplacé return
dans mon bloc avec next
, mais next square(n) if n < 5
donne nil
en 1.8.6.
Y at-il un moyen que je peux obtenir ce travail à la fois dans 1.8.6 et 1.8.7? Je sais que je peux restructurer mes blocs pour utiliser le branchement au lieu d'un retour anticipé, mais certains blocs sont plus complexes et ont plusieurs situations où un retour anticipé est nécessaire.
Aussi, est-ce que cela va changer plus loin si je veux que mon code fonctionne dans ruby 1.9?
Edit: J'ai découvert que la raison pour laquelle il travaille en 1.8.6 et non 1.8.7 est que 1.8.7 définit sa propre instance_exec
dans la source de C, alors que 1.8.6 utilise la mise en œuvre de Rails. Si je remplace instance_exec
en 1.8.7 avec la version de Rails, cela fonctionne aussi.
J'ai voté parce que votre refactoring fonctionne; cependant, le point d'utilisation de instance_exec était tel que l'objet n'a pas besoin d'être transmis aux blocs. Cela fait partie d'un moteur de templates où les utilisateurs (du code) sont capables de créer leurs propres commandes, donc je voulais que ce soit aussi simple que possible de le faire. –
Ok, je comprends. Les utilisateurs vont définir le bloc. J'ai trouvé intéressant que votre code fonctionne correctement sous ruby 1.9 mais pas sous 1.8.7. Instance_exec n'existe que dans les versions 1.8.7 et 1.9. Rails a ajouté sa propre version dans Active_support ce qui lui a permis d'être utilisé dans 1.8.6. – coreypurcell
Je pense que je comprends ce qui se passe maintenant. Voir l'édition. – coreypurcell