table_creator 0.1.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.
- checksums.yaml +7 -0
- data/.gitignore +4 -0
- data/.travis.yml +9 -0
- data/CHANGELOG.md +9 -0
- data/Gemfile +2 -0
- data/LICENSE +21 -0
- data/README.md +10 -0
- data/Rakefile +12 -0
- data/lib/table_creator.rb +22 -0
- data/lib/table_creator/col.rb +92 -0
- data/lib/table_creator/col_group.rb +15 -0
- data/lib/table_creator/result_group.rb +167 -0
- data/lib/table_creator/row.rb +25 -0
- data/lib/table_creator/row_group.rb +39 -0
- data/lib/table_creator/table.rb +32 -0
- data/lib/table_creator/version.rb +3 -0
- data/spec/data_table_spec.rb +66 -0
- data/spec/result_group_spec.rb +86 -0
- data/spec/spec_helper.rb +19 -0
- data/spec/support/coverage_loader.rb +4 -0
- data/table_creator.gemspec +33 -0
- metadata +193 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 332bd4ea2ac0af888861df66f9c77a1dcdbccd96
|
4
|
+
data.tar.gz: e08ba3193eabfb901dc6c9d7fd0e0a7114797a27
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 26fda13a7187b87ce7b587a287dabbd212310cf5bba29d12a837f141435ce685a55c59bc781ee4236a53751f6683a664e37f48b12488aea145e4bf25b50c5b05
|
7
|
+
data.tar.gz: '01078e18ef529bfd2364d90adf1833b4e640889425cf94b3062d0b6a628815c85bc9f02b5e2cfc5d2840b83bd8556bf9313d83fdab9b9acae249d532ebb4332e'
|
data/.gitignore
ADDED
data/.travis.yml
ADDED
data/CHANGELOG.md
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License
|
2
|
+
|
3
|
+
Copyright (c) Tom Preston-Werner
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.md
ADDED
data/Rakefile
ADDED
@@ -0,0 +1,12 @@
|
|
1
|
+
require "bundler/gem_tasks"
|
2
|
+
|
3
|
+
desc 'Default: run specs.'
|
4
|
+
task :default => :spec
|
5
|
+
|
6
|
+
require 'rspec/core/rake_task'
|
7
|
+
|
8
|
+
desc "Run specs"
|
9
|
+
RSpec::Core::RakeTask.new do |t|
|
10
|
+
t.pattern = "./spec/**/*_spec.rb" # don't need this, it's default.
|
11
|
+
# Put spec opts in a file named .rspec in root
|
12
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module TableCreator
|
2
|
+
require 'action_view'
|
3
|
+
require 'active_support/all'
|
4
|
+
|
5
|
+
require 'table_creator/table'
|
6
|
+
require 'table_creator/col'
|
7
|
+
require 'table_creator/row'
|
8
|
+
require 'table_creator/row_group'
|
9
|
+
require 'table_creator/col_group'
|
10
|
+
require 'table_creator/result_group'
|
11
|
+
|
12
|
+
def self.formatters(type)
|
13
|
+
@formatters ||= {}
|
14
|
+
@formatters[type] ||= {}
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.add_formatter(type, klass, method)
|
18
|
+
formatters(type)[klass] = method
|
19
|
+
end
|
20
|
+
|
21
|
+
Error = Class.new(StandardError)
|
22
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
module TableCreator
|
2
|
+
class Col
|
3
|
+
include ActionView::Helpers::TagHelper
|
4
|
+
|
5
|
+
attr_accessor :data, :data_type, :row, :type, :colspan, :link_to, :anchor, :options
|
6
|
+
|
7
|
+
def initialize(data, row, type = nil)
|
8
|
+
@row = row
|
9
|
+
@options = {}
|
10
|
+
if data.is_a? Hash
|
11
|
+
@colspan = data[:colspan]
|
12
|
+
@data = data[:data]
|
13
|
+
@link_to = data[:link_to]
|
14
|
+
@anchor = data[:anchor]
|
15
|
+
@options = data.except(:colspan, :data, :link_to, :anchor)
|
16
|
+
else
|
17
|
+
@data = data
|
18
|
+
end
|
19
|
+
|
20
|
+
@data_type = case @data.class.to_s.to_sym
|
21
|
+
when :Fixnum
|
22
|
+
:number
|
23
|
+
when :String
|
24
|
+
:text
|
25
|
+
else
|
26
|
+
nil
|
27
|
+
end
|
28
|
+
@type = type || :data
|
29
|
+
self
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_csv
|
33
|
+
if @colspan && @colspan > 1
|
34
|
+
cols = [quote(@data)]
|
35
|
+
(@colspan-1).times do
|
36
|
+
cols << ''
|
37
|
+
end
|
38
|
+
cols
|
39
|
+
else
|
40
|
+
quote(@data)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def quote(data)
|
45
|
+
formatted_data = format_csv(data)
|
46
|
+
quoted = formatted_data.to_s.gsub('"', '\"')
|
47
|
+
if formatted_data.to_s.include?(',')
|
48
|
+
'"'+quoted+'"'
|
49
|
+
else
|
50
|
+
quoted
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
def to_html
|
55
|
+
formatter = TableCreator.formatters(:html)[@data.class]
|
56
|
+
content = if formatter
|
57
|
+
result = formatter.is_a?(Symbol) ? @data.send(formatter) : formatter.call(@data)
|
58
|
+
if result.is_a?(Hash)
|
59
|
+
link_to = result[:link_to]
|
60
|
+
anchor = result[:anchor]
|
61
|
+
@options[:class] ||= @data.class.name.underscore
|
62
|
+
result.fetch(:data)
|
63
|
+
else
|
64
|
+
@options[:class] ||= @data.class.name.underscore
|
65
|
+
result
|
66
|
+
end
|
67
|
+
else
|
68
|
+
@data
|
69
|
+
end
|
70
|
+
col_tag = type == :header ? :th : :td
|
71
|
+
content = content_tag :a, content, :href => link_to if link_to
|
72
|
+
content = content_tag :a, content, :name => anchor if anchor
|
73
|
+
tag_class = [options[:class].presence, data_type.presence].compact.join(' ')
|
74
|
+
attributes = options.except(:type).merge(:class => tag_class, :colspan => colspan)
|
75
|
+
|
76
|
+
content_tag col_tag, content.to_s.gsub(/\n/, tag(:br)).html_safe, attributes
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
def format_csv(data)
|
82
|
+
formatter = TableCreator.formatters(:csv)[data.class]
|
83
|
+
return data unless formatter
|
84
|
+
result = formatter.is_a?(Symbol) ? @data.send(formatter) : formatter.call(@data)
|
85
|
+
if result.is_a?(Hash)
|
86
|
+
result.fetch(:data)
|
87
|
+
else
|
88
|
+
result
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,167 @@
|
|
1
|
+
module TableCreator
|
2
|
+
class ResultGroup
|
3
|
+
attr_accessor :group_object, :rows
|
4
|
+
attr_accessor :level, :total_levels
|
5
|
+
attr_accessor :sum
|
6
|
+
|
7
|
+
def initialize(group_object, rows, total_levels = 0)
|
8
|
+
@group_object = (group_object.blank? && group_object != false) ? nil : group_object.to_s
|
9
|
+
@rows = rows
|
10
|
+
@level = 0
|
11
|
+
@total_levels = total_levels
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
def level=(new_level)
|
16
|
+
@level = new_level
|
17
|
+
@rows.each do |row|
|
18
|
+
if row.is_a? ResultGroup
|
19
|
+
row.total_levels = @total_levels
|
20
|
+
row.level = new_level + 1
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
|
26
|
+
def count
|
27
|
+
@rows.map { |r| r.is_a?(self.class) ? r.count : 1 }.sum
|
28
|
+
end
|
29
|
+
|
30
|
+
|
31
|
+
def group(groups, order = nil)
|
32
|
+
groups = [groups] unless groups.is_a?(Array)
|
33
|
+
|
34
|
+
return if groups.empty?
|
35
|
+
new_rows = []
|
36
|
+
|
37
|
+
first_group = groups.shift
|
38
|
+
new_group = if @rows.first.is_a? ResultGroup
|
39
|
+
@rows.map{|rg| [rg.group_object, rg.group_children(first_group, order)]}
|
40
|
+
else
|
41
|
+
if first_group == true
|
42
|
+
{'All' => @rows}
|
43
|
+
elsif first_group.is_a?(Hash)
|
44
|
+
@rows.group_by{|r|
|
45
|
+
r.send(first_group.keys.first).send(first_group.values.first)
|
46
|
+
}
|
47
|
+
else
|
48
|
+
@rows.group_by{|r| r.send(first_group)}
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
new_group = case order.try(:to_sym)
|
53
|
+
when :group_name
|
54
|
+
Hash[new_group.sort { |a,b| a.first.to_s <=> b.first.to_s }]
|
55
|
+
when :row_count
|
56
|
+
Hash[new_group.sort { |a,b| b.last.size <=> a.last.size }]
|
57
|
+
else
|
58
|
+
new_group
|
59
|
+
end
|
60
|
+
|
61
|
+
@total_levels += 1
|
62
|
+
new_group.each do |group, rows|
|
63
|
+
r = ResultGroup.new(group, rows, @total_levels)
|
64
|
+
r.level = @level + 1
|
65
|
+
new_rows << r
|
66
|
+
end
|
67
|
+
|
68
|
+
@rows = new_rows
|
69
|
+
group(groups, order) unless groups.empty?
|
70
|
+
@rows
|
71
|
+
end
|
72
|
+
|
73
|
+
|
74
|
+
def group_children(group, order = nil)
|
75
|
+
if @rows.first.is_a?(ResultGroup)
|
76
|
+
@rows.each{|r| r.group_children(group, order)}
|
77
|
+
@rows
|
78
|
+
else
|
79
|
+
self.group(group, order)
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
|
84
|
+
# fields is a hash where:
|
85
|
+
# key is the field/method
|
86
|
+
# value is the aggregate type (currently only :sum)
|
87
|
+
def aggregate(fields)
|
88
|
+
invalid_aggregates = fields.values.uniq - [:sum]
|
89
|
+
raise Error.new("Aggregation #{invalid_aggregates.to_sentence} not implemented") if invalid_aggregates.present?
|
90
|
+
|
91
|
+
@sum ||= {}
|
92
|
+
|
93
|
+
fields.each do |field, aggregation|
|
94
|
+
@sum[field] = nil
|
95
|
+
|
96
|
+
if @rows.first.is_a?(ResultGroup)
|
97
|
+
@sum[field] = @rows.map do |row|
|
98
|
+
# agregate each lower levels
|
99
|
+
row.aggregate(fields)
|
100
|
+
|
101
|
+
case aggregation
|
102
|
+
when :sum
|
103
|
+
row.sum[field]
|
104
|
+
end
|
105
|
+
end.compact.sum
|
106
|
+
else
|
107
|
+
@sum[field] = @rows.map do |row|
|
108
|
+
case aggregation
|
109
|
+
when :sum
|
110
|
+
row.send(field) || 0 # encase result is nil
|
111
|
+
end
|
112
|
+
end.compact.sum
|
113
|
+
end
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
|
118
|
+
def to_data_rows(&block)
|
119
|
+
rows = []
|
120
|
+
@rows.each do |row|
|
121
|
+
if row.is_a? ResultGroup
|
122
|
+
|
123
|
+
sub_rows = row.to_data_rows(&block)
|
124
|
+
format = block.call(row, nil)
|
125
|
+
|
126
|
+
if format.is_a? Hash
|
127
|
+
group_data = format[:group]
|
128
|
+
group_summary_data = format[:summary]
|
129
|
+
elsif format.is_a? Array
|
130
|
+
group_data = nil
|
131
|
+
group_summary_data = format
|
132
|
+
end
|
133
|
+
|
134
|
+
if group_data.is_a? Array
|
135
|
+
rows << {:class => "d#{@total_levels-row.level} l#{@total_levels} group", :data => group_data}
|
136
|
+
elsif group_data.is_a? Hash
|
137
|
+
rows << group_data.merge(:class => "h#{row.level}")
|
138
|
+
end
|
139
|
+
|
140
|
+
if group_summary_data.is_a? Array
|
141
|
+
rows << {:class => "d#{@total_levels-row.level} l#{@total_levels} summary", :data => group_summary_data}
|
142
|
+
elsif group_summary_data.is_a? Hash
|
143
|
+
rows << group_summary_data.merge(:class => "h#{row.level}")
|
144
|
+
end
|
145
|
+
|
146
|
+
rows += sub_rows
|
147
|
+
else
|
148
|
+
format = block.call(nil, row)
|
149
|
+
|
150
|
+
if format.is_a? Hash
|
151
|
+
if format[:data].first.is_a? Array
|
152
|
+
format[:data].each do |row|
|
153
|
+
rows << row
|
154
|
+
end
|
155
|
+
else
|
156
|
+
rows << format[:data]
|
157
|
+
end
|
158
|
+
|
159
|
+
elsif format.is_a? Array
|
160
|
+
rows << format
|
161
|
+
end
|
162
|
+
end
|
163
|
+
end
|
164
|
+
rows
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module TableCreator
|
2
|
+
class Row
|
3
|
+
include ActionView::Helpers::TagHelper
|
4
|
+
|
5
|
+
attr_accessor :cols, :parent, :options
|
6
|
+
|
7
|
+
def initialize(row, parent, options = {})
|
8
|
+
@parent = parent
|
9
|
+
@options = options
|
10
|
+
@cols = []
|
11
|
+
row.each do |col|
|
12
|
+
@cols << Col.new(col, row, options[:type])
|
13
|
+
end
|
14
|
+
self
|
15
|
+
end
|
16
|
+
|
17
|
+
def to_csv
|
18
|
+
cols.map(&:to_csv).flatten.join(',')
|
19
|
+
end
|
20
|
+
|
21
|
+
def to_html
|
22
|
+
content_tag :tr, cols.map(&:to_html).join.html_safe, options.except(:type)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
# A group of rows
|
2
|
+
#
|
3
|
+
# Can be of type: [:header, :footer, :body]
|
4
|
+
module TableCreator
|
5
|
+
class RowGroup
|
6
|
+
include ActionView::Helpers::TagHelper
|
7
|
+
|
8
|
+
attr_accessor :children, :parent, :options
|
9
|
+
|
10
|
+
def initialize(row_group, parent, type = :body, options = nil)
|
11
|
+
@parent = parent
|
12
|
+
@children = []
|
13
|
+
@options = options
|
14
|
+
@type = type
|
15
|
+
|
16
|
+
row_group.each do |row|
|
17
|
+
if row.is_a? Hash
|
18
|
+
@children << Row.new(row[:data], self, row.except(:data).merge(:type => type))
|
19
|
+
else
|
20
|
+
@children << Row.new(row, self, :type => type)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
self
|
24
|
+
end
|
25
|
+
|
26
|
+
def <<(child)
|
27
|
+
@children << Row.new(child, self, :type => type)
|
28
|
+
end
|
29
|
+
|
30
|
+
def to_csv
|
31
|
+
@children.map(&:to_csv).join("\n")
|
32
|
+
end
|
33
|
+
|
34
|
+
def to_html
|
35
|
+
tag = case @type; when :header; :thead; when :footer; :tfoot; else :tbody; end
|
36
|
+
content_tag tag, children.map(&:to_html).join.html_safe, options
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
module TableCreator
|
2
|
+
class Table
|
3
|
+
include ActionView::Helpers::TagHelper
|
4
|
+
|
5
|
+
attr_accessor :children, :colgroups
|
6
|
+
|
7
|
+
def initialize
|
8
|
+
@children = []
|
9
|
+
@colgroups = []
|
10
|
+
self
|
11
|
+
end
|
12
|
+
|
13
|
+
def <<(child)
|
14
|
+
if child.is_a? Array
|
15
|
+
@children << Row.new(child, self)
|
16
|
+
|
17
|
+
else # hash of one or more types
|
18
|
+
[:header, :footer, :body].each do |type|
|
19
|
+
@children << RowGroup.new(child[type], self, type) if child[type]
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def to_csv
|
25
|
+
@children.map(&:to_csv).join("\n")
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_html(opts={})
|
29
|
+
content_tag :table, (colgroups + children).map(&:to_html).join.html_safe, opts
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -0,0 +1,66 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TableCreator::Table do
|
4
|
+
let(:row) { ['col1', 2, Money.new(3), Booking.new(42, '22TEST')] }
|
5
|
+
let(:money_class) {
|
6
|
+
Class.new do
|
7
|
+
def initialize(dollars)
|
8
|
+
@dollars = dollars
|
9
|
+
end
|
10
|
+
|
11
|
+
def format
|
12
|
+
"$#{with_places}"
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_s
|
16
|
+
with_places
|
17
|
+
end
|
18
|
+
|
19
|
+
def with_places
|
20
|
+
'%.2f' % @dollars
|
21
|
+
end
|
22
|
+
end
|
23
|
+
}
|
24
|
+
let(:booking_class) {
|
25
|
+
Class.new do
|
26
|
+
attr_reader :id, :reference
|
27
|
+
|
28
|
+
def initialize(id, reference)
|
29
|
+
@id = id
|
30
|
+
@reference = reference
|
31
|
+
end
|
32
|
+
end
|
33
|
+
}
|
34
|
+
|
35
|
+
before do
|
36
|
+
stub_const 'Money', money_class
|
37
|
+
stub_const 'Booking', booking_class
|
38
|
+
TableCreator.add_formatter :html, Money, proc { |money| money.format }
|
39
|
+
TableCreator.add_formatter :html, Booking, proc { |booking|
|
40
|
+
{ link_to: "/bookings/#{booking.id}", data: booking.reference }
|
41
|
+
}
|
42
|
+
TableCreator.add_formatter :csv, Money, proc { |money| money.to_s }
|
43
|
+
TableCreator.add_formatter :csv, Booking, :reference
|
44
|
+
|
45
|
+
subject << { body: [row] }
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should generate csv' do
|
49
|
+
expect(subject.to_csv).to eq 'col1,2,3.00,22TEST'
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should generate html' do
|
53
|
+
expect(subject.to_html).to eq(
|
54
|
+
'<table>'\
|
55
|
+
'<tbody>'\
|
56
|
+
'<tr>'\
|
57
|
+
'<td class="text">col1</td>'\
|
58
|
+
'<td class="number">2</td>'\
|
59
|
+
'<td class="money">$3.00</td>'\
|
60
|
+
'<td class="booking"><a href="/bookings/42">22TEST</a></td>'\
|
61
|
+
'</tr>'\
|
62
|
+
'</tbody>'\
|
63
|
+
'</table>'
|
64
|
+
)
|
65
|
+
end
|
66
|
+
end
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe TableCreator::ResultGroup do
|
4
|
+
let(:row1) { double(odd: true) }
|
5
|
+
let(:row2) { double(odd: false) }
|
6
|
+
let(:row3) { double(odd: true) }
|
7
|
+
subject { TableCreator::ResultGroup.new(nil, [row1, row2, row3]) }
|
8
|
+
|
9
|
+
let(:row1_group) { subject.rows[0].group_object }
|
10
|
+
let(:row1_rows) { subject.rows[0].rows }
|
11
|
+
let(:row2_group) { subject.rows[1].group_object }
|
12
|
+
let(:row2_rows) { subject.rows[1].rows }
|
13
|
+
|
14
|
+
it 'should handle basic grouping' do
|
15
|
+
subject.group('odd')
|
16
|
+
expect(row1_group).to eq 'true'
|
17
|
+
expect(row1_rows).to eq [row1, row3]
|
18
|
+
expect(row2_group).to eq 'false'
|
19
|
+
expect(row2_rows).to eq [row2]
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should order by groups name' do
|
23
|
+
subject.group('odd', :group_name)
|
24
|
+
expect(row1_group).to eq 'false'
|
25
|
+
expect(row1_rows).to eq [row2]
|
26
|
+
expect(row2_group).to eq 'true'
|
27
|
+
expect(row2_rows).to eq [row1, row3]
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'should order by groups row count' do
|
31
|
+
subject.group('odd', :row_count)
|
32
|
+
expect(row1_group).to eq 'true'
|
33
|
+
expect(row1_rows).to eq [row1, row3]
|
34
|
+
expect(row2_group).to eq 'false'
|
35
|
+
expect(row2_rows).to eq [row2]
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
describe TableCreator::ResultGroup, 'when aggregating' do
|
40
|
+
let(:row1) { double(odd: true, amount: Money.new(1), quantity: 1) }
|
41
|
+
let(:row2) { double(odd: false, amount: Money.new(9), quantity: 3) }
|
42
|
+
let(:row3) { double(odd: true, amount: Money.new(4), quantity: 4) }
|
43
|
+
subject { TableCreator::ResultGroup.new(nil, [row1, row2, row3]) }
|
44
|
+
|
45
|
+
it 'should not allow non standard/implemented aggregates' do
|
46
|
+
expect { subject.aggregate(amount: :avg) }.to raise_error(
|
47
|
+
TableCreator::Error,
|
48
|
+
'Aggregation avg not implemented'
|
49
|
+
)
|
50
|
+
end
|
51
|
+
|
52
|
+
it 'should aggregate on multiple levels' do
|
53
|
+
expect(subject.sum).to be nil
|
54
|
+
subject.aggregate(amount: :sum, quantity: :sum)
|
55
|
+
expect(subject.sum).to eq(amount: Money.new(14), quantity: 8)
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should group and aggregate at each level' do
|
59
|
+
subject.group(:odd)
|
60
|
+
expect(subject.sum).to be nil
|
61
|
+
subject.aggregate(amount: :sum, quantity: :sum)
|
62
|
+
expect(subject.rows[0].group_object).to eq 'true'
|
63
|
+
expect(subject.rows[0].sum).to eq(amount: Money.new(5), quantity: 5)
|
64
|
+
expect(subject.rows[1].group_object).to eq 'false'
|
65
|
+
expect(subject.rows[1].sum).to eq(amount: Money.new(9), quantity: 3)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
class Money
|
70
|
+
attr_accessor :cents
|
71
|
+
def initialize(cents)
|
72
|
+
@cents = cents
|
73
|
+
end
|
74
|
+
|
75
|
+
def +(money)
|
76
|
+
Money.new(@cents + money.cents)
|
77
|
+
end
|
78
|
+
|
79
|
+
def ==(money)
|
80
|
+
@cents == money.cents
|
81
|
+
end
|
82
|
+
|
83
|
+
def <=>(money)
|
84
|
+
@cents <=> money.cents
|
85
|
+
end
|
86
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
# This file was generated by the `rspec --init` command. Conventionally, all
|
2
|
+
# specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
3
|
+
# Require this file using `require "spec_helper.rb"` to ensure that it is only
|
4
|
+
# loaded once.
|
5
|
+
#
|
6
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
7
|
+
|
8
|
+
require 'rubygems'
|
9
|
+
require 'bundler/setup'
|
10
|
+
|
11
|
+
require 'support/coverage_loader'
|
12
|
+
|
13
|
+
require 'table_creator'
|
14
|
+
|
15
|
+
RSpec.configure do |config|
|
16
|
+
config.raise_errors_for_deprecations!
|
17
|
+
config.run_all_when_everything_filtered = true
|
18
|
+
config.filter_run :focus
|
19
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'table_creator/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = 'table_creator'
|
8
|
+
spec.version = TableCreator::VERSION
|
9
|
+
spec.date = '2013-02-25'
|
10
|
+
spec.summary = "Manage sets of data and export."
|
11
|
+
spec.description = "See README for full details on how to install, use, etc."
|
12
|
+
spec.authors = ["Michael Noack"]
|
13
|
+
spec.email = 'support@travellink.com.au'
|
14
|
+
spec.homepage = 'http://github.com/sealink/table_creator'
|
15
|
+
|
16
|
+
spec.license = "MIT"
|
17
|
+
|
18
|
+
spec.files = `git ls-files`.split($/)
|
19
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
20
|
+
spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
|
21
|
+
spec.require_paths = ["lib"]
|
22
|
+
|
23
|
+
spec.add_dependency 'actionpack' # TagHelpers
|
24
|
+
spec.add_dependency 'activesupport' # Hash#except, blank?, etc.
|
25
|
+
|
26
|
+
spec.add_development_dependency "bundler", "~> 1.3"
|
27
|
+
spec.add_development_dependency "rake"
|
28
|
+
spec.add_development_dependency 'rspec'
|
29
|
+
spec.add_development_dependency 'coverage-kit'
|
30
|
+
spec.add_development_dependency 'simplecov-rcov'
|
31
|
+
spec.add_development_dependency 'coveralls'
|
32
|
+
spec.add_development_dependency 'travis'
|
33
|
+
end
|
metadata
ADDED
@@ -0,0 +1,193 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: table_creator
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Michael Noack
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2013-02-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: actionpack
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - ">="
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '0'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - ">="
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: activesupport
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - ">="
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - ">="
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: bundler
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '1.3'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '1.3'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: rake
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '0'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '0'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: rspec
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - ">="
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '0'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - ">="
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '0'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: coverage-kit
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - ">="
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - ">="
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0'
|
97
|
+
- !ruby/object:Gem::Dependency
|
98
|
+
name: simplecov-rcov
|
99
|
+
requirement: !ruby/object:Gem::Requirement
|
100
|
+
requirements:
|
101
|
+
- - ">="
|
102
|
+
- !ruby/object:Gem::Version
|
103
|
+
version: '0'
|
104
|
+
type: :development
|
105
|
+
prerelease: false
|
106
|
+
version_requirements: !ruby/object:Gem::Requirement
|
107
|
+
requirements:
|
108
|
+
- - ">="
|
109
|
+
- !ruby/object:Gem::Version
|
110
|
+
version: '0'
|
111
|
+
- !ruby/object:Gem::Dependency
|
112
|
+
name: coveralls
|
113
|
+
requirement: !ruby/object:Gem::Requirement
|
114
|
+
requirements:
|
115
|
+
- - ">="
|
116
|
+
- !ruby/object:Gem::Version
|
117
|
+
version: '0'
|
118
|
+
type: :development
|
119
|
+
prerelease: false
|
120
|
+
version_requirements: !ruby/object:Gem::Requirement
|
121
|
+
requirements:
|
122
|
+
- - ">="
|
123
|
+
- !ruby/object:Gem::Version
|
124
|
+
version: '0'
|
125
|
+
- !ruby/object:Gem::Dependency
|
126
|
+
name: travis
|
127
|
+
requirement: !ruby/object:Gem::Requirement
|
128
|
+
requirements:
|
129
|
+
- - ">="
|
130
|
+
- !ruby/object:Gem::Version
|
131
|
+
version: '0'
|
132
|
+
type: :development
|
133
|
+
prerelease: false
|
134
|
+
version_requirements: !ruby/object:Gem::Requirement
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: '0'
|
139
|
+
description: See README for full details on how to install, use, etc.
|
140
|
+
email: support@travellink.com.au
|
141
|
+
executables: []
|
142
|
+
extensions: []
|
143
|
+
extra_rdoc_files: []
|
144
|
+
files:
|
145
|
+
- ".gitignore"
|
146
|
+
- ".travis.yml"
|
147
|
+
- CHANGELOG.md
|
148
|
+
- Gemfile
|
149
|
+
- LICENSE
|
150
|
+
- README.md
|
151
|
+
- Rakefile
|
152
|
+
- lib/table_creator.rb
|
153
|
+
- lib/table_creator/col.rb
|
154
|
+
- lib/table_creator/col_group.rb
|
155
|
+
- lib/table_creator/result_group.rb
|
156
|
+
- lib/table_creator/row.rb
|
157
|
+
- lib/table_creator/row_group.rb
|
158
|
+
- lib/table_creator/table.rb
|
159
|
+
- lib/table_creator/version.rb
|
160
|
+
- spec/data_table_spec.rb
|
161
|
+
- spec/result_group_spec.rb
|
162
|
+
- spec/spec_helper.rb
|
163
|
+
- spec/support/coverage_loader.rb
|
164
|
+
- table_creator.gemspec
|
165
|
+
homepage: http://github.com/sealink/table_creator
|
166
|
+
licenses:
|
167
|
+
- MIT
|
168
|
+
metadata: {}
|
169
|
+
post_install_message:
|
170
|
+
rdoc_options: []
|
171
|
+
require_paths:
|
172
|
+
- lib
|
173
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
174
|
+
requirements:
|
175
|
+
- - ">="
|
176
|
+
- !ruby/object:Gem::Version
|
177
|
+
version: '0'
|
178
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
179
|
+
requirements:
|
180
|
+
- - ">="
|
181
|
+
- !ruby/object:Gem::Version
|
182
|
+
version: '0'
|
183
|
+
requirements: []
|
184
|
+
rubyforge_project:
|
185
|
+
rubygems_version: 2.5.2
|
186
|
+
signing_key:
|
187
|
+
specification_version: 4
|
188
|
+
summary: Manage sets of data and export.
|
189
|
+
test_files:
|
190
|
+
- spec/data_table_spec.rb
|
191
|
+
- spec/result_group_spec.rb
|
192
|
+
- spec/spec_helper.rb
|
193
|
+
- spec/support/coverage_loader.rb
|