Ruby 2.0: respond_to?
It's really quite rare that a new realease of Ruby changes a behavior, and by
"rare", I mean really rare. But, there's one change in Ruby 2.0 that is
definitely breaking some code.
Let's have a look at this example:
<span class="k">class</span> <span class="nc">Lolcat</span> <span class="kp">protected</span> <span class="k">def</span> <span class="nf">serious?</span> <span class="kp">false</span> <span class="k">end</span> <span class="kp">private</span> <span class="k">def</span> <span class="nf">ohai</span> <span class="nb">puts</span> <span class="s2">"ohai"</span> <span class="k">end</span><span class="k">end</span><span class="no">Lolcat</span><span class="o">.</span><span class="n">new</span><span class="o">.</span><span class="n">tap</span> <span class="k">do</span> <span class="o">|</span><span class="n">lolcat</span><span class="o">|</span> <span class="nb">puts</span> <span class="n">lolcat</span><span class="o">.</span><span class="n">respond_to?</span><span class="p">(</span><span class="ss">:serious?</span><span class="p">)</span> <span class="nb">puts</span> <span class="n">lolcat</span><span class="o">.</span><span class="n">respond_to?</span><span class="p">(</span><span class="ss">:ohai</span><span class="p">)</span><span class="k">end</span>
Running this code with Ruby 1.9.3:
<span class="go">ruby lolcat.rb</span><span class="gp">#</span> <span class="nb">true</span><span class="gp">#</span><span class="nb"> false</span>
Running this code with Ruby 2.0:
<span class="go">ruby lolcat.rb</span><span class="gp">#</span> <span class="nb">false</span><span class="gp">#</span><span class="nb"> false</span>
What is happening here ?
From Ruby 2.0, respond_to?
behavior changed to check only public methods.
Before that, public and protected methods were checked.
This change makes actually perfect sense, but it can break some code when
running 2.0:
respond_to?
respond_to?
takes a second argument to check against all methods (protected and private). By
default, this second argument is false.
<span class="no">Lolcat</span><span class="o">.</span><span class="n">new</span><span class="o">.</span><span class="n">tap</span> <span class="k">do</span> <span class="o">|</span><span class="n">lolcat</span><span class="o">|</span> <span class="nb">puts</span> <span class="n">lolcat</span><span class="o">.</span><span class="n">respond_to?</span><span class="p">(</span><span class="ss">:serious?</span><span class="p">,</span> <span class="kp">true</span><span class="p">)</span> <span class="nb">puts</span> <span class="n">lolcat</span><span class="o">.</span><span class="n">respond_to?</span><span class="p">(</span><span class="ss">:ohai</span><span class="p">,</span> <span class="kp">true</span><span class="p">)</span><span class="k">end</span>
Running this code with Ruby 1.9.3:
<span class="go">ruby lolcat.rb</span><span class="gp">#</span> <span class="nb">true</span><span class="gp">#</span><span class="nb"> true</span>
Running this code with Ruby 2.0:
<span class="go">ruby lolcat.rb</span><span class="gp">#</span> <span class="nb">true</span><span class="gp">#</span><span class="nb"> true</span>
The other way of making this code run as expected would be to declare this
method as public. But, sometimes, you do not want a particular method to be
public, and yet, you want to call respond_to
, like for instance in an
ActiveRecord callback.