goldmine 2.1.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Gemfile +0 -1
- data/Gemfile.lock +14 -29
- data/README.md +134 -136
- data/lib/goldmine.rb +7 -13
- data/lib/goldmine/miner.rb +20 -0
- data/lib/goldmine/pivot.rb +52 -0
- data/lib/goldmine/pivot_result.rb +21 -0
- data/lib/goldmine/rollup.rb +41 -0
- data/lib/goldmine/rollup_clean_room.rb +21 -0
- data/lib/goldmine/rollup_result.rb +45 -0
- data/lib/goldmine/version.rb +1 -1
- data/test/test_goldmine.rb +149 -277
- metadata +11 -13
- data/goldmine.gemspec +0 -20
- data/lib/goldmine/array_miner.rb +0 -67
- data/lib/goldmine/cache.rb +0 -28
- data/lib/goldmine/hash_miner.rb +0 -81
- data/lib/goldmine/hash_rollup.rb +0 -83
- data/lib/goldmine/rollup_context.rb +0 -23
- data/license.md +0 -8
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: goldmine
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 3.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Nathan Hopkins
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2016-04-23 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -66,7 +66,7 @@ dependencies:
|
|
66
66
|
- - ">="
|
67
67
|
- !ruby/object:Gem::Version
|
68
68
|
version: '0'
|
69
|
-
description:
|
69
|
+
description:
|
70
70
|
email:
|
71
71
|
- natehop@gmail.com
|
72
72
|
executables: []
|
@@ -77,15 +77,14 @@ files:
|
|
77
77
|
- Gemfile.lock
|
78
78
|
- README.md
|
79
79
|
- Rakefile
|
80
|
-
- goldmine.gemspec
|
81
80
|
- lib/goldmine.rb
|
82
|
-
- lib/goldmine/
|
83
|
-
- lib/goldmine/
|
84
|
-
- lib/goldmine/
|
85
|
-
- lib/goldmine/
|
86
|
-
- lib/goldmine/
|
81
|
+
- lib/goldmine/miner.rb
|
82
|
+
- lib/goldmine/pivot.rb
|
83
|
+
- lib/goldmine/pivot_result.rb
|
84
|
+
- lib/goldmine/rollup.rb
|
85
|
+
- lib/goldmine/rollup_clean_room.rb
|
86
|
+
- lib/goldmine/rollup_result.rb
|
87
87
|
- lib/goldmine/version.rb
|
88
|
-
- license.md
|
89
88
|
- test/test_goldmine.rb
|
90
89
|
homepage: https://github.com/hopsoft/goldmine
|
91
90
|
licenses:
|
@@ -107,10 +106,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
107
106
|
version: '0'
|
108
107
|
requirements: []
|
109
108
|
rubyforge_project:
|
110
|
-
rubygems_version: 2.
|
109
|
+
rubygems_version: 2.5.1
|
111
110
|
signing_key:
|
112
111
|
specification_version: 4
|
113
|
-
summary: Extract a wealth of information from Arrays
|
112
|
+
summary: Extract a wealth of information from Arrays
|
114
113
|
test_files:
|
115
114
|
- test/test_goldmine.rb
|
116
|
-
has_rdoc:
|
data/goldmine.gemspec
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
require File.expand_path("../lib/goldmine/version", __FILE__)
|
2
|
-
|
3
|
-
Gem::Specification.new do |gem|
|
4
|
-
gem.name = "goldmine"
|
5
|
-
gem.license = "MIT"
|
6
|
-
gem.version = Goldmine::VERSION
|
7
|
-
gem.authors = ["Nathan Hopkins"]
|
8
|
-
gem.email = ["natehop@gmail.com"]
|
9
|
-
gem.homepage = "https://github.com/hopsoft/goldmine"
|
10
|
-
gem.summary = "Extract a wealth of information from Arrays and Hashes"
|
11
|
-
gem.description = "Extract a wealth of information from Arrays and Hashes"
|
12
|
-
|
13
|
-
gem.files = Dir["lib/**/*.rb", "bin/*", "[A-Z]*"]
|
14
|
-
gem.test_files = Dir["test/**/*.rb"]
|
15
|
-
|
16
|
-
gem.add_development_dependency "rake"
|
17
|
-
gem.add_development_dependency "pry-test"
|
18
|
-
gem.add_development_dependency "coveralls"
|
19
|
-
gem.add_development_dependency "sinatra"
|
20
|
-
end
|
data/lib/goldmine/array_miner.rb
DELETED
@@ -1,67 +0,0 @@
|
|
1
|
-
require "delegate"
|
2
|
-
|
3
|
-
module Goldmine
|
4
|
-
class ArrayMiner < SimpleDelegator
|
5
|
-
def initialize(array=[])
|
6
|
-
super array.to_a
|
7
|
-
end
|
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.
|
47
|
-
def pivot(name=nil, &block)
|
48
|
-
reduce(HashMiner.new) do |memo, item|
|
49
|
-
value = yield(item)
|
50
|
-
|
51
|
-
if value.is_a?(Array)
|
52
|
-
if value.empty?
|
53
|
-
memo.assign_mined(name, nil, item)
|
54
|
-
else
|
55
|
-
value.each { |v| memo.assign_mined(name, v, item) }
|
56
|
-
end
|
57
|
-
else
|
58
|
-
memo.assign_mined(name, value, item)
|
59
|
-
end
|
60
|
-
|
61
|
-
memo.goldmine = true
|
62
|
-
memo
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
end
|
67
|
-
end
|
data/lib/goldmine/cache.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
module Goldmine
|
2
|
-
class Cache
|
3
|
-
|
4
|
-
def initialize
|
5
|
-
@hash = {}
|
6
|
-
end
|
7
|
-
|
8
|
-
def [](*keys)
|
9
|
-
@hash[make_key(*keys)]
|
10
|
-
end
|
11
|
-
|
12
|
-
def []=(*keys, value)
|
13
|
-
@hash[make_key(*keys)] = value
|
14
|
-
end
|
15
|
-
|
16
|
-
def fetch(*keys)
|
17
|
-
@hash[make_key(*keys)] ||= yield
|
18
|
-
end
|
19
|
-
|
20
|
-
private
|
21
|
-
|
22
|
-
def make_key(*keys)
|
23
|
-
keys.map do |key|
|
24
|
-
key.is_a?(String) ? key.to_sym : key.object_id
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
28
|
-
end
|
data/lib/goldmine/hash_miner.rb
DELETED
@@ -1,81 +0,0 @@
|
|
1
|
-
require "delegate"
|
2
|
-
|
3
|
-
module Goldmine
|
4
|
-
class HashMiner < SimpleDelegator
|
5
|
-
def initialize(hash={})
|
6
|
-
@rollup_cache = Cache.new
|
7
|
-
super @hash = hash.to_h
|
8
|
-
end
|
9
|
-
|
10
|
-
attr_accessor :goldmine
|
11
|
-
|
12
|
-
# Further pivots the Hash into mined data.
|
13
|
-
# This method is what enables the pivot method chaining.
|
14
|
-
#
|
15
|
-
# @example Chained pivot
|
16
|
-
# list = [1,2,3,4,5,6,7,8,9]
|
17
|
-
# data = list.pivot { |i| i < 5 }.pivot { |i| i % 2 == 0 }
|
18
|
-
#
|
19
|
-
# # resulting data
|
20
|
-
# {
|
21
|
-
# [true, false] => [1, 3],
|
22
|
-
# [true, true] => [2, 4],
|
23
|
-
# [false, false] => [5, 7, 9],
|
24
|
-
# [false, true] => [6, 8]
|
25
|
-
# }
|
26
|
-
#
|
27
|
-
# @note This method should not be called directly. Call Array#pivot instead.
|
28
|
-
#
|
29
|
-
# @param name [String] The named of the pivot.
|
30
|
-
# @yield [Object] Yields once for each item in the Array.
|
31
|
-
# @return [Hash] The pivoted Hash of data.
|
32
|
-
def pivot(name=nil, &block)
|
33
|
-
return self unless goldmine
|
34
|
-
|
35
|
-
reduce(HashMiner.new) do |memo, item|
|
36
|
-
key = item.first
|
37
|
-
value = Goldmine.miner(item.last)
|
38
|
-
value.pivot(name, &block).each do |k, v|
|
39
|
-
if key.is_a? Hash
|
40
|
-
k = { block.to_s => k } unless k.is_a?(Hash)
|
41
|
-
new_key = key.merge(k)
|
42
|
-
else
|
43
|
-
new_key = [key, k].flatten
|
44
|
-
end
|
45
|
-
memo[new_key] = v
|
46
|
-
end
|
47
|
-
memo.goldmine = true
|
48
|
-
memo
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Returns a HashRollup with summarized data.
|
53
|
-
#
|
54
|
-
# @yield [Object] Yields once for each pivoted grouping of values.
|
55
|
-
# @return [Hash] The rollup Hash of data.
|
56
|
-
def rollup(name, &block)
|
57
|
-
HashRollup.new(@hash, @rollup_cache).rollup(name, &block)
|
58
|
-
end
|
59
|
-
|
60
|
-
# Assigns a key/value pair to the Hash.
|
61
|
-
# @param name [String] The name of a pivot (can be null).
|
62
|
-
# @param key [Object] The key to use.
|
63
|
-
# @param value [Object] The value to assign
|
64
|
-
# @return [Object] The result of the assignment.
|
65
|
-
def assign_mined(name, key, value)
|
66
|
-
goldmine_key = goldmine_key(name, key)
|
67
|
-
self[goldmine_key] ||= []
|
68
|
-
self[goldmine_key] << value
|
69
|
-
end
|
70
|
-
|
71
|
-
# Creates a key for a pivot-name/key combo.
|
72
|
-
# @param name [String] The name of a pivot (can be null).
|
73
|
-
# @param key [Object] The key to use.
|
74
|
-
# @return [Object] The constructed key.
|
75
|
-
def goldmine_key(name, key)
|
76
|
-
goldmine_key = { name => key } if name
|
77
|
-
goldmine_key ||= key
|
78
|
-
end
|
79
|
-
|
80
|
-
end
|
81
|
-
end
|
data/lib/goldmine/hash_rollup.rb
DELETED
@@ -1,83 +0,0 @@
|
|
1
|
-
require "delegate"
|
2
|
-
require "csv"
|
3
|
-
|
4
|
-
module Goldmine
|
5
|
-
class HashRollup < SimpleDelegator
|
6
|
-
attr_reader :names
|
7
|
-
|
8
|
-
def initialize(pivoted, cache=Cache.new)
|
9
|
-
@names = []
|
10
|
-
@cache = cache
|
11
|
-
@context = RollupContext.new(@cache)
|
12
|
-
@pivoted = pivoted
|
13
|
-
super @rolled = {}
|
14
|
-
end
|
15
|
-
|
16
|
-
def rollup(name, &block)
|
17
|
-
names << name
|
18
|
-
pivoted.each do |key, value|
|
19
|
-
@cache.fetch(name, value) do
|
20
|
-
rolled[key] ||= {}
|
21
|
-
rolled[key][name] = @context.instance_exec(value, &block)
|
22
|
-
end
|
23
|
-
end
|
24
|
-
self
|
25
|
-
end
|
26
|
-
|
27
|
-
def to_tabular
|
28
|
-
[].tap do |rows|
|
29
|
-
rows << tabular_header
|
30
|
-
rows.concat tabular_rows
|
31
|
-
end
|
32
|
-
end
|
33
|
-
|
34
|
-
def to_csv_table
|
35
|
-
rows = to_rows.map { |row| CSV::Row.new(row.keys, row.values) }
|
36
|
-
CSV::Table.new rows
|
37
|
-
end
|
38
|
-
|
39
|
-
def to_rows
|
40
|
-
header = tabular_header
|
41
|
-
tabular_rows.map do |tabular_row|
|
42
|
-
{}.tap do |row|
|
43
|
-
header.each_with_index do |header_name, index|
|
44
|
-
row[header_name] = tabular_row[index]
|
45
|
-
end
|
46
|
-
end
|
47
|
-
end
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
attr_reader :pivoted, :rolled
|
53
|
-
|
54
|
-
def tabular_header
|
55
|
-
return [] if empty?
|
56
|
-
to_tabular_header keys.first, values.first
|
57
|
-
end
|
58
|
-
|
59
|
-
def tabular_rows
|
60
|
-
map do |pair|
|
61
|
-
to_tabular_row pair.first, pair.last
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
def to_tabular_row(key, value)
|
66
|
-
row = key.values.dup if key.is_a?(Hash)
|
67
|
-
row ||= as_array(key).dup
|
68
|
-
row.concat value.values
|
69
|
-
end
|
70
|
-
|
71
|
-
def to_tabular_header(key, value)
|
72
|
-
header = key.keys.map(&:to_s) if key.is_a?(Hash)
|
73
|
-
header ||= (1..as_array(key).size).map { |i| "column#{i}" }
|
74
|
-
header.concat value.keys.map(&:to_s)
|
75
|
-
end
|
76
|
-
|
77
|
-
def as_array(value)
|
78
|
-
return value if value.is_a?(Array)
|
79
|
-
[value]
|
80
|
-
end
|
81
|
-
|
82
|
-
end
|
83
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module Goldmine
|
2
|
-
class RollupContext
|
3
|
-
def initialize(cache)
|
4
|
-
@cache = cache
|
5
|
-
@computations = {}
|
6
|
-
end
|
7
|
-
|
8
|
-
def computed(name)
|
9
|
-
@computations[name.to_sym] ||= Computation.new(name, @cache)
|
10
|
-
end
|
11
|
-
|
12
|
-
class Computation
|
13
|
-
def initialize(name, cache)
|
14
|
-
@name = name
|
15
|
-
@cache = cache
|
16
|
-
end
|
17
|
-
|
18
|
-
def for(list)
|
19
|
-
@cache[@name, list]
|
20
|
-
end
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
data/license.md
DELETED
@@ -1,8 +0,0 @@
|
|
1
|
-
# The MIT License (MIT)
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
|
4
|
-
|
5
|
-
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
|
6
|
-
|
7
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
8
|
-
|