In their Polite Programmer talk at Rubyconf, Jim Weirich and Chris Nelson pointed out that merely adding some behavior with method_missing wasn’t quite polite, as shown below:
123456789101112131415
classStereoPlayerdefmethod_missing(method,*args,&block)ifmethod.to_s=~/play_(\w+)/puts"Here's #{$1}"elsesuperendendendp=StereoPlayer.new# ok:p.play_some_Beethoven# => "Here's some_Beethoven"# not very polite:p.respond_to?:play_some_Beethoven# => false
In order for respond_to? to return true, one can specialize it, as follows:
This is better, but it still doesn’t make play_some_Beethoven behave exactly like a method. Indeed:
123
p.method:play_some_Beethoven# => NameError: undefined method `play_some_Beethoven'# for class `StereoPlayer'
Ruby 1.9.2 introduces respond_to_missing? that provides for a clean solution to the problem. Instead of specializing respond_to? one specializes respond_to_missing?. Here’s a full example:
1234567891011121314151617181920
classStereoPlayer# def method_missing ...# ...# enddefrespond_to_missing?(method,*)method=~/play_(\w+)/||superendendp=StereoPlayer.newp.play_some_Beethoven# => "Here's some_Beethoven"p.respond_to?:play_some_Beethoven# => truem=p.method(:play_some_Beethoven)# => #<Method: StereoPlayer#play_some_Beethoven># m acts like any other method:m.call# => "Here's some_Beethoven"m==p.method(:play_some_Beethoven)# => truem.name# => :play_some_BeethovenStereoPlayer.send:define_method,:ludwig,mp.ludwig# => "Here's some_Beethoven"