goldmine 0.0.4 → 0.9.0
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/Gemfile +3 -3
- data/Gemfile.lock +6 -0
- data/Rakefile +4 -2
- data/lib/goldmine.rb +82 -6
- data/test/test_goldmine.rb +105 -0
- metadata +3 -2
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,16 +1,22 @@
|
|
1
1
|
GEM
|
2
2
|
remote: http://rubygems.org/
|
3
3
|
specs:
|
4
|
+
ansi (1.4.2)
|
4
5
|
coderay (1.0.6)
|
5
6
|
method_source (0.7.1)
|
7
|
+
minitest (3.1.0)
|
6
8
|
pry (0.9.9.6)
|
7
9
|
coderay (~> 1.0.5)
|
8
10
|
method_source (~> 0.7.1)
|
9
11
|
slop (>= 2.4.4, < 3)
|
10
12
|
slop (2.4.4)
|
13
|
+
turn (0.9.5)
|
14
|
+
ansi
|
11
15
|
|
12
16
|
PLATFORMS
|
13
17
|
ruby
|
14
18
|
|
15
19
|
DEPENDENCIES
|
20
|
+
minitest
|
16
21
|
pry
|
22
|
+
turn
|
data/Rakefile
CHANGED
@@ -1,9 +1,11 @@
|
|
1
1
|
require 'rake'
|
2
2
|
require 'rake/testtask'
|
3
|
-
require '
|
3
|
+
require 'rdoc/task'
|
4
|
+
require 'bundler'
|
5
|
+
Bundler.require :development, :test
|
4
6
|
|
5
7
|
Rake::TestTask.new(:test) do |t|
|
6
|
-
t.test_files = FileList['test
|
8
|
+
t.test_files = FileList['test/test_*.rb']
|
7
9
|
end
|
8
10
|
|
9
11
|
task 'test:units' => ['test'] do
|
data/lib/goldmine.rb
CHANGED
@@ -1,7 +1,49 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
|
3
|
+
# Goldmine brings pivot table behavior to Arrays.
|
3
4
|
module Goldmine
|
5
|
+
|
6
|
+
# Extends Array with a pivot method.
|
4
7
|
module ArrayMiner
|
8
|
+
|
9
|
+
# Pivots the Array into a Hash of mined data.
|
10
|
+
# Think of it as creating a pivot table or perhaps an OLAP cube.
|
11
|
+
#
|
12
|
+
# @example Simple pivot
|
13
|
+
# list = [1,2,3,4,5,6,7,8,9]
|
14
|
+
# data = list.pivot { |i| i < 5 }
|
15
|
+
#
|
16
|
+
# # resulting data
|
17
|
+
# # {
|
18
|
+
# # true => [1, 2, 3, 4],
|
19
|
+
# # false => [5, 6, 7, 8, 9]
|
20
|
+
# # }
|
21
|
+
#
|
22
|
+
# @example Named pivot
|
23
|
+
# list = [1,2,3,4,5,6,7,8,9]
|
24
|
+
# data = list.pivot("less than 5") { |i| i < 5 }
|
25
|
+
#
|
26
|
+
# # resulting data
|
27
|
+
# # {
|
28
|
+
# # { "less than 5" => true } => [1, 2, 3, 4],
|
29
|
+
# # { "less than 5" => false } => [5, 6, 7, 8, 9]
|
30
|
+
# # }
|
31
|
+
#
|
32
|
+
# @example Chained pivot
|
33
|
+
# list = [1,2,3,4,5,6,7,8,9]
|
34
|
+
# data = list.pivot { |i| i < 5 }.pivot { |i| i % 2 == 0 }
|
35
|
+
#
|
36
|
+
# # resulting data
|
37
|
+
# {
|
38
|
+
# [true, false] => [1, 3],
|
39
|
+
# [true, true] => [2, 4],
|
40
|
+
# [false, false] => [5, 7, 9],
|
41
|
+
# [false, true] => [6, 8]
|
42
|
+
# }
|
43
|
+
#
|
44
|
+
# @param [String] name The named of the pivot.
|
45
|
+
# @yield [Object] Yields once for each item in the Array
|
46
|
+
# @return [Hash] The pivoted Hash of data.
|
5
47
|
def pivot(name=nil, &block)
|
6
48
|
reduce({}) do |memo, item|
|
7
49
|
value = yield(item)
|
@@ -22,8 +64,31 @@ module Goldmine
|
|
22
64
|
end
|
23
65
|
end
|
24
66
|
|
67
|
+
# Extends Hash with a pivot method.
|
25
68
|
module HashMiner
|
69
|
+
|
26
70
|
attr_accessor :goldmine
|
71
|
+
|
72
|
+
# Further pivots the Hash into mined data.
|
73
|
+
# This method is what enables the pivot method chaining.
|
74
|
+
#
|
75
|
+
# @example Chained pivot
|
76
|
+
# list = [1,2,3,4,5,6,7,8,9]
|
77
|
+
# data = list.pivot { |i| i < 5 }.pivot { |i| i % 2 == 0 }
|
78
|
+
#
|
79
|
+
# # resulting data
|
80
|
+
# {
|
81
|
+
# [true, false] => [1, 3],
|
82
|
+
# [true, true] => [2, 4],
|
83
|
+
# [false, false] => [5, 7, 9],
|
84
|
+
# [false, true] => [6, 8]
|
85
|
+
# }
|
86
|
+
#
|
87
|
+
# @note This method should not be called directly. Call Array#pivot instead.
|
88
|
+
#
|
89
|
+
# @param [String] name The named of the pivot.
|
90
|
+
# @yield [Object] Yields once for each item in the Array
|
91
|
+
# @return [Hash] The pivoted Hash of data.
|
27
92
|
def pivot(name=nil, &block)
|
28
93
|
return self unless goldmine
|
29
94
|
reduce({}) do |memo, item|
|
@@ -34,7 +99,8 @@ module Goldmine
|
|
34
99
|
k = { block.to_s => k } unless k.is_a?(Hash)
|
35
100
|
new_key = key.merge(k)
|
36
101
|
else
|
37
|
-
new_key =
|
102
|
+
new_key = key.push(k) if key.is_a?(Array)
|
103
|
+
new_key ||= [key, k]
|
38
104
|
end
|
39
105
|
memo[new_key] = v
|
40
106
|
end
|
@@ -43,16 +109,26 @@ module Goldmine
|
|
43
109
|
end
|
44
110
|
end
|
45
111
|
|
112
|
+
# Assigns a key/value pair to the Hash.
|
113
|
+
# @param [String] name The name of a pivot (can be null).
|
114
|
+
# @param [Object] key The key to use.
|
115
|
+
# @param [Object] value The value to assign
|
116
|
+
# @return [Object] The result of the assignment.
|
46
117
|
def assign_mined(name, key, value)
|
47
|
-
|
48
|
-
self[
|
49
|
-
self[goldmine_key
|
118
|
+
goldmine_key = goldmine_key(name, key)
|
119
|
+
self[goldmine_key] ||= []
|
120
|
+
self[goldmine_key] << value
|
50
121
|
end
|
51
122
|
|
123
|
+
# Creates a key for a pivot-name/key combo.
|
124
|
+
# @param [String] name The name of a pivot (can be null).
|
125
|
+
# @param [Object] key The key to use.
|
126
|
+
# @return [Object] The constructed key.
|
52
127
|
def goldmine_key(name, key)
|
53
|
-
|
54
|
-
|
128
|
+
goldmine_key = { name => key } if name
|
129
|
+
goldmine_key ||= key
|
55
130
|
end
|
131
|
+
|
56
132
|
end
|
57
133
|
end
|
58
134
|
|
@@ -0,0 +1,105 @@
|
|
1
|
+
require "test/unit"
|
2
|
+
require "turn"
|
3
|
+
require File.join(File.dirname(__FILE__), "..", "lib", "goldmine")
|
4
|
+
|
5
|
+
class TestGoldmine < MiniTest::Unit::TestCase
|
6
|
+
|
7
|
+
def test_simple_pivot
|
8
|
+
list = [1,2,3,4,5,6,7,8,9]
|
9
|
+
data = list.pivot { |i| i < 5 }
|
10
|
+
|
11
|
+
expected = {
|
12
|
+
true => [1, 2, 3, 4],
|
13
|
+
false => [5, 6, 7, 8, 9]
|
14
|
+
}
|
15
|
+
|
16
|
+
assert_equal expected, data
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_named_pivot
|
20
|
+
list = [1,2,3,4,5,6,7,8,9]
|
21
|
+
data = list.pivot("less than 5") { |i| i < 5 }
|
22
|
+
|
23
|
+
expected = {
|
24
|
+
{ "less than 5" => true } => [1, 2, 3, 4],
|
25
|
+
{ "less than 5" => false } => [5, 6, 7, 8, 9]
|
26
|
+
}
|
27
|
+
|
28
|
+
assert_equal expected, data
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_pivot_of_list_values
|
32
|
+
list = [
|
33
|
+
{ :name => "one", :list => [1] },
|
34
|
+
{ :name => "two", :list => [1, 2] },
|
35
|
+
{ :name => "three", :list => [1, 2, 3] },
|
36
|
+
{ :name => "four", :list => [1, 2, 3, 4] },
|
37
|
+
]
|
38
|
+
data = list.pivot { |record| record[:list] }
|
39
|
+
|
40
|
+
expected = {
|
41
|
+
1 => [ { :name => "one", :list => [1] },
|
42
|
+
{ :name => "two", :list => [1, 2] },
|
43
|
+
{ :name => "three", :list => [1, 2, 3] },
|
44
|
+
{ :name => "four", :list => [1, 2, 3, 4] } ],
|
45
|
+
2 => [ { :name => "two", :list => [1, 2] },
|
46
|
+
{ :name => "three", :list => [1, 2, 3] },
|
47
|
+
{ :name => "four", :list => [1, 2, 3, 4] } ],
|
48
|
+
3 => [ { :name => "three", :list => [1, 2, 3] },
|
49
|
+
{ :name => "four", :list => [1, 2, 3, 4] } ],
|
50
|
+
4 => [ { :name => "four", :list => [1, 2, 3, 4] } ]
|
51
|
+
}
|
52
|
+
|
53
|
+
assert_equal expected, data
|
54
|
+
end
|
55
|
+
|
56
|
+
def test_chained_pivots
|
57
|
+
list = [1,2,3,4,5,6,7,8,9]
|
58
|
+
data = list.pivot { |i| i < 5 }.pivot { |i| i % 2 == 0 }
|
59
|
+
|
60
|
+
expected = {
|
61
|
+
[true, false] => [1, 3],
|
62
|
+
[true, true] => [2, 4],
|
63
|
+
[false, false] => [5, 7, 9],
|
64
|
+
[false, true] => [6, 8]
|
65
|
+
}
|
66
|
+
|
67
|
+
assert_equal expected, data
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_deep_chained_pivots
|
71
|
+
list = [1,2,3,4,5,6,7,8,9]
|
72
|
+
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 }
|
73
|
+
|
74
|
+
expected1 = {
|
75
|
+
{"a"=>true, "b"=>true, "c"=>true, "d"=>false, "e"=>false}=>[1],
|
76
|
+
{"a"=>true, "b"=>true, "c"=>true, "d"=>true, "e"=>false}=>[2],
|
77
|
+
{"a"=>false, "b"=>true, "c"=>true, "d"=>false, "e"=>true}=>[3],
|
78
|
+
{"a"=>false, "b"=>true, "c"=>true, "d"=>false, "e"=>false}=>[5],
|
79
|
+
{"a"=>false, "b"=>true, "c"=>true, "d"=>true, "e"=>false}=>[4],
|
80
|
+
{"a"=>false, "b"=>false, "c"=>true, "d"=>true, "e"=>true}=>[6],
|
81
|
+
{"a"=>false, "b"=>false, "c"=>true, "d"=>true, "e"=>false}=>[8],
|
82
|
+
{"a"=>false, "b"=>false, "c"=>true, "d"=>false, "e"=>false}=>[7],
|
83
|
+
{"a"=>false, "b"=>false, "c"=>false, "d"=>false, "e"=>true}=>[9]
|
84
|
+
}
|
85
|
+
|
86
|
+
assert_equal expected1, data
|
87
|
+
end
|
88
|
+
|
89
|
+
def test_named_chained_pivots
|
90
|
+
list = [1,2,3,4,5,6,7,8,9]
|
91
|
+
data = list.pivot("less than 5") { |i| i < 5 }.pivot("divisible by 2") { |i| i % 2 == 0 }
|
92
|
+
|
93
|
+
expected = {
|
94
|
+
{ "less than 5" => true, "divisible by 2" => false } => [1, 3],
|
95
|
+
{ "less than 5" => true, "divisible by 2" => true} => [2, 4],
|
96
|
+
{ "less than 5" => false, "divisible by 2" => false} => [5, 7, 9],
|
97
|
+
{ "less than 5" => false, "divisible by 2" => true} => [6, 8]
|
98
|
+
}
|
99
|
+
|
100
|
+
assert_equal expected, data
|
101
|
+
end
|
102
|
+
|
103
|
+
|
104
|
+
|
105
|
+
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.9.0
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-06-
|
12
|
+
date: 2012-06-20 00:00:00.000000000 Z
|
13
13
|
dependencies: []
|
14
14
|
description: ! ' Goldmine allows you to apply pivot table logic to any list for
|
15
15
|
powerful data mining capabilities.
|
@@ -26,6 +26,7 @@ files:
|
|
26
26
|
- Gemfile.lock
|
27
27
|
- Rakefile
|
28
28
|
- README.md
|
29
|
+
- test/test_goldmine.rb
|
29
30
|
homepage: http://hopsoft.github.com/goldmine/
|
30
31
|
licenses:
|
31
32
|
- MIT
|