# Metaprogramming to generate list of class-specific attribute

**URL:** <https://www.ruby-forum.com/t/metaprogramming-to-generate-list-of-class-specific-attribute/114685>\
**Category:** Ruby\
**Created:** [September 17, 2007, 1:24pm UTC](https://www.ruby-forum.com/t/metaprogramming-to-generate-list-of-class-specific-attribute/114685 "2007-09-17T13:24:08Z")\
**Posts on this page:** 5\
**Page:** 1

<div class="post-metadata">

**Author:** ![Phlip](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ed8c4c/32.png) [@Phlip](https://www.ruby-forum.com/u/Phlip)\
**Post date:** [September 17, 2007, 1:24pm UTC](https://www.ruby-forum.com/t/metaprogramming-to-generate-list-of-class-specific-attribute/114685/1 "2007-09-17T13:24:08Z")

</div>

Rubyists:

Here’s a test case illustrates the problem. Then we’ll have a candidate  
fix  
and some questions.

class Kozmik  
def self.acts\_as\_frog(species)  
@@frog\_list \<\< species  
end  
@@frog\_list = []  
cattr\_accessor :frog\_list  
end

class Toad \< Kozmik  
acts\_as\_frog :bufo  
acts\_as\_frog :kermit  
end

class BullFrog \< Kozmik  
acts\_as\_frog :tree  
acts\_as\_frog :riparian  
end

def test\_fun\_with\_metaclasses  
assert\_equal [:tree, :riparian], BullFrog.frog\_list  
assert\_equal [:bufo, :kermit], Toad.frog\_list  
end

Suppose we need an ‘acts\_as\_’ system to generate some methods for our  
target  
classes. And suppose one method is a list of all the arguments passed to  
each acts\_as\_() in each specific class.

The above test fails because @@ occupies the entire inheritance chain.  
So  
both frog\_list() class-methods return [:tree, :riparian, :bufo,  
:kermit].  
The fix seems to be to reach into the meta-class for each derived class:

class Kozmik  
def self.acts\_as\_frog(species)  
@frog\_list ||= []  
@frog\_list \<\< species  
self.class.send :attr\_accessor, :frog\_list  
end  
end

Is that as clean and lean as it could be? Is there some way to do this  
with  
even fewer lines?

Next question: Couldn’t class Kozmik be a module instead?

---

<div class="post-metadata">

**Author:** ![Phlip](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ed8c4c/32.png) [@Phlip](https://www.ruby-forum.com/u/Phlip)\
**Post date:** [September 17, 2007, 1:25pm UTC](https://www.ruby-forum.com/t/metaprogramming-to-generate-list-of-class-specific-attribute/114685/2 "2007-09-17T13:25:18Z")

</div>

Phlip wrote:  
…

> Next question: Couldn’t class Kozmik be a module instead?

Sure…

module Kozmik  
def acts\_as\_frog(species)  
@frog\_list ||= []  
@frog\_list \<\< species  
self.class.send :attr\_accessor, :frog\_list  
end  
end

class Toad; extend Kozmik  
…  
end

Or is that cheating somehow?

---

<div class="post-metadata">

**Author:** ![Phlip](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ed8c4c/32.png) [@Phlip](https://www.ruby-forum.com/u/Phlip)\
**Post date:** [September 25, 2007, 11:04pm UTC](https://www.ruby-forum.com/t/metaprogramming-to-generate-list-of-class-specific-attribute/114685/3 "2007-09-25T23:04:12Z")

</div>

On Sep 14, 2007, at 5:00 PM, Phlip wrote:

> Rubyists:  
> Here is one answering  
> even fewer lines?  
> I am not really sure if this works, but couldn’t you do:

class Kozmik  
def self.inherited  
module\_eval do  
@frog\_list = []  
end  
end

def self.acts\_as\_frog(species)  
@frog\_list \<\< species  
end  
end

Also, does module\_eval only work in a class method? Why can’t I do  
def something; module\_eval do puts 5 end; end ?

Ari  
-------------------------------------------|  
Nietzsche is my copilot

---

<div class="post-metadata">

**Author:** ![Phlip](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ed8c4c/32.png) [@Phlip](https://www.ruby-forum.com/u/Phlip)\
**Post date:** [September 25, 2007, 11:10pm UTC](https://www.ruby-forum.com/t/metaprogramming-to-generate-list-of-class-specific-attribute/114685/4 "2007-09-25T23:10:04Z")

</div>

Phlip wrote:

> Joel VanderWerf wrote:
> 
> > class Toad; extend Kozmik
> 
> extend… different from include, right?

If you need it to be #include, you can always call #extend from within  
#append\_features as in ruby-talk:35979.

---

<div class="post-metadata">

**Author:** ![Phlip](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/p/ed8c4c/32.png) [@Phlip](https://www.ruby-forum.com/u/Phlip)\
**Post date:** [September 25, 2007, 11:04pm UTC](https://www.ruby-forum.com/t/metaprogramming-to-generate-list-of-class-specific-attribute/114685/5 "2007-09-25T23:04:51Z")

</div>

Joel VanderWerf wrote:

> class Toad; extend Kozmik

extend… different from include, right?
