table_print 0.2.3 → 1.0.0.rc3
Sign up to get free protection for your applications and to get access to all the features.
- data/.rspec +1 -0
- data/.rvmrc +1 -1
- data/.travis.yml +5 -0
- data/Gemfile +11 -10
- data/README.rdoc +85 -32
- data/Rakefile +13 -13
- data/VERSION +1 -1
- data/features/adding_columns.feature +48 -0
- data/features/configuring_output.feature +57 -0
- data/features/excluding_columns.feature +28 -0
- data/features/sensible_defaults.feature +86 -0
- data/features/support/step_definitions/before.rb +3 -0
- data/features/support/step_definitions/steps.rb +77 -0
- data/lib/cattr.rb +46 -0
- data/lib/column.rb +45 -0
- data/lib/config.rb +36 -0
- data/lib/config_resolver.rb +91 -0
- data/lib/fingerprinter.rb +85 -0
- data/lib/formatter.rb +45 -0
- data/lib/hash_extensions.rb +37 -0
- data/lib/kernel_extensions.rb +12 -0
- data/lib/printable.rb +22 -0
- data/lib/returnable.rb +21 -0
- data/lib/row_group.rb +227 -0
- data/lib/table_print.rb +33 -389
- data/spec/column_spec.rb +71 -0
- data/spec/config_resolver_spec.rb +236 -0
- data/spec/config_spec.rb +52 -0
- data/spec/fingerprinter_spec.rb +151 -0
- data/spec/formatter_spec.rb +78 -0
- data/spec/hash_extensions_spec.rb +21 -0
- data/spec/printable_spec.rb +51 -0
- data/spec/returnable_spec.rb +23 -0
- data/spec/row_group_spec.rb +466 -0
- data/spec/spec_helper.rb +8 -0
- data/spec/table_print_spec.rb +59 -0
- data/table_print.gemspec +50 -26
- metadata +147 -68
- data/Gemfile.lock +0 -20
- data/test/helper.rb +0 -56
- data/test/test_column.rb +0 -379
- data/test/test_table_print.rb +0 -162
@@ -0,0 +1,78 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require "formatter"
|
3
|
+
|
4
|
+
include TablePrint
|
5
|
+
|
6
|
+
describe TablePrint::TimeFormatter do
|
7
|
+
describe "#format" do
|
8
|
+
it "only operates on Time objects" do
|
9
|
+
f = TablePrint::TimeFormatter.new
|
10
|
+
f.format(12).should == 12
|
11
|
+
end
|
12
|
+
|
13
|
+
it "uses the config'd time_format" do
|
14
|
+
f = TablePrint::TimeFormatter.new
|
15
|
+
time = Time.local(2012, 01, 11, 1, 23, 45)
|
16
|
+
f.format(time).should == "2012-01-11 01:23:45" # default time format is set in config.rb
|
17
|
+
end
|
18
|
+
|
19
|
+
it "overrides the config'd time format with one it was passed" do
|
20
|
+
f = TablePrint::TimeFormatter.new("%Y")
|
21
|
+
time = Time.local(2012, 01, 11, 1, 23, 45)
|
22
|
+
f.format(time).should == "2012" # default time format is set in config.rb
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
describe TablePrint::NoNewlineFormatter do
|
28
|
+
before(:each) do
|
29
|
+
@f = TablePrint::NoNewlineFormatter.new
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#format" do
|
33
|
+
it "replaces carriage returns with spaces" do
|
34
|
+
@f.format("foo\r\nbar").should == "foo bar"
|
35
|
+
end
|
36
|
+
|
37
|
+
it "replaces newlines with spaces" do
|
38
|
+
@f.format("foo\nbar").should == "foo bar"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
describe TablePrint::FixedWidthFormatter do
|
44
|
+
before(:each) do
|
45
|
+
@f = TablePrint::FixedWidthFormatter.new(10)
|
46
|
+
end
|
47
|
+
|
48
|
+
describe "#format" do
|
49
|
+
it "pads a short field to the specified width" do
|
50
|
+
@f.format("asdf").should == "asdf "
|
51
|
+
end
|
52
|
+
|
53
|
+
it "truncates long fields with periods" do
|
54
|
+
@f.format("1234567890123456").should == "1234567..."
|
55
|
+
end
|
56
|
+
|
57
|
+
it "uses an empty string in place of nils" do
|
58
|
+
@f.format(nil).should == " "
|
59
|
+
end
|
60
|
+
|
61
|
+
it "turns objects into strings before trying to format them" do
|
62
|
+
@f.format(123).should == "123 "
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#width" do
|
67
|
+
it "returns the width" do
|
68
|
+
@f.width.should == 10
|
69
|
+
end
|
70
|
+
|
71
|
+
it "respects the config'd max_width" do
|
72
|
+
max = TablePrint::Config.max_width
|
73
|
+
TablePrint::Config.max_width = 5
|
74
|
+
@f.width.should == 5
|
75
|
+
TablePrint::Config.max_width = max
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'hash_extensions'
|
3
|
+
|
4
|
+
describe "#constructive_merge" do
|
5
|
+
it "merges hashes without clobbering" do
|
6
|
+
x = {'reviews' => {'user' => {}}}
|
7
|
+
y = {'reviews' => {'ratings' => {}}}
|
8
|
+
x.extend TablePrint::HashExtensions::ConstructiveMerge
|
9
|
+
x.constructive_merge(y).should == {'reviews' => {'user' => {}, 'ratings' => {}}}
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
describe "#constructive_merge!" do
|
14
|
+
it "merges hashes in place without clobbering" do
|
15
|
+
x = {'reviews' => {'user' => {}}}
|
16
|
+
y = {'reviews' => {'ratings' => {}}}
|
17
|
+
x.extend TablePrint::HashExtensions::ConstructiveMerge
|
18
|
+
x.constructive_merge!(y)
|
19
|
+
x.should == {'reviews' => {'user' => {}, 'ratings' => {}}}
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'printable'
|
3
|
+
|
4
|
+
describe TablePrint::Printable do
|
5
|
+
before(:each) do
|
6
|
+
Sandbox.cleanup!
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#default_display_methods" do
|
10
|
+
it "returns attribute getters" do
|
11
|
+
Sandbox.add_class("Hat")
|
12
|
+
Sandbox.add_attributes("Hat", "brand")
|
13
|
+
|
14
|
+
p = Sandbox::Hat.new
|
15
|
+
TablePrint::Printable.default_display_methods(p).should == %W(brand)
|
16
|
+
end
|
17
|
+
|
18
|
+
it "ignores dangerous methods" do
|
19
|
+
Sandbox.add_class("Hat")
|
20
|
+
Sandbox.add_method("Hat", "brand!") {}
|
21
|
+
|
22
|
+
p = Sandbox::Hat.new
|
23
|
+
TablePrint::Printable.default_display_methods(p).should == []
|
24
|
+
end
|
25
|
+
|
26
|
+
it "ignores methods defined in a superclass" do
|
27
|
+
Sandbox.add_class("Hat::Bowler")
|
28
|
+
Sandbox.add_attributes("Hat", "brand")
|
29
|
+
Sandbox.add_attributes("Hat::Bowler", "brim_width")
|
30
|
+
|
31
|
+
p = Sandbox::Hat::Bowler.new
|
32
|
+
TablePrint::Printable.default_display_methods(p).should == %W(brim_width)
|
33
|
+
end
|
34
|
+
|
35
|
+
it "ignores methods that require arguments" do
|
36
|
+
Sandbox.add_class("Hat")
|
37
|
+
Sandbox.add_attributes("Hat", "brand")
|
38
|
+
Sandbox.add_method("Hat", "tip?") { |person| person.rapscallion? }
|
39
|
+
|
40
|
+
p = Sandbox::Hat.new
|
41
|
+
TablePrint::Printable.default_display_methods(p).should == %W(brand)
|
42
|
+
end
|
43
|
+
|
44
|
+
it "ignores methods from an included module" do
|
45
|
+
pending "waiting for Cat to support module manipulation"
|
46
|
+
end
|
47
|
+
|
48
|
+
it "uses column information when available (eg, from ActiveRecord objects)"
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'returnable'
|
3
|
+
require 'config'
|
4
|
+
|
5
|
+
describe TablePrint::Returnable do
|
6
|
+
it "returns its initialized value from its to_s method" do
|
7
|
+
r = TablePrint::Returnable.new("foobar")
|
8
|
+
r.to_s.should == "foobar"
|
9
|
+
end
|
10
|
+
|
11
|
+
it "passes #set through to TablePrint::Config" do
|
12
|
+
TablePrint::Config.should_receive(:set).with(Object, [:foo])
|
13
|
+
r = TablePrint::Returnable.new
|
14
|
+
r.set(Object, :foo)
|
15
|
+
end
|
16
|
+
|
17
|
+
it "passes #clear through to TablePrint::Config" do
|
18
|
+
TablePrint::Config.should_receive(:clear).with(Object)
|
19
|
+
r = TablePrint::Returnable.new
|
20
|
+
r.clear(Object)
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
@@ -0,0 +1,466 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'ostruct'
|
3
|
+
require 'cat'
|
4
|
+
require "row_group"
|
5
|
+
|
6
|
+
include TablePrint
|
7
|
+
|
8
|
+
describe RowRecursion do
|
9
|
+
let(:parent) { RowGroup.new }
|
10
|
+
let(:child) { Row.new }
|
11
|
+
|
12
|
+
describe "#set_column" do
|
13
|
+
it "assigns the column object to the column name" do
|
14
|
+
column = Column.new
|
15
|
+
parent.set_column(:foobar, column)
|
16
|
+
parent.column_for(:foobar).should == column
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe "#add_child" do
|
21
|
+
it "adds the child to my children" do
|
22
|
+
parent.add_child(child)
|
23
|
+
parent.child_count.should == 1
|
24
|
+
end
|
25
|
+
|
26
|
+
it "sets me as my child's parent" do
|
27
|
+
parent.add_child(child)
|
28
|
+
child.parent.should == parent
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
describe "#add_children" do
|
33
|
+
let (:child2) {Row.new}
|
34
|
+
|
35
|
+
it "adds all the children to myself" do
|
36
|
+
parent.add_children([child, child2])
|
37
|
+
parent.child_count.should == 2
|
38
|
+
end
|
39
|
+
|
40
|
+
it "sets me as their parent" do
|
41
|
+
parent.add_children([child, child2])
|
42
|
+
child.parent.should == parent
|
43
|
+
child2.parent.should == parent
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "#columns" do
|
48
|
+
it "returns columns populated with names and data" do
|
49
|
+
child.set_cell_values(:title => 'foobar')
|
50
|
+
parent.add_child(child)
|
51
|
+
|
52
|
+
parent.columns.length.should == 1
|
53
|
+
parent.columns.first.name.should == 'title'
|
54
|
+
parent.columns.first.data.should == ['foobar']
|
55
|
+
end
|
56
|
+
|
57
|
+
it "gets the columns from the root node" do
|
58
|
+
parent.add_child(child)
|
59
|
+
child.set_cell_values(:title => 'foobar')
|
60
|
+
|
61
|
+
parent.columns.length.should == 1
|
62
|
+
child.columns.should == parent.columns
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#column_for" do
|
67
|
+
it "returns the column object for a given column name" do
|
68
|
+
parent.add_child(child)
|
69
|
+
child.set_cell_values(:title => 'foobar')
|
70
|
+
column = parent.columns.first
|
71
|
+
parent.column_for(:title).should == column
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
describe "#add_formatter" do
|
76
|
+
it "adds the formatter to the column object" do
|
77
|
+
parent.add_child(child)
|
78
|
+
child.set_cell_values(:title => 'foobar')
|
79
|
+
column = parent.columns.first
|
80
|
+
parent.add_formatter(:title, {})
|
81
|
+
|
82
|
+
column.formatters.should == [{}]
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
describe "#width" do
|
87
|
+
it "returns the total width of the columns" do
|
88
|
+
parent.add_child(r1 = Row.new)
|
89
|
+
parent.add_child(r2 = Row.new)
|
90
|
+
|
91
|
+
r1.set_cell_values(:title => 'foobar')
|
92
|
+
r2.set_cell_values(:subtitle => 'elemental')
|
93
|
+
|
94
|
+
parent.width.should == 18
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
describe "#horizontal_separator" do
|
99
|
+
it "returns hyphens equal to the table width" do
|
100
|
+
child.set_cell_values(:title => 'foobar')
|
101
|
+
child.horizontal_separator.should == '------'
|
102
|
+
end
|
103
|
+
|
104
|
+
it "matches the header width" do
|
105
|
+
child.set_cell_values(:title => 'foobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobarfoobar')
|
106
|
+
child.horizontal_separator.should == '------------------------------' # 30 hyphens
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
describe "#header" do
|
111
|
+
it "returns the column names, padded to the proper width, separated by the | character" do
|
112
|
+
child.set_cell_values(:title => 'first post', :author => 'chris', :subtitle => 'first is the worst')
|
113
|
+
compare_rows(child.header, "AUTHOR | SUBTITLE | TITLE ")
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
describe TablePrint::RowGroup do
|
119
|
+
describe "#raw_column_data" do
|
120
|
+
it "returns the column data from its child rows" do
|
121
|
+
group = RowGroup.new
|
122
|
+
group.add_child(Row.new.set_cell_values(:title => 'foo'))
|
123
|
+
group.add_child(Row.new.set_cell_values(:title => 'bar'))
|
124
|
+
group.raw_column_data(:title).should == ['foo', 'bar']
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
def compare_rows(actual_rows, expected_rows)
|
130
|
+
actual_rows.split("\n").length.should == expected_rows.split("\n").length
|
131
|
+
actual_rows.split("\n").zip(expected_rows.split("\n")).each do |actual, expected|
|
132
|
+
actual.split(//).sort.join.should == expected.split(//).sort.join
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
describe TablePrint::Row do
|
137
|
+
let(:row) { Row.new.set_cell_values({'title' => "wonky", 'author' => "bob jones", 'pub_date' => "2012"}) }
|
138
|
+
|
139
|
+
describe "#format" do
|
140
|
+
it "formats the row with padding" do
|
141
|
+
compare_rows(row.format, "wonky | bob jones | 2012 ")
|
142
|
+
end
|
143
|
+
|
144
|
+
it "also formats the children" do
|
145
|
+
row.add_child(RowGroup.new.add_child(Row.new.set_cell_values(:title => "wonky2", :author => "bob jones2", :pub_date => "20122")))
|
146
|
+
compare_rows(row.format, "wonky | bob jones | 2012 \nwonky2 | bob jones2 | 20122 ")
|
147
|
+
end
|
148
|
+
end
|
149
|
+
|
150
|
+
describe "#apply_formatters" do
|
151
|
+
it "calls the format method on each formatter for that column" do
|
152
|
+
Sandbox.add_class("DoubleFormatter")
|
153
|
+
Sandbox.add_method("DoubleFormatter", :format) { |value| value * 2 }
|
154
|
+
|
155
|
+
Sandbox.add_class("ChopFormatter")
|
156
|
+
Sandbox.add_method("ChopFormatter", :format) { |value| value[0..-2] }
|
157
|
+
|
158
|
+
f1 = Sandbox::DoubleFormatter.new
|
159
|
+
f2 = Sandbox::ChopFormatter.new
|
160
|
+
|
161
|
+
row.stub(:column_for) {OpenStruct.new(:width => 11, :formatters => [f1, f2])}
|
162
|
+
|
163
|
+
row.apply_formatters(:title, "foobar").should == "foobarfooba"
|
164
|
+
end
|
165
|
+
|
166
|
+
it "uses the config'd time_format to format times" do
|
167
|
+
row.stub(:column_for) {OpenStruct.new(:width => 20, :formatters => [], :time_format => "%Y %m %d")}
|
168
|
+
|
169
|
+
time_formatter = TablePrint::TimeFormatter.new
|
170
|
+
TablePrint::TimeFormatter.should_receive(:new).with("%Y %m %d") {time_formatter}
|
171
|
+
row.apply_formatters(:title, Time.local(2012, 6, 1, 14, 20, 20))
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
describe "#raw_column_data" do
|
176
|
+
it "returns all the values for a given column" do
|
177
|
+
row = Row.new.set_cell_values(:title => 'one', :author => 'two')
|
178
|
+
|
179
|
+
group = RowGroup.new
|
180
|
+
['two', 'three', 'four', 'five', 'six', 'seven'].each do |title|
|
181
|
+
group.add_child(Row.new.set_cell_values(:title => title))
|
182
|
+
end
|
183
|
+
row.add_child(group)
|
184
|
+
|
185
|
+
row.raw_column_data('title').should == ['one', 'two', 'three', 'four', 'five', 'six', 'seven']
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
describe "#collapse" do
|
190
|
+
|
191
|
+
# row: foo
|
192
|
+
# group
|
193
|
+
# row: bar
|
194
|
+
# => foo | bar
|
195
|
+
context "for a single row in a single child group" do
|
196
|
+
before(:each) do
|
197
|
+
@row = Row.new
|
198
|
+
@row.set_cell_values(:foo => "foo").add_child(
|
199
|
+
RowGroup.new.add_child(
|
200
|
+
Row.new.set_cell_values(:bar => "bar")
|
201
|
+
)
|
202
|
+
)
|
203
|
+
@row.collapse!
|
204
|
+
end
|
205
|
+
|
206
|
+
it "pulls the cells up into the parent" do
|
207
|
+
@row.cells.should == {"foo" => "foo", "bar" => "bar"}
|
208
|
+
end
|
209
|
+
|
210
|
+
it "dereferences the now-defunct group" do
|
211
|
+
@row.children.length.should == 0
|
212
|
+
end
|
213
|
+
end
|
214
|
+
|
215
|
+
# row: foo
|
216
|
+
# group
|
217
|
+
# row: bar
|
218
|
+
# row: baz
|
219
|
+
# => foo | bar
|
220
|
+
# | baz
|
221
|
+
context "for two rows in a single child group" do
|
222
|
+
before(:each) do
|
223
|
+
@row = Row.new
|
224
|
+
@row.set_cell_values(:foo => "foo").add_child(
|
225
|
+
RowGroup.new.add_children([
|
226
|
+
Row.new.set_cell_values(:bar => "bar"),
|
227
|
+
Row.new.set_cell_values(:bar => "baz")
|
228
|
+
])
|
229
|
+
)
|
230
|
+
@row.collapse!
|
231
|
+
end
|
232
|
+
|
233
|
+
it "pulls the cells from the first row up into the parent" do
|
234
|
+
@row.cells.should == {"foo" => "foo", "bar" => "bar"}
|
235
|
+
end
|
236
|
+
|
237
|
+
it "deletes the absorbed row but leaves the second row in the group" do
|
238
|
+
@row.children.length.should == 1
|
239
|
+
@row.children.first.children.length.should == 1
|
240
|
+
@row.children.first.children.first.cells.should == {"bar" => "baz"}
|
241
|
+
end
|
242
|
+
end
|
243
|
+
|
244
|
+
# row: foo
|
245
|
+
# group
|
246
|
+
# row: bar
|
247
|
+
# group
|
248
|
+
# row: baz
|
249
|
+
# => foo | bar | baz
|
250
|
+
context "for two groups with a single row each" do
|
251
|
+
before(:each) do
|
252
|
+
@row = Row.new
|
253
|
+
@row.set_cell_values(:foo => "foo").add_children([
|
254
|
+
RowGroup.new.add_child(
|
255
|
+
Row.new.set_cell_values(:bar => "bar")
|
256
|
+
),
|
257
|
+
RowGroup.new.add_child(
|
258
|
+
Row.new.set_cell_values(:baz => "baz")
|
259
|
+
)
|
260
|
+
])
|
261
|
+
@row.collapse!
|
262
|
+
end
|
263
|
+
|
264
|
+
it "pulls the cells from both groups into the parent" do
|
265
|
+
@row.cells.should == {"foo" => "foo", "bar" => "bar", "baz" => "baz"}
|
266
|
+
end
|
267
|
+
|
268
|
+
it "dereferences both now-defunct groups" do
|
269
|
+
@row.children.length.should == 0
|
270
|
+
end
|
271
|
+
end
|
272
|
+
|
273
|
+
# row: foo
|
274
|
+
# group
|
275
|
+
# row: bar
|
276
|
+
# group
|
277
|
+
# row: baz
|
278
|
+
# row: bazaar
|
279
|
+
# => foo | bar | baz
|
280
|
+
# | bazaar
|
281
|
+
context "for two groups, one with a single row and one with two rows" do
|
282
|
+
before(:each) do
|
283
|
+
@row = Row.new
|
284
|
+
@row.set_cell_values(:foo => "foo").add_children([
|
285
|
+
RowGroup.new.add_child(
|
286
|
+
Row.new.set_cell_values(:bar => "bar")
|
287
|
+
),
|
288
|
+
RowGroup.new.add_children([
|
289
|
+
Row.new.set_cell_values(:baz => "baz"),
|
290
|
+
Row.new.set_cell_values(:baz => "bazaar"),
|
291
|
+
]),
|
292
|
+
])
|
293
|
+
@row.collapse!
|
294
|
+
end
|
295
|
+
|
296
|
+
it "pulls the single row and the first row from the double into itself" do
|
297
|
+
@row.cells.should == {"foo" => "foo", "bar" => "bar", "baz" => "baz"}
|
298
|
+
end
|
299
|
+
|
300
|
+
it "keeps the second row from the second group in its own group" do
|
301
|
+
@row.children.length.should == 1
|
302
|
+
@row.children.first.children.length.should == 1
|
303
|
+
@row.children.first.children.first.cells.should == {"baz" => "bazaar"}
|
304
|
+
end
|
305
|
+
end
|
306
|
+
|
307
|
+
# row: foo
|
308
|
+
# group
|
309
|
+
# row: bar
|
310
|
+
# group
|
311
|
+
# row: baz
|
312
|
+
# => foo | bar | baz
|
313
|
+
context "for two nested groups, each with one row" do
|
314
|
+
before(:each) do
|
315
|
+
@row = Row.new
|
316
|
+
@row.set_cell_values(:foo => "foo").add_child(
|
317
|
+
RowGroup.new.add_child(
|
318
|
+
Row.new.set_cell_values(:bar => "bar").add_child(
|
319
|
+
RowGroup.new.add_child(
|
320
|
+
Row.new.set_cell_values(:baz => "baz")
|
321
|
+
)
|
322
|
+
)
|
323
|
+
)
|
324
|
+
)
|
325
|
+
@row.collapse!
|
326
|
+
end
|
327
|
+
|
328
|
+
it "pulls the cells from both groups into the parent" do
|
329
|
+
@row.cells.should == {"foo" => "foo", "bar" => "bar", "baz" => "baz"}
|
330
|
+
end
|
331
|
+
|
332
|
+
it "dereferences both now-defunct groups" do
|
333
|
+
@row.children.length.should == 0
|
334
|
+
end
|
335
|
+
end
|
336
|
+
|
337
|
+
# row: foo
|
338
|
+
# group
|
339
|
+
# row: bar
|
340
|
+
# group
|
341
|
+
# row: baz
|
342
|
+
# row: bazaar
|
343
|
+
# => foo | bar | baz
|
344
|
+
# | bazaar
|
345
|
+
context "for a child with one row, which itself has multiple rows" do
|
346
|
+
before(:each) do
|
347
|
+
@row = Row.new
|
348
|
+
@row.set_cell_values(:foo => "foo").add_child(
|
349
|
+
RowGroup.new.add_child(
|
350
|
+
Row.new.set_cell_values(:bar => "bar").add_child(
|
351
|
+
RowGroup.new.add_children([
|
352
|
+
Row.new.set_cell_values(:baz => "baz"),
|
353
|
+
Row.new.set_cell_values(:baz => "bazaar")
|
354
|
+
])
|
355
|
+
)
|
356
|
+
)
|
357
|
+
)
|
358
|
+
@row.collapse!
|
359
|
+
end
|
360
|
+
|
361
|
+
it "pulls the first row from each group up into itself" do
|
362
|
+
@row.cells.should == {"foo" => "foo", "bar" => "bar", "baz" => "baz"}
|
363
|
+
end
|
364
|
+
|
365
|
+
it "deletes only the intermediary group" do
|
366
|
+
@row.children.length.should == 1
|
367
|
+
@row.children.first.children.length.should == 1
|
368
|
+
@row.children.first.children.first.cells.should == {"baz" => "bazaar"}
|
369
|
+
end
|
370
|
+
end
|
371
|
+
|
372
|
+
# row: foo
|
373
|
+
# group
|
374
|
+
# row: bar
|
375
|
+
# row: bar2
|
376
|
+
# group
|
377
|
+
# row: bazaar
|
378
|
+
# row: bazaar2
|
379
|
+
# => foo | bar |
|
380
|
+
# | bar2 |
|
381
|
+
# | | bazaar
|
382
|
+
# | | bazaar2
|
383
|
+
context "for multiple children with multiple rows" do
|
384
|
+
before(:each) do
|
385
|
+
@row = Row.new
|
386
|
+
@row.set_cell_values(:foo => "foo").add_children([
|
387
|
+
RowGroup.new.add_children([
|
388
|
+
Row.new.set_cell_values(:bar => "bar"),
|
389
|
+
Row.new.set_cell_values(:bar => "bar2"),
|
390
|
+
]),
|
391
|
+
RowGroup.new.add_children([
|
392
|
+
Row.new.set_cell_values(:baz => "bazaar"),
|
393
|
+
Row.new.set_cell_values(:baz => "bazaar2"),
|
394
|
+
])
|
395
|
+
])
|
396
|
+
@row.collapse!
|
397
|
+
end
|
398
|
+
|
399
|
+
it "pulls the first row from the first group into the parent" do
|
400
|
+
@row.cells.should == {"foo" => "foo", "bar" => "bar"}
|
401
|
+
end
|
402
|
+
|
403
|
+
it "leaves the second row in the first group" do
|
404
|
+
@row.children.length.should == 2
|
405
|
+
@row.children.first.children.length.should == 1
|
406
|
+
@row.children.first.children.first.cells.should == {"bar" => "bar2"}
|
407
|
+
end
|
408
|
+
|
409
|
+
it "leaves the second group alone" do
|
410
|
+
@row.children.last.children.length.should == 2
|
411
|
+
@row.children.last.children.first.cells.should == {"baz" => "bazaar"}
|
412
|
+
@row.children.last.children.last.cells.should == {"baz" => "bazaar2"}
|
413
|
+
end
|
414
|
+
end
|
415
|
+
|
416
|
+
# row: foo
|
417
|
+
# group
|
418
|
+
# row: bar
|
419
|
+
# group
|
420
|
+
# row: bare
|
421
|
+
# row: bart
|
422
|
+
# row: baz
|
423
|
+
# group
|
424
|
+
# row: bazaar
|
425
|
+
# row: bizarre
|
426
|
+
# => foo | bar | bare
|
427
|
+
# | | bart
|
428
|
+
# | baz | bazaar
|
429
|
+
# | | bizarre
|
430
|
+
context "for multiple children with multiple children" do
|
431
|
+
before(:each) do
|
432
|
+
@row = Row.new
|
433
|
+
@row.set_cell_values(:foo => "foo").add_child(
|
434
|
+
RowGroup.new.add_children([
|
435
|
+
Row.new.set_cell_values(:bar => "bar").add_child(
|
436
|
+
RowGroup.new.add_children([
|
437
|
+
Row.new.set_cell_values(:barry => "bare"),
|
438
|
+
Row.new.set_cell_values(:barry => "bart")
|
439
|
+
])
|
440
|
+
),
|
441
|
+
Row.new.set_cell_values(:bar => "baz").add_child(
|
442
|
+
RowGroup.new.add_children([
|
443
|
+
Row.new.set_cell_values(:barry => "bazaar"),
|
444
|
+
Row.new.set_cell_values(:barry => "bizarre")
|
445
|
+
])
|
446
|
+
)
|
447
|
+
])
|
448
|
+
)
|
449
|
+
@row.collapse!
|
450
|
+
end
|
451
|
+
|
452
|
+
it "pulls the first row from the first child into itself" do
|
453
|
+
@row.cells.should == {"foo" => "foo", "bar" => "bar", "barry" => "bare"}
|
454
|
+
end
|
455
|
+
|
456
|
+
it "leaves the second row from the first child in the first group" do
|
457
|
+
@row.children.first.children.first.cells.should == {"barry" => "bart"}
|
458
|
+
end
|
459
|
+
|
460
|
+
it "collapses the second group" do
|
461
|
+
@row.children.last.children.first.cells.should == {"bar" => "baz", "barry" => "bazaar"}
|
462
|
+
@row.children.last.children.first.children.first.children.first.cells.should == {"barry" => "bizarre"}
|
463
|
+
end
|
464
|
+
end
|
465
|
+
end
|
466
|
+
end
|