ruport 1.0.2 → 1.2.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.
- data/AUTHORS +3 -0
- data/README +11 -5
- data/Rakefile +2 -2
- data/examples/btree/commaleon/commaleon.rb +1 -1
- data/examples/simple_templating_example.rb +34 -0
- data/examples/tattle_rubygems_version.rb +6 -5
- data/examples/trac_ticket_status.rb +2 -2
- data/lib/ruport.rb +5 -4
- data/lib/ruport/acts_as_reportable.rb +63 -37
- data/lib/ruport/data.rb +1 -0
- data/lib/ruport/data/feeder.rb +111 -0
- data/lib/ruport/data/grouping.rb +84 -22
- data/lib/ruport/data/record.rb +1 -1
- data/lib/ruport/data/table.rb +127 -87
- data/lib/ruport/formatter.rb +22 -9
- data/lib/ruport/formatter/csv.rb +27 -3
- data/lib/ruport/formatter/html.rb +26 -6
- data/lib/ruport/formatter/pdf.rb +169 -36
- data/lib/ruport/formatter/template.rb +167 -0
- data/lib/ruport/formatter/text.rb +47 -15
- data/lib/ruport/query.rb +1 -1
- data/lib/ruport/renderer.rb +46 -56
- data/test/acts_as_reportable_test.rb +20 -20
- data/test/csv_formatter_test.rb +26 -1
- data/test/data_feeder_test.rb +88 -0
- data/test/grouping_test.rb +90 -4
- data/test/html_formatter_test.rb +25 -2
- data/test/pdf_formatter_test.rb +69 -3
- data/test/query_test.rb +3 -2
- data/test/record_test.rb +2 -1
- data/test/renderer_test.rb +49 -3
- data/test/sql_split_test.rb +4 -2
- data/test/table_test.rb +159 -65
- data/test/template_test.rb +37 -0
- data/test/text_formatter_test.rb +33 -1
- metadata +9 -4
- data/lib/ruport/renderer.rb.orig +0 -542
- data/test/renderer_test.rb.orig +0 -512
data/test/renderer_test.rb.orig
DELETED
@@ -1,512 +0,0 @@
|
|
1
|
-
require 'test/helpers'
|
2
|
-
|
3
|
-
###########################################################################
|
4
|
-
#
|
5
|
-
# NOTE:
|
6
|
-
#
|
7
|
-
# As it stands, we haven't found a more clever way to test the formatting
|
8
|
-
# system than to just create a bunch of renderers and basic formatters for
|
9
|
-
# different concepts we're trying to test. Patches and ideas welcome:
|
10
|
-
#
|
11
|
-
# list.rubyreports.org
|
12
|
-
############################################################################
|
13
|
-
|
14
|
-
#============================================================================
|
15
|
-
# These two renderers represent the two styles that can be used when defining
|
16
|
-
# renderers in Ruport. The OldSchoolRenderer approach has largely been
|
17
|
-
# deprecated, but still has uses in edge cases that we need to support.
|
18
|
-
#============================================================================
|
19
|
-
|
20
|
-
class OldSchoolRenderer < Ruport::Renderer
|
21
|
-
|
22
|
-
def run
|
23
|
-
formatter do
|
24
|
-
build_header
|
25
|
-
build_body
|
26
|
-
build_footer
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
end
|
31
|
-
|
32
|
-
class VanillaRenderer < Ruport::Renderer
|
33
|
-
stage :header,:body,:footer
|
34
|
-
end
|
35
|
-
|
36
|
-
|
37
|
-
# This formatter implements some junk output so we can be sure
|
38
|
-
# that the hooks are being set up right. Perhaps these could
|
39
|
-
# be replaced by mock objects in the future.
|
40
|
-
class DummyText < Ruport::Formatter
|
41
|
-
|
42
|
-
renders :text, :for => OldSchoolRenderer
|
43
|
-
|
44
|
-
def prepare_document
|
45
|
-
output << "p"
|
46
|
-
end
|
47
|
-
|
48
|
-
def build_header
|
49
|
-
output << "header\n"
|
50
|
-
end
|
51
|
-
|
52
|
-
def build_body
|
53
|
-
output << "body\n"
|
54
|
-
end
|
55
|
-
|
56
|
-
def build_footer
|
57
|
-
output << "footer\n"
|
58
|
-
end
|
59
|
-
|
60
|
-
def finalize_document
|
61
|
-
output << "f"
|
62
|
-
end
|
63
|
-
end
|
64
|
-
|
65
|
-
|
66
|
-
class TestRenderer < Test::Unit::TestCase
|
67
|
-
|
68
|
-
def test_trivial
|
69
|
-
actual = OldSchoolRenderer.render(:text)
|
70
|
-
assert_equal "header\nbody\nfooter\n", actual
|
71
|
-
end
|
72
|
-
|
73
|
-
def test_using_io
|
74
|
-
require "stringio"
|
75
|
-
out = StringIO.new
|
76
|
-
a = OldSchoolRenderer.render(:text) { |r| r.io = out }
|
77
|
-
out.rewind
|
78
|
-
assert_equal "header\nbody\nfooter\n", out.read
|
79
|
-
assert_equal "", out.read
|
80
|
-
end
|
81
|
-
|
82
|
-
def test_formats
|
83
|
-
assert_equal( {}, Ruport::Renderer.formats )
|
84
|
-
assert_equal( { :text => DummyText },OldSchoolRenderer.formats )
|
85
|
-
end
|
86
|
-
|
87
|
-
def test_method_missing
|
88
|
-
actual = OldSchoolRenderer.render_text
|
89
|
-
assert_equal "header\nbody\nfooter\n", actual
|
90
|
-
end
|
91
|
-
|
92
|
-
def test_formatter
|
93
|
-
# normal instance mode
|
94
|
-
rend = OldSchoolRenderer.new
|
95
|
-
rend.send(:use_formatter,:text)
|
96
|
-
|
97
|
-
assert_kind_of Ruport::Formatter, rend.formatter
|
98
|
-
assert_kind_of DummyText, rend.formatter
|
99
|
-
|
100
|
-
# render mode
|
101
|
-
OldSchoolRenderer.render_text do |r|
|
102
|
-
assert_kind_of Ruport::Formatter, r.formatter
|
103
|
-
assert_kind_of DummyText, r.formatter
|
104
|
-
end
|
105
|
-
|
106
|
-
assert_equal "body\n", rend.formatter { build_body }.output
|
107
|
-
|
108
|
-
rend.formatter.clear_output
|
109
|
-
assert_equal "", rend.formatter.output
|
110
|
-
end
|
111
|
-
|
112
|
-
def test_options_act_like_indifferent_hash
|
113
|
-
opts = Ruport::Renderer::Options.new
|
114
|
-
opts.foo = "bar"
|
115
|
-
assert_equal "bar", opts[:foo]
|
116
|
-
assert_equal "bar", opts["foo"]
|
117
|
-
|
118
|
-
opts["f"] = "bar"
|
119
|
-
assert_equal "bar", opts[:f]
|
120
|
-
assert_equal "bar", opts.f
|
121
|
-
assert_equal "bar", opts["f"]
|
122
|
-
|
123
|
-
opts[:apple] = "banana"
|
124
|
-
assert_equal "banana", opts.apple
|
125
|
-
assert_equal "banana", opts["apple"]
|
126
|
-
assert_equal "banana", opts[:apple]
|
127
|
-
end
|
128
|
-
|
129
|
-
end
|
130
|
-
|
131
|
-
|
132
|
-
class TestFormatterWithLayout < Test::Unit::TestCase
|
133
|
-
# This formatter is meant to check out a special case in Ruport's renderer,
|
134
|
-
# in which a layout method is called and yielded to when defined
|
135
|
-
class WithLayout < DummyText
|
136
|
-
renders :text_with_layout, :for => VanillaRenderer
|
137
|
-
|
138
|
-
def layout
|
139
|
-
output << "---\n"
|
140
|
-
yield
|
141
|
-
output << "---\n"
|
142
|
-
end
|
143
|
-
|
144
|
-
end
|
145
|
-
|
146
|
-
def test_layout
|
147
|
-
assert_equal "---\nheader\nbody\nfooter\n---\n",
|
148
|
-
VanillaRenderer.render_text_with_layout
|
149
|
-
end
|
150
|
-
|
151
|
-
end
|
152
|
-
|
153
|
-
|
154
|
-
class TestRendererWithManyHooks < Test::Unit::TestCase
|
155
|
-
# This provides a way to check several hooks that Renderer supports
|
156
|
-
class RendererWithManyHooks < Ruport::Renderer
|
157
|
-
|
158
|
-
add_format DummyText, :text
|
159
|
-
|
160
|
-
prepare :document
|
161
|
-
|
162
|
-
option :subtitle, :subsubtitle
|
163
|
-
|
164
|
-
stage :header
|
165
|
-
stage :body
|
166
|
-
stage :footer
|
167
|
-
|
168
|
-
finalize :document
|
169
|
-
|
170
|
-
def setup
|
171
|
-
options.apple = true
|
172
|
-
end
|
173
|
-
|
174
|
-
end
|
175
|
-
|
176
|
-
def test_hash_options_setters
|
177
|
-
a = RendererWithManyHooks.render(:text, :subtitle => "foo",
|
178
|
-
:subsubtitle => "bar") { |r|
|
179
|
-
assert_equal "foo", r.options.subtitle
|
180
|
-
assert_equal "bar", r.options.subsubtitle
|
181
|
-
}
|
182
|
-
end
|
183
|
-
|
184
|
-
def test_data_accessors
|
185
|
-
a = RendererWithManyHooks.render(:text, :data => [1,2,4]) { |r|
|
186
|
-
assert_equal [1,2,4], r.data
|
187
|
-
}
|
188
|
-
|
189
|
-
b = RendererWithManyHooks.render_text(%w[a b c]) { |r|
|
190
|
-
assert_equal %w[a b c], r.data
|
191
|
-
}
|
192
|
-
|
193
|
-
c = RendererWithManyHooks.render_text(%w[a b f],:snapper => :red) { |r|
|
194
|
-
assert_equal %w[a b f], r.data
|
195
|
-
assert_equal :red, r.options.snapper
|
196
|
-
}
|
197
|
-
end
|
198
|
-
|
199
|
-
def test_stage_helper
|
200
|
-
assert RendererWithManyHooks.stages.include?('body')
|
201
|
-
end
|
202
|
-
|
203
|
-
def test_finalize_helper
|
204
|
-
assert_equal :document, RendererWithManyHooks.final_stage
|
205
|
-
end
|
206
|
-
|
207
|
-
def test_prepare_helper
|
208
|
-
assert_equal :document, RendererWithManyHooks.first_stage
|
209
|
-
end
|
210
|
-
|
211
|
-
def test_finalize_again
|
212
|
-
assert_raise(Ruport::Renderer::StageAlreadyDefinedError) {
|
213
|
-
RendererWithManyHooks.finalize :report
|
214
|
-
}
|
215
|
-
end
|
216
|
-
|
217
|
-
def test_prepare_again
|
218
|
-
assert_raise(Ruport::Renderer::StageAlreadyDefinedError) {
|
219
|
-
RendererWithManyHooks.prepare :foo
|
220
|
-
}
|
221
|
-
end
|
222
|
-
|
223
|
-
def test_renderer_using_helpers
|
224
|
-
actual = RendererWithManyHooks.render(:text)
|
225
|
-
assert_equal "pheader\nbody\nfooter\nf", actual
|
226
|
-
|
227
|
-
actual = RendererWithManyHooks.render_text
|
228
|
-
assert_equal "pheader\nbody\nfooter\nf", actual
|
229
|
-
end
|
230
|
-
|
231
|
-
def test_option_helper
|
232
|
-
RendererWithManyHooks.render_text do |r|
|
233
|
-
r.subtitle = "Test Report"
|
234
|
-
assert_equal "Test Report", r.options.subtitle
|
235
|
-
end
|
236
|
-
end
|
237
|
-
|
238
|
-
def test_required_option_helper
|
239
|
-
a = RendererWithManyHooks.dup
|
240
|
-
a.required_option :title
|
241
|
-
|
242
|
-
a.render_text do |r|
|
243
|
-
r.title = "Test Report"
|
244
|
-
assert_equal "Test Report", r.options.title
|
245
|
-
end
|
246
|
-
|
247
|
-
end
|
248
|
-
|
249
|
-
def test_without_required_option
|
250
|
-
a = RendererWithManyHooks.dup
|
251
|
-
a.required_option :title
|
252
|
-
|
253
|
-
assert_raise(Ruport::Renderer::RequiredOptionNotSet) { a.render(:text) }
|
254
|
-
end
|
255
|
-
|
256
|
-
end
|
257
|
-
|
258
|
-
|
259
|
-
class TestRendererWithRunHook < Test::Unit::TestCase
|
260
|
-
|
261
|
-
class RendererWithRunHook < Ruport::Renderer
|
262
|
-
|
263
|
-
include AutoRunner
|
264
|
-
|
265
|
-
add_format DummyText, :text
|
266
|
-
|
267
|
-
required_option :foo,:bar
|
268
|
-
stage :header
|
269
|
-
stage :body
|
270
|
-
stage :footer
|
271
|
-
|
272
|
-
def run
|
273
|
-
formatter.output << "|"
|
274
|
-
end
|
275
|
-
|
276
|
-
end
|
277
|
-
|
278
|
-
def test_renderer_with_run_hooks
|
279
|
-
assert_equal "|header\nbody\nfooter\n",
|
280
|
-
RendererWithRunHook.render_text(:foo => "bar",:bar => "baz")
|
281
|
-
end
|
282
|
-
|
283
|
-
end
|
284
|
-
|
285
|
-
|
286
|
-
class TestRendererWithHelperModule < Test::Unit::TestCase
|
287
|
-
|
288
|
-
class RendererWithHelperModule < VanillaRenderer
|
289
|
-
|
290
|
-
add_format DummyText, :stub
|
291
|
-
|
292
|
-
module Helpers
|
293
|
-
def say_hello
|
294
|
-
"Hello Dolly"
|
295
|
-
end
|
296
|
-
end
|
297
|
-
end
|
298
|
-
|
299
|
-
def test_renderer_helper_module
|
300
|
-
RendererWithHelperModule.render_stub do |r|
|
301
|
-
assert_equal "Hello Dolly", r.formatter.say_hello
|
302
|
-
end
|
303
|
-
end
|
304
|
-
end
|
305
|
-
|
306
|
-
|
307
|
-
class TestMultiPurposeFormatter < Test::Unit::TestCase
|
308
|
-
# This provides a way to check the multi-format hooks for the Renderer
|
309
|
-
class MultiPurposeFormatter < Ruport::Formatter
|
310
|
-
|
311
|
-
renders [:html,:text], :for => VanillaRenderer
|
312
|
-
|
313
|
-
def build_header
|
314
|
-
a = 10
|
315
|
-
|
316
|
-
text { output << "Foo: #{a}\n" }
|
317
|
-
html { output << "<b>Foo: #{a}</b>\n" }
|
318
|
-
end
|
319
|
-
|
320
|
-
def build_body
|
321
|
-
html { output << "<pre>\n" }
|
322
|
-
output << options.body_text
|
323
|
-
html { output << "\n</pre>\n" }
|
324
|
-
end
|
325
|
-
|
326
|
-
end
|
327
|
-
|
328
|
-
def test_multi_purpose
|
329
|
-
text = VanillaRenderer.render_text(:body_text => "foo")
|
330
|
-
assert_equal "Foo: 10\nfoo", text
|
331
|
-
html = VanillaRenderer.render_html(:body_text => "bar")
|
332
|
-
assert_equal "<b>Foo: 10</b>\n<pre>\nbar\n</pre>\n",html
|
333
|
-
end
|
334
|
-
|
335
|
-
|
336
|
-
def test_method_missing_hack_formatter
|
337
|
-
assert_equal [:html,:text], MultiPurposeFormatter.formats
|
338
|
-
|
339
|
-
a = MultiPurposeFormatter.new
|
340
|
-
a.format = :html
|
341
|
-
|
342
|
-
visited = false
|
343
|
-
a.html { visited = true }
|
344
|
-
|
345
|
-
assert visited
|
346
|
-
|
347
|
-
visited = false
|
348
|
-
a.text { visited = true }
|
349
|
-
assert !visited
|
350
|
-
|
351
|
-
assert_raises(NoMethodError) do
|
352
|
-
a.pdf { 'do nothing' }
|
353
|
-
end
|
354
|
-
end
|
355
|
-
|
356
|
-
end
|
357
|
-
|
358
|
-
|
359
|
-
class TestFormatterErbHelper < Test::Unit::TestCase
|
360
|
-
class ErbFormatter < Ruport::Formatter
|
361
|
-
|
362
|
-
renders :terb, :for => VanillaRenderer
|
363
|
-
|
364
|
-
def build_body
|
365
|
-
# demonstrate local binding
|
366
|
-
@foo = "bar"
|
367
|
-
if options.binding
|
368
|
-
output << erb("Binding Override: <%= reverse %>",
|
369
|
-
:binding => options.binding)
|
370
|
-
else
|
371
|
-
output << erb("Default Binding: <%= @foo %>")
|
372
|
-
end
|
373
|
-
end
|
374
|
-
|
375
|
-
end
|
376
|
-
|
377
|
-
#FIXME: need to test file
|
378
|
-
|
379
|
-
def test_self_bound
|
380
|
-
assert_equal "Default Binding: bar", VanillaRenderer.render_terb
|
381
|
-
end
|
382
|
-
|
383
|
-
def test_custom_bound
|
384
|
-
a = [1,2,3]
|
385
|
-
arr_binding = a.instance_eval { binding }
|
386
|
-
assert_equal "Binding Override: 321",
|
387
|
-
VanillaRenderer.render_terb(:binding => arr_binding)
|
388
|
-
end
|
389
|
-
end
|
390
|
-
|
391
|
-
|
392
|
-
class TestOptionReaders < Test::Unit::TestCase
|
393
|
-
|
394
|
-
class RendererForCheckingOptionReaders < Ruport::Renderer
|
395
|
-
option :foo
|
396
|
-
end
|
397
|
-
|
398
|
-
class RendererForCheckingPassivity < Ruport::Renderer
|
399
|
-
def foo
|
400
|
-
"apples"
|
401
|
-
end
|
402
|
-
option :foo
|
403
|
-
end
|
404
|
-
|
405
|
-
def setup
|
406
|
-
@renderer = RendererForCheckingOptionReaders.new
|
407
|
-
@renderer.formatter = Ruport::Formatter.new
|
408
|
-
|
409
|
-
@passive = RendererForCheckingPassivity.new
|
410
|
-
@passive.formatter = Ruport::Formatter.new
|
411
|
-
end
|
412
|
-
|
413
|
-
def test_options_are_readable
|
414
|
-
@renderer.foo = 5
|
415
|
-
assert_equal 5, @renderer.foo
|
416
|
-
end
|
417
|
-
|
418
|
-
def test_methods_are_not_overridden
|
419
|
-
@passive.foo = 5
|
420
|
-
assert_equal "apples", @passive.foo
|
421
|
-
assert_equal 5, @passive.options.foo
|
422
|
-
assert_equal 5, @passive.formatter.options.foo
|
423
|
-
end
|
424
|
-
|
425
|
-
end
|
426
|
-
|
427
|
-
class TestSetupOrdering < Test::Unit::TestCase
|
428
|
-
|
429
|
-
class RendererWithSetup < Ruport::Renderer
|
430
|
-
option :foo
|
431
|
-
stage :bar
|
432
|
-
def setup
|
433
|
-
foo.capitalize!
|
434
|
-
end
|
435
|
-
end
|
436
|
-
|
437
|
-
class BasicFormatter < Ruport::Formatter
|
438
|
-
renders :text, :for => RendererWithSetup
|
439
|
-
|
440
|
-
def build_bar
|
441
|
-
output << options.foo
|
442
|
-
end
|
443
|
-
end
|
444
|
-
|
445
|
-
def test_render_hash_options_should_be_called_before_setup
|
446
|
-
assert_equal "Hello", RendererWithSetup.render_text(:foo => "hello")
|
447
|
-
end
|
448
|
-
|
449
|
-
def test_render_block_should_be_called_before_setup
|
450
|
-
assert_equal "Hello",
|
451
|
-
RendererWithSetup.render_text { |r| r.foo = "hello" }
|
452
|
-
end
|
453
|
-
|
454
|
-
end
|
455
|
-
|
456
|
-
class TestRendererHooks < Test::Unit::TestCase
|
457
|
-
|
458
|
-
context "when renderable_data omitted" do
|
459
|
-
|
460
|
-
require "mocha"
|
461
|
-
|
462
|
-
class DummyObject
|
463
|
-
include Ruport::Renderer::Hooks
|
464
|
-
renders_as_table
|
465
|
-
end
|
466
|
-
|
467
|
-
def specify_should_return_self
|
468
|
-
a = DummyObject.new
|
469
|
-
rend = mock("renderer")
|
470
|
-
rend.expects(:data=).with(a)
|
471
|
-
Ruport::Renderer::Table.expects(:render).with(:csv,{}).yields(rend)
|
472
|
-
a.as(:csv)
|
473
|
-
end
|
474
|
-
|
475
|
-
end
|
476
|
-
|
477
|
-
context "when using renderable_data" do
|
478
|
-
|
479
|
-
class DummyObject2
|
480
|
-
include Ruport::Renderer::Hooks
|
481
|
-
renders_as_table
|
482
|
-
|
483
|
-
def renderable_data
|
484
|
-
1
|
485
|
-
end
|
486
|
-
end
|
487
|
-
|
488
|
-
def specify_should_return_results_of_renderable_data
|
489
|
-
a = DummyObject2.new
|
490
|
-
rend = mock("renderer")
|
491
|
-
rend.expects(:data=).with(1)
|
492
|
-
Ruport::Renderer::Table.expects(:render).with(:csv,{}).yields(rend)
|
493
|
-
a.as(:csv)
|
494
|
-
end
|
495
|
-
|
496
|
-
class DummyObject3
|
497
|
-
include Ruport::Renderer::Hooks
|
498
|
-
renders_as_table
|
499
|
-
|
500
|
-
def renderable_data
|
501
|
-
raise ArgumentError
|
502
|
-
end
|
503
|
-
end
|
504
|
-
|
505
|
-
def specify_should_not_mask_errors
|
506
|
-
assert_raises(ArgumentError) { DummyObject3.new.as(:csv) }
|
507
|
-
end
|
508
|
-
|
509
|
-
|
510
|
-
end
|
511
|
-
|
512
|
-
end
|