# Quick way to get attributes (without using collect)

**URL:** <https://www.ruby-forum.com/t/quick-way-to-get-attributes-without-using-collect/120795>\
**Category:** Ruby\
**Created:** [November 20, 2007, 6:03pm UTC](https://www.ruby-forum.com/t/quick-way-to-get-attributes-without-using-collect/120795 "2007-11-20T18:03:37Z")\
**Posts on this page:** 6\
**Page:** 1

<div class="post-metadata">

**Author:** ![cmaxvv](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/85f322/32.png) [@cmaxvv](https://www.ruby-forum.com/u/cmaxvv)\
**Post date:** [November 20, 2007, 6:03pm UTC](https://www.ruby-forum.com/t/quick-way-to-get-attributes-without-using-collect/120795/1 "2007-11-20T18:03:37Z")

</div>

This was inspired by Rails, but i think it’s common Ruby question. Say  
i have an array of Employee objects, which have an attribute “name”. I  
want to get all the names, as an array.

Let’s say i already have the variable “employees”, which points to an  
array of Employee objects.

What i want to do is something like this -

employee\_names = employees.names

But what i have to keep on doing is something like this -

employee\_names = employees.collect{ |emp| emp.name}

Now, this isn’t a _massive_ hassle, and i find Array#collect incredibly  
useful, but it’s a bit annoying to have to keep typing it again and  
again. Is there a way to set it up so that

.foos

is automatically treated as

.collect { |x| x.foo }

?

Or another way to do this simply?

thanks  
max

---

<div class="post-metadata">

**Author:** ![cmaxvv](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/85f322/32.png) [@cmaxvv](https://www.ruby-forum.com/u/cmaxvv)\
**Post date:** [November 20, 2007, 6:13pm UTC](https://www.ruby-forum.com/t/quick-way-to-get-attributes-without-using-collect/120795/2 "2007-11-20T18:13:08Z")

</div>

On 20/11/2007, Max W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> is automatically treated as
> 
> .collect { |x| x.foo }
> 
> ?
> 
> Or another way to do this simply?

You can use the Symbol#to\_proc method

class Symbol  
def to\_proc  
Proc.new {|e| e.send(self)}  
end  
end

Which will let you right  
employee\_names = employees.collect(&:name)

Farrel

---

<div class="post-metadata">

**Author:** ![cmaxvv](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/85f322/32.png) [@cmaxvv](https://www.ruby-forum.com/u/cmaxvv)\
**Post date:** [November 20, 2007, 6:17pm UTC](https://www.ruby-forum.com/t/quick-way-to-get-attributes-without-using-collect/120795/3 "2007-11-20T18:17:23Z")

</div>

On Nov 20, 2007 6:03 PM, Max W. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid)  
wrote:

> is automatically treated as
> 
> .collect { |x| x.foo }
> 
> ?
> 
> Or another way to do this simply?

Let me introduce to you #method\_missing. It’s being called when the  
method called is not found. The standard implementation just raises  
NoMethodError,  
but you can do anything there. In fact, this is how Rails does it’s  
find\_by\_this\_and\_that magic.

So, this is the idea (not tested, just written in the mail):

class Array  
def method\_missing(name, \*args)  
single\_method = name.to\_s.chop # 1. name is a symbol, 2. chop for  
simplicity  
if !empty? && first.respond\_to?(single\_method)  
collect { |x| x.send(single\_method, \*args) } # do whatever you  
want here  
else  
super # inherited implementation  
end  
end  
end

Just make sure that this will not break the whole system (check for  
‘s’, and look any methods that might end with it, etc.)

Lookup the code in the Rails’ sources, most probably you’ll find there  
nice singular/plural conversion etc.

---

<div class="post-metadata">

**Author:** ![cmaxvv](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/85f322/32.png) [@cmaxvv](https://www.ruby-forum.com/u/cmaxvv)\
**Post date:** [November 20, 2007, 6:30pm UTC](https://www.ruby-forum.com/t/quick-way-to-get-attributes-without-using-collect/120795/4 "2007-11-20T18:30:50Z")

</div>

Thanks guys - i’ll try the method missing approach, and also the rails  
built in slightly shorter version 🙂

cheers  
max

---

<div class="post-metadata">

**Author:** ![cmaxvv](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/85f322/32.png) [@cmaxvv](https://www.ruby-forum.com/u/cmaxvv)\
**Post date:** [November 20, 2007, 7:00pm UTC](https://www.ruby-forum.com/t/quick-way-to-get-attributes-without-using-collect/120795/5 "2007-11-20T19:00:42Z")

</div>

On Nov 20, 12:12 pm, Farrel L. [removed\_email\_address@domain.invalid](mailto:removed_email_address@domain.invalid) wrote:

> Which will let you right  
> employee\_names = employees.collect(&:name)

map is shorter than collect. Also, adding optional args to to\_proc  
will make it more generally useful.

class Symbol  
def to\_proc  
lambda {|obj, \*args| obj.send(self, \*args) }  
end  
end

employee\_names = employees.map(&:name)

I’d be wary of using method\_missing for this.

Brian A.

---

<div class="post-metadata">

**Author:** ![cmaxvv](https://www.ruby-forum.com/letter_avatar_proxy/v4/letter/c/85f322/32.png) [@cmaxvv](https://www.ruby-forum.com/u/cmaxvv)\
**Post date:** [November 20, 2007, 6:26pm UTC](https://www.ruby-forum.com/t/quick-way-to-get-attributes-without-using-collect/120795/6 "2007-11-20T18:26:10Z")

</div>

Max W. wrote:

> This was inspired by Rails, but i think it’s common Ruby question.  
> […]  
> What i want to do is something like this -
> 
> employee\_names = employees.names
> 
> But what i have to keep on doing is something like this -
> 
> employee\_names = employees.collect{ |emp| emp.name}

In rails you can do “employee\_names = employees.collect(&:name)” which  
is  
somewhat more concise (though it incurs a performance penalty, I am  
told).

> Is there a way to set it up so that  
> .foos  
> is automatically treated as  
> .collect { |x| x.foo }

module Enumerable  
def method\_missing(meth, \*args, &blk)  
map {|x| x.send(meth,\*args, &blk)}  
end  
end

This might easily lead to bugs though if you want to invoke method on  
the  
elements of the enum, not considering or not knowing that the enum  
itself  
implements that method as well. For example:  
[2,4,6] / 2 #=\> [1, 2, 3]  
But:  
[2,4,6] \* 2 #=\> [2,4,6,2,4,6]

Or:  
[“1”,“2”,“3”].to\_i #=\> [1, 2, 3]  
But:  
[1,2,3].to\_s #=\> “123”

HTH,  
Sebastian
