Method_missing gotchas in Ruby

Are there any questions to consider when defining a method_missing method in Ruby? I am wondering if there are any not so obvious interactions from inheritance, throwing exceptions, performance, or anything else.

+46
ruby metaprogramming
Nov 14 '08 at 19:39
source share
5 answers

Somewhat obvious: always override respond_to? if you override method_missing . If method_missing(:sym) working, respond_to?(:sym) should always return true. There are many libraries for this.

Further:

Example:

 # 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 
+57
Nov 14 '08 at 22:57
source share

If your method, which is not in the method, searches only for specific method names, do not forget to call super if you did not find what you are looking for, so that other missing methods can perform their task.

+11
Apr 23 '11 at 0:30
source share

If you can anticipate method names, it is better to declare them dynamically than rely on method_missing, because method_missing carries a performance penalty. For example, suppose you want to extend a database descriptor to be able to access database views using this syntax:

 selected_view_rows = @dbh.viewname( :column => value, ... ) 

Instead of relying on method_missing on the database descriptor and sending the method name to the database as the name of the view, you could pre-define all the views in the database and then iterate over them to create the "viewname" methods on @dbh.

+9
Nov 15 '08 at 18:00
source share

Based on Pistol Point : method_missing is at least an order of magnitude slower than the regular method that calls all the Ruby implementations I tried. He is right when you can avoid calls to method_missing .

If you're feeling adventurous, check out the little-known ruby class .

+5
Nov 17 '08 at 23:49
source share

Other information:

method_missing behaves differently between obj.call_method and obj.send(:call_method) . In fact, the first of them skips all private and undefined methods, and later does not skip private methods.

So, you method_missing will never catch a call when someone calls your private method via send .

0
Mar 13 '17 at 6:22
source share



All Articles