|
|
|
|
||||||
![]() |
|
|
LinkBack | Outils de la discussion |
|
|
#1 |
|
Messages: n/a
Hébergeur: |
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 -- Posted via http://www.ruby-forum.com/. |
|
|
|
#2 |
|
Messages: n/a
Hébergeur: |
On 20/11/2007, Max Williams <toastkid.williams@gmail.com> wrote:
> 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? 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 |
|
|
|
#3 |
|
Messages: n/a
Hébergeur: |
On Nov 20, 2007 6:03 PM, Max Williams <toastkid.williams@gmail.com> wrote:
> 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? 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. |
|
|
|
#4 |
|
Messages: n/a
Hébergeur: |
Max Williams 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 -- Jabber: sepp2k@jabber.org ICQ: 205544826 |
|
|
|
#5 |
|
Messages: n/a
Hébergeur: |
Thanks guys - i'll try the method missing approach, and also the rails
built in slightly shorter version ![]() cheers max -- Posted via http://www.ruby-forum.com/. |
|
|
|
#6 |
|
Messages: n/a
Hébergeur: |
On Nov 20, 12:12 pm, Farrel Lifson <farrel.lif...@gmail.com> wrote:
> On 20/11/2007, Max Williams <toastkid.willi...@gmail.com> wrote: > > Say > > i have an array of Employee objects, which have an attribute "name". I > > want to get all the names, as an array. > > ... > > 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} > > 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) 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 Adkins |
|
![]() |
| Outils de la discussion | |
|
|