KeyMapable

Easily transform keys from one format to another.

Installation

Add this line to your application's Gemfile:

gem 'key_mapable'

And then execute:

$ bundle

Or install it yourself as:

$ gem install key_mapable

A quick example

class Espresso
  extend KeyMapable

  define_map(:to_h) do
    key_map(:strength, 'Strength')
    key_map(:temperature, 'Temperature, transform: ->(value) { value.to_i })
    key_value('IsHot') { |espresso| espresso.temperature >= 80 }
    array_key_map(:sips, 'Sips') do
      key_map(:sipper, 'Sipper')
      key_map(:temperature, 'Temperature')
    end
  end
end

Usage

To map keys from one format to another. You must first extend the KeyMapable module. This will add the necessary methods to define a map.

class Espresso
  extend KeyMapable
end

The .define_map method lets you define a method that will return a hash from the given map rules defined in the block. The following example will map #strength to the key 'Strength' in the hash returned from #to_h.

class Espresso
  extend KeyMapable

  attr_accessor :strength

  define_map(:to_h) do
    key_map(:strength, 'Strength')
  end
end

You can then use the #to_h method like so:

espresso = Espresso.new
espresso.strength = 10
espresso.to_h
#=> { 'Strength' => 10 }

The map definition can be arbitrarily nested as long as the returned objects respond to the described methods.

define_map(:to_h) do
  key_map(:manufacturer, 'Manufacturer') do
    key_map(:location, 'Location') do
      key_map(:country, 'Country')
    end
  end
end

If you wish to transform the value you can provide a third argument which must be a lambda and return the transformed value.

define_map(:to_h) do
  key_map(:temperature, 'Temperature', transform: ->(value) { value.to_i })
end

You can define a structure for a custom key by using the #key method.

define_map(:to_h) do
  key('Coffee') do
    key_map(:brand, 'Brand')
  end
end

Use #array_key_map to define maps over arrays:

define_map(:to_h) do
  array_key_map(:sips, 'Sips') do
    key_map(:sipper, 'Sipper')
    key_map(:temperature, 'Temperature')
  end
end

Use #key_value to define a key that will have a manufactured value. The block is yielded the subject and must return the manufactured value.

define_map(:to_h) do
  key_value('IsHot') { |espresso| espresso.temperature >= 80 }
end

By default the object the keys are read on is the object itself. If you want to use another object you can set the :subject keyword to a reader method on the object.

define_map(:to_h, subject: :my_reader) do
  # ...
end

Sometimes you do not want to return a hash. Provide the :resolve keyword to transform the resulting hash to your own format.

define_map(:to_h, resolve: ->(value) { OpenStruct.new(value)}) do
  # ...
end

If the object itself is an hash you might want to use hash notation to access the values. In that case pass :hash as the :access argument.

define_map(:to_h, access: :hash) do
  # ...
end

You can also pass a custom accessor. The accessor must respond to #access. It will then be passed the subject and key.

Development

After checking out the repo, run bin/setup to install dependencies. Then, run rake spec to run the tests. You can also run bin/console for an interactive prompt that will allow you to experiment.

To install this gem onto your local machine, run bundle exec rake install. To release a new version, update the version number in version.rb, and then run bundle exec rake release, which will create a git tag for the version, push git commits and tags, and push the .gem file to rubygems.org.

Contributing

Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/key_mapable.

License

The gem is available as open source under the terms of the MIT License.