tag:blogger.com,1999:blog-49374887290222456452008-07-17T12:47:03.687-05:00Stochastic BytesChristopher J. Bottarohttp://www.blogger.com/profile/14116593743589959438noreply@blogger.comBlogger10125tag:blogger.com,1999:blog-4937488729022245645.post-18776513251723647632008-07-17T12:45:00.002-05:002008-07-17T12:47:03.726-05:00callback chains and metaclasses<p>For whatever reason (don't ask) our Rails app needed to be able to define callbacks on objects. As it stands now, you can only define callbacks on classes. Well, metaclasses are classes that pertain to a single specific object, so I figured I could add the callbacks there and everything will work.</p>
<p>Please excuse my <em>extremely</em> contrived example.</p>
<pre class="textmate-source mac_classic"><span class="source source_ruby">p <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="support support_class support_class_ruby">Post</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>find<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">...</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class="keyword keyword_control keyword_control_ruby">if</span> p<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>contains_porn?
<span class="meta meta_class meta_class_ruby"> <span class="keyword keyword_control keyword_control_class keyword_control_class_ruby">class</span> <span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby"><span class="variable variable_other variable_other_object variable_other_object_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby"><<</span> p</span></span></span>
before_save <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>filter_content</span>
<span class="keyword keyword_control keyword_control_ruby">end</span>
<span class="keyword keyword_control keyword_control_ruby">end</span>
p<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>save <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> should trigger filter_content</span></span></pre>
<p>Well it doesn't work.</p>
<p>After digging through the ActiveSupport source code, I saw that it only looks for callback chains in the object's class, not metaclass. That's not too hard to fix...</p>
<pre class="textmate-source mac_classic"><span class="source source_ruby"><span class="meta meta_module meta_module_ruby"><span class="keyword keyword_control keyword_control_module keyword_control_module_ruby">module</span> <span class="entity entity_name entity_name_type entity_name_type_module entity_name_type_module_ruby">ActiveSupport</span></span>
<span class="meta meta_module meta_module_ruby"> <span class="keyword keyword_control keyword_control_module keyword_control_module_ruby">module</span> <span class="entity entity_name entity_name_type entity_name_type_module entity_name_type_module_ruby">Callbacks</span></span>
<span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">run_callbacks</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby">kind<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> options <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby">{}</span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">&</span>block</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
callback_chain_method <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span><span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>kind<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span>_callback_chain<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"> <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> Meta class inherits Class so we don't have to merge it in 1.9
</span> <span class="keyword keyword_control keyword_control_ruby">if</span> <span class="variable variable_other variable_other_constant variable_other_constant_ruby">RUBY_VERSION</span> <span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby">>=</span> <span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>1.9<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span>
metaclass<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>send<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>callback_chain_method<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>run<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="variable variable_language variable_language_ruby">self</span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> options<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">&</span>block<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class="keyword keyword_control keyword_control_ruby">else</span>
callbacks <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="variable variable_language variable_language_ruby">self</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>class<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>send<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>callback_chain_method<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span> <span class="keyword keyword_operator keyword_operator_other keyword_operator_other_ruby">|</span> metaclass<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>send<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>callback_chain_method<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
callbacks<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>run<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="variable variable_language variable_language_ruby">self</span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> options<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">&</span>block<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class="keyword keyword_control keyword_control_ruby">end</span>
<span class="keyword keyword_control keyword_control_ruby">end</span>
<span class="keyword keyword_control keyword_control_ruby">end</span>
<span class="keyword keyword_control keyword_control_ruby">end</span></span></pre>
<p>Credit to Josh Peek for the Ruby 1.9 fix</p>
<p>Ok, so that got it working... with <strong>one major caveat: you cannot serialize objects that use callbacks</strong>. Ruby cannot serialize objects that have metaclasses and the <tt>run_callbacks</tt> method creates a metaclass whether you use it or not.</p>
<p>That's fine with me, I don't really like serializing objects anyways, but apparently it's a major problem for other people...</p>
<p>
<a href="http://github.com/rails/rails/commit/e0846c8417093853f4f7f62732983e990c28d669">http://github.com/rails/rails/commit/e0846c8417093853f4f7f62732983e990c28d669</a>
<br/>
<a href="http://rails.lighthouseapp.com/projects/8994/tickets/575-callbacks-don-t-work-from-extended-modules">http://rails.lighthouseapp.com/projects/8994/tickets/575-callbacks-don-t-work-from-extended-modules</a>
</p>
<p>Josh Peek suggested a solution where we store the callback chains on the objects themselves, so object specific callbacks would be done like this...</p>
<pre class="textmate-source mac_classic"><span class="source source_ruby">p <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="support support_class support_class_ruby">Post</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>find<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">...</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
p<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>before_save <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>filter_content</span> <span class="keyword keyword_control keyword_control_ruby">if</span> p<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>contains_porn?
p<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>save <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> should trigger filter_content</span></span></pre>
<p>That seems like a very simple, clean and rational solution. I'll look into coding it up later.</p>Christopher J. Bottarohttp://www.blogger.com/profile/14116593743589959438noreply@blogger.comtag:blogger.com,1999:blog-4937488729022245645.post-58049083795920312002008-07-06T21:52:00.005-05:002008-07-06T22:05:39.834-05:00named scopes pwns will_paginate<style type="text/css">
/* Stylesheet generated from TextMate theme
*
* Mac Classic
*
*
*/
/* Mostly to improve view within the TextMate HTML viewer */
body {
margin: 0;
padding: 0;
}
pre.textmate-source {
margin: 0;
padding: 0 0 0 2px;
font-family: Monaco, monospace;
font-size: 11px;
line-height: 1.3em;
word-wrap: break-word;
white-space: pre;
white-space: pre-wrap;
white-space: -moz-pre-wrap;
white-space: -o-pre-wrap;
}
pre.textmate-source.mac_classic {
color: #000000;
background-color: #FFFFFF;
}
pre.textmate-source .linenum {
width: 75px;
padding: 0.1em 1em 0.2em 0;
color: #888;
background-color: #eee;
}
pre.textmate-source.mac_classic span {
padding-top: 0.2em;
padding-bottom: 0.1em;
}
pre.textmate-source.mac_classic ::selection {
background-color: rgba(77, 151, 255, 0.33);
}
/* Comment */
pre.textmate-source.mac_classic .comment {
color: #0066FF;
font-style: italic;
}
/* Keyword */
pre.textmate-source.mac_classic .keyword, pre.textmate-source.mac_classic .storage {
color: #0000FF;
font-weight: bold;
}
/* Number */
pre.textmate-source.mac_classic .constant_numeric {
color: #0000CD;
}
/* User-defined constant */
pre.textmate-source.mac_classic .constant {
color: #C5060B;
font-weight: bold;
}
/* Built-in constant */
pre.textmate-source.mac_classic .constant_language {
color: #585CF6;
font-weight: bold;
}
/* Variable */
pre.textmate-source.mac_classic .variable_language, pre.textmate-source.mac_classic .variable_other {
color: #318495;
}
/* String */
pre.textmate-source.mac_classic .string {
color: #036A07;
}
/* String interpolation */
pre.textmate-source.mac_classic .constant_character_escape, pre.textmate-source.mac_classic .string .source {
color: #26B31A;
}
/* Preprocessor line */
pre.textmate-source.mac_classic .meta_preprocessor {
color: #1A921C;
}
/* Preprocessor directive */
pre.textmate-source.mac_classic .keyword_control_import {
color: #0C450D;
font-weight: bold;
}
/* Function name */
pre.textmate-source.mac_classic .entity_name_function, pre.textmate-source.mac_classic .support_function_any-method {
color: #0000A2;
font-weight: bold;
}
/* Type name */
pre.textmate-source.mac_classic .entity_name_type {
text-decoration: underline;
}
/* Inherited class name */
pre.textmate-source.mac_classic .entity_other_inherited-class {
font-style: italic;
}
/* Function parameter */
pre.textmate-source.mac_classic .variable_parameter {
font-style: italic;
}
/* Function argument and result types */
pre.textmate-source.mac_classic .storage_type_method {
color: #70727E;
}
/* Section */
pre.textmate-source.mac_classic .meta_section .entity_name_section, pre.textmate-source.mac_classic .declaration_section .entity_name_section {
font-style: italic;
}
/* Library function */
pre.textmate-source.mac_classic .support_function {
color: #3C4C72;
font-weight: bold;
}
/* Library object */
pre.textmate-source.mac_classic .support_class, pre.textmate-source.mac_classic .support_type {
color: #6D79DE;
font-weight: bold;
}
/* Library constant */
pre.textmate-source.mac_classic .support_constant {
color: #06960E;
font-weight: bold;
}
/* Library variable */
pre.textmate-source.mac_classic .support_variable {
color: #21439C;
font-weight: bold;
}
/* JS: Operator */
pre.textmate-source.mac_classic .keyword_operator_js {
color: #687687;
}
/* Invalid */
pre.textmate-source.mac_classic .invalid {
color: #FFFFFF;
background-color: #990000;
}
/* Invalid trailing whitespace */
pre.textmate-source.mac_classic .invalid_deprecated_trailing-whitespace {
background-color: #FFD0D0;
}
/* Embedded source */
pre.textmate-source.mac_classic .text .source, pre.textmate-source.mac_classic .string_unquoted {
background-color: rgba(0, 0, 0, 0.05);
}
/* Embedded embedded source */
pre.textmate-source.mac_classic .text .source .string_unquoted, pre.textmate-source.mac_classic .text .source .text .source {
background-color: rgba(0, 0, 0, 0.06);
}
/* Markup XML declaration */
pre.textmate-source.mac_classic .meta_tag_preprocessor_xml {
color: #68685B;
}
/* Markup DOCTYPE */
pre.textmate-source.mac_classic .meta_tag_sgml_doctype, pre.textmate-source.mac_classic .meta_tag_sgml_doctype .entity, pre.textmate-source.mac_classic .meta_tag_sgml_doctype .string, pre.textmate-source.mac_classic .meta_tag_preprocessor_xml, pre.textmate-source.mac_classic .meta_tag_preprocessor_xml .entity, pre.textmate-source.mac_classic .meta_tag_preprocessor_xml .string {
color: #888888;
}
/* Markup DTD */
pre.textmate-source.mac_classic .string_quoted_docinfo_doctype_DTD {
font-style: italic;
}
/* Markup tag */
pre.textmate-source.mac_classic .meta_tag, pre.textmate-source.mac_classic .declaration_tag {
color: #1C02FF;
}
/* Markup name of tag */
pre.textmate-source.mac_classic .entity_name_tag {
font-weight: bold;
}
/* Markup tag attribute */
pre.textmate-source.mac_classic .entity_other_attribute-name {
font-style: italic;
}
/* Markup: Heading */
pre.textmate-source.mac_classic .markup_heading {
color: #0C07FF;
font-weight: bold;
}
/* Markup: Quote */
pre.textmate-source.mac_classic .markup_quote {
color: #000000;
font-style: italic;
}
/* Markup: List */
pre.textmate-source.mac_classic .markup_list {
color: #B90690;
}
</style>
<p><tt>will_paginate</tt> has its place. It's good for paginating when your queries are simple. My queries usually aren't simple, are yours? I noticed recently that one of my pages was taking a long time to display, around 1.9 seconds. I tracked it down to the <tt>will_paginate</tt>.</p>
<p>The problem is that <tt>will_paginate</tt> takes a single hash of ActiveRecord::Base#find arguments. That means if your query is really complex, then it's going to use that same complex query for both the result set and the count.</p>
<p>This is more or less what I was doing with <tt>will_paginate</tt> that it was choking on.</p>
<pre class="textmate-source mac_classic"><span class="source source_ruby source_ruby_rails"><span class="meta meta_rails meta_rails_model"><span class="meta meta_class meta_class_ruby"><span class="keyword keyword_control keyword_control_class keyword_control_class_ruby">class</span> <span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby">Post<span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"> <span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"><</span> ActiveRecord::Base</span></span></span>
<span class="variable variable_other variable_other_constant variable_other_constant_ruby">STATUS_OK</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="constant constant_numeric constant_numeric_ruby">1</span>
<span class="support support_function support_function_activesupport support_function_activesupport_rails">cattr_accessor</span> <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>per_page</span>
per_page <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="constant constant_numeric constant_numeric_ruby">15</span>
<span class="support support_function support_function_activerecord support_function_activerecord_rails">has_many</span> <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>watchers</span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">...</span>
</span><span class="keyword keyword_control keyword_control_ruby">end</span>
<span class="meta meta_rails meta_rails_controller"><span class="meta meta_class meta_class_ruby"><span class="keyword keyword_control keyword_control_class keyword_control_class_ruby">class</span> <span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby">PostsController<span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"> <span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"><</span> ApplicationController</span></span></span>
<span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">index</span></span>
page_no <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>params<span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">[</span><span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>page</span><span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">]</span> <span class="keyword keyword_operator keyword_operator_logical keyword_operator_logical_ruby">&&</span> params<span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">[</span><span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>page</span><span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">]</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>to_i<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span> <span class="keyword keyword_operator keyword_operator_logical keyword_operator_logical_ruby">||</span> <span class="constant constant_numeric constant_numeric_ruby">1</span>
<span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@</span>posts</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="support support_class support_class_ruby">Post</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>paginate <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>conditions</span> <span class="punctuation punctuation_separator punctuation_separator_key-value">=></span> <span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">[</span><span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>posts.status_id = ?<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="support support_class support_class_ruby">Post</span><span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby">::</span><span class="variable variable_other variable_other_constant variable_other_constant_ruby">STATUS_OK</span><span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">]</span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span>
<span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>order</span> <span class="punctuation punctuation_separator punctuation_separator_key-value">=></span> <span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>group_id DESC, checksum<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> don't ask, it's complicated
</span> <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>include</span> <span class="punctuation punctuation_separator punctuation_separator_key-value">=></span> <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>watchers</span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span>
<span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>page</span> <span class="punctuation punctuation_separator punctuation_separator_key-value">=></span> page_no
<span class="keyword keyword_control keyword_control_ruby">end</span>
</span><span class="keyword keyword_control keyword_control_ruby">end</span></span></pre>
<br/>
<p>The counting sql it makes out of that query does an outer join on <tt>watchers</tt> and selects distinct <tt>posts.id</tt>. Ouch. So the obvious solution is to simply do the count and result set queries ourselves. No biggie, but let's use named scopes to pretty things up.</p>
<pre class="textmate-source mac_classic"><span class="source source_ruby source_ruby_rails"><span class="meta meta_rails meta_rails_model"><span class="meta meta_class meta_class_ruby"><span class="keyword keyword_control keyword_control_class keyword_control_class_ruby">class</span> <span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby">Post<span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"> <span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"><</span> ActiveRecord::Base</span></span></span>
<span class="variable variable_other variable_other_constant variable_other_constant_ruby">STATUS_OK</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="constant constant_numeric constant_numeric_ruby">1</span>
<span class="support support_function support_function_activesupport support_function_activesupport_rails">cattr_accessor</span> <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>per_page</span>
per_page <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="constant constant_numeric constant_numeric_ruby">15</span>
<span class="support support_function support_function_activerecord support_function_activerecord_rails">has_many</span> <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>watchers</span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">...</span>
named_scope <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>ok</span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>conditions</span> <span class="punctuation punctuation_separator punctuation_separator_key-value">=></span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby">{</span><span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>posts.status_id<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span> <span class="punctuation punctuation_separator punctuation_separator_key-value">=></span> <span class="support support_class support_class_ruby">Post</span><span class="punctuation punctuation_separator punctuation_separator_other punctuation_separator_other_ruby">::</span><span class="variable variable_other variable_other_constant variable_other_constant_ruby">STATUS_OK</span><span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby">}</span>
named_scope <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>recent</span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>order</span> <span class="punctuation punctuation_separator punctuation_separator_key-value">=></span> <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>group_id DESC, checksum<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
named_scope <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>paginate</span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> lambda <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby">{</span><span class="meta meta_syntax meta_syntax_ruby meta_syntax_ruby_start-block"> </span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span><span class="variable variable_other variable_other_block variable_other_block_ruby">page_no</span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby">{</span><span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>offset</span> <span class="punctuation punctuation_separator punctuation_separator_key-value">=></span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby">{</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>page_no<span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">-</span><span class="constant constant_numeric constant_numeric_ruby">1</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span><span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">*</span>per_page<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby">}</span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>limit</span> <span class="punctuation punctuation_separator punctuation_separator_key-value">=></span> per_page<span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby">}</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby">}</span>
</span><span class="keyword keyword_control keyword_control_ruby">end</span>
<span class="meta meta_rails meta_rails_controller"><span class="meta meta_class meta_class_ruby"><span class="keyword keyword_control keyword_control_class keyword_control_class_ruby">class</span> <span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby">PostsController<span class="entity entity_other entity_other_inherited-class entity_other_inherited-class_ruby"> <span class="punctuation punctuation_separator punctuation_separator_inheritance punctuation_separator_inheritance_ruby"><</span> ApplicationController</span></span></span>
<span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">index</span></span>
page_no <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>params<span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">[</span><span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>page</span><span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">]</span> <span class="keyword keyword_operator keyword_operator_logical keyword_operator_logical_ruby">&&</span> params<span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">[</span><span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>page</span><span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">]</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>to_i<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span> <span class="keyword keyword_operator keyword_operator_logical keyword_operator_logical_ruby">||</span> <span class="constant constant_numeric constant_numeric_ruby">1</span>
<span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@</span>posts</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="support support_class support_class_ruby">Post</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>ok<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>recent<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>paginate<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>page_no<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>all<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>include</span> <span class="punctuation punctuation_separator punctuation_separator_key-value">=></span> <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>watchers</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class="variable variable_other variable_other_readwrite variable_other_readwrite_instance variable_other_readwrite_instance_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@</span>post_count</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="support support_class support_class_ruby">Post</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>ok<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>count
<span class="keyword keyword_control keyword_control_ruby">end</span>
</span><span class="keyword keyword_control keyword_control_ruby">end</span></span></pre>
<br/>
<p>Pretty slick... and since we're doing the pagination "explicitly", we know that the counting is as simple as it needs to be. Let's take a look at the benchmarks, before and after.</p>
<pre class="textmate-source mac_classic"><span class="source source_sql source_sql_ruby"><span class="comment comment_line comment_line_number-sign comment_line_number-sign_sql"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_sql">#</span> The SQL calls generated by will_paginate
</span>Post Load (<span class="constant constant_numeric constant_numeric_sql">0</span>.<span class="constant constant_numeric constant_numeric_sql">341523</span>)
<span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">SELECT</span> <span class="keyword keyword_operator keyword_operator_star keyword_operator_star_sql">*</span> <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">FROM</span> <span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>posts"</span> <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">WHERE</span> (<span class="constant constant_other constant_other_database-name constant_other_database-name_sql">post</span>.<span class="constant constant_other constant_other_table-name constant_other_table-name_sql">status_id</span> <span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_sql">=</span> <span class="constant constant_numeric constant_numeric_sql">1</span>) <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">ORDER BY</span> group_id <span class="keyword keyword_other keyword_other_order keyword_other_order_sql">DESC</span>, checksum <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">LIMIT</span> <span class="constant constant_numeric constant_numeric_sql">15</span> OFFSET <span class="constant constant_numeric constant_numeric_sql">0</span>
Watcher Load (<span class="constant constant_numeric constant_numeric_sql">0</span>.<span class="constant constant_numeric constant_numeric_sql">005799</span>)
<span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">SELECT</span> <span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>watchers"</span>.<span class="keyword keyword_operator keyword_operator_star keyword_operator_star_sql">*</span> <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">FROM</span> <span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>watchers"</span> <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">WHERE</span> (<span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>watchers"</span>.page_id <span class="keyword keyword_other keyword_other_data-integrity keyword_other_data-integrity_sql">IN</span> (...)) <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">ORDER BY</span> id
SQL (<span class="constant constant_numeric constant_numeric_sql">1</span>.<span class="constant constant_numeric constant_numeric_sql">335042</span>)
<span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">SELECT</span> <span class="support support_function support_function_aggregate support_function_aggregate_sql">count</span>(DISTINCT <span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>posts"</span>.id) <span class="keyword keyword_other keyword_other_alias keyword_other_alias_sql">AS</span> count_all <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">FROM</span> <span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>posts"</span> <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">LEFT OUTER JOIN</span> <span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>watchers"</span> <span class="keyword keyword_other keyword_other_DDL keyword_other_DDL_create keyword_other_DDL_create_II keyword_other_DDL_create_II_sql">ON</span> <span class="constant constant_other constant_other_database-name constant_other_database-name_sql">watchers</span>.<span class="constant constant_other constant_other_table-name constant_other_table-name_sql">post_id</span> <span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_sql">=</span> <span class="constant constant_other constant_other_database-name constant_other_database-name_sql">posts</span>.<span class="constant constant_other constant_other_table-name constant_other_table-name_sql">id</span> <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">WHERE</span> (<span class="constant constant_other constant_other_database-name constant_other_database-name_sql">posts</span>.<span class="constant constant_other constant_other_table-name constant_other_table-name_sql">status_id</span> <span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_sql">=</span> <span class="constant constant_numeric constant_numeric_sql">1</span>)
<span class="comment comment_line comment_line_number-sign comment_line_number-sign_sql"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_sql">#</span> The SQL calls generated when we "manually paginate".
</span>Post Load (<span class="constant constant_numeric constant_numeric_sql">0</span>.<span class="constant constant_numeric constant_numeric_sql">350336</span>)
<span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">SELECT</span> <span class="keyword keyword_operator keyword_operator_star keyword_operator_star_sql">*</span> <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">FROM</span> <span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>posts"</span> <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">WHERE</span> (<span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>posts"</span>.<span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>status_id"</span> <span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_sql">=</span> <span class="constant constant_numeric constant_numeric_sql">1</span>) <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">ORDER BY</span> group_id <span class="keyword keyword_other keyword_other_order keyword_other_order_sql">DESC</span>, checksum <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">LIMIT</span> <span class="constant constant_numeric constant_numeric_sql">15</span> OFFSET <span class="constant constant_numeric constant_numeric_sql">0</span>
Watcher Load (<span class="constant constant_numeric constant_numeric_sql">0</span>.<span class="constant constant_numeric constant_numeric_sql">004582</span>)
<span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">SELECT</span> <span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>watchers"</span>.<span class="keyword keyword_operator keyword_operator_star keyword_operator_star_sql">*</span> <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">FROM</span> <span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>watchers"</span> <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">WHERE</span> (<span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>watchers"</span>.post_id <span class="keyword keyword_other keyword_other_data-integrity keyword_other_data-integrity_sql">IN</span> (...)) <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">ORDER BY</span> id
SQL (<span class="constant constant_numeric constant_numeric_sql">0</span>.<span class="constant constant_numeric constant_numeric_sql">023346</span>)
<span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">SELECT</span> <span class="support support_function support_function_aggregate support_function_aggregate_sql">count</span>(<span class="keyword keyword_operator keyword_operator_star keyword_operator_star_sql">*</span>) <span class="keyword keyword_other keyword_other_alias keyword_other_alias_sql">AS</span> count_all <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">FROM</span> <span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>posts"</span> <span class="keyword keyword_other keyword_other_DML keyword_other_DML_sql">WHERE</span> (<span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>posts"</span>.<span class="string string_quoted string_quoted_double string_quoted_double_sql"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_sql">"</span>status_id"</span> <span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_sql">=</span> <span class="constant constant_numeric constant_numeric_sql">1</span>)</span></pre>
<br/>
<p>We save roughly 1.3 seconds by intelligently doing the counting. I really don't think using <tt>will_paginate</tt> buys you any cleaner code over using named scopes. Now all you have to do is implement a method similar to the <tt>will_paginate</tt> view helper and you can remove <tt>will_paginate</tt> from your project.</p>Christopher J. Bottarohttp://www.blogger.com/profile/14116593743589959438noreply@blogger.comtag:blogger.com,1999:blog-4937488729022245645.post-60333012781622639342008-05-18T20:48:00.001-05:002008-05-18T20:48:15.977-05:00Metaprogramming Fun in Ruby<p>My friend, who is just learning Ruby, asked how he can automatically wrap some code around each user defined method in a class. The requirement (from his bosses) is to log when each method is being called. </p>
<p>To be more concrete, we want to factor out lines 3, 5, 9 and 11 from the following snippet.</p>
<pre class="textmate-source mac_classic"><span class='linenum'> 1</span> <span class="source source_ruby"><span class="meta meta_class meta_class_ruby"><span class="keyword keyword_control keyword_control_class keyword_control_class_ruby">class</span> <span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby">AutoLogger</span></span>
<span class='linenum'> 2</span> <span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">method_a</span></span>
<span class='linenum'> 3</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>start logging method_a<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 4</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>calling method_a<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 5</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>end logging method_a<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 6</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 7</span>
<span class='linenum'> 8</span> <span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">method_b</span></span>
<span class='linenum'> 9</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>start logging method_b<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 10</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>calling method_b<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 11</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>end logging method_b<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 12</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 13</span> <span class="keyword keyword_control keyword_control_ruby">end</span></span></pre>
<p>The problem really boils down to two problems. First, how to redefine a method to be the original method body wrapped between the logging code. Second, how do we specify which methods in a class should be wrapped.</p>
<p>Each solution (except for the first one) relies on using <tt>Module#define_method</tt> to redefine the method in question. Sometimes we pass in a block that defines the original method, other times we make an <tt>UnboundMethod</tt> out of the original method and call it from the block that makes the new method body, binding it to <tt>self</tt> which at execution time is an instance of our class.</p>
<p>My friend said ideally, he wants every "user defined" method to automatically be wrapped.</p>
<p>The first solution I came up with was using <tt>method_missing</tt>. This solution has the drawback of having to refactor all your code to call <tt>log_some_method</tt> instead of <tt>some_method</tt>.</p>
<pre class="textmate-source mac_classic"><span class='linenum'> 1</span> <span class="source source_ruby source_ruby_rails"><span class="meta meta_class meta_class_ruby"><span class="keyword keyword_control keyword_control_class keyword_control_class_ruby">class</span> <span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby">AutoLogger</span></span>
<span class='linenum'> 2</span>
<span class='linenum'> 3</span> <span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">method_missing</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby">name<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">*</span>args</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
<span class='linenum'> 4</span> name <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> name<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>to_s
<span class='linenum'> 5</span> <span class="keyword keyword_control keyword_control_ruby">if</span> name<span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">[</span><span class="constant constant_numeric constant_numeric_ruby">0</span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span><span class="constant constant_numeric constant_numeric_ruby">4</span><span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">]</span> <span class="keyword keyword_operator keyword_operator_comparison keyword_operator_comparison_ruby">==</span> <span class="string string_quoted string_quoted_single string_quoted_single_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">'</span>log_<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">'</span></span>
<span class='linenum'> 6</span> method_name <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> name<span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">[</span><span class="constant constant_numeric constant_numeric_ruby">4</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">..</span><span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">-</span><span class="constant constant_numeric constant_numeric_ruby">1</span><span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">]</span>
<span class='linenum'> 7</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>start logging <span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>method_name<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 8</span> <span class="variable variable_language variable_language_ruby">self</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>send<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>method_name<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>to_sym<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">*</span>args<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class='linenum'> 9</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>end logging <span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>method_name<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 10</span> <span class="keyword keyword_control keyword_control_ruby">else</span>
<span class='linenum'> 11</span> <span class="keyword keyword_control keyword_control_pseudo-method keyword_control_pseudo-method_ruby">super</span>
<span class='linenum'> 12</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 13</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 14</span>
<span class='linenum'> 15</span> <span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">method_a</span></span>
<span class='linenum'> 16</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>calling method_a<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 17</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 18</span>
<span class='linenum'> 19</span> <span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">method_b</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby">arg1<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> arg2</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
<span class='linenum'> 20</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>calling method_b(<span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>arg1<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span>, <span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>arg2<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span>)<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 21</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 22</span>
<span class='linenum'> 23</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 24</span>
<span class='linenum'> 25</span> o <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="support support_class support_class_ruby">AutoLogger</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span><span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">new</span>
<span class='linenum'> 26</span> o<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>method_a
<span class='linenum'> 27</span> o<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>method_b<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>test<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="constant constant_numeric constant_numeric_ruby">1</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class='linenum'> 28</span> o<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>log_method_a
<span class='linenum'> 29</span> o<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>log_method_b<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>test<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="constant constant_numeric constant_numeric_ruby">1</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class='linenum'> 30</span>
<span class='linenum'> 31</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span>#########
</span><span class='linenum'> 32</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> OUTPUT #
</span><span class='linenum'> 33</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span>#########
</span><span class='linenum'> 34</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> calling method_a
</span><span class='linenum'> 35</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> calling method_b(test, 1)
</span><span class='linenum'> 36</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> start logging method_a
</span><span class='linenum'> 37</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> calling method_a
</span><span class='linenum'> 38</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> end logging method_a
</span><span class='linenum'> 39</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> start logging method_b
</span><span class='linenum'> 40</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> calling method_b(test, 1)
</span><span class='linenum'> 41</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> end logging method_b</span></span></pre>
<p>With this approach, you can see that the original methods are kept intact and are callable. You have to call the special prefixed version of them to get the logging.</p>
<p>The next solution uses a special method to define methods instead of the <tt>def</tt> keyword.</p>
<pre class="textmate-source mac_classic"><span class='linenum'> 1</span> <span class="source source_ruby source_ruby_rails"><span class="meta meta_class meta_class_ruby"><span class="keyword keyword_control keyword_control_class keyword_control_class_ruby">class</span> <span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby">AutoLogger</span></span>
<span class='linenum'> 2</span>
<span class='linenum'> 3</span> <span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">self.def_with_logging</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby">method_name<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">&</span>block</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
<span class='linenum'> 4</span> define_method<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>method_name<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span> <span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby">do </span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span>*<span class="variable variable_other variable_other_block variable_other_block_ruby">args</span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span>
<span class='linenum'> 5</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>start logging <span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>method_name<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 6</span> <span class="keyword keyword_control keyword_control_pseudo-method keyword_control_pseudo-method_ruby">yield</span> <span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">*</span>args
<span class='linenum'> 7</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>end logging <span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>method_name<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 8</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 9</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 10</span>
<span class='linenum'> 11</span> def_with_logging<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>method_a</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span> <span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby">do
</span><span class='linenum'> 12</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>calling method_a<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 13</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 14</span>
<span class='linenum'> 15</span> def_with_logging<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>method_b</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span> <span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby">do </span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span><span class="variable variable_other variable_other_block variable_other_block_ruby">arg1</span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">,</span> <span class="variable variable_other variable_other_block variable_other_block_ruby">arg2</span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span>
<span class='linenum'> 16</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>calling method_b(<span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>arg1<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span>, <span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>arg2<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span>)<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 17</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 18</span>
<span class='linenum'> 19</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 20</span>
<span class='linenum'> 21</span> o <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="support support_class support_class_ruby">AutoLogger</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span><span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">new</span>
<span class='linenum'> 22</span> o<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>method_a
<span class='linenum'> 23</span> o<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>method_b<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>test<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="constant constant_numeric constant_numeric_ruby">1</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class='linenum'> 24</span>
<span class='linenum'> 25</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span>#########
</span><span class='linenum'> 26</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> OUTPUT #
</span><span class='linenum'> 27</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span>#########
</span><span class='linenum'> 28</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> start logging method_a
</span><span class='linenum'> 29</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> calling method_a
</span><span class='linenum'> 30</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> end logging method_a
</span><span class='linenum'> 31</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> start logging method_b
</span><span class='linenum'> 32</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> calling method_b(test, 1)
</span><span class='linenum'> 33</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> end logging method_b</span></span></pre>
<p>Again, this solution requires the programmer to refactor a lot of existing code (rewriting all your methods using <tt>def_with_logging</tt> instead of <tt>def</tt>).</p>
<p>The third solution is more "Rails-like" by adding a method to the class itself which can be called to add logging to existing methods.</p>
<pre class="textmate-source mac_classic"><span class='linenum'> 1</span> <span class="source source_ruby source_ruby_rails"><span class="meta meta_class meta_class_ruby"><span class="keyword keyword_control keyword_control_class keyword_control_class_ruby">class</span> <span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby">AutoLogger</span></span>
<span class='linenum'> 2</span> <span class="variable variable_other variable_other_readwrite variable_other_readwrite_class variable_other_readwrite_class_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@@</span>inited</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="constant constant_language constant_language_ruby">false</span>
<span class='linenum'> 3</span>
<span class='linenum'> 4</span> <span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">self.do_logging_for</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby"><span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">*</span>method_names</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
<span class='linenum'> 5</span> <span class="variable variable_other variable_other_readwrite variable_other_readwrite_class variable_other_readwrite_class_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@@</span>method_names</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby">||=</span> <span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">[]</span>
<span class='linenum'> 6</span> <span class="variable variable_other variable_other_readwrite variable_other_readwrite_class variable_other_readwrite_class_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@@</span>method_names</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby">+=</span> method_names
<span class='linenum'> 7</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 8</span>
<span class='linenum'> 9</span> do_logging_for <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>method_a</span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="constant constant_other constant_other_symbol constant_other_symbol_ruby"><span class="punctuation punctuation_definition punctuation_definition_constant punctuation_definition_constant_ruby">:</span>method_b</span>
<span class='linenum'> 10</span>
<span class='linenum'> 11</span> <span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">initialize</span></span>
<span class='linenum'> 12</span> <span class="keyword keyword_control keyword_control_ruby">unless</span> <span class="variable variable_other variable_other_readwrite variable_other_readwrite_class variable_other_readwrite_class_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@@</span>inited</span>
<span class='linenum'> 13</span> <span class="variable variable_other variable_other_readwrite variable_other_readwrite_class variable_other_readwrite_class_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@@</span>method_names</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>each <span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby">do </span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span><span class="variable variable_other variable_other_block variable_other_block_ruby">method_name</span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span>
<span class='linenum'> 14</span> <span class="variable variable_language variable_language_ruby">self</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>class<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>class_eval <span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby">do
</span><span class='linenum'> 15</span> method <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> instance_method<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>method_name<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class='linenum'> 16</span> define_method<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>method_name<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span> <span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby">do </span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span>*<span class="variable variable_other variable_other_block variable_other_block_ruby">args</span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span>
<span class='linenum'> 17</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>start logging <span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>method_name<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 18</span> method<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>bind<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="variable variable_language variable_language_ruby">self</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>call<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">*</span>args<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class='linenum'> 19</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>end logging <span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>method_name<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 20</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 21</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 22</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 23</span> <span class="variable variable_other variable_other_readwrite variable_other_readwrite_class variable_other_readwrite_class_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@@</span>inited</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="constant constant_language constant_language_ruby">true</span>
<span class='linenum'> 24</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 25</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 26</span>
<span class='linenum'> 27</span> <span class="meta meta_function meta_function_method meta_function_method_without-arguments meta_function_method_without-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">method_a</span></span>
<span class='linenum'> 28</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>calling method_a<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 29</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 30</span>
<span class='linenum'> 31</span> <span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">method_b</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby">arg1<span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> arg2</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
<span class='linenum'> 32</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>calling method_b(<span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>arg1<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span>, <span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>arg2<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span>)<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 33</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 34</span>
<span class='linenum'> 35</span> <span class="keyword keyword_control keyword_control_ruby">end</span>
<span class='linenum'> 36</span>
<span class='linenum'> 37</span> o <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="support support_class support_class_ruby">AutoLogger</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span><span class="keyword keyword_other keyword_other_special-method keyword_other_special-method_ruby">new</span>
<span class='linenum'> 38</span> o<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>method_a
<span class='linenum'> 39</span> o<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>method_b<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>test<span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span><span class="punctuation punctuation_separator punctuation_separator_object punctuation_separator_object_ruby">,</span> <span class="constant constant_numeric constant_numeric_ruby">1</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class='linenum'> 40</span>
<span class='linenum'> 41</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span>#########
</span><span class='linenum'> 42</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> OUTPUT #
</span><span class='linenum'> 43</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span>#########
</span><span class='linenum'> 44</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> start logging method_a
</span><span class='linenum'> 45</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> calling method_a
</span><span class='linenum'> 46</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> end logging method_a
</span><span class='linenum'> 47</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> start logging method_b
</span><span class='linenum'> 48</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> calling method_b(test, 1)
</span><span class='linenum'> 49</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"><span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> end logging method_b</span></span></pre>
<p>Notice how most of the work is deferred to <tt>initialize</tt>. This is so we can call <tt>do_logging_for</tt> <em>before</em> we define the methods it works on.</p>
<p>The fourth approach takes the least work because it does not require the programmer to do anything special or extra to get the desired effect. It all happens automatically.</p>
<pre class="textmate-source mac_classic"><span class='linenum'> 1</span> <span class="source source_ruby source_ruby_rails"><span class="meta meta_class meta_class_ruby"><span class="keyword keyword_control keyword_control_class keyword_control_class_ruby">class</span> <span class="entity entity_name entity_name_type entity_name_type_class entity_name_type_class_ruby">AutoLogger</span></span>
<span class='linenum'> 2</span>
<span class='linenum'> 3</span> <span class="meta meta_function meta_function_method meta_function_method_with-arguments meta_function_method_with-arguments_ruby"><span class="keyword keyword_control keyword_control_def keyword_control_def_ruby">def</span> <span class="entity entity_name entity_name_function entity_name_function_ruby">self.method_added</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">(</span><span class="variable variable_parameter variable_parameter_function variable_parameter_function_ruby">method_name</span><span class="punctuation punctuation_definition punctuation_definition_parameters punctuation_definition_parameters_ruby">)</span></span>
<span class='linenum'> 4</span>
<span class='linenum'> 5</span> <span class="comment comment_line comment_line_number-sign comment_line_number-sign_ruby"> <span class="punctuation punctuation_definition punctuation_definition_comment punctuation_definition_comment_ruby">#</span> so we don't get stuck in infinite recursion
</span><span class='linenum'> 6</span> <span class="variable variable_other variable_other_readwrite variable_other_readwrite_class variable_other_readwrite_class_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@@</span>seen_methods</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_augmented keyword_operator_assignment_augmented_ruby">||=</span> <span class="punctuation punctuation_section punctuation_section_scope punctuation_section_scope_ruby">{}</span>
<span class='linenum'> 7</span> <span class="keyword keyword_control keyword_control_pseudo-method keyword_control_pseudo-method_ruby">return</span> <span class="keyword keyword_control keyword_control_ruby">if</span> <span class="variable variable_other variable_other_readwrite variable_other_readwrite_class variable_other_readwrite_class_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@@</span>seen_methods</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>has_key?<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>method_name<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class='linenum'> 8</span> <span class="variable variable_other variable_other_readwrite variable_other_readwrite_class variable_other_readwrite_class_ruby"><span class="punctuation punctuation_definition punctuation_definition_variable punctuation_definition_variable_ruby">@@</span>seen_methods</span><span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">[</span>method_name<span class="punctuation punctuation_section punctuation_section_array punctuation_section_array_ruby">]</span> <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> <span class="constant constant_language constant_language_ruby">true</span>
<span class='linenum'> 9</span>
<span class='linenum'> 10</span> method <span class="keyword keyword_operator keyword_operator_assignment keyword_operator_assignment_ruby">=</span> instance_method<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>method_name<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class='linenum'> 11</span> define_method<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span>method_name<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span> <span class="keyword keyword_control keyword_control_start-block keyword_control_start-block_ruby">do </span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span>*<span class="variable variable_other variable_other_block variable_other_block_ruby">args</span><span class="punctuation punctuation_separator punctuation_separator_variable punctuation_separator_variable_ruby">|</span>
<span class='linenum'> 12</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>start logging <span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>method_name<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>
<span class='linenum'> 13</span> method<span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>bind<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="variable variable_language variable_language_ruby">self</span><span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span><span class="punctuation punctuation_separator punctuation_separator_method punctuation_separator_method_ruby">.</span>call<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">(</span><span class="keyword keyword_operator keyword_operator_arithmetic keyword_operator_arithmetic_ruby">*</span>args<span class="punctuation punctuation_section punctuation_section_function punctuation_section_function_ruby">)</span>
<span class='linenum'> 14</span> puts <span class="string string_quoted string_quoted_double string_quoted_double_ruby"><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_begin punctuation_definition_string_begin_ruby">"</span>end logging <span class="source source_ruby source_ruby_embedded source_ruby_embedded_source"><span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">#{</span>method_name<span class="punctuation punctuation_section punctuation_section_embedded punctuation_section_embedded_ruby">}</span></span><span class="punctuation punctuation_definition punctuation_definition_string punctuation_definition_string_end punctuation_definition_string_end_ruby">"</span></span>