# Quick metaprogramming question: collecting arguments across

**URL:** <https://www.ruby-forum.com/t/quick-metaprogramming-question-collecting-arguments-across/97435>\
**Category:** Ruby\
**Created:** [July 7, 2006, 2:21am UTC](https://www.ruby-forum.com/t/quick-metaprogramming-question-collecting-arguments-across/97435 "2006-07-07T02:21:56Z")\
**Posts on this page:** 8\
**Page:** 1

<div class="post-metadata">

**Author:** ![trucker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@trucker](https://www.ruby-forum.com/u/trucker)\
**Post date:** [July 7, 2006, 2:21am UTC](https://www.ruby-forum.com/t/quick-metaprogramming-question-collecting-arguments-across/97435/1 "2006-07-07T02:21:56Z")

</div>

Hi all,

Quick question: is there a better way to write Foo.contains below?  
Forcing the lexical scoping like this feels wrong.

class Foo  
def self.contains \*o  
@contents ||= []  
@contents += o  
contents = @contents  
define\_method(:contents) { contents }  
end  
end

class Bar \< Foo  
contains :goat, :boat  
contains :stoat  
end

p Bar.new.contents # =\> [:goat, :boat, :stoat]

Thanks!

---

<div class="post-metadata">

**Author:** ![trucker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@trucker](https://www.ruby-forum.com/u/trucker)\
**Post date:** [July 7, 2006, 2:31am UTC](https://www.ruby-forum.com/t/quick-metaprogramming-question-collecting-arguments-across/97435/2 "2006-07-07T02:31:27Z")

</div>

William M. wrote:

> Hi all,
> 
> Quick question: is there a better way to write Foo.contains below?  
> Forcing the lexical scoping like this feels wrong.

Maybe:

class Foo  
def contents  
self.class.contains  
end  
def self.contains \*o  
@contents ||= []  
return @contents if o.empty?  
@contents += o  
end  
end

> class Bar \< Foo  
> contains :goat, :boat  
> contains :stoat  
> end
> 
> p Bar.new.contents # =\> [:goat, :boat, :stoat]

T.

---

<div class="post-metadata">

**Author:** ![trucker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@trucker](https://www.ruby-forum.com/u/trucker)\
**Post date:** [July 7, 2006, 2:37am UTC](https://www.ruby-forum.com/t/quick-metaprogramming-question-collecting-arguments-across/97435/3 "2006-07-07T02:37:40Z")

</div>

On 7/6/06, William M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> define\_method(:contents) { contents }  
> end  
> end
> 
> class Bar \< Foo  
> contains :goat, :boat  
> contains :stoat  
> end
> 
> p Bar.new.contents # =\> [:goat, :boat, :stoat]

How about:

class Foo  
class \<\< self  
def contains \*o  
@contents ||= []  
@contents += o  
end  
attr\_accessor :contents  
end  
def contents  
@contents ||= self.class.contents  
end  
end

class Bar \< Foo  
contains :goat, :boat  
contains :stoat  
end

p Bar.new.contents #=\> [:goat, :boat, :stoat]

---

<div class="post-metadata">

**Author:** ![trucker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@trucker](https://www.ruby-forum.com/u/trucker)\
**Post date:** [July 7, 2006, 4:06am UTC](https://www.ruby-forum.com/t/quick-metaprogramming-question-collecting-arguments-across/97435/4 "2006-07-07T04:06:37Z")

</div>

On 7/7/06, Phil T. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > > @contents += o  
> > > p Bar.new.contents # =\> [:goat, :boat, :stoat]  
> > > attr\_accessor :contents
> 
> > end
> 
> Phil

A tiny refinement (in the golfing mood):

class Foo  
class \<\< self  
def contains(\*args)  
(@contents ||= []).push(\*args)  
end  
end  
def contents  
self.class.contains  
end  
end

class Bar \< Foo  
contains :goat, :boat  
contains :stoat  
end

p Bar.contains  
p Bar.new.contents

**END**  
[:goat, :boat, :stoat]  
[:goat, :boat, :stoat]

Regards,  
Sean

---

<div class="post-metadata">

**Author:** ![trucker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@trucker](https://www.ruby-forum.com/u/trucker)\
**Post date:** [July 7, 2006, 2:40am UTC](https://www.ruby-forum.com/t/quick-metaprogramming-question-collecting-arguments-across/97435/5 "2006-07-07T02:40:49Z")

</div>

On 7/6/06, Phil T. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> > contents = @contents
> 
> end  
> def contents  
> @contents ||= self.class.contents  
> end

Actually, after thinking about it a bit more, I’d probably go with:

```
 def contents
   self.class.contents
 end

```

> end

Phil

---

<div class="post-metadata">

**Author:** ![trucker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@trucker](https://www.ruby-forum.com/u/trucker)\
**Post date:** [July 7, 2006, 2:49pm UTC](https://www.ruby-forum.com/t/quick-metaprogramming-question-collecting-arguments-across/97435/6 "2006-07-07T14:49:10Z")

</div>

2006/7/7, William M. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid):

> ```
> define_method(:contents) { contents }
> 
> ```
> 
> end  
> end

Any reason why you cannot simply use a normal attribute accessor?

class Foo  
class \<\<self  
attr\_reader :contents

```
def contains *o
  (@contents ||= []).concat o
end

```

end  
end

Note, you may want to use a Set to avoid duplicates.

Kind regards

robert

---

<div class="post-metadata">

**Author:** ![trucker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@trucker](https://www.ruby-forum.com/u/trucker)\
**Post date:** [July 7, 2006, 5:50am UTC](https://www.ruby-forum.com/t/quick-metaprogramming-question-collecting-arguments-across/97435/7 "2006-07-07T05:50:37Z")

</div>

On Fri, 7 Jul 2006, William M. wrote:

> define\_method(:contents) { contents }  
> end  
> end
> 
> class Bar \< Foo  
> contains :goat, :boat  
> contains :stoat  
> end
> 
> p Bar.new.contents # =\> [:goat, :boat, :stoat]

if the behaviour is useful - abstract it:

harp:~ \> cat a.rb  
module Container  
module ClassMethods  
def contents() @contents ||= [] end  
def contains(\*list) contents.push \*list.flatten end  
end  
def contents() self.class.contents end  
def self.included other  
other.extend ClassMethods  
super  
end  
end

class Foo  
include Container  
end

class Bar \< Foo  
contains :goat, :boat  
contains :stoat  
end

p Bar.new.contents # =\> [:goat, :boat, :stoat]

harp:~ \> ruby a.rb  
[:goat, :boat, :stoat]

regards.

-a

---

<div class="post-metadata">

**Author:** ![trucker](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/t/ecae2f/32.png) [@trucker](https://www.ruby-forum.com/u/trucker)\
**Post date:** [July 7, 2006, 5:07pm UTC](https://www.ruby-forum.com/t/quick-metaprogramming-question-collecting-arguments-across/97435/8 "2006-07-07T17:07:13Z")

</div>

Excerpts from William M.'s mail of 6 Jul 2006 (PDT):

> Quick question: is there a better way to write Foo.contains below?  
> Forcing the lexical scoping like this feels wrong.

Thanks for all the replies. A case of overlooking the obvious solution.
