Gray Soft / Ruby Tutorials / Class Level Mix-instag:graysoftinc.com,2014-03-20:/posts/112014-03-27T01:38:23ZJames Edward Gray IIThe 1st Comment on "Class Level Mix-ins"tag:graysoftinc.com,2006-03-03:/comments/182014-03-27T01:38:23ZHmm... this now makes extend really clear to me, I've never hit a case where I *absolutely* needed it but plenty of places where this would have been handy if I knew how to use it.
Thanks James!<p>Hmm... this now makes extend really clear to me, I've never hit a case where I <em>absolutely</em> needed it but plenty of places where this would have been handy if I knew how to use it.</p>
<p>Thanks James!</p>Gregory BrownClass Level Mix-instag:graysoftinc.com,2006-02-22:/posts/112014-03-28T21:32:39ZIn this article, I show how to mix methods in as class methods, instead of instance methods.<p>A question that comes up pretty often in Ruby circles was posed again today, by Xavier Noria:</p>
<div class="highlight highlight-ruby"><pre><span class="c1">#</span>
<span class="c1"># Is there standard idiom to add module methods to classes that mix them in?</span>
<span class="c1">#</span>
<span class="c1"># That is, I would like class C to croak:</span>
<span class="c1">#</span>
<span class="k">module</span> <span class="nn">M</span>
<span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">croak</span>
<span class="nb">puts</span> <span class="s2">"Croak!"</span>
<span class="k">end</span>
<span class="k">end</span>
<span class="k">class</span> <span class="nc">C</span>
<span class="kp">include</span> <span class="n">M</span>
<span class="n">croak</span> <span class="c1"># doesn't work</span>
<span class="k">end</span>
</pre></div>
<p>This brings up a couple of interesting points about mix-ins. Obviously, class methods are not easily added to things, but we generally want class methods so we can call them directly from the module. Here's how I deal with this issue.</p>
<p>First, instance methods are the way to go for anything you will be mixing in, period. With instance methods, you can inject them into a class or object. With anything else you have to start hacking. That gives us our first change:</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">M</span>
<span class="k">def</span> <span class="nf">croak</span>
<span class="nb">puts</span> <span class="s2">"Croak!"</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>Now, we really wanted a module method, so I've made things worse. However, as I've said, we have all the choices with this setup. Let's just mix the module into it's own class!</p>
<div class="highlight highlight-ruby"><pre><span class="k">module</span> <span class="nn">M</span>
<span class="kp">extend</span> <span class="nb">self</span> <span class="c1"># creates self.croak</span>
<span class="k">def</span> <span class="nf">croak</span>
<span class="nb">puts</span> <span class="s2">"Croak!"</span>
<span class="k">end</span>
<span class="k">end</span>
</pre></div>
<p>This trick of duplicating all instance methods as module methods is quite handy. I use it in Rails to make testing helper methods trivial, for example. You basically get two interfaces for the price of one. You can call module methods or mix it into objects.</p>
<p>We've already seen how to fix Xavier's class using the new module, but here it is in writing:</p>
<div class="highlight highlight-ruby"><pre><span class="k">class</span> <span class="nc">C</span>
<span class="kp">extend</span> <span class="n">M</span>
<span class="n">croak</span> <span class="c1"># works fine now</span>
<span class="k">end</span>
</pre></div>
<p>Remember, module methods are more powerful if they are instance methods, because you then have all the easy choices. Just mix them into whatever you like, even if it is the module itself.</p>James Edward Gray II