ms_pivot 0.1.1
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/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.md +89 -0
- data/Rakefile +47 -0
- data/VERSION +1 -0
- data/lib/ms_pivot/measure.rb +64 -0
- data/lib/ms_pivot/row.rb +38 -0
- data/lib/ms_pivot/table.rb +121 -0
- data/lib/ms_pivot.rb +3 -0
- data/ms_pivot.gemspec +59 -0
- data/spec/measure_spec.rb +100 -0
- data/spec/pivot_spec.rb +104 -0
- data/spec/table_spec.rb +72 -0
- metadata +90 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2010 VisFleet Ltd.
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,89 @@
|
|
1
|
+
# Ms Pivot
|
2
|
+
by [vWorkApp](http://www.vworkapp.com)
|
3
|
+
|
4
|
+
A little gem to help you pivot your arrays.
|
5
|
+
|
6
|
+
my_array = [
|
7
|
+
["ProductA", "AU", 1],
|
8
|
+
["ProductA", "AU", 2],
|
9
|
+
["ProductB", "NZ", 3],
|
10
|
+
["ProductB", "US", 4],
|
11
|
+
]
|
12
|
+
|
13
|
+
pv = MsPivot::Table.new(my_array, 0, 1, MsPivot::SUM)
|
14
|
+
puts pv.inspect
|
15
|
+
|
16
|
+
# AU NZ US
|
17
|
+
# ProductA 3 - -
|
18
|
+
# ProductB - 3 4
|
19
|
+
|
20
|
+
## Install
|
21
|
+
|
22
|
+
sudo gem install ms_pivot
|
23
|
+
|
24
|
+
## Usage
|
25
|
+
|
26
|
+
- Specify which items (indicies) to use as row and column headers. All remaining items must have a measure specified.
|
27
|
+
|
28
|
+
my_array = [
|
29
|
+
["ProductA", "AU", 1, "x"],
|
30
|
+
["ProductA", "AU", 2, "t"],
|
31
|
+
["ProductB", "NZ", 3, "z"],
|
32
|
+
["ProductB", "US", 4, "a"],
|
33
|
+
]
|
34
|
+
pv = MsPivot::Table.new(my_array, 0, 1, MsPivot::SUM, MsPivot::COUNT)
|
35
|
+
|
36
|
+
Item 0 is used as the row headers, item 1 is used as the column headers, item 2 and 3 are aggregated (summed and counted respectively).
|
37
|
+
|
38
|
+
- Use of of the following built-in measures (i.e. methods to aggregate the grouped data)
|
39
|
+
|
40
|
+
- MSPivot::SUM
|
41
|
+
- MSPivot::COUNT
|
42
|
+
- MSPivot::AVG
|
43
|
+
- MSPivot::MIN
|
44
|
+
- MSPivot::MAX
|
45
|
+
- MSPivot::APPEND (builds an array)
|
46
|
+
|
47
|
+
- Or specify your own measure function
|
48
|
+
|
49
|
+
pv = MsPivot::Table.new(orig_array, 0, 1, MsPivot::Measure.new { |current_value, new_value|
|
50
|
+
# sum of squares
|
51
|
+
current_value ||= 0
|
52
|
+
current_value + (new_value ** 2)
|
53
|
+
end
|
54
|
+
|
55
|
+
- Let Ms Pivot work out automatically what the column headers are from the data (in which case it'll order them alphabetically) or tell it explicitly what columns you want
|
56
|
+
|
57
|
+
pv = MsPivot::Table.new(orig_array, 0, 1, MsPivot::SUM)
|
58
|
+
pv.column_headers = ["AU", "US", "UK"]
|
59
|
+
|
60
|
+
- Get the results out as an array
|
61
|
+
|
62
|
+
a = pv.column_headers
|
63
|
+
b = pv.to_a
|
64
|
+
|
65
|
+
# a = ["AU", "NZ", "US"]
|
66
|
+
# b = [
|
67
|
+
# ["ProductA", [3, 2], [], []],
|
68
|
+
# ["ProductB", [], [3, 1], [4, 1]]
|
69
|
+
# ]
|
70
|
+
|
71
|
+
- Or iterate over them
|
72
|
+
|
73
|
+
pv.each do |row_header, columns| do
|
74
|
+
columns.each do |col_header, values| do
|
75
|
+
values.each do |value|
|
76
|
+
// do stuff
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
See /spec/pivot_spec.rb for some examples of Ms Pivot being used.
|
82
|
+
|
83
|
+
## Todo
|
84
|
+
|
85
|
+
- Write RDOC
|
86
|
+
|
87
|
+
## Copyright
|
88
|
+
|
89
|
+
Copyright (c) 2010 VisFleet. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "ms_pivot"
|
8
|
+
gem.summary = %Q{A little gem to help you pivot your arrays}
|
9
|
+
gem.description = %Q{A little gem to help you pivot your arrays}
|
10
|
+
gem.email = "aisha.fenton@visfleet.com"
|
11
|
+
gem.homepage = "http://github.com/aishafenton/ms_pivot"
|
12
|
+
gem.authors = ["Aisha Fenton"]
|
13
|
+
gem.add_development_dependency "rspec", ">= 2.3"
|
14
|
+
end
|
15
|
+
Jeweler::GemcutterTasks.new
|
16
|
+
rescue LoadError
|
17
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
18
|
+
end
|
19
|
+
|
20
|
+
begin
|
21
|
+
require 'rcov/rcovtask'
|
22
|
+
Rcov::RcovTask.new do |test|
|
23
|
+
test.libs << 'test'
|
24
|
+
test.pattern = 'test/**/test_*.rb'
|
25
|
+
test.verbose = true
|
26
|
+
end
|
27
|
+
rescue LoadError
|
28
|
+
task :rcov do
|
29
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
begin
|
34
|
+
require 'rspec/core/rake_task'
|
35
|
+
RSpec::Core::RakeTask.new(:spec)
|
36
|
+
rescue LoadError
|
37
|
+
end
|
38
|
+
|
39
|
+
require 'rake/rdoctask'
|
40
|
+
Rake::RDocTask.new do |rdoc|
|
41
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
42
|
+
|
43
|
+
rdoc.rdoc_dir = 'rdoc'
|
44
|
+
rdoc.title = "ms_pivot #{version}"
|
45
|
+
rdoc.rdoc_files.include('README*')
|
46
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
47
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.1
|
@@ -0,0 +1,64 @@
|
|
1
|
+
module MsPivot
|
2
|
+
|
3
|
+
##
|
4
|
+
# The table to pivot
|
5
|
+
#
|
6
|
+
class Measure
|
7
|
+
|
8
|
+
def initialize(finalize_func = nil, &measure_func)
|
9
|
+
@measure_func = measure_func
|
10
|
+
@finalize_func = finalize_func
|
11
|
+
end
|
12
|
+
|
13
|
+
def measure(current_value, new_value)
|
14
|
+
@measure_func.call(current_value, new_value)
|
15
|
+
end
|
16
|
+
|
17
|
+
def finalize(value)
|
18
|
+
return value if @finalize_func.nil?
|
19
|
+
@finalize_func.call(value)
|
20
|
+
end
|
21
|
+
|
22
|
+
end
|
23
|
+
|
24
|
+
# Built-in measures
|
25
|
+
APPEND = Measure.new do |current_value, new_value|
|
26
|
+
current_value ||= []
|
27
|
+
current_value << new_value
|
28
|
+
end
|
29
|
+
|
30
|
+
SUM = Measure.new do |current_value, new_value|
|
31
|
+
current_value ||= 0
|
32
|
+
current_value + new_value
|
33
|
+
end
|
34
|
+
|
35
|
+
MIN = Measure.new do |current_value, new_value|
|
36
|
+
if current_value.nil?
|
37
|
+
new_value
|
38
|
+
else
|
39
|
+
new_value < current_value ? new_value : current_value
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
MAX = Measure.new do |current_value, new_value|
|
44
|
+
if current_value.nil?
|
45
|
+
new_value
|
46
|
+
else
|
47
|
+
new_value > current_value ? new_value : current_value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
COUNT = Measure.new do |current_value, new_value|
|
52
|
+
current_value ||= 0
|
53
|
+
current_value + 1
|
54
|
+
end
|
55
|
+
|
56
|
+
AVG = Measure.new(Proc.new { |value| value[1] / value[0].to_f }) do |current_value, new_value|
|
57
|
+
current_value ||= Struct.new(:count, :sum).new(0,0)
|
58
|
+
current_value.count += 1
|
59
|
+
current_value.sum += new_value
|
60
|
+
current_value
|
61
|
+
end
|
62
|
+
|
63
|
+
|
64
|
+
end
|
data/lib/ms_pivot/row.rb
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
module MsPivot
|
2
|
+
|
3
|
+
##
|
4
|
+
# The table to pivot
|
5
|
+
#
|
6
|
+
class Row
|
7
|
+
|
8
|
+
attr_accessor :column_headers
|
9
|
+
|
10
|
+
def initialize
|
11
|
+
@values = Hash.new { |h,k| h[k] = [] }
|
12
|
+
end
|
13
|
+
|
14
|
+
def each
|
15
|
+
@column_headers.each do |col_header|
|
16
|
+
yield col_header, @values[col_header]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def []=(col_header, *values)
|
21
|
+
@values[col_header] = values
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](col_header)
|
25
|
+
@values[col_header]
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_a
|
29
|
+
result = []
|
30
|
+
self.each do |col_header, values|
|
31
|
+
result << values
|
32
|
+
end
|
33
|
+
result
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
|
38
|
+
end
|
@@ -0,0 +1,121 @@
|
|
1
|
+
module MsPivot
|
2
|
+
|
3
|
+
##
|
4
|
+
# The table to pivot
|
5
|
+
#
|
6
|
+
class Table
|
7
|
+
|
8
|
+
attr_accessor :column_headers
|
9
|
+
|
10
|
+
def initialize(orig_array, row_index, col_index, *measures)
|
11
|
+
@data = {}
|
12
|
+
@column_headers = nil
|
13
|
+
@row_index = row_index
|
14
|
+
@col_index = col_index
|
15
|
+
@measures = measures
|
16
|
+
@orig_array = orig_array
|
17
|
+
@orig_array
|
18
|
+
|
19
|
+
compile(@orig_array)
|
20
|
+
end
|
21
|
+
|
22
|
+
def column_headers=(column_headers)
|
23
|
+
@column_headers = column_headers
|
24
|
+
compile(@orig_array)
|
25
|
+
end
|
26
|
+
|
27
|
+
def each
|
28
|
+
@data.each do |row_header, columns|
|
29
|
+
yield row_header, columns
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
def row_headers
|
34
|
+
@data.keys
|
35
|
+
end
|
36
|
+
|
37
|
+
def to_a
|
38
|
+
result = []
|
39
|
+
self.each do |row_header, columns|
|
40
|
+
result << Array(row_header) + columns.to_a
|
41
|
+
end
|
42
|
+
result
|
43
|
+
end
|
44
|
+
|
45
|
+
def inspect
|
46
|
+
result = "\t"
|
47
|
+
self.column_headers.each do |header|
|
48
|
+
result << "\t#{header}"
|
49
|
+
end
|
50
|
+
result << "\n"
|
51
|
+
|
52
|
+
self.each do |row_header, columns|
|
53
|
+
result << row_header.to_s
|
54
|
+
columns.each do |col_header, values|
|
55
|
+
result << "\t" + (values.empty? ? "-" : "#{values.join(",")}")
|
56
|
+
end
|
57
|
+
result << "\n"
|
58
|
+
end
|
59
|
+
result
|
60
|
+
end
|
61
|
+
|
62
|
+
private
|
63
|
+
|
64
|
+
def clear
|
65
|
+
@data = {}
|
66
|
+
end
|
67
|
+
|
68
|
+
def compile(orig_array)
|
69
|
+
clear
|
70
|
+
|
71
|
+
column_headers = {}
|
72
|
+
|
73
|
+
# group rows
|
74
|
+
orig_array.each do |row|
|
75
|
+
row_header = row[@row_index]
|
76
|
+
col_header = row[@col_index]
|
77
|
+
|
78
|
+
row = strip_headers(row, @row_index, @col_index)
|
79
|
+
@data[row_header] ||= Row.new
|
80
|
+
|
81
|
+
# group cols, and run measures on remaining rows
|
82
|
+
data_row_idx = 0
|
83
|
+
row.size.times do |i|
|
84
|
+
|
85
|
+
if row.size != @measures.size
|
86
|
+
raise "You need to have a measure for each row (excluding the row and column headers). \
|
87
|
+
You have #{@measures.size} measures, and #{row.size} rows (excluding headers)"
|
88
|
+
end
|
89
|
+
|
90
|
+
@data[row_header][col_header][i] = @measures[i].measure(@data[row_header][col_header][i], row[i])
|
91
|
+
end
|
92
|
+
|
93
|
+
column_headers[col_header] = true
|
94
|
+
end
|
95
|
+
|
96
|
+
# set column_headers, now that we know what they are
|
97
|
+
@column_headers ||= column_headers.keys.sort
|
98
|
+
@data.each_value { |row| row.column_headers = @column_headers }
|
99
|
+
|
100
|
+
# Invoke finalize methods on measures
|
101
|
+
self.each do |header, columns|
|
102
|
+
columns.each do |header, values|
|
103
|
+
values.each_with_index do |value, i|
|
104
|
+
values[i] = @measures[i].finalize(value)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
end
|
110
|
+
|
111
|
+
def strip_headers(row, *indexes)
|
112
|
+
result = []
|
113
|
+
row.each_with_index do |cell, i|
|
114
|
+
result << cell unless indexes.include?(i)
|
115
|
+
end
|
116
|
+
result
|
117
|
+
end
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
end
|
data/lib/ms_pivot.rb
ADDED
data/ms_pivot.gemspec
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{ms_pivot}
|
8
|
+
s.version = "0.1.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Aisha Fenton"]
|
12
|
+
s.date = %q{2010-12-16}
|
13
|
+
s.description = %q{A little gem to help you pivot your arrays}
|
14
|
+
s.email = %q{aisha.fenton@visfleet.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.md"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.md",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"lib/ms_pivot.rb",
|
27
|
+
"lib/ms_pivot/measure.rb",
|
28
|
+
"lib/ms_pivot/row.rb",
|
29
|
+
"lib/ms_pivot/table.rb",
|
30
|
+
"ms_pivot.gemspec",
|
31
|
+
"spec/measure_spec.rb",
|
32
|
+
"spec/pivot_spec.rb",
|
33
|
+
"spec/table_spec.rb"
|
34
|
+
]
|
35
|
+
s.homepage = %q{http://github.com/aishafenton/ms_pivot}
|
36
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
37
|
+
s.require_paths = ["lib"]
|
38
|
+
s.rubygems_version = %q{1.3.6}
|
39
|
+
s.summary = %q{A little gem to help you pivot your arrays}
|
40
|
+
s.test_files = [
|
41
|
+
"spec/measure_spec.rb",
|
42
|
+
"spec/pivot_spec.rb",
|
43
|
+
"spec/table_spec.rb"
|
44
|
+
]
|
45
|
+
|
46
|
+
if s.respond_to? :specification_version then
|
47
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
48
|
+
s.specification_version = 3
|
49
|
+
|
50
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
51
|
+
s.add_development_dependency(%q<rspec>, [">= 2.3"])
|
52
|
+
else
|
53
|
+
s.add_dependency(%q<rspec>, [">= 2.3"])
|
54
|
+
end
|
55
|
+
else
|
56
|
+
s.add_dependency(%q<rspec>, [">= 2.3"])
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'lib/ms_pivot'
|
2
|
+
|
3
|
+
describe MsPivot::Measure do
|
4
|
+
|
5
|
+
it "supports a SUM measure" do
|
6
|
+
orig_array = [
|
7
|
+
["ProductA", "NZ", 1],
|
8
|
+
["ProductA", "NZ", 2],
|
9
|
+
["ProductB", "NZ", 3],
|
10
|
+
]
|
11
|
+
|
12
|
+
pv = MsPivot::Table.new(orig_array, 0, 1, MsPivot::SUM)
|
13
|
+
|
14
|
+
pv.to_a.should == [
|
15
|
+
["ProductA", [3]],
|
16
|
+
["ProductB", [3]]
|
17
|
+
]
|
18
|
+
end
|
19
|
+
|
20
|
+
it "supports a MIN measure" do
|
21
|
+
orig_array = [
|
22
|
+
["ProductA", "NZ", -100],
|
23
|
+
["ProductA", "NZ", 0],
|
24
|
+
["ProductB", "NZ", 1],
|
25
|
+
["ProductB", "NZ", 3],
|
26
|
+
]
|
27
|
+
|
28
|
+
pv = MsPivot::Table.new(orig_array, 0, 1, MsPivot::MIN)
|
29
|
+
|
30
|
+
pv.to_a.should == [
|
31
|
+
["ProductA", [-100]],
|
32
|
+
["ProductB", [1]]
|
33
|
+
]
|
34
|
+
end
|
35
|
+
|
36
|
+
it "supports a MAX measure" do
|
37
|
+
orig_array = [
|
38
|
+
["ProductA", "NZ", -2],
|
39
|
+
["ProductA", "NZ", 2],
|
40
|
+
["ProductB", "NZ", 1],
|
41
|
+
["ProductB", "NZ", 3],
|
42
|
+
]
|
43
|
+
|
44
|
+
pv = MsPivot::Table.new(orig_array, 0, 1, MsPivot::MAX)
|
45
|
+
|
46
|
+
pv.to_a.should == [
|
47
|
+
["ProductA", [2]],
|
48
|
+
["ProductB", [3]]
|
49
|
+
]
|
50
|
+
end
|
51
|
+
|
52
|
+
it "supports a COUNT measure" do
|
53
|
+
|
54
|
+
orig_array = [
|
55
|
+
["ProductA", "NZ", "z"],
|
56
|
+
["ProductA", "NZ", "z"],
|
57
|
+
["ProductA", "US", "z"],
|
58
|
+
["ProductB", "NZ", "z"],
|
59
|
+
["ProductB", "US", "z"],
|
60
|
+
]
|
61
|
+
|
62
|
+
pv = MsPivot::Table.new(orig_array, 0, 1, MsPivot::COUNT)
|
63
|
+
|
64
|
+
pv.to_a.should == [
|
65
|
+
["ProductA", [2], [1]],
|
66
|
+
["ProductB", [1], [1]]
|
67
|
+
]
|
68
|
+
end
|
69
|
+
|
70
|
+
it "supports a AVG measure" do
|
71
|
+
orig_array = [
|
72
|
+
["ProductA", "NZ", 2],
|
73
|
+
["ProductA", "NZ", 3],
|
74
|
+
["ProductA", "US", 3],
|
75
|
+
["ProductB", "US", 1],
|
76
|
+
["ProductB", "US", 1],
|
77
|
+
]
|
78
|
+
|
79
|
+
pv = MsPivot::Table.new(orig_array, 0, 1, MsPivot::AVG)
|
80
|
+
|
81
|
+
pv.to_a.should == [
|
82
|
+
["ProductA", [2.5], [3]],
|
83
|
+
["ProductB", [], [1]]
|
84
|
+
]
|
85
|
+
end
|
86
|
+
|
87
|
+
it "supports an APPEND measure" do
|
88
|
+
orig_array = [
|
89
|
+
["ProductA", "NZ", "x"],
|
90
|
+
["ProductA", "NZ", "y"],
|
91
|
+
]
|
92
|
+
|
93
|
+
pv = MsPivot::Table.new(orig_array, 0, 1, MsPivot::APPEND)
|
94
|
+
|
95
|
+
pv.to_a.should == [
|
96
|
+
["ProductA", [["x", "y"]]],
|
97
|
+
]
|
98
|
+
end
|
99
|
+
|
100
|
+
end
|
data/spec/pivot_spec.rb
ADDED
@@ -0,0 +1,104 @@
|
|
1
|
+
require 'lib/ms_pivot'
|
2
|
+
|
3
|
+
describe "Pivot Features!" do
|
4
|
+
|
5
|
+
it "lets you pivot an array" do
|
6
|
+
|
7
|
+
orig_array = [
|
8
|
+
["ProductA", "AU", 1],
|
9
|
+
["ProductA", "NZ", 2],
|
10
|
+
["ProductA", "US", 3],
|
11
|
+
["ProductB", "AU", 4],
|
12
|
+
["ProductB", "NZ", 5],
|
13
|
+
["ProductB", "US", 6],
|
14
|
+
]
|
15
|
+
|
16
|
+
pv = MsPivot::Table.new(orig_array, 0, 1, MsPivot::SUM)
|
17
|
+
|
18
|
+
pv.column_headers.should == [
|
19
|
+
"AU", "NZ", "US"
|
20
|
+
]
|
21
|
+
|
22
|
+
pv.to_a.should == [
|
23
|
+
["ProductA", [1], [2], [3]],
|
24
|
+
["ProductB", [4], [5], [6]]
|
25
|
+
]
|
26
|
+
end
|
27
|
+
|
28
|
+
it "works with multiple 'measures'" do
|
29
|
+
|
30
|
+
orig_array = [
|
31
|
+
["ProductA", "NZ", 1, "a", "x"],
|
32
|
+
["ProductA", "US", 2, "b", "y"],
|
33
|
+
["ProductA", "US", 3, "b", "z"],
|
34
|
+
["ProductB", "NZ", 4, "a", "x"],
|
35
|
+
["ProductB", "NZ", 5, "b", "y"],
|
36
|
+
["ProductB", "US", 6, "b", "z"],
|
37
|
+
]
|
38
|
+
|
39
|
+
pv = MsPivot::Table.new(orig_array, 0, 1, MsPivot::SUM, MsPivot::COUNT, MsPivot::APPEND)
|
40
|
+
|
41
|
+
pv.to_a.should == [
|
42
|
+
["ProductA", [1, 1, ["x"]], [5, 2, ["y", "z"]]],
|
43
|
+
["ProductB", [9, 2, ["x", "y"]], [6, 1, ["z"]]]
|
44
|
+
]
|
45
|
+
end
|
46
|
+
|
47
|
+
it "works when not all rows have all columns" do
|
48
|
+
orig_array = [
|
49
|
+
["ProductA", "NZ", 1],
|
50
|
+
["ProductA", "NZ", 1],
|
51
|
+
["ProductB", "US", 4],
|
52
|
+
]
|
53
|
+
|
54
|
+
pv = MsPivot::Table.new(orig_array, 0, 1, MsPivot::SUM)
|
55
|
+
|
56
|
+
pv.to_a.should == [
|
57
|
+
["ProductA", [2], []],
|
58
|
+
["ProductB", [], [4]]
|
59
|
+
]
|
60
|
+
|
61
|
+
end
|
62
|
+
|
63
|
+
it "lets you specify your own measures" do
|
64
|
+
orig_array = [
|
65
|
+
["ProductA", "NZ", 1, "a"],
|
66
|
+
["ProductA", "NZ", 2, "b"],
|
67
|
+
["ProductB", "NZ", 3, "c"],
|
68
|
+
["ProductB", "US", 4, "d"],
|
69
|
+
]
|
70
|
+
|
71
|
+
pv = MsPivot::Table.new(orig_array, 0, 1, MsPivot::Measure.new { |current_value, new_value|
|
72
|
+
# sum of squares
|
73
|
+
current_value ||= 0
|
74
|
+
current_value + (new_value ** 2)
|
75
|
+
}, MsPivot::Measure.new { |current_value, new_value|
|
76
|
+
# concat string
|
77
|
+
current_value ||= ""
|
78
|
+
current_value + new_value
|
79
|
+
})
|
80
|
+
|
81
|
+
pv.to_a.should == [
|
82
|
+
["ProductA", [5, "ab"], []],
|
83
|
+
["ProductB", [9, "c"], [16, "d"]]
|
84
|
+
]
|
85
|
+
end
|
86
|
+
|
87
|
+
it "lets you specify the column headers (and their order)" do
|
88
|
+
orig_array = [
|
89
|
+
["ProductA", "NZ", 1],
|
90
|
+
["ProductA", "UK", 2],
|
91
|
+
["ProductB", "US", 3],
|
92
|
+
["ProductB", "AU", 4],
|
93
|
+
]
|
94
|
+
|
95
|
+
pv = MsPivot::Table.new(orig_array, 0, 1, MsPivot::SUM)
|
96
|
+
pv.column_headers = ["AU", "US", "UK"]
|
97
|
+
|
98
|
+
pv.to_a.should == [
|
99
|
+
["ProductA", [], [], [2]],
|
100
|
+
["ProductB", [4], [3], []]
|
101
|
+
]
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
data/spec/table_spec.rb
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'lib/ms_pivot'
|
2
|
+
|
3
|
+
describe MsPivot::Table, "with a single measure" do
|
4
|
+
|
5
|
+
subject do
|
6
|
+
orig_array = [
|
7
|
+
["ProductA", "NZ", 1],
|
8
|
+
["ProductA", "US", 2],
|
9
|
+
["ProductB", "NZ", 3],
|
10
|
+
]
|
11
|
+
MsPivot::Table.new(orig_array, 0, 1, MsPivot::SUM)
|
12
|
+
end
|
13
|
+
|
14
|
+
its(:row_headers) { should == ["ProductA", "ProductB"] }
|
15
|
+
|
16
|
+
context "when calling each_row" do
|
17
|
+
|
18
|
+
it "returns the row headers" do
|
19
|
+
headers = []
|
20
|
+
subject.each { |header, columns| headers << header }
|
21
|
+
headers.should == ["ProductA", "ProductB"]
|
22
|
+
end
|
23
|
+
|
24
|
+
it "returns the row values" do
|
25
|
+
columns = []
|
26
|
+
subject.each { |header, cols| columns << cols }
|
27
|
+
columns[0].to_a.should == [[1], [2]]
|
28
|
+
columns[1].to_a.should == [[3], []]
|
29
|
+
end
|
30
|
+
|
31
|
+
end
|
32
|
+
|
33
|
+
its(:to_a) { should == [ ["ProductA", [1], [2]], ["ProductB", [3], []] ] }
|
34
|
+
|
35
|
+
it "remeasures when the column headers are explicitly set" do
|
36
|
+
subject.column_headers = ["US", "NZ", "AU"]
|
37
|
+
|
38
|
+
subject.column_headers.should == ["US", "NZ", "AU"]
|
39
|
+
subject.to_a.should == [ ["ProductA", [2], [1], []], ["ProductB", [], [3], []] ]
|
40
|
+
end
|
41
|
+
|
42
|
+
it "works when rows are missing column headers" do
|
43
|
+
subject.column_headers = ["US", "XX", "YY"]
|
44
|
+
subject.to_a.should == [ ["ProductA", [2], [], []], ["ProductB", [], [], []] ]
|
45
|
+
end
|
46
|
+
|
47
|
+
its(:inspect) do
|
48
|
+
should == <<-EOL
|
49
|
+
\t\tNZ\tUS
|
50
|
+
ProductA\t1\t2
|
51
|
+
ProductB\t3\t-
|
52
|
+
EOL
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|
56
|
+
|
57
|
+
describe MsPivot::Table, "with mulitple measures" do
|
58
|
+
|
59
|
+
subject do
|
60
|
+
orig_array = [
|
61
|
+
["ProductA", "NZ", 1, "x", 2],
|
62
|
+
["ProductA", "US", 2, "y", 3],
|
63
|
+
["ProductB", "NZ", 3, "z", 4],
|
64
|
+
]
|
65
|
+
MsPivot::Table.new(orig_array, 0, 1, MsPivot::SUM, MsPivot::COUNT, MsPivot::MIN)
|
66
|
+
end
|
67
|
+
|
68
|
+
it "throws a exception when there aren't enough measures specified" do
|
69
|
+
expect{ MsPivot::Table.new(orig_array, 0, 1, MsPivot::SUM) }.to raise_error
|
70
|
+
end
|
71
|
+
|
72
|
+
end
|
metadata
ADDED
@@ -0,0 +1,90 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ms_pivot
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 1
|
9
|
+
version: 0.1.1
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Aisha Fenton
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2010-12-16 00:00:00 +13:00
|
18
|
+
default_executable:
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rspec
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
segments:
|
28
|
+
- 2
|
29
|
+
- 3
|
30
|
+
version: "2.3"
|
31
|
+
type: :development
|
32
|
+
version_requirements: *id001
|
33
|
+
description: A little gem to help you pivot your arrays
|
34
|
+
email: aisha.fenton@visfleet.com
|
35
|
+
executables: []
|
36
|
+
|
37
|
+
extensions: []
|
38
|
+
|
39
|
+
extra_rdoc_files:
|
40
|
+
- LICENSE
|
41
|
+
- README.md
|
42
|
+
files:
|
43
|
+
- .document
|
44
|
+
- .gitignore
|
45
|
+
- LICENSE
|
46
|
+
- README.md
|
47
|
+
- Rakefile
|
48
|
+
- VERSION
|
49
|
+
- lib/ms_pivot.rb
|
50
|
+
- lib/ms_pivot/measure.rb
|
51
|
+
- lib/ms_pivot/row.rb
|
52
|
+
- lib/ms_pivot/table.rb
|
53
|
+
- ms_pivot.gemspec
|
54
|
+
- spec/measure_spec.rb
|
55
|
+
- spec/pivot_spec.rb
|
56
|
+
- spec/table_spec.rb
|
57
|
+
has_rdoc: true
|
58
|
+
homepage: http://github.com/aishafenton/ms_pivot
|
59
|
+
licenses: []
|
60
|
+
|
61
|
+
post_install_message:
|
62
|
+
rdoc_options:
|
63
|
+
- --charset=UTF-8
|
64
|
+
require_paths:
|
65
|
+
- lib
|
66
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
segments:
|
71
|
+
- 0
|
72
|
+
version: "0"
|
73
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
74
|
+
requirements:
|
75
|
+
- - ">="
|
76
|
+
- !ruby/object:Gem::Version
|
77
|
+
segments:
|
78
|
+
- 0
|
79
|
+
version: "0"
|
80
|
+
requirements: []
|
81
|
+
|
82
|
+
rubyforge_project:
|
83
|
+
rubygems_version: 1.3.6
|
84
|
+
signing_key:
|
85
|
+
specification_version: 3
|
86
|
+
summary: A little gem to help you pivot your arrays
|
87
|
+
test_files:
|
88
|
+
- spec/measure_spec.rb
|
89
|
+
- spec/pivot_spec.rb
|
90
|
+
- spec/table_spec.rb
|