ruport 1.6.3 → 1.7.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.
- checksums.yaml +7 -0
- data/AUTHORS +11 -0
- data/README.rdoc +105 -0
- data/Rakefile +13 -44
- data/examples/add_row_table.rb +46 -0
- data/examples/data/wine.csv +255 -0
- data/examples/pdf_grouping.rb +39 -0
- data/examples/pdf_table.rb +28 -0
- data/examples/pdf_table_from_csv.rb +26 -0
- data/examples/pdf_table_prawn.rb +30 -0
- data/examples/pdf_table_simple.rb +13 -0
- data/lib/ruport.rb +0 -12
- data/lib/ruport/controller.rb +16 -20
- data/lib/ruport/data/feeder.rb +2 -2
- data/lib/ruport/data/grouping.rb +2 -2
- data/lib/ruport/data/table.rb +314 -202
- data/lib/ruport/formatter.rb +53 -52
- data/lib/ruport/formatter/csv.rb +6 -7
- data/lib/ruport/formatter/html.rb +13 -11
- data/lib/ruport/formatter/pdf.rb +73 -75
- data/lib/ruport/formatter/prawn_pdf.rb +72 -0
- data/lib/ruport/formatter/template.rb +1 -1
- data/lib/ruport/version.rb +1 -1
- data/test/controller_test.rb +100 -122
- data/test/csv_formatter_test.rb +15 -15
- data/test/data_feeder_test.rb +26 -26
- data/test/grouping_test.rb +30 -29
- data/test/helpers.rb +18 -10
- data/test/html_formatter_test.rb +24 -24
- data/test/record_test.rb +14 -14
- data/test/samples/sales.csv +21 -0
- data/test/table_pivot_test.rb +68 -24
- data/test/table_test.rb +365 -336
- data/test/template_test.rb +1 -1
- data/test/text_formatter_test.rb +19 -19
- data/util/bench/data/table/bench_init.rb +1 -1
- metadata +123 -75
- data/README +0 -114
- data/test/pdf_formatter_test.rb +0 -354
@@ -0,0 +1,72 @@
|
|
1
|
+
module Ruport
|
2
|
+
class Formatter::PrawnPDF < Formatter
|
3
|
+
|
4
|
+
renders :prawn_pdf, :for =>[Controller::Row, Controller::Table,
|
5
|
+
Controller::Group, Controller::Grouping]
|
6
|
+
|
7
|
+
attr_accessor :pdf
|
8
|
+
|
9
|
+
def method_missing(id,*args, &block)
|
10
|
+
pdf.send(id,*args, &block)
|
11
|
+
end
|
12
|
+
|
13
|
+
def initialize
|
14
|
+
require 'prawn'
|
15
|
+
require 'prawn/layout'
|
16
|
+
end
|
17
|
+
|
18
|
+
def pdf
|
19
|
+
@pdf ||= (options.formatter ||
|
20
|
+
::Prawn::Document.new(options[:pdf_format] || {} ))
|
21
|
+
end
|
22
|
+
|
23
|
+
def draw_table(table, format_opts={})
|
24
|
+
m = "PDF Formatter requires column_names to be defined"
|
25
|
+
raise FormatterError, m if table.column_names.empty?
|
26
|
+
|
27
|
+
table.rename_columns { |c| c.to_s }
|
28
|
+
|
29
|
+
table_array = [table.column_names]
|
30
|
+
table_array += table_to_array(table)
|
31
|
+
table_array.map { |array| array.map! { |elem| elem.class != String ? elem.to_s : elem }}
|
32
|
+
|
33
|
+
if options[:table_format]
|
34
|
+
opt = options[:table_format]
|
35
|
+
else
|
36
|
+
opt = {}
|
37
|
+
end
|
38
|
+
|
39
|
+
pdf.table(table_array,opt)
|
40
|
+
|
41
|
+
end
|
42
|
+
|
43
|
+
def table_to_array(tbl)
|
44
|
+
tbl.map { |row| row.to_a}
|
45
|
+
end
|
46
|
+
|
47
|
+
def finalize
|
48
|
+
output << pdf.render
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_table_body
|
52
|
+
draw_table(data)
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_group_body
|
56
|
+
render_table data, options.to_hash.merge(:formatter => pdf)
|
57
|
+
end
|
58
|
+
|
59
|
+
def build_grouping_body
|
60
|
+
data.each do |name,group|
|
61
|
+
|
62
|
+
# Group heading
|
63
|
+
move_down(20)
|
64
|
+
text name, :style => :bold, :size => 15
|
65
|
+
|
66
|
+
# Table
|
67
|
+
move_down(10)
|
68
|
+
draw_table group
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -140,7 +140,7 @@ class Ruport::Formatter::TemplateNotDefined < StandardError; end
|
|
140
140
|
#
|
141
141
|
# format_options All options Corresponding values
|
142
142
|
# available to
|
143
|
-
#
|
143
|
+
# ::CSV.new
|
144
144
|
#
|
145
145
|
class Ruport::Formatter::Template < Ruport::Controller::Options
|
146
146
|
|
data/lib/ruport/version.rb
CHANGED
data/test/controller_test.rb
CHANGED
@@ -94,7 +94,7 @@ class SpecialFinalize < Ruport::Formatter
|
|
94
94
|
end
|
95
95
|
end
|
96
96
|
|
97
|
-
class TestController < Test
|
97
|
+
class TestController < Minitest::Test
|
98
98
|
|
99
99
|
def teardown
|
100
100
|
Ruport::Formatter::Template.instance_variable_set(:@templates, nil)
|
@@ -115,14 +115,14 @@ class TestController < Test::Unit::TestCase
|
|
115
115
|
context "when using templates" do
|
116
116
|
def specify_apply_template_should_be_called
|
117
117
|
Ruport::Formatter::Template.create(:stub)
|
118
|
-
Table(%w[a b c]).to_csv(:template => :stub) do |r|
|
118
|
+
Ruport.Table(%w[a b c]).to_csv(:template => :stub) do |r|
|
119
119
|
r.formatter.expects(:apply_template)
|
120
120
|
end
|
121
121
|
end
|
122
122
|
|
123
123
|
def specify_undefined_template_should_throw_sensible_error
|
124
124
|
assert_raises(Ruport::Formatter::TemplateNotDefined) do
|
125
|
-
Table(%w[a b c]).to_csv(:template => :sub)
|
125
|
+
Ruport.Table(%w[a b c]).to_csv(:template => :sub)
|
126
126
|
end
|
127
127
|
end
|
128
128
|
end
|
@@ -130,7 +130,7 @@ class TestController < Test::Unit::TestCase
|
|
130
130
|
context "when using default templates" do
|
131
131
|
def specify_default_template_should_be_called
|
132
132
|
Ruport::Formatter::Template.create(:default)
|
133
|
-
Table(%w[a b c]).to_csv do |r|
|
133
|
+
Ruport.Table(%w[a b c]).to_csv do |r|
|
134
134
|
r.formatter.expects(:apply_template)
|
135
135
|
assert r.formatter.template == Ruport::Formatter::Template[:default]
|
136
136
|
end
|
@@ -139,7 +139,7 @@ class TestController < Test::Unit::TestCase
|
|
139
139
|
def specify_specific_should_override_default
|
140
140
|
Ruport::Formatter::Template.create(:default)
|
141
141
|
Ruport::Formatter::Template.create(:stub)
|
142
|
-
Table(%w[a b c]).to_csv(:template => :stub) do |r|
|
142
|
+
Ruport.Table(%w[a b c]).to_csv(:template => :stub) do |r|
|
143
143
|
r.formatter.expects(:apply_template)
|
144
144
|
assert r.formatter.template == Ruport::Formatter::Template[:stub]
|
145
145
|
end
|
@@ -147,7 +147,7 @@ class TestController < Test::Unit::TestCase
|
|
147
147
|
|
148
148
|
def specify_should_be_able_to_disable_templates
|
149
149
|
Ruport::Formatter::Template.create(:default)
|
150
|
-
Table(%w[a b c]).to_csv(:template => false) do |r|
|
150
|
+
Ruport.Table(%w[a b c]).to_csv(:template => false) do |r|
|
151
151
|
r.formatter.expects(:apply_template).never
|
152
152
|
end
|
153
153
|
end
|
@@ -176,7 +176,7 @@ class TestController < Test::Unit::TestCase
|
|
176
176
|
def test_using_file_via_rendering_tools
|
177
177
|
f = []
|
178
178
|
File.expects(:open).yields(f)
|
179
|
-
Table(%w[a b c], :data => [[1,2,3],[4,5,6]]).save_as("foo.csv")
|
179
|
+
Ruport.Table(%w[a b c], :data => [[1,2,3],[4,5,6]]).save_as("foo.csv")
|
180
180
|
assert_equal "a,b,c\n1,2,3\n4,5,6\n", f[0]
|
181
181
|
end
|
182
182
|
|
@@ -231,7 +231,7 @@ class TestController < Test::Unit::TestCase
|
|
231
231
|
end
|
232
232
|
|
233
233
|
|
234
|
-
class TestFormatterUsingBuild < Test
|
234
|
+
class TestFormatterUsingBuild < Minitest::Test
|
235
235
|
# This formatter uses the build syntax
|
236
236
|
class UsesBuild < Ruport::Formatter
|
237
237
|
renders :text_using_build, :for => VanillaController
|
@@ -261,7 +261,7 @@ class TestFormatterUsingBuild < Test::Unit::TestCase
|
|
261
261
|
end
|
262
262
|
|
263
263
|
|
264
|
-
class TestFormatterWithLayout < Test
|
264
|
+
class TestFormatterWithLayout < Minitest::Test
|
265
265
|
# This formatter is meant to check out a special case in Ruport's renderer,
|
266
266
|
# in which a layout method is called and yielded to when defined
|
267
267
|
class WithLayout < DummyText
|
@@ -288,7 +288,7 @@ class TestFormatterWithLayout < Test::Unit::TestCase
|
|
288
288
|
end
|
289
289
|
|
290
290
|
|
291
|
-
class TestControllerWithManyHooks < Test
|
291
|
+
class TestControllerWithManyHooks < Minitest::Test
|
292
292
|
# This provides a way to check several hooks that controllers supports
|
293
293
|
class ControllerWithManyHooks < Ruport::Controller
|
294
294
|
add_format DummyText, :text
|
@@ -351,13 +351,13 @@ class TestControllerWithManyHooks < Test::Unit::TestCase
|
|
351
351
|
end
|
352
352
|
|
353
353
|
def test_finalize_again
|
354
|
-
|
354
|
+
assert_raises(Ruport::Controller::StageAlreadyDefinedError) {
|
355
355
|
ControllerWithManyHooks.finalize :report
|
356
356
|
}
|
357
357
|
end
|
358
358
|
|
359
359
|
def test_prepare_again
|
360
|
-
|
360
|
+
assert_raises(Ruport::Controller::StageAlreadyDefinedError) {
|
361
361
|
ControllerWithManyHooks.prepare :foo
|
362
362
|
}
|
363
363
|
end
|
@@ -385,13 +385,13 @@ class TestControllerWithManyHooks < Test::Unit::TestCase
|
|
385
385
|
a = ControllerWithManyHooks.dup
|
386
386
|
a.required_option :title
|
387
387
|
|
388
|
-
|
388
|
+
assert_raises(Ruport::Controller::RequiredOptionNotSet) { a.render(:text) }
|
389
389
|
end
|
390
390
|
|
391
391
|
end
|
392
392
|
|
393
393
|
|
394
|
-
class TestControllerWithRunHook < Test
|
394
|
+
class TestControllerWithRunHook < Minitest::Test
|
395
395
|
|
396
396
|
class ControllerWithRunHook < Ruport::Controller
|
397
397
|
add_format DummyText, :text
|
@@ -416,7 +416,7 @@ class TestControllerWithRunHook < Test::Unit::TestCase
|
|
416
416
|
end
|
417
417
|
|
418
418
|
|
419
|
-
class TestControllerWithHelperModule < Test
|
419
|
+
class TestControllerWithHelperModule < Minitest::Test
|
420
420
|
|
421
421
|
class ControllerWithHelperModule < VanillaController
|
422
422
|
|
@@ -437,7 +437,7 @@ class TestControllerWithHelperModule < Test::Unit::TestCase
|
|
437
437
|
end
|
438
438
|
|
439
439
|
|
440
|
-
class TestMultiPurposeFormatter < Test
|
440
|
+
class TestMultiPurposeFormatter < Minitest::Test
|
441
441
|
# This provides a way to check the multi-format hooks for the Controller
|
442
442
|
class MultiPurposeFormatter < Ruport::Formatter
|
443
443
|
|
@@ -489,40 +489,40 @@ class TestMultiPurposeFormatter < Test::Unit::TestCase
|
|
489
489
|
end
|
490
490
|
|
491
491
|
|
492
|
-
class TestFormatterErbHelper < Test
|
492
|
+
class TestFormatterErbHelper < Minitest::Test
|
493
493
|
class ErbFormatter < Ruport::Formatter
|
494
|
-
|
494
|
+
|
495
495
|
renders :terb, :for => VanillaController
|
496
|
-
|
497
|
-
def build_body
|
496
|
+
|
497
|
+
def build_body
|
498
498
|
# demonstrate local binding
|
499
|
-
@foo = "bar"
|
499
|
+
@foo = "bar"
|
500
500
|
if options.binding
|
501
|
-
output << erb("Binding Override: <%= reverse %>",
|
502
|
-
:binding => options.binding)
|
503
|
-
else
|
504
|
-
output << erb("Default Binding: <%= @foo %>")
|
505
|
-
end
|
501
|
+
output << erb("Binding Override: <%= reverse.inspect %>",
|
502
|
+
:binding => options.binding)
|
503
|
+
else
|
504
|
+
output << erb("Default Binding: <%= @foo %>")
|
505
|
+
end
|
506
506
|
end
|
507
507
|
|
508
508
|
end
|
509
509
|
|
510
|
-
|
510
|
+
#FIXME: need to test file
|
511
511
|
|
512
512
|
def test_self_bound
|
513
513
|
assert_equal "Default Binding: bar", VanillaController.render_terb
|
514
514
|
end
|
515
|
-
|
515
|
+
|
516
516
|
def test_custom_bound
|
517
517
|
a = [1,2,3]
|
518
518
|
arr_binding = a.instance_eval { binding }
|
519
|
-
assert_equal "Binding Override:
|
519
|
+
assert_equal "Binding Override: [3, 2, 1]",
|
520
520
|
VanillaController.render_terb(:binding => arr_binding)
|
521
521
|
end
|
522
|
-
end
|
522
|
+
end
|
523
523
|
|
524
524
|
|
525
|
-
class TestOptionReaders < Test
|
525
|
+
class TestOptionReaders < Minitest::Test
|
526
526
|
|
527
527
|
class ControllerForCheckingOptionReaders < Ruport::Controller
|
528
528
|
required_option :foo
|
@@ -557,7 +557,7 @@ class TestOptionReaders < Test::Unit::TestCase
|
|
557
557
|
|
558
558
|
end
|
559
559
|
|
560
|
-
class TestSetupOrdering < Test
|
560
|
+
class TestSetupOrdering < Minitest::Test
|
561
561
|
|
562
562
|
class ControllerWithSetup < Ruport::Controller
|
563
563
|
stage :bar
|
@@ -630,24 +630,20 @@ class ControllerWithAnonymousFormatters < Ruport::Controller
|
|
630
630
|
|
631
631
|
end
|
632
632
|
|
633
|
-
class TestAnonymousFormatter < Test
|
634
|
-
context "When using built in Ruport formatters" do
|
633
|
+
class TestAnonymousFormatter < Minitest::Test
|
635
634
|
|
636
|
-
|
637
|
-
|
638
|
-
|
639
|
-
|
635
|
+
def test_text_formatter_shortcut_is_accessible
|
636
|
+
assert_equal "Hello world", ControllerWithAnonymousFormatters.render_text
|
637
|
+
assert_equal "1,2,3\n", ControllerWithAnonymousFormatters.render_csv
|
638
|
+
assert_equal "<h1>Hi there</h1>", ControllerWithAnonymousFormatters.render_html
|
639
|
+
if RUBY_VERSION < "1.9"
|
640
640
|
assert_not_nil ControllerWithAnonymousFormatters.render_pdf
|
641
641
|
end
|
642
|
-
|
643
642
|
end
|
644
643
|
|
645
|
-
|
646
|
-
|
647
|
-
assert_equal "This is Custom!", ControllerWithAnonymousFormatters.render_custom
|
648
|
-
end
|
644
|
+
def test_custom_formatter_shortcut_is_accessible
|
645
|
+
assert_equal "This is Custom!", ControllerWithAnonymousFormatters.render_custom
|
649
646
|
end
|
650
|
-
|
651
647
|
end
|
652
648
|
|
653
649
|
# Used to ensure that problems in controller code aren't mistakenly intercepted
|
@@ -663,106 +659,88 @@ class MisbehavingFormatter < Ruport::Formatter
|
|
663
659
|
end
|
664
660
|
end
|
665
661
|
|
666
|
-
class TestMisbehavingController < Test
|
662
|
+
class TestMisbehavingController < Minitest::Test
|
667
663
|
|
668
|
-
|
669
|
-
|
670
|
-
|
671
|
-
MisbehavingController.render :text
|
672
|
-
end
|
664
|
+
def test_controller_errors_should_bubble_up
|
665
|
+
assert_raises(NoMethodError) do
|
666
|
+
MisbehavingController.render :text
|
673
667
|
end
|
674
668
|
end
|
675
669
|
|
676
670
|
end
|
677
671
|
|
678
|
-
class TestControllerHooks < Test
|
679
|
-
|
680
|
-
context "when renderable_data omitted" do
|
681
|
-
|
682
|
-
require "mocha"
|
683
|
-
|
684
|
-
class DummyObject
|
685
|
-
include Ruport::Controller::Hooks
|
686
|
-
renders_as_table
|
687
|
-
end
|
672
|
+
class TestControllerHooks < Minitest::Test
|
688
673
|
|
689
|
-
|
690
|
-
a = DummyObject.new
|
691
|
-
rend = mock("renderer")
|
692
|
-
rend.expects(:data=).with(a)
|
693
|
-
Ruport::Controller::Table.expects(:render).with(:csv,{}).yields(rend)
|
694
|
-
a.as(:csv)
|
695
|
-
end
|
674
|
+
require "mocha"
|
696
675
|
|
676
|
+
class DummyObject
|
677
|
+
include Ruport::Controller::Hooks
|
678
|
+
renders_as_table
|
697
679
|
end
|
698
680
|
|
699
|
-
|
700
|
-
|
701
|
-
|
702
|
-
|
703
|
-
|
704
|
-
|
705
|
-
|
706
|
-
1
|
707
|
-
end
|
708
|
-
end
|
709
|
-
|
710
|
-
def specify_should_return_results_of_renderable_data
|
711
|
-
a = DummyObject2.new
|
712
|
-
rend = mock("renderer")
|
713
|
-
rend.expects(:data=).with(1)
|
714
|
-
Ruport::Controller::Table.expects(:render).with(:csv,{}).yields(rend)
|
715
|
-
a.as(:csv)
|
716
|
-
end
|
681
|
+
def test_should_return_self
|
682
|
+
a = DummyObject.new
|
683
|
+
rend = mock("renderer")
|
684
|
+
rend.expects(:data=).with(a)
|
685
|
+
Ruport::Controller::Table.expects(:render).with(:csv,{}).yields(rend)
|
686
|
+
a.as(:csv)
|
687
|
+
end
|
717
688
|
|
718
|
-
|
719
|
-
|
720
|
-
|
721
|
-
|
722
|
-
def renderable_data
|
723
|
-
raise ArgumentError
|
724
|
-
end
|
725
|
-
end
|
689
|
+
class DummyObject2
|
690
|
+
include Ruport::Controller::Hooks
|
691
|
+
renders_as_table
|
726
692
|
|
727
|
-
def
|
728
|
-
|
693
|
+
def renderable_data(format)
|
694
|
+
1
|
729
695
|
end
|
696
|
+
end
|
730
697
|
|
731
|
-
|
732
|
-
|
733
|
-
|
734
|
-
|
735
|
-
|
736
|
-
|
737
|
-
|
738
|
-
1
|
739
|
-
when :csv
|
740
|
-
2
|
741
|
-
end
|
742
|
-
end
|
743
|
-
end
|
698
|
+
def test_should_return_results_of_renderable_data
|
699
|
+
a = DummyObject2.new
|
700
|
+
rend = mock("renderer")
|
701
|
+
rend.expects(:data=).with(1)
|
702
|
+
Ruport::Controller::Table.expects(:render).with(:csv,{}).yields(rend)
|
703
|
+
a.as(:csv)
|
704
|
+
end
|
744
705
|
|
745
|
-
|
746
|
-
|
747
|
-
|
748
|
-
|
749
|
-
|
750
|
-
|
706
|
+
class DummyObject3
|
707
|
+
include Ruport::Controller::Hooks
|
708
|
+
renders_as_table
|
709
|
+
|
710
|
+
def renderable_data
|
711
|
+
raise ArgumentError
|
751
712
|
end
|
713
|
+
end
|
752
714
|
|
753
|
-
|
754
|
-
|
755
|
-
|
715
|
+
def test_should_not_mask_errors
|
716
|
+
assert_raises(ArgumentError) { DummyObject3.new.as(:csv) }
|
717
|
+
end
|
756
718
|
|
757
|
-
|
719
|
+
class DummyObject4
|
720
|
+
include Ruport::Controller::Hooks
|
721
|
+
renders_as_table
|
758
722
|
|
759
|
-
|
760
|
-
|
723
|
+
def renderable_data(format)
|
724
|
+
case format
|
725
|
+
when :html
|
726
|
+
1
|
727
|
+
when :csv
|
728
|
+
2
|
761
729
|
end
|
762
|
-
|
763
730
|
end
|
764
731
|
end
|
765
732
|
|
733
|
+
def test_should_return_results_of_renderable_data_using_format
|
734
|
+
a = DummyObject4.new
|
735
|
+
rend = mock("renderer")
|
736
|
+
rend.expects(:data=).with(2)
|
737
|
+
Ruport::Controller::Table.expects(:render).with(:csv,{}).yields(rend)
|
738
|
+
a.as(:csv)
|
739
|
+
end
|
766
740
|
|
767
|
-
|
741
|
+
def test_an_unknown_format_error_should_be_raised
|
742
|
+
assert_raises(Ruport::Controller::UnknownFormatError) do
|
743
|
+
Ruport::Controller.render_foo
|
744
|
+
end
|
745
|
+
end
|
768
746
|
end
|