This small mixin allows the deep iteration / mapping of Enumerable
s instances.
Adopted to be used with hashes/arrays. It is not intended to be used with large objects.
require 'iteraptor'
Blog post with detailed API documentation.
Iteraptor
is intended to be used for iteration of complex nested structures.
The yielder is being called with two parameters: “current key” and “current value.”
The key is an index (converted to string for convenience) of an element for any
Enumerable
save for Hash
.
Nested Enumerable
s are called with a compound key, represented as a “breadcrumb,”
which is a path to current key, joined with Iteraptor::DELIMITER
constant. The
latter is just a dot in current release.
enum = [{foo: {bar: [:baz, 42]}}, [:foo, {bar: {baz: 42}}]].random
— enum.iteraptor.each(**params, ->(full_key, value))
— enum.iteraptor.map(**params, ->(full_key, (key, value)))
— enum.iteraptor.select(*filters, **params, ->(full_key, value))
— enum.iteraptor.reject(*filters, **params, ->(full_key, value))
— enum.iteraptor.compact(**params)
— enum.iteraptor.flat_map(**params, ->(full_key, value))
— enum.iteraptor.flatten(**params, ->(full_key, value))
— enum.iteraptor.collect(**params, ->(full_key, value))
cada
(sp.each
) iterates through all the levels of the nestedEnumerable
, yieldingparent, element
tuple; parent is returned as a delimiter-joined stringmapa
(sp.map
) iterates all the elements, yieldingparent, (key, value)
; the mapper should return either[key, value]
array ornil
to remove this element;- NB this method always maps to
Hash
, to map toArray
useplana_mapa
- NB this method will raise if the returned value is neither
[key, value]
tuple nornil
- NB this method always maps to
plana_mapa
iterates yieldingkey, value
, maps to the yielded value, whatever it is;nil
s are not treated in some special wayaplanar
(sp.flatten
) the analogue ofArray#flatten
, but flattens the deep enumerable intoHash
instancerecoger
(sp.harvest
,collect
) the opposite toaplanar
, it builds the nested structure out of flattened hashsegar
(sp.yield
), aliasescoger
(sp.select
) allows to filter and collect elelementsrechazar
(sp.reject
) allows to filter out and collect elelementscompactar
(sp.compact
), allows to filter out allnil
s
▶ require 'iteraptor'
#⇒ true
▶ hash = {company: {name: "Me", currencies: ["A", "B", "C"],
▷ password: "12345678",
▷ details: {another_password: "QWERTYUI"}}}
#⇒ {:company=>{:name=>"Me", :currencies=>["A", "B", "C"],
# :password=>"12345678",
# :details=>{:another_password=>"QWERTYUI"}}}
▶ hash.segar(/password/i) { "*" * 8 }
#⇒ {"company"=>{"password"=>"********",
# "details"=>{"another_password"=>"********"}}}
▶ hash.segar(/password/i) { |*args| puts args.inspect }
["company.password", "12345678"]
["company.details.another_password", "QWERTYUI"]
#⇒ {"company"=>{"password"=>nil, "details"=>{"another_password"=>nil}}}
▶ hash.rechazar(/password/)
#⇒ {"company"=>{"name"=>"Me", "currencies"=>["A", "B", "C"]}}
▶ hash.aplanar
#⇒ {"company.name"=>"Me",
# "company.currencies.0"=>"A",
# "company.currencies.1"=>"B",
# "company.currencies.2"=>"C",
# "company.password"=>"12345678",
# "company.details.another_password"=>"QWERTYUI"}
▶ hash.aplanar.recoger
#⇒ {"company"=>{"name"=>"Me", "currencies"=>["A", "B", "C"],
# "password"=>"12345678",
# "details"=>{"another_password"=>"QWERTYUI"}}}
▶ hash.aplanar.recoger(symbolize_keys: true)
#⇒ {:company=>{:name=>"Me", :currencies=>["A", "B", "C"],
# :password=>"12345678",
# :details=>{:another_password=>"QWERTYUI"}}}
Iteraptor#cada
iterates all the Enumerable
elements, recursively. As it meets
the Enumerable
, it yields it and then iterates items through.
λ = ->(parent, element) { puts "#{parent} » #{element.inspect}" }
[:a, b: {c: 42}].cada &λ
#⇒ 0 » :a
#⇒ 1 » {:b=>{:c=>42}}
#⇒ 1.b » {:c=>42}
#⇒ 1.b.c » 42
{a: 42, b: [:c, :d]}.cada &λ
#⇒ a » 42
#⇒ b » [:c, :d]
#⇒ b.0 » :c
#⇒ b.1 » :d
Mapper function should return a pair [k, v]
or nil
when called from hash,
or just a value when called from an array. E. g., deep hash filtering:
▶ hash = {a: true, b: {c: '', d: 42}, e: ''}
#⇒ {:a=>true, :b=>{:c=>"", :d=>42}, :e=>""}
▶ hash.mapa { |parent, (k, v)| v == '' ? nil : [k, v] }
#⇒ {:a=>true, :b=>{:d=>42}}
This is not quite convenient, but I currently have no idea how to help
the consumer to decide what to return, besides analyzing the arguments,
received by code block. That is because internally both Hash
and Array
are
iterated as Enumerable
s.
▶ hash = {a: true, b: {c: '', d: 42}, e: ''}
#⇒ {:a=>true, :b=>{:c=>"", :d=>42}, :e=>""}
▶ hash.cada { |k, v| puts "#{k} has an empty value" if v == '' }
#⇒ b.c has an empty value
#⇒ e has an empty value
In the example below we yield all keys, that matches the regexp given as parameter.
▶ hash.segar(/[abc]/) do |parent, elem|
▷ puts "Parent: #{parent.inspect}, Element: #{elem.inspect}"
▷ end
# Parent: "a", Element: true
# Parent: "b", Element: {:c=>"", :d=>42}
# Parent: "b.c", Element: ""
# Parent: "b.d", Element: 42
#⇒ {"a"=>true, "b"=>{:c=>"", :d=>42}, "b.c"=>"", "b.d"=>42}
▶ hash = {a: true, b: {c: '', d: 42}, e: ''}
#⇒ {:a=>true, :b=>{:c=>"", :d=>42}, :e=>""}
▶ hash.mapa { |parent, (k, v)| [k, v == '' ? v = 'N/A' : v] }
#⇒ {:a=>true, :b=>{:c=>"N/A", :d=>42}, :e=>"N/A"}
▶ hash = {a: true, b: {c: '', d: 42}, e: ''}
#⇒ {:a=>true, :b=>{:c=>"", :d=>42}, :e=>""}
▶ hash.aplanar(delimiter: '_', symbolize_keys: true)
#⇒ {:a=>true, :b_c=>"", :b_d=>42, :e=>""}
Add this line to your application's Gemfile:
gem 'iteraptor'
And then execute:
$ bundle
Or install it yourself as:
$ gem install iteraptor
0.6.0
— experimental support forfull_parent: true
param0.5.0
—rechazar
andescoger
0.4.0
—aplanar
andplana_mapa
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.
Bug reports and pull requests are welcome on GitHub at https://github.com/am-kantox/iteraptor. 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.
The gem is available as open source under the terms of the MIT License.