goldmine 0.0.3 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.md +336 -129
- data/lib/goldmine.rb +8 -9
- metadata +2 -2
data/README.md
CHANGED
@@ -1,180 +1,387 @@
|
|
1
1
|
# Goldmine
|
2
2
|
|
3
|
-
##
|
4
|
-
### Turn any list into a treasure trove.
|
3
|
+
## Pivot tables for the Rubyist
|
5
4
|
|
6
|
-
|
5
|
+
### Pivot any list into a wealth of information.
|
7
6
|
|
8
|
-
|
7
|
+
Goldmine allows you to apply pivot table logic to any list for powerful data mining capabilities.
|
9
8
|
|
10
|
-
|
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
|
-
|
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
|
-
|
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.
|
48
|
+
data = list.pivot { |i| i < 5 }
|
26
49
|
|
27
|
-
#
|
28
|
-
|
29
|
-
|
30
|
-
|
50
|
+
# resulting data
|
51
|
+
{
|
52
|
+
true => [1, 2, 3, 4],
|
53
|
+
false => [5, 6, 7, 8, 9]
|
54
|
+
}
|
31
55
|
```
|
32
56
|
|
33
|
-
|
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.
|
62
|
+
data = list.pivot("less than 5") { |i| i < 5 }
|
38
63
|
|
39
|
-
#
|
40
|
-
|
41
|
-
|
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
|
-
|
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.
|
52
|
-
|
53
|
-
#
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
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
|
-
|
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.
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
#
|
70
|
-
|
71
|
-
|
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
|
-
|
135
|
+
### Build a moderately complex dataset of Cities
|
78
136
|
|
79
137
|
```ruby
|
80
|
-
|
81
|
-
{ :name => "
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
{
|
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
|
-
|
183
|
+
### Pivot cities by state for population over 750k
|
111
184
|
|
112
185
|
```ruby
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
]
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
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
|
-
|
146
|
-
|
147
|
-
|
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
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
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 < 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
|
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
|
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.
|
33
|
-
|
34
|
-
|
35
|
-
new_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
|
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 =
|
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.
|
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:
|
53
|
+
summary: Pivot tables for the Rubyist
|
54
54
|
test_files: []
|