

Practical Metaprogramming with Ruby: Storing Preferences - patio11
http://www.kalzumeus.com/2009/11/17/practical-metaprogramming-with-ruby-storing-preferences/

======
patio11
Inspired by previous HN discussion here:
<http://news.ycombinator.com/item?id=943597> which discussed _how_ you go
about programmatically creating methods in Ruby. This post provides more of
the _why_. (Short version: get more stuff done faster, go home early!)

Unfortunately by the time I got the syntax highlighting working it was already
3:15 AM, so it is unlikely I'll have much to say in the comments. Enjoy the
article!

~~~
wgj
Patrick, excellent post. I'm glad I asked you to do it!

------
cmatthias
Great article, thanks.

Another way to do this (and one that Rails makes extensive use of internally)
is to override method_missing in your object, which gets called as a "last
resort" whenever ruby can't find a method of a particular name. Inside this
method you can check to see if the method being called matches one of the keys
of your hash, and if so do what you need. This is a little bit more "meta" (if
there is such a thing) than your example because the getters/setters for each
of the options are never actually defined on the class, not even at runtime.

~~~
stephenjudkins
I'd argue that using define_method is a far better solution, for a few
reasons.

First, you also should override respond_to? as well when using method_missing
so that other people's code that relies on respond_to? doesn't break in
mysterious ways. You have to make sure that both of these methods work
consistently. This provides a few chances to break things. If someone else is
metaprogramming and relying on instance_methods or methods, you would have to
override those too to make things work consistently.

Also, using method_missing doesn't let you use alias_method_chain or several
other metaprogramming techniques at all. For instance, since ActiveRecord
models use method_missing to generate attribute accessors and dynamic finders,
it's impossible to use alias_method_chain or something like it on them. You
have to rely on ActiveRecord's unique and different kind of metaprogramming
methods (alias_attribute, among others) which is, in my opinion, undesirable.

Finally, when using method_missing, you vastly limit your ability leverage
inheritance or mixins at all. If you'd like to inherit from a class that
relies on method_missing, it is impossible to use method_missing in that class
without breaking behavior. It's also possible to define methods in mixins
using define_method, while using method_missing in a mixin means it could
stomp all over other mixins.

So, in conclusion, method_missing is something that I think should be
considered generally harmful and a last resort. The original poster's use of
define_method is more durable, less "magic", and a better option.

~~~
cmatthias
All excellent points. Sorry if my original comment wasn't clear -- I wasn't
trying to say that method_missing is a better way to do it, just that it's a
different way to accomplish the same thing.

------
tptacek
Another minor security nit: when you dynamically add accessors to an AR class,
you make it harder to control which accessors should be exposed to mass
assignment (foo.update(params)).

It was thoughtful for you to bring security up at all, though.

