goldmine 0.0.3 → 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (3) hide show
  1. data/README.md +336 -129
  2. data/lib/goldmine.rb +8 -9
  3. metadata +2 -2
data/README.md CHANGED
@@ -1,180 +1,387 @@
1
1
  # Goldmine
2
2
 
3
- ## Data mining made easy... the Ruby way.
4
- ### Turn any list into a treasure trove.
3
+ ## Pivot tables for the Rubyist
5
4
 
6
- Goldmine allows you to apply pivot table logic to any list for powerful data mining capabilities.
5
+ ### Pivot any list into a wealth of information.
7
6
 
8
- In the nomenclature of Goldmine, we call this digging for data. So we've added a `dig` method to `Array`.
7
+ Goldmine allows you to apply pivot table logic to any list for powerful data mining capabilities.
9
8
 
10
- #### More reasons to love it
9
+ ### Reasons to love it
11
10
 
12
11
  * Provides ETL like functionality... but simple and elegant
12
+ * Easily build OLAP cubes using Ruby
13
13
  * Supports method chaining for deep data mining
14
14
  * Handles values that are lists themselves
15
- * Allows you to name your pivots
16
15
 
17
- What does this all mean for you? Lets have a look.
16
+ [Why use it?](#putting-it-all-together)
17
+
18
+ ## Quick start
19
+
20
+ Install
21
+
22
+ ```
23
+ $gem install goldmine
24
+ ```
25
+
26
+ Use
27
+
28
+ ```ruby
29
+ [1,2,3,4,5,6,7,8,9].pivot { |i| i < 5 }
30
+ ```
31
+
32
+ ### Usage examples
33
+
34
+ * [Pivot a list](#pivot-a-list-of-numbers-based-on-whether-or-not-they-are-less-than-5)
35
+ * [Create a named pivot](#explicitly-name-a-pivot)
36
+ * [Pivot values that are lists themselves](#pivot-values-that-are-lists-themselves)
37
+ * [Chain pivots](#chain-pivots-together)
38
+ * [Chain pivots conditionally](#conditionally-chain-pivots-together)
39
+ * [Dig deep and extract meaningful data](#deep-cuts)
18
40
 
19
41
  ## The Basics
20
42
 
21
- #### Pivot a simple list of numbers based on whether or not they are less than 5
43
+ ### Pivot a list of numbers based on whether or not they are less than 5
22
44
 
23
45
  ```ruby
46
+ # operation
24
47
  list = [1,2,3,4,5,6,7,8,9]
25
- data = list.dig { |i| i < 5 }
48
+ data = list.pivot { |i| i < 5 }
26
49
 
27
- # {
28
- # true => [1, 2, 3, 4],
29
- # false => [5, 6, 7, 8, 9]
30
- # }
50
+ # resulting data
51
+ {
52
+ true => [1, 2, 3, 4],
53
+ false => [5, 6, 7, 8, 9]
54
+ }
31
55
  ```
32
56
 
33
- #### The same pivot as above but explicitly named
57
+ ### Explicitly name a pivot
34
58
 
35
59
  ```ruby
60
+ # operation
36
61
  list = [1,2,3,4,5,6,7,8,9]
37
- data = list.dig("less than 5") { |i| i < 5 }
62
+ data = list.pivot("less than 5") { |i| i < 5 }
38
63
 
39
- # {
40
- # "less than 5: true" => [1, 2, 3, 4],
41
- # "less than 5: false" => [5, 6, 7, 8, 9]
42
- # }
64
+ # resulting data
65
+ {
66
+ { "less than 5" => true } => [1, 2, 3, 4],
67
+ { "less than 5" => false } => [5, 6, 7, 8, 9]
68
+ }
43
69
  ```
44
70
 
45
71
  ## Next Steps
46
72
 
47
- #### Chain pivots together
73
+ ### Pivot values that are lists themselves
48
74
 
49
75
  ```ruby
76
+ # operation
77
+ list = [
78
+ { :name => "one", :list => [1] },
79
+ { :name => "two", :list => [1, 2] },
80
+ { :name => "three", :list => [1, 2, 3] },
81
+ { :name => "four", :list => [1, 2, 3, 4] },
82
+ ]
83
+ data = list.pivot { |record| record[:list] }
84
+
85
+ # resulting data
86
+ {
87
+ 1 => [ { :name => "one", :list => [1] },
88
+ { :name => "two", :list => [1, 2] },
89
+ { :name => "three", :list => [1, 2, 3] },
90
+ { :name => "four", :list => [1, 2, 3, 4] } ],
91
+ 2 => [ { :name => "two", :list => [1, 2] },
92
+ { :name => "three", :list => [1, 2, 3] },
93
+ { :name => "four", :list => [1, 2, 3, 4] } ],
94
+ 3 => [ { :name => "three", :list => [1, 2, 3] },
95
+ { :name => "four", :list => [1, 2, 3, 4] } ],
96
+ 4 => [ { :name => "four", :list => [1, 2, 3, 4] } ]
97
+ }
98
+ ```
99
+
100
+ ### Chain pivots together
101
+
102
+ ```ruby
103
+ # operation
50
104
  list = [1,2,3,4,5,6,7,8,9]
51
- data = list.dig { |i| i < 5 }.dig { |i| i % 2 == 0 }
52
-
53
- # {
54
- # [true, false] => [1, 3],
55
- # [true, true] => [2, 4],
56
- # [false, false] => [5, 7, 9],
57
- # [false, true] => [6, 8]
58
- # }
105
+ data = list.pivot { |i| i < 5 }.pivot { |i| i % 2 == 0 }
106
+
107
+ # resulting data
108
+ {
109
+ [true, false] => [1, 3],
110
+ [true, true] => [2, 4],
111
+ [false, false] => [5, 7, 9],
112
+ [false, true] => [6, 8]
113
+ }
59
114
  ```
60
115
 
61
- #### The same pivot as above but explicitly named
116
+ ### Conditionally chain pivots together
62
117
 
63
118
  ```ruby
119
+ # operation
120
+ params = { :divisible_by_two => false, :next_greater_than_five => true }
64
121
  list = [1,2,3,4,5,6,7,8,9]
65
- data = list.dig("less than 5") { |i| i < 5 }.dig("divisible by 2") { |i| i % 2 == 0 }
66
-
67
- # {
68
- # ["less than 5: true", "divisible by 2: false"] => [1, 3],
69
- # ["less than 5: true", "divisible by 2: true"] => [2, 4],
70
- # ["less than 5: false", "divisible by 2: false"] => [5, 7, 9],
71
- # ["less than 5: false", "divisible by 2: true"] => [6, 8]
72
- # }
122
+ data = list.pivot("less than 5") { |i| i < 5 }
123
+ data = data.pivot("divisible by 2") { |i| i % 2 == 0 } if params[:divisible_by_two]
124
+ data = data.pivot("next greater than 5") { |i| i.next > 5 } if params[:next_greater_than_five]
125
+
126
+ # resulting data
127
+ {
128
+ { "less than 5" => true, "next greater than 5" => false } => [1, 2, 3, 4],
129
+ { "less than 5" => false, "next greater than 5" => true } => [5, 6, 7, 8, 9]
130
+ }
73
131
  ```
74
132
 
75
133
  ## Deep Cuts
76
134
 
77
- #### Pivot a list of users based on a value that is itself a list
135
+ ### Build a moderately complex dataset of Cities
78
136
 
79
137
  ```ruby
80
- list = [
81
- { :name => "Nathan", :projects => [:a, :b] },
82
- { :name => "Eric", :projects => [:a, :d, :g] },
83
- { :name => "Brian", :projects => [:b, :c, :e, :f] },
84
- { :name => "Mark", :projects => [:g] },
85
- { :name => "Josh", :projects => [:a, :c] },
86
- { :name => "Matthew", :projects => [:b, :c, :d] }
138
+ cities = [
139
+ { :name => "San Francisco",
140
+ :state => "CA",
141
+ :population => 805235,
142
+ :airlines => [ "Delta", "United", "SouthWest" ]
143
+ },
144
+ {
145
+ :name => "Mountain View",
146
+ :state => "CA",
147
+ :population => 74066,
148
+ :airlines => [ "SkyWest", "United", "SouthWest" ]
149
+ },
150
+ {
151
+ :name => "Manhattan",
152
+ :state => "NY",
153
+ :population => 1586698,
154
+ :airlines => [ "Delta", "JetBlue", "United" ]
155
+ },
156
+ {
157
+ :name => "Brooklyn",
158
+ :state => "NY",
159
+ :population => 2504700,
160
+ :airlines => [ "Delta", "American", "US Airways" ]
161
+ },
162
+ {
163
+ :name => "Boston",
164
+ :state => "MA",
165
+ :population => 617594,
166
+ :airlines => [ "Delta", "JetBlue", "American" ]
167
+ },
168
+ {
169
+ :name => "Atlanta",
170
+ :state => "GA",
171
+ :population => 420003,
172
+ :airlines => [ "Delta", "United", "SouthWest" ]
173
+ },
174
+ {
175
+ :name => "Dallas",
176
+ :state => "TX",
177
+ :population => 1197816,
178
+ :airlines => [ "Delta", "SouthWest", "Frontier" ]
179
+ }
87
180
  ]
88
- data = list.dig { |record| record[:projects] }
89
-
90
- # {
91
- # :a => [ { :name => "Nathan", :projects => [:a, :b] },
92
- # { :name => "Eric", :projects => [:a, :d, :g] },
93
- # { :name => "Josh", :projects => [:a, :c] } ],
94
- # :b => [ { :name => "Nathan", :projects => [:a, :b] },
95
- # { :name => "Brian", :projects => [:b, :c, :e, :f] },
96
- # { :name => "Matthew", :projects => [:b, :c, :d] } ],
97
- # :d => [ { :name => "Eric", :projects => [:a, :d, :g] },
98
- # { :name => "Matthew", :projects => [:b, :c, :d] } ],
99
- # :g => [ { :name => "Eric", :projects => [:a, :d, :g] },
100
- # { :name => "Mark", :projects => [:g] } ],
101
- # :c => [ { :name => "Brian", :projects => [:b, :c, :e, :f] },
102
- # { :name => "Josh", :projects => [:a, :c] },
103
- # { :name => "Matthew", :projects => [:b, :c, :d] } ],
104
- # :e => [ { :name => "Brian", :projects => [:b, :c, :e, :f] } ],
105
- # :f => [ { :name => "Brian", :projects => [:b, :c, :e, :f] } ]
106
- # }
107
-
108
181
  ```
109
182
 
110
- #### Pivot a list of users based on lang and number of projects owned
183
+ ### Pivot cities by state for population over 750k
111
184
 
112
185
  ```ruby
113
- list = [
114
- { :name => "Nathan", :langs => [:ruby, :javascript], :projects => [:a, :b] },
115
- { :name => "Eric", :langs => [:ruby, :javascript, :groovy], :projects => [:a, :d, :g] },
116
- { :name => "Brian", :langs => [:ruby, :javascript, :c, :go], :projects => [:b, :c, :e, :f] },
117
- { :name => "Mark", :langs => [:ruby, :java, :scala], :projects => [:g] },
118
- { :name => "Josh", :langs => [:ruby, :lisp, :clojure], :projects => [:a, :c] },
119
- { :name => "Matthew", :langs => [:ruby, :c, :clojure], :projects => [:b, :c, :d] }
120
- ]
121
- data = list
122
- .dig("lang") { |rec| rec[:langs] }
123
- .dig("project count") { |rec| rec[:projects].length }
124
-
125
- # {
126
- # ["lang: ruby", "project count: 2"] => [ { :name => "Nathan", ... }, { :name => "Josh", ... } ],
127
- # ["lang: ruby", "project count: 3"] => [ { :name => "Eric", ... }, { :name => "Matthew", ... } ],
128
- # ["lang: ruby", "project count: 4"] => [ { :name => "Brian", ... } ],
129
- # ["lang: ruby", "project count: 1"] => [ { :name => "Mark", ... } ],
130
- # ["lang: javascript", "project count: 2"] => [ { :name => "Nathan", ... } ],
131
- # ["lang: javascript", "project count: 3"] => [ { :name => "Eric", ... } ],
132
- # ["lang: javascript", "project count: 4"] => [ { :name => "Brian", ... } ],
133
- # ["lang: groovy", "project count: 3"] => [ { :name => "Eric", ... } ],
134
- # ["lang: c", "project count: 4"] => [ { :name => "Brian", ... } ],
135
- # ["lang: c", "project count: 3"] => [ { :name => "Matthew", ... } ],
136
- # ["lang: go", "project count: 4"] => [ { :name => "Brian", ... } ],
137
- # ["lang: java", "project count: 1"] => [ { :name => "Mark", ... } ],
138
- # ["lang: scala", "project count: 1"] => [ { :name => "Mark", ... } ],
139
- # ["lang: lisp", "project count: 2"] => [ { :name => "Josh", ... } ],
140
- # ["lang: clojure", "project count: 2"] => [ { :name => "Josh", ... } ],
141
- # ["lang: clojure", "project count: 3"] => [ { :name => "Matthew", ... } ]
142
- # }
186
+ # operation
187
+ data = cities
188
+ .pivot("state") { |city| city[:state] }
189
+ .pivot("population >= 750k") { |city| city[:population] >= 750000 }
190
+
191
+ # resulting data
192
+ {
193
+ { "state" => "CA", "population >= 750k" => true } => [ { :name => "San Francisco", ... } ],
194
+ { "state" => "CA", "population >= 750k" => false } => [ { :name => "Mountain View", ... } ],
195
+ { "state" => "NY", "population >= 750k" => true } => [ { :name => "Manhattan", ... }, { :name => "Brooklyn", ... } ],
196
+ { "state" => "MA", "population >= 750k" => false } => [ { :name => "Boston", ... } ],
197
+ { "state" => "GA", "population >= 750k" => false } => [ { :name => "Atlanta", ... } ],
198
+ { "state" => "TX", "population >= 750k" => true } => [ { :name => "Dallas", ... } ]
199
+ }
143
200
  ```
144
201
 
145
- #### Pivot a list of users based on whether or not they know javascript, what other languages they know, and whether or not their name contains the letter 'a'
146
-
147
- *Pretty contrived example here, but hopefully illustrates the type of power thats available.*
202
+ ### Putting it all together
203
+
204
+ **The end goal of all this is to support the creation of aggregate reports.**
205
+
206
+ *You can think of these reports as individual data cubes.*
207
+
208
+ Here is a table view of the pivoted city data from above.
209
+
210
+ <table>
211
+ <thead>
212
+ <tr>
213
+ <th>state</th>
214
+ <th>population >= 750k</th>
215
+ <th>cities</th>
216
+ </tr>
217
+ </thead>
218
+ <tbody>
219
+ <tr>
220
+ <td>CA</td>
221
+ <td>true</td>
222
+ <td>1</td>
223
+ </tr>
224
+ <tr>
225
+ <td>CA</td>
226
+ <td>false</td>
227
+ <td>1</td>
228
+ </tr>
229
+ <tr>
230
+ <td>NY</td>
231
+ <td>true</td>
232
+ <td>2</td>
233
+ </tr>
234
+ <tr>
235
+ <td>MA</td>
236
+ <td>false</td>
237
+ <td>1</td>
238
+ </tr>
239
+ <tr>
240
+ <td>GA</td>
241
+ <td>false</td>
242
+ <td>1</td>
243
+ </tr>
244
+ <tr>
245
+ <td>TX</td>
246
+ <td>true</td>
247
+ <td>1</td>
248
+ </tr>
249
+ </tbody>
250
+ </table>
251
+
252
+ Lets try another one.
253
+
254
+ ### Determine which airlines service cities with fewer than 750k people
148
255
 
149
256
  ```ruby
150
- list = [
151
- { :name => "Nathan", :langs => [:ruby, :javascript], :projects => [:a, :b] },
152
- { :name => "Eric", :langs => [:ruby, :javascript, :groovy], :projects => [:a, :d, :g] },
153
- { :name => "Brian", :langs => [:ruby, :javascript, :c, :go], :projects => [:b, :c, :e, :f] },
154
- { :name => "Mark", :langs => [:ruby, :java, :scala], :projects => [:g] },
155
- { :name => "Josh", :langs => [:ruby, :lisp, :clojure], :projects => [:a, :c] },
156
- { :name => "Matthew", :langs => [:ruby, :c, :clojure], :projects => [:b, :c, :d] }
157
- ]
158
- data = list
159
- .dig("knows javascript") { |rec| rec[:langs].include?(:javascript) }
160
- .dig("lang") { |rec| rec[:langs] }
161
- .dig("name includes 'a'") { |rec| rec[:name].include?("a") }
162
-
163
- # {
164
- # ["knows javascript: true", "lang: ruby", "name includes 'a': true"] => [ { :name => "Nathan", ... }, { :name => "Brian", ... } ],
165
- # ["knows javascript: true", "lang: ruby", "name includes 'a': false"] => [ { :name => "Eric", ... } ],
166
- # ["knows javascript: true", "lang: javascript", "name includes 'a': true"] => [ { :name => "Nathan", ... }, { :name => "Brian", ... } ],
167
- # ["knows javascript: true", "lang: javascript", "name includes 'a': false"] => [ { :name => "Eric", ... } ],
168
- # ["knows javascript: true", "lang: groovy", "name includes 'a': false"] => [ { :name => "Eric", ... } ],
169
- # ["knows javascript: true", "lang: c", "name includes 'a': true"] => [ { :name => "Brian", ... } ],
170
- # ["knows javascript: true", "lang: go", "name includes 'a': true"] => [ { :name => "Brian", ... } ],
171
- # ["knows javascript: false", "lang: ruby", "name includes 'a': true"] => [ { :name => "Mark", ... }, { :name => "Matthew", ... } ],
172
- # ["knows javascript: false", "lang: ruby", "name includes 'a': false"] => [ { :name => "Josh", ... } ],
173
- # ["knows javascript: false", "lang: java", "name includes 'a': true"] => [ { :name => "Mark", ... } ],
174
- # ["knows javascript: false", "lang: scala", "name includes 'a': true"] => [ { :name => "Mark", ... } ],
175
- # ["knows javascript: false", "lang: lisp", "name includes 'a': false"] => [ { :name => "Josh", ... } ],
176
- # ["knows javascript: false", "lang: clojure", "name includes 'a': false"] => [ { :name => "Josh", ... } ],
177
- # ["knows javascript: false", "lang: clojure", "name includes 'a': true"] => [ { :name => "Matthew", ... } ],
178
- # ["knows javascript: false", "lang: c", "name includes 'a': true"] => [ { :name => "Matthew", ... } ]
179
- # }
257
+ # operation
258
+ data = cities
259
+ .pivot("airline") { |city| city[:airlines] }
260
+ .pivot("population < 750k") { |city| city[:population] < 750000 }
261
+
262
+ # resulting data
263
+ {
264
+ { "airline" => "Delta", "population < 750k" => false } => [
265
+ { :name => "San Francisco", ... },
266
+ { :name => "Manhattan", ... },
267
+ { :name => "Brooklyn", ... },
268
+ { :name => "Dallas", ... }],
269
+ { "airline" => "Delta", "population < 750k" => true } => [
270
+ { :name => "Boston", ... },
271
+ { :name => "Atlanta", ... }],
272
+ { "airline" => "United", "population < 750k" => false } => [
273
+ { :name => "San Francisco", ... },
274
+ { :name => "Manhattan", ... }],
275
+ { "airline" => "United", "population < 750k" => true } => [
276
+ { :name => "Mountain View", ... },
277
+ { :name => "Atlanta", ... }],
278
+ { "airline" => "SouthWest", "population < 750k" => false } => [
279
+ { :name => "San Francisco", ... },
280
+ { :name => "Dallas", ... }],
281
+ { "airline" => "SouthWest", "population < 750k" => true } => [
282
+ { :name => "Mountain View", ... },
283
+ { :name => "Atlanta", ... }],
284
+ { "airline" => "SkyWest", "population < 750k" => true } => [
285
+ { :name => "Mountain View", ... }],
286
+ { "airline" => "JetBlue", "population < 750k" => false } => [
287
+ { :name => "Manhattan", ... }],
288
+ { "airline" => "JetBlue", "population < 750k" => true } => [
289
+ { :name => "Boston", ... }],
290
+ { "airline" => "American", "population < 750k" => false } => [
291
+ { :name => "Brooklyn", ... }],
292
+ { "airline" => "American", "population < 750k" => true } => [
293
+ { :name => "Boston", ... }],
294
+ { "airline" => "US Airways", "population < 750k" => false } => [
295
+ { :name => "Brooklyn", ... }],
296
+ { "airline" => "Frontier", "population < 750k" => false } => [
297
+ { :name => "Dallas", ... }]
298
+ }
180
299
  ```
300
+
301
+ Here is the corresponding table view for the above dataset.
302
+
303
+ <table>
304
+ <thead>
305
+ <tr>
306
+ <th>airline</th>
307
+ <th>population &lt; 750k</th>
308
+ <th>cities</th>
309
+ </tr>
310
+ </thead>
311
+ <tbody>
312
+ <tr>
313
+ <td>Delta</td>
314
+ <td>false</td>
315
+ <td>4</td>
316
+ </tr>
317
+ <tr>
318
+ <td>Delta</td>
319
+ <td>true</td>
320
+ <td>2</td>
321
+ </tr>
322
+ <tr>
323
+ <td>United</td>
324
+ <td>false</td>
325
+ <td>2</td>
326
+ </tr>
327
+ <tr>
328
+ <td>United</td>
329
+ <td>true</td>
330
+ <td>2</td>
331
+ </tr>
332
+ <tr>
333
+ <td>SouthWest</td>
334
+ <td>false</td>
335
+ <td>2</td>
336
+ </tr>
337
+ <tr>
338
+ <td>SouthWest</td>
339
+ <td>true</td>
340
+ <td>2</td>
341
+ </tr>
342
+ <tr>
343
+ <td>SkyWest</td>
344
+ <td>true</td>
345
+ <td>1</td>
346
+ </tr>
347
+ <tr>
348
+ <td>JetBlue</td>
349
+ <td>false</td>
350
+ <td>1</td>
351
+ </tr>
352
+ <tr>
353
+ <td>JetBlue</td>
354
+ <td>true</td>
355
+ <td>1</td>
356
+ </tr>
357
+ <tr>
358
+ <td>American</td>
359
+ <td>false</td>
360
+ <td>1</td>
361
+ </tr>
362
+ <tr>
363
+ <td>American</td>
364
+ <td>true</td>
365
+ <td>1</td>
366
+ </tr>
367
+ <tr>
368
+ <td>US Airways</td>
369
+ <td>false</td>
370
+ <td>1</td>
371
+ </tr>
372
+ <tr>
373
+ <td>Frontier</td>
374
+ <td>false</td>
375
+ <td>1</td>
376
+ </tr>
377
+ </tbody>
378
+ </table>
379
+
380
+ Hopefully you can see the potential even though the above examples are somewhat contrived.
381
+
382
+ ## Special thanks
383
+
384
+ * One on One Marketing - for sponsoring the development of Goldmine
385
+ * Eric Berry - for constructive feedback
386
+ * Josh Bowles - for early adoption and feedback
387
+ * Brett Beers - for early adoption and feedback
data/lib/goldmine.rb CHANGED
@@ -2,7 +2,7 @@ require "rubygems"
2
2
 
3
3
  module Goldmine
4
4
  module ArrayMiner
5
- def dig(name=nil, &block)
5
+ def pivot(name=nil, &block)
6
6
  reduce({}) do |memo, item|
7
7
  value = yield(item)
8
8
 
@@ -24,19 +24,18 @@ module Goldmine
24
24
 
25
25
  module HashMiner
26
26
  attr_accessor :goldmine
27
- def dig(name=nil, &block)
27
+ def pivot(name=nil, &block)
28
28
  return self unless goldmine
29
29
  reduce({}) do |memo, item|
30
30
  key = item.first
31
31
  value = item.last
32
- value.dig(name, &block).each do |k, v|
33
- new_key = []
34
- if key.is_a? Array
35
- new_key = new_key + key
32
+ value.pivot(name, &block).each do |k, v|
33
+ if key.is_a? Hash
34
+ k = { block.to_s => k } unless k.is_a?(Hash)
35
+ new_key = key.merge(k)
36
36
  else
37
- new_key << key
37
+ new_key = [key, k]
38
38
  end
39
- new_key << k
40
39
  memo[new_key] = v
41
40
  end
42
41
  memo.goldmine = true
@@ -51,7 +50,7 @@ module Goldmine
51
50
  end
52
51
 
53
52
  def goldmine_key(name, key)
54
- mine_key = "#{name}: #{key}" if name
53
+ mine_key = { name => key } if name
55
54
  mine_key ||= key
56
55
  end
57
56
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: goldmine
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.3
4
+ version: 0.0.4
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -50,5 +50,5 @@ rubyforge_project:
50
50
  rubygems_version: 1.8.10
51
51
  signing_key:
52
52
  specification_version: 3
53
- summary: Data mining made easy... the Ruby way.
53
+ summary: Pivot tables for the Rubyist
54
54
  test_files: []