duplo 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -0,0 +1,5 @@
1
+ # Duplo changelog
2
+
3
+ ### 0.1.0 (2015-05-09)
4
+
5
+ * First release
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).
@@ -0,0 +1,3 @@
1
+ module Duplo
2
+ VERSION = "0.1.0"
3
+ end
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
@@ -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: