goldmine 0.9.2 → 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 657692c39740a0cf3b3c14851f886387616aa417
4
+ data.tar.gz: 8a611460c2a55d95d8e2d406dca9b1e72ab50682
5
+ SHA512:
6
+ metadata.gz: c4821192a956bedf128bf1f9013712f12d11ff1b69e7b7decd14655998243bdc449775ae2ec0485f49f39cf7c1701134f46430c8b1e1ddc80e0f89848e6fff51
7
+ data.tar.gz: 987848b18ed99c765401567937b8ffcc80411248f1e07ccb1d649a8c5a2ccce41b0139168c4f9133a1553475dee1b69b2c434f01e2b7c7c2936dc4b8995afd50
@@ -1,30 +1,34 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- goldmine (0.9.2)
4
+ goldmine (1.0.0)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
8
8
  specs:
9
- ansi (1.4.3)
10
9
  coderay (1.0.9)
11
- method_source (0.8.1)
12
- minitest (4.7.2)
13
- pry (0.9.12)
10
+ method_source (0.8.2)
11
+ micro_test (0.4.0)
12
+ os
13
+ multi_json (1.8.2)
14
+ os (0.9.6)
15
+ pry (0.9.12.2)
14
16
  coderay (~> 1.0.5)
15
17
  method_source (~> 0.8)
16
18
  slop (~> 3.4)
17
- rake (10.0.4)
18
- slop (3.4.4)
19
- turn (0.9.6)
20
- ansi
19
+ rake (10.1.0)
20
+ simplecov (0.7.1)
21
+ multi_json (~> 1.0)
22
+ simplecov-html (~> 0.7.1)
23
+ simplecov-html (0.7.1)
24
+ slop (3.4.6)
21
25
 
22
26
  PLATFORMS
23
27
  ruby
24
28
 
25
29
  DEPENDENCIES
26
30
  goldmine!
27
- minitest
31
+ micro_test
28
32
  pry
29
33
  rake
30
- turn
34
+ simplecov
data/README.md CHANGED
@@ -4,113 +4,46 @@
4
4
  [![Dependency Status](https://gemnasium.com/hopsoft/goldmine.png)](https://gemnasium.com/hopsoft/goldmine)
5
5
  [![Code Climate](https://codeclimate.com/github/hopsoft/goldmine.png)](https://codeclimate.com/github/hopsoft/goldmine)
6
6
 
7
- ## Pivot tables for the Rubyist
7
+ ### Extract a wealth of information from Arrays & Hashes
8
8
 
9
- ![Goldmine GEM](http://hopsoft.github.com/goldmine/images/gold.jpg)
9
+ Think of it as an enhanced `Enumerable#group_by`.
10
10
 
11
- ### Pivot any list into a wealth of information
11
+ ## Uses
12
12
 
13
- Goldmine allows you to apply pivot table logic to any list for powerful data mining capabilities.
13
+ - Data mining
14
+ - Data transformation
15
+ - CSV report generation
16
+ - Prep for data visualization
17
+ - Fact table creation
14
18
 
15
- ### Reasons to love it
19
+ The [demo project](http://hopsoft.github.io/goldmine/) demonstrates some of Goldmine's uses.
16
20
 
17
- * Provides ETL like functionality... but simple and elegant
18
- * Easily build OLAP cubes using Ruby
19
- * Supports method chaining for deep data mining
20
- * Handles values that are lists themselves
21
+ ## Quick Start
21
22
 
22
- [Why use it?](#putting-it-all-together)
23
-
24
- ## Quick start
25
-
26
- Install
27
-
28
- ```bash
29
- $gem install goldmine
30
23
  ```
31
-
32
- Use
33
-
34
- ```ruby
35
- require "goldmine"
36
- [1,2,3,4,5,6,7,8,9].pivot { |i| i < 5 }
24
+ gem install goldmine
25
+ irb
37
26
  ```
38
27
 
39
- ### Usage examples
40
-
41
- * [Pivot a list](#pivot-a-list-of-numbers-based-on-whether-or-not-they-are-less-than-5)
42
- * [Create a named pivot](#explicitly-name-a-pivot)
43
- * [Pivot values that are lists themselves](#pivot-values-that-are-lists-themselves)
44
- * [Chain pivots](#chain-pivots-together)
45
- * [Dig deep and extract meaningful data](#deep-cuts)
46
-
47
- ## The Basics
48
-
49
- ### Pivot a list of numbers based on whether or not they are less than 5
50
-
51
28
  ```ruby
52
- # operation
29
+ require "goldmine"
53
30
  list = [1,2,3,4,5,6,7,8,9]
54
- data = list.pivot { |i| i < 5 }
55
-
56
- # resulting data
31
+ list = Goldmine::ArrayMiner.new(list)
32
+ list.pivot { |i| i < 5 }
33
+ # result:
57
34
  {
58
35
  true => [1, 2, 3, 4],
59
36
  false => [5, 6, 7, 8, 9]
60
37
  }
61
38
  ```
62
39
 
63
- ### Explicitly name a pivot
64
-
65
- ```ruby
66
- # operation
67
- list = [1,2,3,4,5,6,7,8,9]
68
- data = list.pivot("less than 5") { |i| i < 5 }
69
-
70
- # resulting data
71
- {
72
- { "less than 5" => true } => [1, 2, 3, 4],
73
- { "less than 5" => false } => [5, 6, 7, 8, 9]
74
- }
75
- ```
76
-
77
- ## Next Steps
78
-
79
- ### Pivot values that are lists themselves
80
-
81
- ```ruby
82
- # operation
83
- list = [
84
- { :name => "one", :list => [1] },
85
- { :name => "two", :list => [1, 2] },
86
- { :name => "three", :list => [1, 2, 3] },
87
- { :name => "four", :list => [1, 2, 3, 4] },
88
- ]
89
- data = list.pivot { |record| record[:list] }
90
-
91
- # resulting data
92
- {
93
- 1 => [ { :name => "one", :list => [1] },
94
- { :name => "two", :list => [1, 2] },
95
- { :name => "three", :list => [1, 2, 3] },
96
- { :name => "four", :list => [1, 2, 3, 4] } ],
97
- 2 => [ { :name => "two", :list => [1, 2] },
98
- { :name => "three", :list => [1, 2, 3] },
99
- { :name => "four", :list => [1, 2, 3, 4] } ],
100
- 3 => [ { :name => "three", :list => [1, 2, 3] },
101
- { :name => "four", :list => [1, 2, 3, 4] } ],
102
- 4 => [ { :name => "four", :list => [1, 2, 3, 4] } ]
103
- }
104
- ```
105
-
106
- ### Chain pivots together
40
+ ## Chained Pivots
107
41
 
108
42
  ```ruby
109
- # operation
110
43
  list = [1,2,3,4,5,6,7,8,9]
111
- data = list.pivot { |i| i < 5 }.pivot { |i| i % 2 == 0 }
112
-
113
- # resulting data
44
+ list = Goldmine::ArrayMiner.new(list)
45
+ list.pivot { |i| i < 5 }.pivot { |i| i % 2 == 0 }
46
+ # result:
114
47
  {
115
48
  [true, false] => [1, 3],
116
49
  [true, true] => [2, 4],
@@ -119,261 +52,87 @@ data = list.pivot { |i| i < 5 }.pivot { |i| i % 2 == 0 }
119
52
  }
120
53
  ```
121
54
 
122
- ## Deep Cuts
123
-
124
- ### Build a moderately complex dataset of Cities
55
+ ## Named Pivots
125
56
 
126
57
  ```ruby
127
- cities = [
128
- { :name => "San Francisco",
129
- :state => "CA",
130
- :population => 805235,
131
- :airlines => [ "Delta", "United", "SouthWest" ]
132
- },
133
- {
134
- :name => "Mountain View",
135
- :state => "CA",
136
- :population => 74066,
137
- :airlines => [ "SkyWest", "United", "SouthWest" ]
138
- },
139
- {
140
- :name => "Manhattan",
141
- :state => "NY",
142
- :population => 1586698,
143
- :airlines => [ "Delta", "JetBlue", "United" ]
144
- },
145
- {
146
- :name => "Brooklyn",
147
- :state => "NY",
148
- :population => 2504700,
149
- :airlines => [ "Delta", "American", "US Airways" ]
150
- },
151
- {
152
- :name => "Boston",
153
- :state => "MA",
154
- :population => 617594,
155
- :airlines => [ "Delta", "JetBlue", "American" ]
156
- },
157
- {
158
- :name => "Atlanta",
159
- :state => "GA",
160
- :population => 420003,
161
- :airlines => [ "Delta", "United", "SouthWest" ]
162
- },
163
- {
164
- :name => "Dallas",
165
- :state => "TX",
166
- :population => 1197816,
167
- :airlines => [ "Delta", "SouthWest", "Frontier" ]
168
- }
169
- ]
58
+ list = [1,2,3,4,5,6,7,8,9]
59
+ list = Goldmine::ArrayMiner.new(list)
60
+ list.pivot(:less_than_5) { |i| i < 5 }
61
+ # result:
62
+ {
63
+ { :less_than_5 => true } => [1, 2, 3, 4],
64
+ { :less_than_5 => false } => [5, 6, 7, 8, 9]
65
+ }
170
66
  ```
171
67
 
172
- ### Pivot cities by state for population over 750k
68
+ ## Value Pivots
173
69
 
174
70
  ```ruby
175
- # operation
176
- data = cities
177
- .pivot("state") { |city| city[:state] }
178
- .pivot("population >= 750k") { |city| city[:population] >= 750000 }
179
-
180
- # resulting data
71
+ list = [
72
+ { :name => "Sally", :favorite_colors => [:blue] },
73
+ { :name => "John", :favorite_colors => [:blue, :green] },
74
+ { :name => "Stephen", :favorite_colors => [:red, :pink, :purple] },
75
+ { :name => "Emily", :favorite_colors => [:orange, :green] },
76
+ { :name => "Joe", :favorite_colors => [:red] }
77
+ ]
78
+ list = Goldmine::ArrayMiner.new(list)
79
+ list.pivot { |record| record[:favorite_colors] }
80
+ # result:
181
81
  {
182
- { "state" => "CA", "population >= 750k" => true } => [ { :name => "San Francisco", ... } ],
183
- { "state" => "CA", "population >= 750k" => false } => [ { :name => "Mountain View", ... } ],
184
- { "state" => "NY", "population >= 750k" => true } => [ { :name => "Manhattan", ... }, { :name => "Brooklyn", ... } ],
185
- { "state" => "MA", "population >= 750k" => false } => [ { :name => "Boston", ... } ],
186
- { "state" => "GA", "population >= 750k" => false } => [ { :name => "Atlanta", ... } ],
187
- { "state" => "TX", "population >= 750k" => true } => [ { :name => "Dallas", ... } ]
82
+ :blue => [
83
+ { :name => "Sally", :favorite_colors => [:blue] },
84
+ { :name => "John", :favorite_colors => [:blue, :green] }
85
+ ],
86
+ :green => [
87
+ { :name => "John", :favorite_colors => [:blue, :green] },
88
+ { :name => "Emily", :favorite_colors => [:orange, :green] }
89
+ ],
90
+ :red => [
91
+ { :name => "Stephen", :favorite_colors => [:red, :pink, :purple] },
92
+ { :name => "Joe", :favorite_colors => [:red] }
93
+ ],
94
+ :pink => [
95
+ { :name => "Stephen", :favorite_colors => [:red, :pink, :purple] }
96
+ ],
97
+ :purple => [
98
+ { :name => "Stephen", :favorite_colors => [:red, :pink, :purple] }
99
+ ],
100
+ :orange => [
101
+ { :name => "Emily", :favorite_colors => [:orange, :green] }
102
+ ]
188
103
  }
189
104
  ```
190
105
 
191
- ### Putting it all together
192
-
193
- **The end goal of all this is to support the creation of aggregate reports.**
194
-
195
- *You can think of these reports as individual data cubes.*
196
-
197
- Here is a table view of the pivoted city data from above.
198
-
199
- <table class="table table-bordered table-striped">
200
- <thead>
201
- <tr>
202
- <th>state</th>
203
- <th>population >= 750k</th>
204
- <th>cities</th>
205
- </tr>
206
- </thead>
207
- <tbody>
208
- <tr>
209
- <td>CA</td>
210
- <td>true</td>
211
- <td>1</td>
212
- </tr>
213
- <tr>
214
- <td>CA</td>
215
- <td>false</td>
216
- <td>1</td>
217
- </tr>
218
- <tr>
219
- <td>NY</td>
220
- <td>true</td>
221
- <td>2</td>
222
- </tr>
223
- <tr>
224
- <td>MA</td>
225
- <td>false</td>
226
- <td>1</td>
227
- </tr>
228
- <tr>
229
- <td>GA</td>
230
- <td>false</td>
231
- <td>1</td>
232
- </tr>
233
- <tr>
234
- <td>TX</td>
235
- <td>true</td>
236
- <td>1</td>
237
- </tr>
238
- </tbody>
239
- </table>
240
-
241
- Lets try another one.
242
-
243
- ### Determine which airlines service cities with fewer than 750k people
106
+ # Stacked pivots
244
107
 
245
108
  ```ruby
246
- # operation
247
- data = cities
248
- .pivot("airline") { |city| city[:airlines] }
249
- .pivot("population < 750k") { |city| city[:population] < 750000 }
250
-
251
- # resulting data
109
+ list = [
110
+ { :name => "Sally", :age => 21 },
111
+ { :name => "John", :age => 28 },
112
+ { :name => "Stephen", :age => 37 },
113
+ { :name => "Emily", :age => 32 },
114
+ { :name => "Joe", :age => 18 }
115
+ ]
116
+ list = Goldmine::ArrayMiner.new(list)
117
+ mined = list.pivot("Name has an 'e'") do |record|
118
+ !!record[:name].match(/e/i)
119
+ end
120
+ mined = mined.pivot(">= 21 years old") do |record|
121
+ record[:age] >= 21
122
+ end
123
+ # result:
252
124
  {
253
- { "airline" => "Delta", "population < 750k" => false } => [
254
- { :name => "San Francisco", ... },
255
- { :name => "Manhattan", ... },
256
- { :name => "Brooklyn", ... },
257
- { :name => "Dallas", ... }],
258
- { "airline" => "Delta", "population < 750k" => true } => [
259
- { :name => "Boston", ... },
260
- { :name => "Atlanta", ... }],
261
- { "airline" => "United", "population < 750k" => false } => [
262
- { :name => "San Francisco", ... },
263
- { :name => "Manhattan", ... }],
264
- { "airline" => "United", "population < 750k" => true } => [
265
- { :name => "Mountain View", ... },
266
- { :name => "Atlanta", ... }],
267
- { "airline" => "SouthWest", "population < 750k" => false } => [
268
- { :name => "San Francisco", ... },
269
- { :name => "Dallas", ... }],
270
- { "airline" => "SouthWest", "population < 750k" => true } => [
271
- { :name => "Mountain View", ... },
272
- { :name => "Atlanta", ... }],
273
- { "airline" => "SkyWest", "population < 750k" => true } => [
274
- { :name => "Mountain View", ... }],
275
- { "airline" => "JetBlue", "population < 750k" => false } => [
276
- { :name => "Manhattan", ... }],
277
- { "airline" => "JetBlue", "population < 750k" => true } => [
278
- { :name => "Boston", ... }],
279
- { "airline" => "American", "population < 750k" => false } => [
280
- { :name => "Brooklyn", ... }],
281
- { "airline" => "American", "population < 750k" => true } => [
282
- { :name => "Boston", ... }],
283
- { "airline" => "US Airways", "population < 750k" => false } => [
284
- { :name => "Brooklyn", ... }],
285
- { "airline" => "Frontier", "population < 750k" => false } => [
286
- { :name => "Dallas", ... }]
125
+ { "Name has an 'e'" => false, ">= 21 years old" => true } => [
126
+ { :name => "Sally", :age => 21 },
127
+ { :name => "John", :age => 28 }
128
+ ],
129
+ { "Name has an 'e'" => true, ">= 21 years old" => true } => [
130
+ { :name => "Stephen", :age => 37 },
131
+ { :name => "Emily", :age => 32 }
132
+ ],
133
+ { "Name has an 'e'" => true, ">= 21 years old" => false } => [
134
+ { :name => "Joe", :age => 18 }
135
+ ]
287
136
  }
288
137
  ```
289
138
 
290
- Here is the corresponding table view for the above dataset.
291
-
292
- <table class="table table-bordered table-striped">
293
- <thead>
294
- <tr>
295
- <th>airline</th>
296
- <th>population &lt; 750k</th>
297
- <th>cities</th>
298
- </tr>
299
- </thead>
300
- <tbody>
301
- <tr>
302
- <td>Delta</td>
303
- <td>false</td>
304
- <td>4</td>
305
- </tr>
306
- <tr>
307
- <td>Delta</td>
308
- <td>true</td>
309
- <td>2</td>
310
- </tr>
311
- <tr>
312
- <td>United</td>
313
- <td>false</td>
314
- <td>2</td>
315
- </tr>
316
- <tr>
317
- <td>United</td>
318
- <td>true</td>
319
- <td>2</td>
320
- </tr>
321
- <tr>
322
- <td>SouthWest</td>
323
- <td>false</td>
324
- <td>2</td>
325
- </tr>
326
- <tr>
327
- <td>SouthWest</td>
328
- <td>true</td>
329
- <td>2</td>
330
- </tr>
331
- <tr>
332
- <td>SkyWest</td>
333
- <td>true</td>
334
- <td>1</td>
335
- </tr>
336
- <tr>
337
- <td>JetBlue</td>
338
- <td>false</td>
339
- <td>1</td>
340
- </tr>
341
- <tr>
342
- <td>JetBlue</td>
343
- <td>true</td>
344
- <td>1</td>
345
- </tr>
346
- <tr>
347
- <td>American</td>
348
- <td>false</td>
349
- <td>1</td>
350
- </tr>
351
- <tr>
352
- <td>American</td>
353
- <td>true</td>
354
- <td>1</td>
355
- </tr>
356
- <tr>
357
- <td>US Airways</td>
358
- <td>false</td>
359
- <td>1</td>
360
- </tr>
361
- <tr>
362
- <td>Frontier</td>
363
- <td>false</td>
364
- <td>1</td>
365
- </tr>
366
- </tbody>
367
- </table>
368
-
369
- Hopefully you can see the potential even though the above examples are somewhat contrived.
370
-
371
- ## Special thanks
372
-
373
- * [One on One Marketing](http://www.1on1.com/) - for sponsoring the development of Goldmine
374
- * [Eric Berry](https://github.com/cavneb/) - for constructive feedback
375
- * [Spencer Roan](https://github.com/spencerroan) - for constructive feedback
376
- * [Brian Johnson](https://github.com/whap/) - for bringing some sanity to the recursion
377
- * [Josh Bowles](https://github.com/jbowles/) - for early adoption and feedback
378
- * [Brett Beers](https://github.com/beersbr/) - for early adoption and feedback
379
-
data/Rakefile CHANGED
@@ -1,10 +1,7 @@
1
- require "rake"
2
- require "rake/testtask"
3
1
  require "bundler/gem_tasks"
4
2
 
5
3
  task :default => [:test]
6
4
 
7
- Rake::TestTask.new(:test) do |t|
8
- t.test_files = Dir["test/test_*.rb"]
5
+ task :test do
6
+ exec "bundle exec mt"
9
7
  end
10
-
@@ -2,5 +2,10 @@ $:.unshift File.join(File.dirname(__FILE__), "goldmine")
2
2
  require "array_miner"
3
3
  require "hash_miner"
4
4
 
5
- ::Array.send(:include, Goldmine::ArrayMiner)
6
- ::Hash.send(:include, Goldmine::HashMiner)
5
+ module Goldmine
6
+ def self.miner(object)
7
+ return ArrayMiner.new(object) if object.is_a?(Array)
8
+ return HashMiner.new(object) if object.is_a?(Hash)
9
+ nil
10
+ end
11
+ end
@@ -1,7 +1,11 @@
1
+ require "delegate"
2
+
1
3
  module Goldmine
4
+ class ArrayMiner < SimpleDelegator
2
5
 
3
- # Extends Array with a pivot method.
4
- module ArrayMiner
6
+ def initialize(array=[])
7
+ super array
8
+ end
5
9
 
6
10
  # Pivots the Array into a Hash of mined data.
7
11
  # Think of it as creating a pivot table or perhaps an OLAP cube.
@@ -42,7 +46,7 @@ module Goldmine
42
46
  # @yield [Object] Yields once for each item in the Array
43
47
  # @return [Hash] The pivoted Hash of data.
44
48
  def pivot(name=nil, &block)
45
- reduce({}) do |memo, item|
49
+ reduce(HashMiner.new) do |memo, item|
46
50
  value = yield(item)
47
51
 
48
52
  if value.is_a?(Array)
@@ -1,7 +1,12 @@
1
+ require "delegate"
2
+ require "hash_miner"
3
+
1
4
  module Goldmine
5
+ class HashMiner < SimpleDelegator
2
6
 
3
- # Extends Hash with a pivot method.
4
- module HashMiner
7
+ def initialize(hash={})
8
+ super hash
9
+ end
5
10
 
6
11
  attr_accessor :goldmine
7
12
 
@@ -28,9 +33,9 @@ module Goldmine
28
33
  def pivot(name=nil, &block)
29
34
  return self unless goldmine
30
35
 
31
- reduce({}) do |memo, item|
36
+ reduce(HashMiner.new) do |memo, item|
32
37
  key = item.first
33
- value = item.last
38
+ value = Goldmine.miner(item.last)
34
39
  value.pivot(name, &block).each do |k, v|
35
40
  if key.is_a? Hash
36
41
  k = { block.to_s => k } unless k.is_a?(Hash)
@@ -1,3 +1,3 @@
1
1
  module Goldmine
2
- VERSION = "0.9.2"
2
+ VERSION = "1.0.0"
3
3
  end
@@ -1,13 +1,26 @@
1
+ require "micro_test"
1
2
  require "simplecov"
3
+ SimpleCov.command_name "MicroTest"
2
4
  SimpleCov.start
3
- require "test/unit"
4
- require "turn"
5
- require File.join(File.dirname(__FILE__), "..", "lib", "goldmine")
5
+ require File.expand_path("../../lib/goldmine", __FILE__)
6
6
 
7
- class TestGoldmine < MiniTest::Unit::TestCase
7
+ class TestGoldmine < MicroTest::Test
8
8
 
9
- def test_simple_pivot
9
+ test "miner from array" do
10
+ assert Goldmine.miner([]).is_a?(Goldmine::ArrayMiner)
11
+ end
12
+
13
+ test "miner from hash" do
14
+ assert Goldmine.miner({}).is_a?(Goldmine::HashMiner)
15
+ end
16
+
17
+ test "miner from usupported object" do
18
+ assert Goldmine.miner(Object.new).nil?
19
+ end
20
+
21
+ test "simple pivot" do
10
22
  list = [1,2,3,4,5,6,7,8,9]
23
+ list = Goldmine::ArrayMiner.new(list)
11
24
  data = list.pivot { |i| i < 5 }
12
25
 
13
26
  expected = {
@@ -15,11 +28,12 @@ class TestGoldmine < MiniTest::Unit::TestCase
15
28
  false => [5, 6, 7, 8, 9]
16
29
  }
17
30
 
18
- assert_equal expected, data
31
+ assert data == expected
19
32
  end
20
33
 
21
- def test_named_pivot
34
+ test "named pivot" do
22
35
  list = [1,2,3,4,5,6,7,8,9]
36
+ list = Goldmine::ArrayMiner.new(list)
23
37
  data = list.pivot("less than 5") { |i| i < 5 }
24
38
 
25
39
  expected = {
@@ -27,16 +41,17 @@ class TestGoldmine < MiniTest::Unit::TestCase
27
41
  { "less than 5" => false } => [5, 6, 7, 8, 9]
28
42
  }
29
43
 
30
- assert_equal expected, data
44
+ assert data == expected
31
45
  end
32
46
 
33
- def test_pivot_of_list_values
47
+ test "pivot of list values" do
34
48
  list = [
35
49
  { :name => "one", :list => [1] },
36
50
  { :name => "two", :list => [1, 2] },
37
51
  { :name => "three", :list => [1, 2, 3] },
38
52
  { :name => "four", :list => [1, 2, 3, 4] },
39
53
  ]
54
+ list = Goldmine::ArrayMiner.new(list)
40
55
  data = list.pivot { |record| record[:list] }
41
56
 
42
57
  expected = {
@@ -52,11 +67,40 @@ class TestGoldmine < MiniTest::Unit::TestCase
52
67
  4 => [ { :name => "four", :list => [1, 2, 3, 4] } ]
53
68
  }
54
69
 
55
- assert_equal expected, data
70
+ assert data == expected
56
71
  end
57
72
 
58
- def test_chained_pivots
73
+ test "pivot of list values with empty list" do
74
+ list = [
75
+ { :name => "empty", :list => [] },
76
+ { :name => "one", :list => [1] },
77
+ { :name => "two", :list => [1, 2] },
78
+ { :name => "three", :list => [1, 2, 3] },
79
+ { :name => "four", :list => [1, 2, 3, 4] },
80
+ ]
81
+ list = Goldmine::ArrayMiner.new(list)
82
+ data = list.pivot { |record| record[:list] }
83
+
84
+ expected = {
85
+ nil => [ {:name => "empty", :list => [] } ],
86
+ 1 => [ { :name => "one", :list => [1] },
87
+ { :name => "two", :list => [1, 2] },
88
+ { :name => "three", :list => [1, 2, 3] },
89
+ { :name => "four", :list => [1, 2, 3, 4] } ],
90
+ 2 => [ { :name => "two", :list => [1, 2] },
91
+ { :name => "three", :list => [1, 2, 3] },
92
+ { :name => "four", :list => [1, 2, 3, 4] } ],
93
+ 3 => [ { :name => "three", :list => [1, 2, 3] },
94
+ { :name => "four", :list => [1, 2, 3, 4] } ],
95
+ 4 => [ { :name => "four", :list => [1, 2, 3, 4] } ]
96
+ }
97
+
98
+ assert data == expected
99
+ end
100
+
101
+ test "chained pivots" do
59
102
  list = [1,2,3,4,5,6,7,8,9]
103
+ list = Goldmine::ArrayMiner.new(list)
60
104
  data = list.pivot { |i| i < 5 }.pivot { |i| i % 2 == 0 }
61
105
 
62
106
  expected = {
@@ -66,12 +110,12 @@ class TestGoldmine < MiniTest::Unit::TestCase
66
110
  [false, true] => [6, 8]
67
111
  }
68
112
 
69
- assert_equal expected, data
113
+ assert data == expected
70
114
  end
71
115
 
72
- def test_deep_chained_pivots
116
+ test "deep chained pivots" do
73
117
  list = [1,2,3,4,5,6,7,8,9]
74
- # list = [2,5,9]
118
+ list = Goldmine::ArrayMiner.new(list)
75
119
  data = list
76
120
  .pivot { |i| i < 3 }
77
121
  .pivot { |i| i < 6 }
@@ -91,11 +135,12 @@ class TestGoldmine < MiniTest::Unit::TestCase
91
135
  [false, false, false, false, true] => [9]
92
136
  }
93
137
 
94
- assert_equal expected, data
138
+ assert data == expected
95
139
  end
96
140
 
97
- def test_named_deep_chained_pivots
141
+ test "named deep chained pivots" do
98
142
  list = [1,2,3,4,5,6,7,8,9]
143
+ list = Goldmine::ArrayMiner.new(list)
99
144
  data = list.pivot("a") { |i| i < 3 }.pivot("b") { |i| i < 6 }.pivot("c") { |i| i < 9 }.pivot("d") { |i| i % 2 == 0 }.pivot("e") { |i| i % 3 == 0 }
100
145
 
101
146
  expected = {
@@ -110,11 +155,12 @@ class TestGoldmine < MiniTest::Unit::TestCase
110
155
  {"a"=>false, "b"=>false, "c"=>false, "d"=>false, "e"=>true} => [9]
111
156
  }
112
157
 
113
- assert_equal expected, data
158
+ assert data == expected
114
159
  end
115
160
 
116
- def test_named_chained_pivots
161
+ test "named chained pivots" do
117
162
  list = [1,2,3,4,5,6,7,8,9]
163
+ list = Goldmine::ArrayMiner.new(list)
118
164
  data = list.pivot("less than 5") { |i| i < 5 }.pivot("divisible by 2") { |i| i % 2 == 0 }
119
165
 
120
166
  expected = {
@@ -124,9 +170,7 @@ class TestGoldmine < MiniTest::Unit::TestCase
124
170
  { "less than 5" => false, "divisible by 2" => true} => [6, 8]
125
171
  }
126
172
 
127
- assert_equal expected, data
173
+ assert data == expected
128
174
  end
129
175
 
130
-
131
-
132
176
  end
metadata CHANGED
@@ -1,97 +1,72 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: goldmine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.9.2
5
- prerelease:
4
+ version: 1.0.0
6
5
  platform: ruby
7
6
  authors:
8
7
  - Nathan Hopkins
9
8
  autorequire:
10
9
  bindir: bin
11
10
  cert_chain: []
12
- date: 2013-04-19 00:00:00.000000000 Z
11
+ date: 2013-10-16 00:00:00.000000000 Z
13
12
  dependencies:
14
13
  - !ruby/object:Gem::Dependency
15
14
  name: rake
16
15
  requirement: !ruby/object:Gem::Requirement
17
- none: false
18
16
  requirements:
19
- - - ! '>='
17
+ - - '>='
20
18
  - !ruby/object:Gem::Version
21
19
  version: '0'
22
20
  type: :development
23
21
  prerelease: false
24
22
  version_requirements: !ruby/object:Gem::Requirement
25
- none: false
26
23
  requirements:
27
- - - ! '>='
24
+ - - '>='
28
25
  - !ruby/object:Gem::Version
29
26
  version: '0'
30
27
  - !ruby/object:Gem::Dependency
31
- name: minitest
28
+ name: micro_test
32
29
  requirement: !ruby/object:Gem::Requirement
33
- none: false
34
30
  requirements:
35
- - - ! '>='
31
+ - - '>='
36
32
  - !ruby/object:Gem::Version
37
33
  version: '0'
38
34
  type: :development
39
35
  prerelease: false
40
36
  version_requirements: !ruby/object:Gem::Requirement
41
- none: false
42
37
  requirements:
43
- - - ! '>='
38
+ - - '>='
44
39
  - !ruby/object:Gem::Version
45
40
  version: '0'
46
41
  - !ruby/object:Gem::Dependency
47
42
  name: simplecov
48
43
  requirement: !ruby/object:Gem::Requirement
49
- none: false
50
44
  requirements:
51
- - - ! '>='
45
+ - - '>='
52
46
  - !ruby/object:Gem::Version
53
47
  version: '0'
54
48
  type: :development
55
49
  prerelease: false
56
50
  version_requirements: !ruby/object:Gem::Requirement
57
- none: false
58
51
  requirements:
59
- - - ! '>='
60
- - !ruby/object:Gem::Version
61
- version: '0'
62
- - !ruby/object:Gem::Dependency
63
- name: turn
64
- requirement: !ruby/object:Gem::Requirement
65
- none: false
66
- requirements:
67
- - - ! '>='
68
- - !ruby/object:Gem::Version
69
- version: '0'
70
- type: :development
71
- prerelease: false
72
- version_requirements: !ruby/object:Gem::Requirement
73
- none: false
74
- requirements:
75
- - - ! '>='
52
+ - - '>='
76
53
  - !ruby/object:Gem::Version
77
54
  version: '0'
78
55
  - !ruby/object:Gem::Dependency
79
56
  name: pry
80
57
  requirement: !ruby/object:Gem::Requirement
81
- none: false
82
58
  requirements:
83
- - - ! '>='
59
+ - - '>='
84
60
  - !ruby/object:Gem::Version
85
61
  version: '0'
86
62
  type: :development
87
63
  prerelease: false
88
64
  version_requirements: !ruby/object:Gem::Requirement
89
- none: false
90
65
  requirements:
91
- - - ! '>='
66
+ - - '>='
92
67
  - !ruby/object:Gem::Version
93
68
  version: '0'
94
- description: Pivot tables for the Rubyist.
69
+ description: Extract a wealth of information from Arrays & Hashes
95
70
  email:
96
71
  - natehop@gmail.com
97
72
  executables: []
@@ -110,28 +85,27 @@ files:
110
85
  homepage: https://github.com/hopsoft/goldmine
111
86
  licenses:
112
87
  - MIT
88
+ metadata: {}
113
89
  post_install_message:
114
90
  rdoc_options: []
115
91
  require_paths:
116
92
  - lib
117
93
  required_ruby_version: !ruby/object:Gem::Requirement
118
- none: false
119
94
  requirements:
120
- - - ! '>='
95
+ - - '>='
121
96
  - !ruby/object:Gem::Version
122
97
  version: '0'
123
98
  required_rubygems_version: !ruby/object:Gem::Requirement
124
- none: false
125
99
  requirements:
126
- - - ! '>='
100
+ - - '>='
127
101
  - !ruby/object:Gem::Version
128
102
  version: '0'
129
103
  requirements: []
130
104
  rubyforge_project:
131
- rubygems_version: 1.8.23
105
+ rubygems_version: 2.0.3
132
106
  signing_key:
133
- specification_version: 3
134
- summary: Pivot tables for the Rubyist.
107
+ specification_version: 4
108
+ summary: Extract a wealth of information from Arrays & Hashes
135
109
  test_files:
136
110
  - test/test_goldmine.rb
137
111
  has_rdoc: