Duplo
Generate nested collections with minimum effort.
.-===============-.
| ( ) ( ) ( ) ( ) |
| ( ) ( ) ( ) ( ) |
'-----------------' ndt.
Usage
Let's say you like matrices (bear with me), but not rolling them out by hand or writing nested loops to populate them. Or you might need a few nested hashes to test something real quick in the console, but generating them can be a royal PITA.
So how about this:
require "duplo"
include Duplo
a3a4
# => [[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
Bam. A 3x4 matrix.
Want it random? Sure. Pass it a block to populate the entries:
a3a4 { rand -5..5 }
# => [[1, 9, 8, 3], [3, 0, -1, -2], [2, 0, 5, -7]]
a3a4 { rand }
# => [[0.6222777300676433, 0.5613390139342668, 0.37293736375203324, 0.7319666374054961],
# [0.3798588109025701, 0.33483069318178915, 0.8779112502970073, 0.22476545143154103],
# [0.37651300630626683, 0.5035024403835663, 0.8237420938739567, 0.7611012983149591]]
Accessing the current entry path is easy peasy. Have an identity matrix:
I4 = a4a4 { |i, j| i == j ? 1 : 0 }
# => [[1, 0, 0, 0], [0, 1, 0, 0], [0, 0, 1, 0], [0, 0, 0, 1]]
Have I mentioned that you can go up to an arbitrary number of dimensions?
a3a3a2 { |i,j,k| [i,j,k].join(":") }
# => [[["0:0:0", "0:0:1"], ["0:1:0", "0:1:1"], ["0:2:0", "0:2:1"]],
# [["1:0:0", "1:0:1"], ["1:1:0", "1:1:1"], ["1:2:0", "1:2:1"]],
# [["2:0:0", "2:0:1"], ["2:1:0", "2:1:1"], ["2:2:0", "2:2:1"]]]
Heads up, it might get a bit sluggish with higher dims due to the recursive approach under the hood.
Now how 'bout them Hashes:
h3h2h2 { |path| "I'm a #{path.join}" }
# => {0=>{0=>{0=>"I'm a 000", 1=>"I'm a 001"}, 1=>{0=>"I'm a 010", 1=>"I'm a 011"}},
# 1=>{0=>{0=>"I'm a 100", 1=>"I'm a 101"}, 1=>{0=>"I'm a 110", 1=>"I'm a 111"}},
# 2=>{0=>{0=>"I'm a 200", 1=>"I'm a 201"}, 1=>{0=>"I'm a 210", 1=>"I'm a 211"}}}
You can also use s for Sets, and mix and match collection types to
your little heart's desire:
ah2s3 { abc.sample(2).join }
# => [{0=>#<Set: {"kx", "by", "fi"}>, 1=>#<Set: {"uz", "ow", "tx"}>},
# {0=>#<Set: {"tp", "ch", "ba"}>, 1=>#<Set: {"nu", "mn", "ve"}>},
# {0=>#<Set: {"nc", "dh", "dc"}>, 1=>#<Set: {"le", "ks", "th"}>},
# {0=>#<Set: {"ca", "xj", "lm"}>, 1=>#<Set: {"hg", "xg", "rz"}>},
# {0=>#<Set: {"oq", "vb", "ed"}>, 1=>#<Set: {"gq", "px", "sv"}>}]
You get the picture. If you're really bored, you can spell those out loud:
Duplo.spell "ah2s0"
# => "5-element Array containing 2-element Hashes containing empty Sets"
Note that I've omitted a dim for the root array in that last
example. It defaults to 5, so as2h means the same thing as
a5s2h5. You can easily change it like this:
Duplo.default_size = 3
Also, I sneaked in a cute little abc method that returns the
alphabet as an array (as seen in the last example).
Installation
You know the drill.
Add this line to your application's Gemfile, presumably in the "development" or "test" group:
gem "duplo"
or install it yourself as:
$ gem install duplo
It's not really necessary to include the module, you can use it directly:
Duplo.a2a2
If you do include it, don't worry about monkey patching - the gem
works its magic by utilizing method_missing, so there should be no
name clashes.
My personal preference is to drop this in .pryrc (or .irbrc):
begin
require "duplo"
include Duplo
rescue LoadError
end
and have those handy shortcuts available in every session, a and h
in particular.
Testing
To test the gem, clone the repo and run:
$ bundle
$ bundle exec rake
Contributing
- Fork it
- Create your feature branch (
git checkout -b my-new-feature) - Commit your changes (
git commit -am 'Add some feature') - Push to the branch (
git push origin my-new-feature) - Create a new pull request
License
This gem is released under the MIT License.