# Are my metaprogramming underpants showing?

**URL:** <https://www.ruby-forum.com/t/are-my-metaprogramming-underpants-showing/49549>\
**Category:** Ruby\
**Created:** [December 6, 2005, 12:54am UTC](https://www.ruby-forum.com/t/are-my-metaprogramming-underpants-showing/49549 "2005-12-06T00:54:43Z")\
**Posts on this page:** 9\
**Page:** 1

<div class="post-metadata">

**Author:** ![M.B.Smillie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/a88e4f/32.png) [@M.B.Smillie](https://www.ruby-forum.com/u/M.B.Smillie)\
**Post date:** [December 6, 2005, 12:54am UTC](https://www.ruby-forum.com/t/are-my-metaprogramming-underpants-showing/49549/1 "2005-12-06T00:54:43Z")

</div>

Hello all,

I’ve done a quick little project to see if I can wrap my head around  
Ruby metaprogramming, and I’d like to run it by some more-experienced  
minds.

I picked the quick little task of coding up the web API for flickr  
([Flickr Services](http://flickr.com/services/API)). Not necessarily for practical  
usage (though I may use it myself), but more because it struck me as  
a good example since there are a lot of methods with extremely  
similar behaviour on the client side (send parameters to this URL).  
In any case, here’s the code:

require ‘pp’  
class Flickr  
def method\_missing(method\_id, \*params)  
# Find the desired class name  
class\_name = method\_id.to\_s.capitalize  
# Find the corresponding instance variable  
ivar = :“@#{method\_id}”

```
 # have we already made this particular class before?
 unless self.class.const_defined?(class_name)
   # new class which inherits from this one.
   new_class = self.class.const_set(class_name, Class.new

```

(self.class))  
# new instance variable  
instance\_variable\_set(ivar, new\_class.new)  
end

```
 # if we have parameters, execute the appropriate method (returning
 # what, though?) otherwise return the instance we just made so
 # that the next thing can be called correctly.
 return instance_variable_get(ivar) unless params.length > 0

 the_method = instance_variable_get(ivar).class.name.downcase.gsub

```

(/::/, ‘.’)  
# abstract out the actual API call for the moment.  
puts “call: [http://flickr.com/services/rest/?method=](http://flickr.com/services/rest/?method=)‘#  
{the\_method}’”  
puts "with these other params: "  
pp \*params  
end  
end

# envisaged usage

flickr = Flickr.new  
result = flickr.test.echo({“api\_key” =\> “something long”, “foo” =\>  
“bar”})

The idea is that the usage should mirror how the methods are defined  
in the flickr docs.

In general I’m asking (like the subject suggests) if my  
metaprogramming underpants are showing? Have I defied any particular  
conventions? Does this seem like a sensible approach, and if so, a  
sensible implementation? Have I set myself up for some rather  
spectacular failures?

Specifically, though, there are three aspects of the code that I’m  
particularly curious whether anyone has any alternate approaches:

1. encoding the method name as a class heirarchy. e.g.  
‘flickr.test.echo’ is implicit in the class definition that results  
from that call (Flickr::Test::Echo), then the method name gets  
reconstructed from that when the eventual call is made. Any other  
ways to do this?

2. relying on params.length to determine the ‘end’ of the call seems  
a little funny. On the other hand, every method call takes at least  
one parameter. One idea I had was to inherit from Proc, and define  
#call, which would let flickr methods get passed around as, well,  
methods, though this seems to have its own dangers. (If I were to  
implement this as a practical library, I think I’d use flickr’s  
reflection methods to sort this out, but is there a way to do it that  
doesn’t require that sort of external oracle?)

3. using method\_missing strikes me as a potential pitfall, but I can  
re-raise this if/when the flickr API returns its own ‘method not  
found’ error. Are there any other ‘gotchas’ I should watch out for?

Thanks in advance for any feedback.

matthew smillie.

---

<div class="post-metadata">

**Author:** ![M.B.Smillie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/a88e4f/32.png) [@M.B.Smillie](https://www.ruby-forum.com/u/M.B.Smillie)\
**Post date:** [December 6, 2005, 1:06am UTC](https://www.ruby-forum.com/t/are-my-metaprogramming-underpants-showing/49549/2 "2005-12-06T01:06:56Z")

</div>

Matthew S. wrote:

> Hello all,  
> …

> In general I’m asking (like the subject suggests) if my metaprogramming  
> underpants are showing? Have I defied any particular conventions? Does  
> this seem like a sensible approach, and if so, a sensible  
> implementation? Have I set myself up for some rather spectacular failures?
> 
> Specifically, though, there are three aspects of the code that I’m  
> particularly curious whether anyone has any alternate approaches:

A suggestion: move the code that munges method\_id and \*params into  
separate methods. Much easier to test and make sure it does what you  
want and that it doesn’t barf on weird input.

James

–

[http://www.ruby-doc.org](http://www.ruby-doc.org) - Ruby Help & Documentation  
[Ruby Code & Style](http://www.artima.com/rubycs/) - Ruby Code & Style: Writers wanted  
[http://www.rubystuff.com](http://www.rubystuff.com) - The Ruby Store for Ruby Stuff  
[http://www.jamesbritt.com](http://www.jamesbritt.com) - Playing with Better Toys  
[http://www.30secondrule.com](http://www.30secondrule.com) - Building Better Tools

---

<div class="post-metadata">

**Author:** ![M.B.Smillie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/a88e4f/32.png) [@M.B.Smillie](https://www.ruby-forum.com/u/M.B.Smillie)\
**Post date:** [December 6, 2005, 3:20am UTC](https://www.ruby-forum.com/t/are-my-metaprogramming-underpants-showing/49549/3 "2005-12-06T03:20:46Z")

</div>

On Dec 6, 2005, at 0:03, James B. wrote:

> > I’m particularly curious whether anyone has any alternate  
> > approaches:
> 
> A suggestion: move the code that munges method\_id and \*params into  
> separate methods. Much easier to test and make sure it does what  
> you want and that it doesn’t barf on weird input.

Done, with a due sense of embarrassment since I as soon as I started  
thinking about that aspect of the code, I immediately found a bug  
involving using capitalize/downcase and flickr’s camelCase method  
names. Whoops & thanks for the reminder (I’ll flatter myself that I  
would have caught that during refactoring and testing anyway).

While I appreciate the input, I’m not particularly worried about  
weird input and barfing at this stage, rather that my overall  
approach with the metaprogramming is relatively sane. I’ve barfed  
over lots of weird input in my time (mixing wine and spirits, for  
instance), but the metaprogramming is relatively new.

thanks again,  
matthew smillie.

---

<div class="post-metadata">

**Author:** ![M.B.Smillie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/a88e4f/32.png) [@M.B.Smillie](https://www.ruby-forum.com/u/M.B.Smillie)\
**Post date:** [December 6, 2005, 4:13am UTC](https://www.ruby-forum.com/t/are-my-metaprogramming-underpants-showing/49549/4 "2005-12-06T04:13:37Z")

</div>

The whole class as method thing seems very odd.n I suspect there’s a  
better way. But I’m not sure what you’re trying to do exactly (the link  
to the Fliker API didn’t work btw)

T.

---

<div class="post-metadata">

**Author:** ![M.B.Smillie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/a88e4f/32.png) [@M.B.Smillie](https://www.ruby-forum.com/u/M.B.Smillie)\
**Post date:** [December 6, 2005, 5:50am UTC](https://www.ruby-forum.com/t/are-my-metaprogramming-underpants-showing/49549/5 "2005-12-06T05:50:46Z")

</div>

> Here is, hopefully, a fuller explanation

Ah, I see. Okay. I’m too tired to go into tonight, but I get back to  
you in the morning. In the mean time, iyou have some time, you might  
want to have a look at the Functor class --that may give you some ideas  
(see [http://rubyforge.org/frs/?group\_id=483](http://rubyforge.org/frs/?group_id=483))

T.

---

<div class="post-metadata">

**Author:** ![M.B.Smillie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/a88e4f/32.png) [@M.B.Smillie](https://www.ruby-forum.com/u/M.B.Smillie)\
**Post date:** [December 6, 2005, 4:54am UTC](https://www.ruby-forum.com/t/are-my-metaprogramming-underpants-showing/49549/6 "2005-12-06T04:54:05Z")

</div>

* * *

Matthew S. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
Institute for Communicating and Collaborative Systems  
University of Edinburgh

On Dec 6, 2005, at 2:37, Trans wrote:

> The whole class as method thing seems very odd.n I suspect there’s a  
> better way. But I’m not sure what you’re trying to do exactly (the  
> link  
> to the Fliker API didn’t work btw)
> 
> T.

Gah. Serves me right for doing this late at night. Here is the  
fixed link:

> **[Flickr Services](https://www.flickr.com/services/api/)**
>
> The safest and most inclusive global community of photography enthusiasts. The best place for inspiration, connection, and sharing!

Do you mind if I ask how you find it odd? Or what you might do  
otherwise? Here is, hopefully, a fuller explanation:

The reasoning was like this. I wanted the Ruby method calls to look  
just like they’re defined in the api (modulus the parameters), so  
like this:  
flickr.test.echo({“api\_key” =\> “…”})

The catch is that in Ruby, that’s a calling ‘echo’ on ‘flickr.test’,  
and so the ‘echo’ there needs to somehow know what the name of the  
entire method (flickr.test.echo) is. The point of the exercise for  
me was to avoid defining each and every API method specifically, so I  
needed a way encode the entire API method name into that ‘echo’, and  
the class heirarchy seemed like a reasonable fit:

- simpler than tracing callers

So when a the above call is made, this happens:

- flickr object create a Flickr::Test class, and an instance of it  
in @test
- flickr.test creates a Flickr::Test::Echo class, and an instance  
of it in @echo, and then calls Flickr::Test::Echo#request
- #request extracts the flickr API method name (flickr.test.echo)  
by downcasing the first letter of each element in the class name (the  
case-mangling was necessary since Ruby classnames are constants).

The first and simplest thing I did was to use method\_missing just to  
dynamically construct the API method name by concatenating the  
method\_id’s in #method\_missing and returning self. This worked, but  
didn’t leave open much flexibility for adding, well, much of anything.

Another alternative I considered was instead of using instances of  
the classes, was just to instead create a class method with analogous  
behaviour (e.g. Flickr.test would create Flickr::Test, etc), but that  
meant treating the Flickr class differently from the other classes,  
since it would need to be instantiated to match the “flickr =  
Flickr.new” intuition as well as the 'flickr.x.y" requirement.  
Seemed better to do it all at once.

thanks once again,  
matthew smillie.

---

<div class="post-metadata">

**Author:** ![M.B.Smillie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/a88e4f/32.png) [@M.B.Smillie](https://www.ruby-forum.com/u/M.B.Smillie)\
**Post date:** [December 7, 2005, 7:35am UTC](https://www.ruby-forum.com/t/are-my-metaprogramming-underpants-showing/49549/7 "2005-12-07T07:35:46Z")

</div>

Sorry I didn’t get to this until this evening. Hope it’s helpful. -T.

require ‘calibre/functor’

module Flickr  
extend self

```
@@api = {}

def method_missing( sym , *args )
    @@api[sym] ||= Functor.new { |op, *args|
        api_call("#{sym}.#{op}", *args )
    }
end

def api_call( method, *args )
  puts "call: http://flickr.com/services/rest/?method='#{method}'"
  puts "with parameters:"
  p args
end

```

end

Flickr.test.echo(“api\_key” =\> “something long”, “foo” =\> “bar”)

---

<div class="post-metadata">

**Author:** ![M.B.Smillie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/a88e4f/32.png) [@M.B.Smillie](https://www.ruby-forum.com/u/M.B.Smillie)\
**Post date:** [December 8, 2005, 1:55am UTC](https://www.ruby-forum.com/t/are-my-metaprogramming-underpants-showing/49549/8 "2005-12-08T01:55:42Z")

</div>

> Sorry I didn’t get to this until this evening. Hope it’s helpful. -T.

Noone’s in a hurry over here, so no worries.

> end  
> Well, it helps (and that calibre library is quite cool), but: it  
> fails when there’s more than three terms in the method, e.g.:  
> Flickr.photos.licenses.getInfo({“something” =\> “blah”})  
> undefined method `getInfo’ for nil:NilClass (NoMethodError)

The general case (flickr.a.b…n), doesn’t seem possible to me  
without the object returned from #method\_missing having the same  
behaviour (i.e. implementation of #method\_missing) as the initial  
object, but with the previous calls as part of the object’s state.

matt.

---

<div class="post-metadata">

**Author:** ![M.B.Smillie](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/a88e4f/32.png) [@M.B.Smillie](https://www.ruby-forum.com/u/M.B.Smillie)\
**Post date:** [December 8, 2005, 4:09am UTC](https://www.ruby-forum.com/t/are-my-metaprogramming-underpants-showing/49549/9 "2005-12-08T04:09:20Z")

</div>

Hmm… that does make it trickier b/c when will the chain end? The  
only thing I can think of the top of my head is to use an ‘!’ method to  
indicate it.

Flickr.test.echo!

Then you can just return the same Functor-like object collecting the  
parts along the way until the ‘!’ is hit.

T.
