🗺 HashRemapper
A little lib which maps original keys to the new ones *
Installation
Add this line to your application's Gemfile:
gem 'hash_remapper'
And then execute:
$ bundle
Or install it yourself as:
$ gem install hash_remapper
Features [*]
- maps original keys to the new ones 1
- auto-ignores all the skipped keys 2
- preprocess a value with a lambda 3
- allows to remap the keys within preprocessing 4
- allows to keep data subsets only 5
- allows to include data with the original key names 6
- allows to use global context to create composite fields 7
- merges values if the key already exists and supports #merge 8
- replaces values if the key already exists and doesn't support #merge 9
- allows to assign static defaults through lambdas 10
- allows to remap to the deep values within the context 11
- allows to create completely new keys (including nested ones) 12
Usage
# Having such a Hash
original_hash = {
test: 42,
'data' => [
1,
2,
'string!'
],
ignore: :me,
nested: {
hash: :data,
really: {
deep: true
}
},
recursive: [
{ number: 21 },
{ number: 42 },
{ test: 13 }
]
}
0: Basic Idea
HashRemapper.remap(
{ a: 1, b: 2 },
:a => :hello,
:b => :world
)
# => { hello: 1, world: 2 }
1: Map original keys to the new ones
HashRemapper.remap(
original_hash, # pass original Hash
test: :magic_number, # List old_key => new_key pairs
'data' => :data, # including type change if needed
ignore: :dont_ignore,
nested: :internal # values will be just passed to the new keys
)
# =>
# {
# magic_number: 42,
# data: [1, 2, 'string!'],
# dont_ignore: :me,
# internal: { hash: :data, really: { deep: true } },
# recursive: [ { number: 21 }, { number: 42 }, { test: 13 } ]
# }
2: Auto-ignore all the skipped keys
HashRemapper.remap(
original_hash,
test: :magic_number
)
# =>
# {
# magic_number: 42
# }
HashRemapper.remap(
original_hash,
false, # a flag to pass through the original key => value pairs
test: :magic_number
)
# =>
# {
# "data" => [1, 2, "string!"],
# :ignore => :me,
# :magic_number => 42,
# :nested => {:hash=>:data, :really=>{:deep=>true}}
# :recursive => [ { number: 21 }, { number: 42 }, { test: 13 } ]
# }
3: Preprocess the values with lambdas
HashRemapper.remap(
original_hash,
test: ->(_, __) { [:test, 21] } # do whatever you want and return "key: value" Array
)
# =>
# {
# test: 21
# }
4: Remap keys within preprocessing
HashRemapper.remap(
original_hash,
test: ->(data, _) { [:magic_number, data.to_s] }
)
# =>
# {
# magic_number: '42'
# }
5: Keep data subsets only
HashRemapper.remap(
original_hash,
'data' => ->(data, _) { ['data', data[0..1]] },
)
# =>
# {
# 'data' => [1, 2]
# }
6: Include data with the original key name
HashRemapper.remap(
original_hash,
test: :magic_number,
ignore: :ignore
)
# =>
# {
# magic_number: 42,
# ignore: :me
# }
7: Use global context to create composite fields
HashRemapper.remap(
original_hash,
test: ->(data, context) { [:magic_number, data + context['data'][1]] }
)
# =>
# {
# magic_number: 44
# }
8: Merges values
HashRemapper.remap(
original_hash,
test: ->(_, __) { [:magic_number, { one: 1 }] },
whatever: ->(_, __) { [:magic_number, { two: 2 }] }
)
# =>
# {
# magic_number: { one: 1, two: 2 }
# }
9: Replace values if the key already exists and doesn't support #merge
HashRemapper.remap(
original_hash,
test: ->(_, __) { [:magic_number, 42] },
whatever: ->(_, __) { [:magic_number, 21] }
)
# =>
# {
# magic_number: 21
# }
10: Assign static defaults
HashRemapper.remap(
original_hash,
test: ->(_, __) { [:magic_number, 21] }
)
# =>
# {
# magic_number: 21
# }
11: Remap to the deep values
# INFO: For advanced usage see the specs!
HashRemapper.remap(
original_hash,
test: [:magic_bool, { path: 'nested.really.deep' }]]
)
# =>
# {
# magic_bool: true
# }
HashRemapper.remap(
original_hash,
test: [:magic_numbers, {path: 'recursive.*.number', strict: false}]]
)
# =>
# {
# magic_numbers: [21, 42, nil]
# }
12: Create completely new keys (including nested ones)
HashRemapper.remap(
original_hash,
test: :magic_number,
absolutely_new_key: ->(_, __) { [:absolutely_new_key, 'shiny new value'] }
)
# =>
# {
# magic_number: 42,
# absolutely_new_key: 'shiny new value'
# }
HashRemapper.remap(
original_hash,
_: [[:nested, :new, :key], :test]
)
# =>
# {
# nested: {
# new: {
# key: 42
# }
# }
# }
# mapping a deep target from a deep source (BEWARE an old digging API <= v0.1.0)
HashRemapper.remap(
original_hash,
_: [[:nested, :new, :key], [:nested, :really, :deep]]
)
# =>
# {
# nested: {
# new: {
# key: true
# }
# }
# }
# mapping a deep target from a deep source (new digging API >= v0.2.0)
HashRemapper.remap(
original_hash,
_: [[:new, :deeply, :nested, :value], {path: 'recursive.*.number', strict: false, default: 3.14}]
)
# =>
# {
# new: {
# deeply: {
# nested: {
# value: [21, 42, 3.14]
# }
# }
# }
# }
Examples
For advanced usage and examples see specs and examples
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
Initial version of this lib was written in pair with @bronislav, so thank him for the invaluable contribution and help.
Bug reports and pull requests are welcome on GitHub at https://github.com/smileart/hash_remapper. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the Contributor Covenant code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the HashRemapper project’s codebase, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.