5

I would like to use something similar to Lodash's get and set, but in Ruby instead of JavaScript. I tried few searches but I can't find anything similar.

Lodash's documentation will probably explain it in a better way, but it's getting and setting a property from a string path ('x[0].y.z' for example). If the full path doesn't exist when setting a property, it is automatically created.

4 Answers4

2

I eventually ported Lodash _.set and _.get from JavaScript to Ruby and made a Gem.

1

Ruby 2.3 introduces the new safe navigator operator for getting nested/chained values:

x[0]&.y&.z #=> result or nil

Otherwise, Rails monkey patches all objects with try(…), allowing you to:

x[0].try(:y).try(:z) #=> result or nil

Setting is a bit harder, and I'd recommend ensuring you have the final object before attempting to set a property, e.g.:

if obj = x[0]&.y&.z
  z.name = "Dr Robot"
end
maniacalrobot
  • 2,413
  • 2
  • 18
  • 20
1

You can use the Rudash Gem that comes with most of the Lodash utilities, and not only the _.get and _.set.

Islam Attrash
  • 94
  • 1
  • 9
0

Sometimes I have had the need to programmatically get the value for a property deep into an object, but the thing is that sometimes the property is really a method, and sometimes it needs parameters!

So I came up with this solution, hope it helps devising one for your problem: (Needs Rails' #try)

def reduce_attributes_for( object, options )
  options.reduce( {} ) do |hash, ( attribute, methods )|
    hash[attribute] = methods.reduce( object ) { |a, e| a.try!(:send, *e) }
    hash
  end
end

# Usage example
o = Object.new

attribute_map = {
    # same as o.object_id
    id: [:object_id],
    # same as o.object_id.to_s
    id_as_string: [:object_id, :to_s],
    # same as o.object_id.to_s.length
    id_as_string_length: [:object_id, :to_s, :length],
    # I know, this one is a contrived example, but its purpose is
    # to illustrate how you would call methods with parameters
    # same as o.object_id.to_s.scan(/\d/)[1].to_i
    second_number_from_id: [:object_id, :to_s, [:scan, /\d/], [:[],1], :to_i]
}

reduce_attributes_for( o, attribute_map )
# {:id=>47295942175460,
#  :id_as_string=>"47295942175460",
#  :id_as_string_length=>14,
#  :second_number_from_id=>7}
zenw0lf
  • 1,232
  • 1
  • 13
  • 22