# Tricky metaprogramming

**URL:** <https://www.ruby-forum.com/t/tricky-metaprogramming/145985>\
**Category:** Rails\
**Created:** [August 15, 2008, 8:23pm UTC](https://www.ruby-forum.com/t/tricky-metaprogramming/145985 "2008-08-15T20:23:39Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![makire](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/fbc32d/32.png) [@makire](https://www.ruby-forum.com/u/makire)\
**Post date:** [August 15, 2008, 8:23pm UTC](https://www.ruby-forum.com/t/tricky-metaprogramming/145985/1 "2008-08-15T20:23:39Z")

</div>

Hi  
This is a tricky one I think.I have a Rails plugin that handles  
collections. For example I want to be able to write the following in a  
model:

class User \< ActiveRecord::Base  
my\_class\_method :collections =\> [:pages, :chapters, :books]  
end

With only the relevant pieces left and with neutral names the module  
file looks like this:

module MyModule1  
module MyModule2 #:nodoc:  
module MyModule3 #:nodoc:

```
  def self.included(mod)
    mod.extend(ClassMethods)
  end

  module ClassMethods
    def my_class_method(*args)
      @collections = args[0][:collections]

      extend

```

MyModule1::MyModule2::MyModule3::CollectionSingletonMethods  
include  
MyModule1::MyModule2::MyModule3::CollectionInstanceMethods  
end  
end

```
  module CollectionSingletonMethods
  end

  module CollectionInstanceMethods
    def self.included(base)
      base.class_eval do
        @collections.each do |collection|
          define_method collection do
            # Do something useful for the collection here
          end
        end
      end
    end
  end
end

```

end  
end

This means I can create one method per entry in the collection to be  
called like user\_instance.pages, user\_instance.chapters and so on. So  
far so good.

But now I want to define one method that does something for every  
collection. So this call:

user\_instance.do\_something\_for\_all

would call a method that if it was hardcoded would look like something  
like this:

class User  
def so\_something\_for\_all  
@pages = []  
@chapters = []  
@books = []  
end  
end

Does anyone know how to accomplish this in the framework above. I  
would be extremely happy for all input in this, references to texts  
about it is very welcome.

Kindest regards

Erik L.

---

<div class="post-metadata">

**Author:** ![makire](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/fbc32d/32.png) [@makire](https://www.ruby-forum.com/u/makire)\
**Post date:** [August 15, 2008, 9:40pm UTC](https://www.ruby-forum.com/t/tricky-metaprogramming/145985/2 "2008-08-15T21:40:25Z")

</div>

On 15 Aug 2008, at 19:22, Erik L. wrote:

> @books = []  
> end  
> end
> 
> Does anyone know how to accomplish this in the framework above. I  
> would be extremely happy for all input in this, references to texts  
> about it is very welcome.

is it any more complicated than

def do\_something\_for\_all  
self.class.collections.each {|collection| yield  
self.send(collection)}  
end

or have I missed something? (assuming you have a class method that  
returns the names of the collections and an accessor method for each  
collection)

Fred

---

<div class="post-metadata">

**Author:** ![makire](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/fbc32d/32.png) [@makire](https://www.ruby-forum.com/u/makire)\
**Post date:** [August 15, 2008, 11:56pm UTC](https://www.ruby-forum.com/t/tricky-metaprogramming/145985/3 "2008-08-15T23:56:52Z")

</div>

Hi Fred and thanks for taking the time to read through this long  
question.

I think for this particular example I can build a method in the way  
you describe. I got so intertwined in Procs and metaprogramming that  
this solution eluded me.

But for arguments sake, assume I wanted to construct the whole method  
body in advance, for example as a string and create a method from  
that. Would that be possible? Maybe put the whole define\_method  
thingie in a string and run eval on that?

Kindest regards

Erik

---

<div class="post-metadata">

**Author:** ![makire](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/fbc32d/32.png) [@makire](https://www.ruby-forum.com/u/makire)\
**Post date:** [August 16, 2008, 12:13am UTC](https://www.ruby-forum.com/t/tricky-metaprogramming/145985/4 "2008-08-16T00:13:14Z")

</div>

On 15 Aug 2008, at 22:55, Erik L. wrote:

> that. Would that be possible? Maybe put the whole define\_method  
> thingie in a string and run eval on that?

I’m not quite sure what you’re getting at but you ca do pretty much  
anything you want with the string form of class\_eval.

Fred

---

<div class="post-metadata">

**Author:** ![makire](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/m/fbc32d/32.png) [@makire](https://www.ruby-forum.com/u/makire)\
**Post date:** [August 16, 2008, 12:29am UTC](https://www.ruby-forum.com/t/tricky-metaprogramming/145985/5 "2008-08-16T00:29:36Z")

</div>

Hi Fred

Yes, the string form of class\_eval did just the trick.

Many thanks for the help. Priceless.

Regards

Erik
