# Metakoans.rb (#67)

**URL:** <https://www.ruby-forum.com/t/metakoans-rb-67/72315>\
**Category:** Ruby\
**Created:** [February 23, 2006, 2:55pm UTC](https://www.ruby-forum.com/t/metakoans-rb-67/72315 "2006-02-23T14:55:17Z")\
**Posts on this page:** 1\
**Page:** 1

<div class="post-metadata">

**Author:** ![bbazzarrakk](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/b/47e85d/32.png) [@bbazzarrakk](https://www.ruby-forum.com/u/bbazzarrakk)\
**Post date:** [February 23, 2006, 2:55pm UTC](https://www.ruby-forum.com/t/metakoans-rb-67/72315/1 "2006-02-23T14:55:17Z")

</div>

This was a wildly popular quiz with solutions all over the board. I  
will do my  
best to hit the highlights below…

```
Where to Define

```

Probably the first question that needs answering when meta-programming  
is, where  
do I stick this method? Some defined it at the top-level (creating a  
private  
method on Object), others reopened Object to stick it inside, and a  
third group  
defined a method in Module. All three would satisfy the tests. The  
real  
question is, how do we know which one is best?

I used the extremely unscientific method of copy Ruby. The core method  
attr()  
is defined in Module, so it seemed like attribute() belonged there too.  
Ross  
Bamford had much more intelligent reasoning. Here is Ross’s response to  
Adam  
Shelly’s question about why people were using Module when Object works:

```
Well, you're extending Object with a method that relies on methods
defined in Module (class_eval), and your method is available in places
where it really didn't ought to be.

[snip quoted solution]

attribute :oops

-:7:in `attribute': undefined method `class_eval' for main:Object
(NoMethodError)
        from -:3:in `attribute'
        from -:15

By defining an instance method on Module (from which Class inherits) 

```

you  
ensure that a) class\_eval is there, and b) attribute can be called only  
in a module/class definition context.

That convinced me. Now that we know where it goes, let’s break down a  
solution.

```
A Common Approach

```

Here’s a solution, similar to many submitted, by Christian N.:

```
class Module
  def attribute(a, &block)
    if a.kind_of? Hash
      a, default = a.to_a.first
    else
      default = nil
    end

    a = a.to_sym
    ivar = "@#{a}"

    define_method(a) {
      if instance_variables.include? ivar
        instance_variable_get ivar
      else
        block ? instance_eval(&block) : default
      end
    }
    define_method("#{a}=") { |v| instance_variable_set ivar, v }
    define_method("#{a}?") { !! __send__ (a) }
  end
end

```

The if statement at the beginning of the method handles the case where a  
default  
argument is, or isn’t, provided. If the first argument to attribute()  
was a  
Hash, a default was given and it is extracted here. Note that this  
solution  
just pulls a single pair from the Hash. That’s all the tests required,  
but many  
chose to support declaring multiple arguments at once as we will see in  
a bit.  
If a default was not provided, it is set to nil.

The next two lines place the attribute method and instance variable  
names in  
local variables for future use.

The last chunk of code defines the three methods attribute() is expected  
to  
create. Note that they are built using define\_method(), which takes the  
name of  
the method to define and a block of code to execute as the method body.  
Now  
remember, Ruby’s blocks are closures and thus have access to the local  
variables  
defined in the scope where they are created. That’s the key to this  
kind of  
solution, as the code needs to access things like the default argument  
and/or  
the provided block.

The first method, the attribute getter, checks to see if the  
instance\_variables() of the class include?() our new attribute. In  
other words,  
this is a check to see if the variable has been set yet. If it has, the  
stored  
value is retrieved and returned with a call to instance\_variable\_get().  
If the  
variable is not set, the code executes a block, if provided, or uses the  
default  
(which may have been set to nil earlier). The tests required that the  
block  
have access to the instance though, so the block is instance\_eval()ed  
when  
invoked.

The second method, the setter, is trivial. Just stuff the new value in  
the  
variable with instance\_variable\_set().

The third and final method, for querying, uses a clever trick.  
Technically, the  
tests only required that the query method return the stored value and  
some  
implemented it that way. Here’s Florian G.'s implementation (name  
holds the  
attribute’s name):

```
alias_method(:"#{name}?", name)

```

The real purpose of the method though is to find out if the attribute  
currently  
holds a true or false value. Christian made sure only this true/false  
answer  
was returned. The code works by fetching the value with **send** ()  
(calling the  
getter) and hitting it with Ruby’s ! operator. That will convert the  
value to  
it’s opposite, but the key to the conversion is that it will only return  
true or  
false. We really don’t want the opposite though, so the ! operator is  
applied  
again. That takes us back to the original truth of the argument, but  
now in  
true/false form.

```
Using def Instead of define_method()

```

You can solve this challenge by defining methods normally, but you have  
to  
approach it differently. First, def is a keyword and not a method in  
Ruby.  
This has two effects: you can’t just inline the definitions and the  
method  
bodies are not closures. Neither of these is a deal-breaker, they just  
require  
an additional tool. Here’s a solution introducing class\_eval(), by  
Wilson  
Bilkovich (minus the clever poems that made it exactly 42 lines):

```
class Module
  def attribute(name, &block)
    return name.map {|k,v| attribute(k) {v}} if name.is_a?(Hash)
    define_method(" __#{name}__", block || proc{nil})
    class_eval <<-ZEN
      attr_writer :#{name}
      def #{name}
        defined?(@#{name}) ? @#{name} : @#{name} = __#{name}__
      end
      def #{name}?
        true unless #{name}.nil?
      end
    ZEN
  end
end

```

Here you can see support for multiple attributes right off the bat.  
Notice that  
it works just by recursively calling attribute(), passing a block that  
returns  
the default argument. That makes it so you only have one special case,  
the  
block. I like the simplification there.

Next you can see that this code uses define\_method() to set a  
**attribute\_name** () method, which will return the default value for  
that  
attribute. It uses the block as a method body, if one was provided.  
This  
eliminates the need for instance\_eval() we saw in the last solution,  
since the  
method body naturally works on the object instance. In the event we  
don’t have  
a block for the body, one is manufactured to return a default nil.

Now we get to defining the three methods. Because we are using def here  
and  
have lost the closure trick, a new trick is needed to pass down the  
attribute  
name. Wilson wraps the definitions in class\_eval(), which just executes  
the  
code in the context of the class. The String argument version of  
class\_eval()  
is used here (with a heredoc for the String) so that the attribute name  
can be  
interpolated as needed.

This time the setter is generated with attr\_writer(), which should be  
familiar  
enough to everyone I hope.

The getter uses some new techniques though. First, it checks for the  
instance  
variable using Ruby’s defined? keyword. This should be faster for  
classes that  
have a bunch of instance variables because the Array doesn’t need to be  
constructed and traversed. Just as with the first solution, the  
variable is  
returned if set. If it’s not, the default method created earlier is  
invoked to  
set the variable (efficient, since it will only happen once) and that  
value is  
returned.

We will skip the query method this time, since I don’t believe it  
functions as  
Ara intended. Some people, including myself, misunderstood the  
intentions of  
this method. No big deal.

```
The Inner Meaning Approach

```

This week I am going to reverse my normal strategy of suggesting  
everyone read  
all the solutions and recommend that people spend some time studying the  
quiz  
itself. It’s really quite clever if you stop and think about it.

Ara couldn’t use Test::Unit in this case, because the koans needed to be  
tried  
in a set order and the process halted as soon as one failed. Given that  
Ara  
rolled up a linear fail-fast test framework just for the purposes of  
this quiz.

Well that and you simply have to respect a framework with lines like:

```
MetaGuru.enlighten student

```

Once you have studied the quiz a bit, one of the solutions will take on  
a whole  
new meaning for you. Ilmari H. sent in a solution that passes  
quiz tests  
not by properly implementing the attribute() method, but instead by  
altering  
parts of the quiz framework. When you think about it, this kind of  
solution is  
also a form of meta-programming and thus was probably equally  
enlightening.

Ilmari’s code is actually eight solutions in one and it randomly selects  
which  
one it will bypass the tests with when run. Even more fun, these  
solutions come  
with great sayings in the spirit of the quiz itself.

Here are a few of my favorite hacks used by Ilmari:

```
# ...

puts "sometimes thinking about a problem makes it worse"
class MetaStudent; def ponder(a) 0 end end

# ...

puts "don't send a student to do a guru's job"
class MetaStudent; def send(a) 0 end end

# ...

puts "question what you have been taught"
module MetaKoans; 9.times{|i| eval("def koan_#{i+1};0 end")} end

# ...

```

The first one replaces the method the MetaStudent uses to ponder() each  
koan  
with a trivial implementation. The second works in a similar way  
replacing  
send(), which is used to call the koans themselves, with a trivial  
implementation. The third redefines the problems themselves with  
trivial  
implementations. Don’t miss the other five!

```
Wrap Up

```

My thanks to the quiz creator and numerous solvers for what turned out  
to be a  
fun little diversion. We must do more problems like this!

Tomorrows problem is the first from Caleb T., after I killed two  
previous  
suggestions. (Yes, I’m very, very mean.) Luckily Caleb didn’t give up  
on me  
and this problem is a great one…
