Question

Lets say that I have the class:

class Car
  attr_accessor :brand, :color
  def initialize(br, col)
    @brand = br
    @color = col 
  end
end

first_car = Car.new 'Mercedes', 'Yellow'
second_car = Car.new 'Jaguar', 'Orange'
third_car = Car.new 'Bentley', 'Pink'

array_of_cars = [first_car, second_car]

So, the idea is to define a method to_proc in the class Array so this can happen:

array_of_cars.map(&[:brand, :color]) #=> [['Mercedes', 'Yellow'], ['Jaguar', 'Orange'], ['Bentley', 'Pink']]

or how could I somehow do something like this:

[:brand, :color].to_proc.call(first_car) #=> ['Mercedes', 'Yellow']
Was it helpful?

Solution

The standard Symbol#to_proc is, more or less, a e.send(self) call and you just want to send an array full of symbols to each element so just say exactly that with something like this:

class Array
  def to_proc
    proc { |e| self.map { |m| e.send(m) } }
  end
end

I'd probably not patch Array for this, I'd just use a local lambda if I wanted something easier to read:

brand_and_color = lambda { |e| [:brand, :color].map { |s| e.send(s) } }
array_of_cars.map(&brand_and_color)

OTHER TIPS

class Array

  def to_proc(arr)
    self.map do |elem|
       arr.map { |attr| elem.send(attr) }
    end
  end

end

Like mu is too short mentioned, I wouldn't patch Array like this.

But, this will get the work done for you.

Invoke it as such:

array_of_cars.to_proc([:brand, :color])

Maybe use a normal method?

module ConvertInstanceToHash

  def to_proc(obj, keys)
    hash = {}
    obj.instance_variables.each {|var| hash[var.to_s.delete("@")] = obj.instance_variable_get(var)}
    hash = hash.inject({}){|memo,(k,v)| memo[k.to_sym] = v; memo}
    hash.values_at(*keys).compact
  end

end

irb(main):009:0> first_car = Car.new 'Mercedes', 'Yellow'
=> #<Car:0x000000045fb870 @brand="Mercedes", @color="Yellow">
irb(main):010:0> to_proc(first_car, [:brand, :color])
=> ["Mercedes", "Yellow"]
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top