duplo 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +5 -0
- data/LICENSE +21 -0
- data/README.md +160 -0
- data/lib/duplo/version.rb +3 -0
- data/lib/duplo.rb +85 -0
- data/spec/duplo_spec.rb +88 -0
- metadata +80 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 93bf9116a547102fde94dcfc60589763f00f53e0
|
4
|
+
data.tar.gz: 84d1ce7ffe10cc5cf596236e648faa9d4b92eca0
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 0fed2f92b20b3bfb3261cb91573e60b56260c9fcddd2a8b9c91838a0c6f5b2bcc1f9be4a03b14aa389709cbfe24a5960f836c8a75b36f4d4da8cd923ab72e88e
|
7
|
+
data.tar.gz: fcf4f4e86ab76a7bc060c64033f9f5f5f7a842490e68796f26b39ec89e55b1f595fd59c0d63b2e1d4842e3a5dbc11d93a4c99a5a9fa09ae20d9f3d0e08d0a970
|
data/CHANGELOG.md
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2015 Nikola Topalović
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,160 @@
|
|
1
|
+
Duplo
|
2
|
+
=====
|
3
|
+
|
4
|
+
Generating nested collections with minimum effort.
|
5
|
+
|
6
|
+
```
|
7
|
+
.-===============-.
|
8
|
+
| ( ) ( ) ( ) ( ) |
|
9
|
+
| ( ) ( ) ( ) ( ) |
|
10
|
+
'-----------------' ndt.
|
11
|
+
```
|
12
|
+
|
13
|
+
|
14
|
+
## Usage
|
15
|
+
|
16
|
+
Say you like matrices (bear with me), but not rolling them out by hand
|
17
|
+
or writing nested loops to populate them. You might need a nested hash
|
18
|
+
to test something real quick in your console, but generating it can be
|
19
|
+
a royal PITA.
|
20
|
+
|
21
|
+
So how about this:
|
22
|
+
|
23
|
+
```ruby
|
24
|
+
require "duplo"
|
25
|
+
include Duplo
|
26
|
+
|
27
|
+
a3a4
|
28
|
+
# => [[0, 1, 2, 3], [0, 1, 2, 3], [0, 1, 2, 3]]
|
29
|
+
```
|
30
|
+
|
31
|
+
Bam. A 3x4 matrix.
|
32
|
+
|
33
|
+
Want it random? Sure. Pass it a block to populate the entries:
|
34
|
+
|
35
|
+
```ruby
|
36
|
+
a3a4 { rand -5..5 }
|
37
|
+
# => [[1, 9, 8, 3], [3, 0, -1, -2], [2, 0, 5, -7]]
|
38
|
+
a3a4 { rand }
|
39
|
+
# => [[0.6222777300676433, 0.5613390139342668, 0.37293736375203324, 0.7319666374054961],
|
40
|
+
# [0.3798588109025701, 0.33483069318178915, 0.8779112502970073, 0.22476545143154103],
|
41
|
+
# [0.37651300630626683, 0.5035024403835663, 0.8237420938739567, 0.7611012983149591]]
|
42
|
+
```
|
43
|
+
|
44
|
+
Accessing the current entry path is easy peasy:
|
45
|
+
|
46
|
+
```ruby
|
47
|
+
a3a3a2 { |i,j,k| [i,j,k].join(":") }
|
48
|
+
# => [[["0:0:0", "0:0:1"], ["0:1:0", "0:1:1"], ["0:2:0", "0:2:1"]],
|
49
|
+
# [["1:0:0", "1:0:1"], ["1:1:0", "1:1:1"], ["1:2:0", "1:2:1"]],
|
50
|
+
# [["2:0:0", "2:0:1"], ["2:1:0", "2:1:1"], ["2:2:0", "2:2:1"]]]
|
51
|
+
```
|
52
|
+
|
53
|
+
Have I mentioned that you can go up to an arbitrary number of
|
54
|
+
dimensions? Just watch out, it might get sluggish with higher dims due
|
55
|
+
to the recursive approach under the hood.
|
56
|
+
|
57
|
+
So how 'bout them Hashes:
|
58
|
+
|
59
|
+
```ruby
|
60
|
+
h3h2h2 { |path| "I'm a #{path.join}" }
|
61
|
+
# => {0=>{0=>{0=>"I'm a 000", 1=>"I'm a 001"}, 1=>{0=>"I'm a 010", 1=>"I'm a 011"}},
|
62
|
+
# 1=>{0=>{0=>"I'm a 100", 1=>"I'm a 101"}, 1=>{0=>"I'm a 110", 1=>"I'm a 111"}},
|
63
|
+
# 2=>{0=>{0=>"I'm a 200", 1=>"I'm a 201"}, 1=>{0=>"I'm a 210", 1=>"I'm a 211"}}}
|
64
|
+
```
|
65
|
+
|
66
|
+
You can also use `s` for Sets, and mix and match collection types to
|
67
|
+
your little heart's desire:
|
68
|
+
|
69
|
+
```ruby
|
70
|
+
ah2s3 { abc.sample(2).join }
|
71
|
+
# => [{0=>#<Set: {"kx", "by", "fi"}>, 1=>#<Set: {"uz", "ow", "tx"}>},
|
72
|
+
# {0=>#<Set: {"tp", "ch", "ba"}>, 1=>#<Set: {"nu", "mn", "ve"}>},
|
73
|
+
# {0=>#<Set: {"nc", "dh", "dc"}>, 1=>#<Set: {"le", "ks", "th"}>},
|
74
|
+
# {0=>#<Set: {"ca", "xj", "lm"}>, 1=>#<Set: {"hg", "xg", "rz"}>},
|
75
|
+
# {0=>#<Set: {"oq", "vb", "ed"}>, 1=>#<Set: {"gq", "px", "sv"}>}]
|
76
|
+
```
|
77
|
+
|
78
|
+
You get the picture. If you're *really* bored, you can spell those out
|
79
|
+
for fun:
|
80
|
+
|
81
|
+
```ruby
|
82
|
+
Duplo.spell "ah2s0"
|
83
|
+
# => "5-element Array containing 2-element Hashes containing empty Sets"
|
84
|
+
```
|
85
|
+
|
86
|
+
Note that I've omitted a dim for the root array in that last
|
87
|
+
example. It defaults to 5, so `as2h` means the same thing as
|
88
|
+
`a5s2h5`. You can easily change the default size like this:
|
89
|
+
|
90
|
+
```ruby
|
91
|
+
Duplo.default_size = 3
|
92
|
+
```
|
93
|
+
|
94
|
+
Also, I sneaked in a cute little `abc` method that returns the
|
95
|
+
alphabet as an array (as seen in the last example).
|
96
|
+
|
97
|
+
|
98
|
+
## Installation
|
99
|
+
|
100
|
+
You know the drill. Add this line to your application's Gemfile
|
101
|
+
(presumably in the "development" or "test" group):
|
102
|
+
|
103
|
+
```ruby
|
104
|
+
gem "duplo"
|
105
|
+
```
|
106
|
+
|
107
|
+
or install it yourself as:
|
108
|
+
|
109
|
+
```console
|
110
|
+
$ gem install duplo
|
111
|
+
```
|
112
|
+
|
113
|
+
It's not exactly necessary to include the module, so you can work like
|
114
|
+
this:
|
115
|
+
|
116
|
+
```ruby
|
117
|
+
Duplo.a2a2
|
118
|
+
```
|
119
|
+
|
120
|
+
If you do include it, don't worry about monkey patching - the gem
|
121
|
+
works its magic by utilizing `method_missing`, so there should be no
|
122
|
+
name clashes.
|
123
|
+
|
124
|
+
My personal preference is to drop this in `.pryrc` (or `.irbrc`):
|
125
|
+
|
126
|
+
|
127
|
+
```ruby
|
128
|
+
begin
|
129
|
+
require "duplo"
|
130
|
+
include Duplo
|
131
|
+
rescue LoadError
|
132
|
+
end
|
133
|
+
```
|
134
|
+
|
135
|
+
and have those handy shortcuts available in every session, `a` and `h`
|
136
|
+
in particular.
|
137
|
+
|
138
|
+
|
139
|
+
## Testing
|
140
|
+
|
141
|
+
To test the gem, clone the repo and run:
|
142
|
+
|
143
|
+
```
|
144
|
+
$ bundle
|
145
|
+
$ bundle exec rake
|
146
|
+
```
|
147
|
+
|
148
|
+
|
149
|
+
## Contributing
|
150
|
+
|
151
|
+
1. [Fork it](https://github.com/topalovic/duplo/fork)
|
152
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
153
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
154
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
155
|
+
5. Create a new pull request
|
156
|
+
|
157
|
+
|
158
|
+
## License
|
159
|
+
|
160
|
+
This gem is released under the [MIT License](http://www.opensource.org/licenses/MIT).
|
data/lib/duplo.rb
ADDED
@@ -0,0 +1,85 @@
|
|
1
|
+
require "duplo/version"
|
2
|
+
require "set"
|
3
|
+
|
4
|
+
module Duplo
|
5
|
+
|
6
|
+
TOYS = {
|
7
|
+
"a" => Array,
|
8
|
+
"s" => Set,
|
9
|
+
"h" => Hash
|
10
|
+
}
|
11
|
+
|
12
|
+
BRICK = /[#{TOYS.keys.join}]\d*/
|
13
|
+
|
14
|
+
class << self
|
15
|
+
|
16
|
+
attr_writer :default_size
|
17
|
+
|
18
|
+
def default_size
|
19
|
+
@default_size || 5
|
20
|
+
end
|
21
|
+
|
22
|
+
def add(toy, part)
|
23
|
+
case toy
|
24
|
+
when Array, Set
|
25
|
+
toy << part
|
26
|
+
when Hash
|
27
|
+
toy.store(toy.size, part)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
def can_build?(toy)
|
32
|
+
!!(toy.strip =~ /\A#{BRICK}+\z/)
|
33
|
+
end
|
34
|
+
|
35
|
+
def build(part, path = [], &block)
|
36
|
+
part = part.dup
|
37
|
+
brick = part.slice! BRICK
|
38
|
+
type, size = crack brick
|
39
|
+
toy = type.new
|
40
|
+
|
41
|
+
if part.empty?
|
42
|
+
_block = block_given? ? block : proc { |path| path.last }
|
43
|
+
size.times { |i| add toy, _block.call(path + [i]) }
|
44
|
+
else
|
45
|
+
size.times { |i| add toy, build(part, path + [i], &block) }
|
46
|
+
end
|
47
|
+
|
48
|
+
toy
|
49
|
+
end
|
50
|
+
|
51
|
+
def smash(toy)
|
52
|
+
toy.scan(BRICK).map { |brick| crack brick }
|
53
|
+
end
|
54
|
+
|
55
|
+
def crack(brick)
|
56
|
+
type, size = brick.split("", 2)
|
57
|
+
size = size.empty? ? default_size : size.to_i
|
58
|
+
[TOYS[type], size]
|
59
|
+
end
|
60
|
+
|
61
|
+
def spell(toy)
|
62
|
+
smash(toy).map.with_index do |(type, size), idx|
|
63
|
+
plural = idx == 0 ? "" : type == Hash ? "es" : "s"
|
64
|
+
size.zero? ? "empty #{type}#{plural}" : "#{size}-element #{type}#{plural}"
|
65
|
+
end.join(" containing ")
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
module_function
|
70
|
+
|
71
|
+
def abc(n = nil)
|
72
|
+
range = "a".."z"
|
73
|
+
n ? range.take(n) : range.to_a
|
74
|
+
end
|
75
|
+
|
76
|
+
def method_missing(method_name, *arguments, &block)
|
77
|
+
toy = method_name.to_s
|
78
|
+
|
79
|
+
if Duplo.can_build? toy
|
80
|
+
Duplo.build toy, *arguments, &block
|
81
|
+
else
|
82
|
+
super
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
data/spec/duplo_spec.rb
ADDED
@@ -0,0 +1,88 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
describe Duplo do
|
4
|
+
|
5
|
+
let(:default_size) { Duplo.default_size }
|
6
|
+
|
7
|
+
it "has a version number" do
|
8
|
+
expect(Duplo::VERSION).not_to be nil
|
9
|
+
end
|
10
|
+
|
11
|
+
describe ".abc" do
|
12
|
+
it "provides alphabet" do
|
13
|
+
expect(Duplo.abc).to eq ("a".."z").to_a
|
14
|
+
expect(Duplo.abc 4).to eq ("a".."d").to_a
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
describe ".can_build?" do
|
19
|
+
let(:valid_bricks) { %w[a aa s ss h hh a0 a1h a2s33h44] }
|
20
|
+
let(:invalid_bricks) { %w[A n 0 11 1s a2s33t44] }
|
21
|
+
|
22
|
+
it "can build valid bricks" do
|
23
|
+
valid_bricks.each do |brick|
|
24
|
+
expect(Duplo.can_build? brick).to be true
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
it "cannot build invalid bricks" do
|
29
|
+
invalid_bricks.each do |brick|
|
30
|
+
expect(Duplo.can_build? brick).to be false
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
describe ".build" do
|
36
|
+
let(:bricks) do
|
37
|
+
{
|
38
|
+
"a" => [0, 1, 2, 3, 4],
|
39
|
+
"h" => { 0 => 0, 1 => 1, 2 => 2, 3 => 3, 4 => 4 },
|
40
|
+
"a2a3" => [[0, 1, 2]] * 2,
|
41
|
+
"a3s2" => [[0, 1].to_set] * 3,
|
42
|
+
"a2h3" => [{ 0 => 0, 1 => 1, 2 => 2 }, { 0 => 0, 1 => 1, 2 => 2 }],
|
43
|
+
"a2h3s4" => [{ 0 => (0..3).to_set, 1 => (0..3).to_set, 2 => (0..3).to_set }] * 2
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
it "builds toys from bricks" do
|
48
|
+
bricks.each do |brick, toy|
|
49
|
+
expect(Duplo.build brick).to eq toy
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe ".smash" do
|
55
|
+
let(:bricks) do
|
56
|
+
{
|
57
|
+
"a" => [[Array, default_size]],
|
58
|
+
"aa" => [[Array, default_size], [Array, default_size]],
|
59
|
+
"a2a" => [[Array, 2], [Array, 5]],
|
60
|
+
"a2h0" => [[Array, 2], [Hash, 0]],
|
61
|
+
"a22h3s4" => [[Array, 22], [Hash, 3], [Set, 4]]
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
it "smashes bricks, rawr!" do
|
66
|
+
bricks.each do |brick, parts|
|
67
|
+
expect(Duplo.smash brick).to eq parts
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
describe ".spell" do
|
73
|
+
let(:bricks) do
|
74
|
+
{
|
75
|
+
"a" => "5-element Array",
|
76
|
+
"aa" => "5-element Array containing 5-element Arrays",
|
77
|
+
"a2h0" => "2-element Array containing empty Hashes",
|
78
|
+
"a22h3s4" => "22-element Array containing 3-element Hashes containing 4-element Sets"
|
79
|
+
}
|
80
|
+
end
|
81
|
+
|
82
|
+
it "spells bricks properly" do
|
83
|
+
bricks.each do |brick, description|
|
84
|
+
expect(Duplo.spell brick).to eq description
|
85
|
+
end
|
86
|
+
end
|
87
|
+
end
|
88
|
+
end
|
metadata
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: duplo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Nikola Topalović
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-05-09 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
description: Generating nested collections with minimum effort.
|
42
|
+
email:
|
43
|
+
- nikola.topalovic@gmail.com
|
44
|
+
executables: []
|
45
|
+
extensions: []
|
46
|
+
extra_rdoc_files: []
|
47
|
+
files:
|
48
|
+
- CHANGELOG.md
|
49
|
+
- LICENSE
|
50
|
+
- README.md
|
51
|
+
- lib/duplo.rb
|
52
|
+
- lib/duplo/version.rb
|
53
|
+
- spec/duplo_spec.rb
|
54
|
+
homepage: https://github.com/topalovic/duplo
|
55
|
+
licenses:
|
56
|
+
- MIT
|
57
|
+
metadata: {}
|
58
|
+
post_install_message:
|
59
|
+
rdoc_options: []
|
60
|
+
require_paths:
|
61
|
+
- lib
|
62
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
63
|
+
requirements:
|
64
|
+
- - ">="
|
65
|
+
- !ruby/object:Gem::Version
|
66
|
+
version: 1.9.2
|
67
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
68
|
+
requirements:
|
69
|
+
- - ">="
|
70
|
+
- !ruby/object:Gem::Version
|
71
|
+
version: '0'
|
72
|
+
requirements: []
|
73
|
+
rubyforge_project:
|
74
|
+
rubygems_version: 2.4.5
|
75
|
+
signing_key:
|
76
|
+
specification_version: 4
|
77
|
+
summary: Generating nested collections with minimum effort.
|
78
|
+
test_files:
|
79
|
+
- spec/duplo_spec.rb
|
80
|
+
has_rdoc:
|