Last Updated: February 25, 2016
·
8.088K
· gus

Rename Hash keys

When dealing with hashified objects that are sent to an external API the original instance variables names may not comply with such API. Renaming all Hash keys would do the trick, fortunately Ruby blesses us with awesome methods such as eachwithobject, which iterates the given block for each element with an arbitrary object given and returns the initially given object.

Show me some code!

Consider the following class:

class Dog
    attr_accessor :name, :breed, :owner_name, :birth_place

    def initialize(opts = {})
        @name ||= opts[:name]
        @breed ||= opts[:breed]
        @owner_name ||= opts[:owner_name]
        @birth_place ||= opts[:birth_place]
    end

    def attributes
        Hash[instance_variables.map { |name, _| [name.to_s.sub!(%r{@}, '').to_sym, instance_variable_get(name)] }]
    end
end

It gives us a hashified object that looks like this:

> dog = Dog.new({name: 'John', breed: 'labrador', owner_name: 'Peter', birth_place: 'Canada'})
=>#<Dog:0x00000003381578 @name="John", @breed="labrador", @owner_name="Peter", @birth_place="Canada">
> hsh = dog.attributes
=> {:name=>"John", :breed=>"labrador", :owner_name=>"Peter", :birth_place=>"Canada"}

Our API does not allow snake-case or camel-case keys so we need to get rid of them

def remove_snake_case(word)
    conversion = word.to_s.gsub(/_/, '')

    return conversion.to_sym if word.is_a?(Symbol)

    conversion
end

each_with_object to the rescue!

> hsh.each_with_object({}) {|(key, value), obj| obj[remove_snake_case(key)] = value}
=> {:name=>"John", :breed=>"labrador", :ownername=>"Peter", :birthplace=>"Canada"}

Isn't ruby great?