Y a-t-il des choses auxquelles il faut faire attention lors de la définition de la method_missing
en Ruby ? Je me demande s'il y a des interactions pas si évidentes que ça entre l'héritage, la levée d'exceptions, les performances ou autre chose.
Réponses
Trop de publicités?Un point assez évident : toujours redéfinir respond_to?
si vous redéfinissez method_missing
. Si method_missing(:sym)
travaux, respond_to?(:sym)
devrait toujours retourner vrai. De nombreuses bibliothèques s'appuient sur ce principe.
Plus tard :
Un exemple :
# Wrap a Foo; don't expose the internal guts.
# Pass any method that starts with 'a' on to the
# Foo.
class FooWrapper
def initialize(foo)
@foo = foo
end
def some_method_that_doesnt_start_with_a
'bar'
end
def a_method_that_does_start_with_a
'baz'
end
def respond_to?(sym, include_private = false)
pass_sym_to_foo?(sym) || super(sym, include_private)
end
def method_missing(sym, *args, &block)
return foo.call(sym, *args, &block) if pass_sym_to_foo?(sym)
super(sym, *args, &block)
end
private
def pass_sym_to_foo?(sym)
sym.to_s =~ /^a/ && @foo.respond_to?(sym)
end
end
class Foo
def argh
'argh'
end
def blech
'blech'
end
end
w = FooWrapper.new(Foo.new)
w.respond_to?(:some_method_that_doesnt_start_with_a)
# => true
w.some_method_that_doesnt_start_with_a
# => 'bar'
w.respond_to?(:a_method_that_does_start_with_a)
# => true
w.a_method_that_does_start_with_a
# => 'baz'
w.respond_to?(:argh)
# => true
w.argh
# => 'argh'
w.respond_to?(:blech)
# => false
w.blech
# NoMethodError
w.respond_to?(:glem!)
# => false
w.glem!
# NoMethodError
w.respond_to?(:apples?)
w.apples?
# NoMethodError
Si vous pouvez anticiper les noms des méthodes, il est préférable de les déclarer dynamiquement plutôt que de compter sur method_missing, car method_missing entraîne une pénalité de performance. Par exemple, supposons que vous vouliez étendre un handle de base de données pour pouvoir accéder aux vues de la base de données avec cette syntaxe :
selected_view_rows = @dbh.viewname( :column => value, ... )
Plutôt que de s'appuyer sur method_missing sur le handle de la base de données et d'envoyer le nom de la méthode à la base de données en tant que nom d'une vue, vous pourriez déterminer toutes les vues de la base de données à l'avance, puis itérer sur elles pour créer des méthodes "viewname" sur @dbh.
Construire sur Le point de vue de Pistos : method_missing
est au moins un ordre de grandeur plus lent que l'appel de méthode ordinaire dans toutes les implémentations Ruby que j'ai essayées. Il a raison d'anticiper quand c'est possible pour éviter les appels à method_missing
.
Si vous vous sentez l'âme d'un aventurier, allez voir le site peu connu de Ruby. Délégué classe.