elskwid-munger 0.1.4.5 → 0.1.4.6
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/Rakefile +7 -32
- data/munger.gemspec +44 -34
- data/{spec/munger/render/csv_spec.rb → test/munger/csv_test.rb} +9 -9
- data/test/munger/data_ar_test.rb +194 -0
- data/test/munger/data_test.rb +185 -0
- data/test/munger/html_test.rb +87 -0
- data/test/munger/item_test.rb +43 -0
- data/{spec/munger/data/new_spec.rb → test/munger/new_test.rb} +9 -9
- data/test/munger/render_test.rb +37 -0
- data/test/munger/report_test.rb +156 -0
- data/{spec/munger/render/text_spec.rb → test/munger/text_test.rb} +9 -9
- data/test/test_helper.rb +60 -0
- metadata +88 -50
- data/spec/munger/data_spec.rb +0 -183
- data/spec/munger/item_spec.rb +0 -43
- data/spec/munger/render/html_spec.rb +0 -87
- data/spec/munger/render_spec.rb +0 -38
- data/spec/munger/report_spec.rb +0 -155
- data/spec/spec_helper.rb +0 -107
@@ -0,0 +1,87 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
describe Munger::Render::Html do
|
4
|
+
include MungerSpecHelper
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@data = Munger::Data.new(:data => test_data)
|
8
|
+
@report = Munger::Report.new(:data => @data)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "must accept a Munger::Report object" do
|
12
|
+
Munger::Render::Html.new(@report.process).must_be :valid?
|
13
|
+
end
|
14
|
+
|
15
|
+
it "must render a basic html table" do
|
16
|
+
@render = Munger::Render::Html.new(@report.process)
|
17
|
+
count = @report.rows
|
18
|
+
|
19
|
+
html = @render.render
|
20
|
+
html.must_have_tag('table')
|
21
|
+
html.must_have_tag('tr', :count => count + 1) # rows plus header
|
22
|
+
end
|
23
|
+
|
24
|
+
it "must render a thead section for the table" do
|
25
|
+
@render = Munger::Render::Html.new(@report.process)
|
26
|
+
html = @render.render
|
27
|
+
html.must_have_tag('thead', :count => 1)
|
28
|
+
end
|
29
|
+
|
30
|
+
it "must render a tbody section for the table" do
|
31
|
+
@render = Munger::Render::Html.new(@report.process)
|
32
|
+
html = @render.render
|
33
|
+
html.must_have_tag('tbody', :count => 1)
|
34
|
+
end
|
35
|
+
|
36
|
+
it "must accept a custom table class" do
|
37
|
+
rep = Munger::Render::Html.new(@report.process, :classes => {:table => 'helloClass'})
|
38
|
+
html = rep.render
|
39
|
+
html.must_have_tag('table.helloClass')
|
40
|
+
end
|
41
|
+
|
42
|
+
it "must use aliased column titles" do
|
43
|
+
@report = @report.columns([:age, :name, :score])
|
44
|
+
@report.column_titles = {:age => "The Age", :name => "The Name"}
|
45
|
+
html = Munger::Render::Html.new(@report.process).render
|
46
|
+
html.must_match(/The Age/)
|
47
|
+
end
|
48
|
+
|
49
|
+
it "must render columns in the right order" do
|
50
|
+
@report = @report.columns([:age, :name]).process
|
51
|
+
html = Munger::Render::Html.new(@report).render
|
52
|
+
html.must_have_tag('th', :count => 2) # rows plus header
|
53
|
+
html.must_match(/age(.*?)name/)
|
54
|
+
end
|
55
|
+
|
56
|
+
it "must render groups" do
|
57
|
+
@report = @report.subgroup(:age).aggregate(:sum => :score).process
|
58
|
+
html = Munger::Render::Html.new(@report).render
|
59
|
+
html.must_match(/151/) # only in the aggregate group
|
60
|
+
html.must_have_tag('tr.group0', :count => 1)
|
61
|
+
html.must_have_tag('tr.group1', :count => 9)
|
62
|
+
end
|
63
|
+
|
64
|
+
it "must render group headers" do
|
65
|
+
@report = @report.subgroup(:age, :with_headers => true).process
|
66
|
+
html = Munger::Render::Html.new(@report).render
|
67
|
+
html.must_have_tag('tr.groupHeader1', :count => 9)
|
68
|
+
end
|
69
|
+
|
70
|
+
it "must render cell styles" do
|
71
|
+
@report.process.style_rows('over_thirty') { |row| row.age > 29 }
|
72
|
+
|
73
|
+
html = Munger::Render::Html.new(@report).render
|
74
|
+
html.must_have_tag('tr.over_thirty', :count => 6)
|
75
|
+
end
|
76
|
+
|
77
|
+
it "must render row styles" do
|
78
|
+
@report.process.style_cells('highlight', :only => :age) { |c, r| c == 32 }
|
79
|
+
html = Munger::Render::Html.new(@report).render
|
80
|
+
html.must_have_tag('td.highlight')
|
81
|
+
end
|
82
|
+
|
83
|
+
it "must render column styles"
|
84
|
+
|
85
|
+
it "must render default css if you ask"
|
86
|
+
|
87
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
describe Munger::Item do
|
4
|
+
include MungerSpecHelper
|
5
|
+
|
6
|
+
before(:all) do
|
7
|
+
@data = Munger::Data.new(:data => test_data)
|
8
|
+
end
|
9
|
+
|
10
|
+
it "must accept a hash with symbols" do
|
11
|
+
hash = {'key1' => 'value1', 'key2' => 'value2'}
|
12
|
+
item = Munger::Item.ensure(hash)
|
13
|
+
item.key1.must_equal('value1')
|
14
|
+
end
|
15
|
+
|
16
|
+
it "must accept a hash with strings" do
|
17
|
+
hash = {:key1 => 'value1', :key2 => 'value2'}
|
18
|
+
item = Munger::Item.ensure(hash)
|
19
|
+
item.key1.must_equal('value1')
|
20
|
+
item.key2.wont_equal('value1')
|
21
|
+
item.key3.must_equal(nil)
|
22
|
+
end
|
23
|
+
|
24
|
+
it "must accept mixed types" do
|
25
|
+
hash = {:key1 => 'value1', 'key2' => 'value2'}
|
26
|
+
item = Munger::Item.ensure(hash)
|
27
|
+
item.key1.must_equal('value1')
|
28
|
+
item.key2.must_equal('value2')
|
29
|
+
end
|
30
|
+
|
31
|
+
it "must be able to access hash values indifferently" do
|
32
|
+
hash = {:key1 => 'value1', 'key2' => 'value2'}
|
33
|
+
item = Munger::Item.ensure(hash)
|
34
|
+
item['key1'].must_equal('value1')
|
35
|
+
item[:key2].must_equal('value2')
|
36
|
+
end
|
37
|
+
|
38
|
+
it "must return a hash after being initialized with a hash" do
|
39
|
+
hash = {:key1 => "value1", :key2 => "value2"}
|
40
|
+
Munger::Item.ensure(hash).to_hash.must_be_kind_of(Hash)
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
@@ -1,18 +1,18 @@
|
|
1
|
-
require
|
1
|
+
require "test_helper"
|
2
2
|
|
3
3
|
describe Munger::Data do
|
4
|
-
|
4
|
+
|
5
5
|
describe '.new' do
|
6
|
-
|
6
|
+
|
7
7
|
it 'initializes the data attribute to the :data value' do
|
8
8
|
data = [{:foo => '1'}, {:foo => 2}]
|
9
|
-
Munger::Data.new(:data => data).data.
|
9
|
+
Munger::Data.new(:data => data).data.must_equal(data)
|
10
10
|
end
|
11
|
-
|
11
|
+
|
12
12
|
it 'yields itself to the given block' do
|
13
|
-
Munger::Data.new { |data| data.
|
13
|
+
Munger::Data.new { |data| data.must_be_kind_of(Munger::Data) }
|
14
14
|
end
|
15
|
-
|
15
|
+
|
16
16
|
end
|
17
|
-
|
18
|
-
end
|
17
|
+
|
18
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
describe Munger::Render do
|
4
|
+
include MungerSpecHelper
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@data = Munger::Data.new(:data => test_data)
|
8
|
+
@report = Munger::Report.new(:data => @data).process
|
9
|
+
end
|
10
|
+
|
11
|
+
it "must render html" do
|
12
|
+
html = Munger::Render.to_html(@report)
|
13
|
+
html.must_have_tag('table')
|
14
|
+
end
|
15
|
+
|
16
|
+
it "must render sortable html" do
|
17
|
+
html = Munger::Render.to_sortable_html(@report, :sort => "name", :order => "asc", :url => "test")
|
18
|
+
html.must_have_tag("table")
|
19
|
+
html.must_have_tag("th.unsorted")
|
20
|
+
html.must_have_tag("th.sorted")
|
21
|
+
html.must_have_tag("th.sorted-asc")
|
22
|
+
html.must_have_tag("sort")
|
23
|
+
end
|
24
|
+
|
25
|
+
it "must render text" do
|
26
|
+
text = Munger::Render.to_text(@report)
|
27
|
+
text.wont_have_tag('table')
|
28
|
+
text.split("\n").length.must_be :>=, 5
|
29
|
+
end
|
30
|
+
|
31
|
+
it "must render xls"
|
32
|
+
|
33
|
+
it "must render csv"
|
34
|
+
|
35
|
+
it "must render pdf"
|
36
|
+
|
37
|
+
end
|
@@ -0,0 +1,156 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
|
3
|
+
describe Munger::Report do
|
4
|
+
include MungerSpecHelper
|
5
|
+
|
6
|
+
before(:each) do
|
7
|
+
@data = Munger::Data.new(:data => test_data)
|
8
|
+
@report = Munger::Report.new(:data => @data)
|
9
|
+
end
|
10
|
+
|
11
|
+
it "must accept a Munger::Data object" do
|
12
|
+
Munger::Report.new(:data => @data).must_be :valid?
|
13
|
+
end
|
14
|
+
|
15
|
+
it "must accept a array of hashes" do
|
16
|
+
Munger::Report.new(:data => test_data).must_be :valid?
|
17
|
+
Munger::Report.new(:data => invalid_test_data).wont_be :valid?
|
18
|
+
end
|
19
|
+
|
20
|
+
it "must be able to sort fields by array" do
|
21
|
+
@report.sort = 'name'
|
22
|
+
data = @report.process.process_data
|
23
|
+
data.map { |a| a[:data].name }[0, 4].join(',').must_equal('Alice,Alice,Alice,Chaz')
|
24
|
+
|
25
|
+
@report.sort = ['name', 'age']
|
26
|
+
data = @report.process.process_data
|
27
|
+
data.map { |a| a[:data].age }[0, 4].join(',').must_equal('33,33,34,28')
|
28
|
+
|
29
|
+
@report.sort = [['name', :asc], ['age', :desc]]
|
30
|
+
data = @report.process.process_data
|
31
|
+
data.map { |a| a[:data].age }[0, 4].join(',').must_equal('34,33,33,28')
|
32
|
+
end
|
33
|
+
|
34
|
+
it "must be able to custom sort fields" do
|
35
|
+
@report.sort = [['name', Proc.new {|a, b| a[2] <=> b[2]} ]]
|
36
|
+
data = @report.process.process_data
|
37
|
+
data.map { |a| a[:data].name }[0, 4].join(',').must_equal('Chaz,Rich,Alice,Alice')
|
38
|
+
end
|
39
|
+
|
40
|
+
it "must be able to order columns" do
|
41
|
+
@report.columns([:name, :age, :score])
|
42
|
+
@report.columns.must_equal([:name, :age, :score])
|
43
|
+
end
|
44
|
+
|
45
|
+
it "must be able to alias column titles" do
|
46
|
+
titles = {:name => 'My Name', :age => 'The Age', :score => 'Super Score'}
|
47
|
+
@report.column_titles = titles
|
48
|
+
@report.column_titles.must_equal(titles)
|
49
|
+
end
|
50
|
+
|
51
|
+
it "must default to all columns" do
|
52
|
+
@report.columns.map { |c| c.to_s }.sort.join(',').must_equal('age,day,name,score')
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
it "must be able to subgroup data" do
|
57
|
+
@report.sort('name').subgroup('name').process
|
58
|
+
@report.get_subgroup_rows.size.must_equal(6)
|
59
|
+
end
|
60
|
+
|
61
|
+
it "must be able to add subgroup headers"
|
62
|
+
# do
|
63
|
+
# @report.sort('score').subgroup('score', :with_headers => true)
|
64
|
+
# @report.aggregate(:sum => :score).process
|
65
|
+
# puts Munger::Render.to_text(@report)
|
66
|
+
# end
|
67
|
+
|
68
|
+
it "must add the grouping name on the group line somewhere"
|
69
|
+
|
70
|
+
it "must be able to subgroup in multiple dimensions"
|
71
|
+
|
72
|
+
it "must be able to aggregate columns into subgroup rows" do
|
73
|
+
@report.sort('name').subgroup('name').aggregate(:sum => :score).process
|
74
|
+
@report.get_subgroup_rows(1).size.must_equal(6)
|
75
|
+
@report.get_subgroup_rows(0).size.must_equal(1)
|
76
|
+
@report.get_subgroup_rows(0).first[:data][:score].must_equal(151)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "must be able to aggregate multiple columns into subgroup rows" do
|
80
|
+
@report.sort('name').subgroup('name').aggregate(:sum => [:score, :age]).process
|
81
|
+
data = @report.get_subgroup_rows(0).first[:data]
|
82
|
+
data[:score].must_equal(151)
|
83
|
+
data[:age].must_equal(294)
|
84
|
+
|
85
|
+
@report.sort('name').subgroup('name').aggregate(:sum => :score, :average => :age).process
|
86
|
+
data = @report.get_subgroup_rows(0).first[:data]
|
87
|
+
data[:score].must_equal(151)
|
88
|
+
data[:age].must_equal(29)
|
89
|
+
end
|
90
|
+
|
91
|
+
it "must be able to aggregate with :average" do
|
92
|
+
@report.sort('name').subgroup('name').aggregate(:average => :score).process
|
93
|
+
@report.get_subgroup_rows(0).first[:data][:score].must_equal(15)
|
94
|
+
end
|
95
|
+
|
96
|
+
it "must be able to aggregate with :custom" do
|
97
|
+
@report.sort('name').subgroup('name')
|
98
|
+
@report.aggregate(Proc.new { |d| d.inject { |t, a| 2 * (t + a) } } => :score).process
|
99
|
+
@report.get_subgroup_rows(0).first[:data][:score].must_equal(19508)
|
100
|
+
end
|
101
|
+
|
102
|
+
it "must be able to style cells" do
|
103
|
+
@report.process
|
104
|
+
@report.style_cells('highlight') { |c, r| c == 32 }
|
105
|
+
styles = @report.process_data.select { |r| r[:meta][:cell_styles] }
|
106
|
+
styles.size.must_equal(2)
|
107
|
+
end
|
108
|
+
|
109
|
+
it "must be able to style cells in certain columns" do
|
110
|
+
@report.process
|
111
|
+
@report.style_cells('highlight', :only => :age) { |c, r| c == 32 }
|
112
|
+
@report.style_cells('big', :except => [:name, :day]) { |c, r| c.size > 2 }
|
113
|
+
styles = @report.process_data.select { |r| r[:meta][:cell_styles] }
|
114
|
+
styles.size.must_equal(10)
|
115
|
+
|
116
|
+
janet = @report.process_data.select { |r| r[:data].name == 'Janet' }.first
|
117
|
+
jstyles = janet[:meta][:cell_styles]
|
118
|
+
|
119
|
+
jstyles[:age].sort.join(',').must_equal('big,highlight')
|
120
|
+
jstyles[:score].must_equal(["big"])
|
121
|
+
end
|
122
|
+
|
123
|
+
it "must be able to style rows" do
|
124
|
+
@report.process
|
125
|
+
@report.style_rows('over_thirty') { |row| row.age > 29 }
|
126
|
+
@report.style_cells('highlight', :only => :age) { |c, r| c == 32 }
|
127
|
+
|
128
|
+
janet = @report.process_data.select { |r| r[:data].name == 'Janet' }.first[:meta]
|
129
|
+
janet[:row_styles].must_equal(["over_thirty"])
|
130
|
+
janet[:cell_styles].size.must_equal(1)
|
131
|
+
janet[:cell_styles][:age].must_equal(["highlight"])
|
132
|
+
end
|
133
|
+
|
134
|
+
it "must know when it is processed" do
|
135
|
+
@report.processed?.wont_equal(true)
|
136
|
+
@report.process
|
137
|
+
@report.processed?.must_equal(true)
|
138
|
+
end
|
139
|
+
|
140
|
+
it "must be able to style columns"
|
141
|
+
|
142
|
+
it "must be able to attach formatting independent of content"
|
143
|
+
# so can format numbers without hurting ability to aggregate correctly
|
144
|
+
# or add hyperlinks using data from columns not being shown
|
145
|
+
|
146
|
+
it "must be able to add and retrieve column formatters" do
|
147
|
+
@report.column_formatters = {:name => :to_s}
|
148
|
+
@report.process
|
149
|
+
@report.column_formatters.size.must_equal(1)
|
150
|
+
@report.column_formatter(:name).must_equal(:to_s)
|
151
|
+
end
|
152
|
+
|
153
|
+
it "must be able to aggregate rows into new column"
|
154
|
+
|
155
|
+
|
156
|
+
end
|
@@ -1,22 +1,22 @@
|
|
1
|
-
require
|
1
|
+
require "test_helper"
|
2
2
|
|
3
|
-
describe Munger::Render::Text do
|
3
|
+
describe Munger::Render::Text do
|
4
4
|
include MungerSpecHelper
|
5
|
-
|
6
|
-
before(:each) do
|
5
|
+
|
6
|
+
before(:each) do
|
7
7
|
@data = Munger::Data.new(:data => test_data)
|
8
8
|
@report = Munger::Report.new(:data => @data)
|
9
9
|
end
|
10
10
|
|
11
11
|
it "should accept a Munger::Report object" do
|
12
|
-
Munger::Render::Text.new(@report.process).
|
12
|
+
Munger::Render::Text.new(@report.process).must_be :valid?
|
13
13
|
end
|
14
|
-
|
14
|
+
|
15
15
|
it "should render a basic text table" do
|
16
16
|
@render = Munger::Render::Text.new(@report.process)
|
17
17
|
count = @report.rows
|
18
18
|
text = @render.render
|
19
|
-
text.split("\n").
|
19
|
+
text.split("\n").size.must_be :>, count
|
20
20
|
end
|
21
|
-
|
22
|
-
end
|
21
|
+
|
22
|
+
end
|
data/test/test_helper.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
require "minitest/autorun"
|
2
|
+
require "minitest/pride"
|
3
|
+
require "munger"
|
4
|
+
|
5
|
+
require "fileutils"
|
6
|
+
require "logger"
|
7
|
+
require "pp"
|
8
|
+
require "date"
|
9
|
+
|
10
|
+
# Load support files
|
11
|
+
Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
|
12
|
+
|
13
|
+
module MungerSpecHelper
|
14
|
+
def test_data
|
15
|
+
[{:name => "Scott", :age => 23, :day => 1, :score => 12},
|
16
|
+
{:name => "Chaz", :age => 28, :day => 1, :score => 12},
|
17
|
+
{:name => "Scott", :age => 23, :day => 2, :score => 1},
|
18
|
+
{:name => "Janet", :age => 32, :day => 2, :score => 24},
|
19
|
+
{:name => "Rich", :age => 32, :day => 2, :score => 14},
|
20
|
+
{:name => "Gordon", :age => 33, :day => 1, :score => 21},
|
21
|
+
{:name => "Scott", :age => 23, :day => 1, :score => 31},
|
22
|
+
{:name => "Alice", :age => 33, :day => 1, :score => 12},
|
23
|
+
{:name => "Alice", :age => 34, :day => 2, :score => 12},
|
24
|
+
{:name => "Alice", :age => 33, :day => 2, :score => 12}
|
25
|
+
]
|
26
|
+
end
|
27
|
+
|
28
|
+
def more_test_data
|
29
|
+
[{:name => "David", :age => 40, :day => 1, :score => 12},
|
30
|
+
{:name => "Michael", :age => 32, :day => 2, :score => 20},
|
31
|
+
{:name => "David", :age => 40, :day => 2, :score => 13},
|
32
|
+
{:name => "Michael", :age => 28, :day => 1, :score => 15}]
|
33
|
+
end
|
34
|
+
|
35
|
+
def invalid_test_data
|
36
|
+
["one", "two", "three"]
|
37
|
+
end
|
38
|
+
|
39
|
+
def test_ar_data
|
40
|
+
test_data.map{|r| ARLike.new(r)}
|
41
|
+
end
|
42
|
+
|
43
|
+
end
|
44
|
+
|
45
|
+
# Hack to provide assertion for tags without needing
|
46
|
+
# hpricot or Nokogiri
|
47
|
+
module Minitest::Assertions
|
48
|
+
def assert_has_tag(tag, html, options = {})
|
49
|
+
tag = tag.split(".").join("|") if tag.include?(".")
|
50
|
+
# ignore options for now
|
51
|
+
assert html.match(/#{tag}/)
|
52
|
+
end
|
53
|
+
|
54
|
+
def refute_has_tag(tag, html, options = {})
|
55
|
+
refute html.match(/#{tag}/)
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
String.infect_an_assertion :assert_has_tag, :must_have_tag
|
60
|
+
String.infect_an_assertion :refute_has_tag, :wont_have_tag
|