ruport 1.4.0 → 1.6.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/Rakefile +3 -3
- data/examples/anon.rb +43 -0
- data/examples/btree/commaleon/commaleon.rb +9 -9
- data/examples/centered_pdf_text_box.rb +7 -7
- data/examples/line_plotter.rb +1 -1
- data/examples/pdf_report_with_common_base.rb +4 -4
- data/examples/png_embed.rb +4 -4
- data/examples/row_renderer.rb +4 -4
- data/examples/simple_pdf_lines.rb +1 -1
- data/examples/trac_ticket_status.rb +1 -1
- data/lib/ruport.rb +15 -3
- data/lib/ruport/{renderer.rb → controller.rb} +183 -87
- data/lib/ruport/{renderer → controller}/grouping.rb +5 -5
- data/lib/ruport/{renderer → controller}/table.rb +5 -5
- data/lib/ruport/data/grouping.rb +2 -2
- data/lib/ruport/data/record.rb +4 -2
- data/lib/ruport/data/table.rb +128 -4
- data/lib/ruport/formatter.rb +36 -37
- data/lib/ruport/formatter/csv.rb +37 -20
- data/lib/ruport/formatter/html.rb +11 -12
- data/lib/ruport/formatter/pdf.rb +10 -6
- data/lib/ruport/formatter/template.rb +1 -1
- data/lib/ruport/formatter/text.rb +8 -15
- data/test/{renderer_test.rb → controller_test.rb} +179 -74
- data/test/csv_formatter_test.rb +6 -6
- data/test/grouping_test.rb +4 -4
- data/test/helpers.rb +1 -0
- data/test/html_formatter_test.rb +18 -18
- data/test/pdf_formatter_test.rb +28 -3
- data/test/record_test.rb +2 -2
- data/test/table_pivot_test.rb +134 -0
- data/test/table_test.rb +10 -3
- data/test/text_formatter_test.rb +6 -6
- data/util/bench/data/record/bench_as_vs_to.rb +1 -1
- metadata +19 -16
data/Rakefile
CHANGED
@@ -2,7 +2,7 @@ require "rake/rdoctask"
|
|
2
2
|
require "rake/testtask"
|
3
3
|
require "rake/gempackagetask"
|
4
4
|
|
5
|
-
RUPORT_VERSION = "1.
|
5
|
+
RUPORT_VERSION = "1.6.0"
|
6
6
|
|
7
7
|
begin
|
8
8
|
require "rubygems"
|
@@ -32,8 +32,8 @@ spec = Gem::Specification.new do |spec|
|
|
32
32
|
spec.extra_rdoc_files = %w{README LICENSE AUTHORS}
|
33
33
|
spec.rdoc_options << '--title' << 'Ruport Documentation' <<
|
34
34
|
'--main' << 'README' << '-q'
|
35
|
-
spec.add_dependency('fastercsv', '
|
36
|
-
spec.add_dependency('pdf-writer',
|
35
|
+
spec.add_dependency('fastercsv', '= 1.2.3')
|
36
|
+
spec.add_dependency('pdf-writer','= 1.1.8')
|
37
37
|
spec.author = "Gregory Brown"
|
38
38
|
spec.email = " gregory.t.brown@gmail.com"
|
39
39
|
spec.rubyforge_project = "ruport"
|
data/examples/anon.rb
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# Demonstrates building a parent controller which provides additional 'built in'
|
2
|
+
# formats, allowing anonymous formatter support to use the simple interface
|
3
|
+
# rather than the :format => FormatterClass approach.
|
4
|
+
|
5
|
+
require "ruport"
|
6
|
+
module FooCorp
|
7
|
+
class Controller < Ruport::Controller
|
8
|
+
def self.built_in_formats
|
9
|
+
super.merge(:xml => FooCorp::Formatter::XML)
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
class Formatter
|
14
|
+
class XML < Ruport::Formatter
|
15
|
+
|
16
|
+
def xmlify(stuff)
|
17
|
+
output << "Wouldn't you like to see #{stuff} in XML?"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
class MyController < FooCorp::Controller
|
23
|
+
stage :foo
|
24
|
+
|
25
|
+
formatter :xml do
|
26
|
+
build :foo do
|
27
|
+
xmlify "Red Snapper"
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
formatter :text do
|
32
|
+
build :foo do
|
33
|
+
output << "Red Snapper"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
puts "XML:"
|
40
|
+
puts FooCorp::MyController.render_xml
|
41
|
+
|
42
|
+
puts "Text:"
|
43
|
+
puts FooCorp::MyController.render_text
|
@@ -10,7 +10,7 @@
|
|
10
10
|
# of CSV dumps to see what has been removed or altered (we don't care
|
11
11
|
# about new records )
|
12
12
|
#
|
13
|
-
# It's a camping app, but the core of it is a
|
13
|
+
# It's a camping app, but the core of it is a controller/formatter combo.
|
14
14
|
# (Marked by %%%%%%%%%%% below)
|
15
15
|
#
|
16
16
|
# You'll need the camping omnibus and the F() ruport plugin to run this app.
|
@@ -51,13 +51,13 @@ module Commaleon::Helpers
|
|
51
51
|
|
52
52
|
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
53
53
|
# This is the bulk of the Ruport code in this app
|
54
|
-
# (
|
54
|
+
# (CSVDiffController and CSVDiffFormatter)
|
55
55
|
# The rest is just camping. The interesting thing here is that
|
56
56
|
# you could easily define these in another file and just require
|
57
57
|
# them here, and use them standalone outside of your web app.
|
58
58
|
# %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
59
59
|
|
60
|
-
class
|
60
|
+
class CSVDiffController < Ruport::Controller
|
61
61
|
stage :diff_report
|
62
62
|
option :key, :mcsv, :ccsv
|
63
63
|
|
@@ -65,7 +65,7 @@ module Commaleon::Helpers
|
|
65
65
|
# manipulations on the data and options before handing off the
|
66
66
|
# rendering task to the formatters.
|
67
67
|
#
|
68
|
-
# We're using grouping mainly for the
|
68
|
+
# We're using grouping mainly for the controller support,
|
69
69
|
# and rather than reducing a table, we're building up the
|
70
70
|
# group objects via the helper methods missing_from_compare
|
71
71
|
# and different_from_compare
|
@@ -133,7 +133,7 @@ module Commaleon::Helpers
|
|
133
133
|
#
|
134
134
|
# http://stonecode.svnrepository.com/ruport/trac.cgi/wiki/F
|
135
135
|
#
|
136
|
-
class CSVDiffFormatter < F([:html,:text,:csv,:pdf], :for =>
|
136
|
+
class CSVDiffFormatter < F([:html,:text,:csv,:pdf], :for => CSVDiffController)
|
137
137
|
def build_diff_report
|
138
138
|
# this is using the selective blocks for formatters that implement
|
139
139
|
# more than one format. The block below will only be called when this
|
@@ -183,7 +183,7 @@ module Commaleon::Controllers
|
|
183
183
|
|
184
184
|
def post
|
185
185
|
@state.key = @input.csv_id
|
186
|
-
@table =
|
186
|
+
@table = CSVDiffController.render_html(:key => @state.key,
|
187
187
|
:mcsv => @state.mfile,
|
188
188
|
:ccsv => @state.cfile )
|
189
189
|
render :html_diff
|
@@ -207,11 +207,11 @@ module Commaleon::Controllers
|
|
207
207
|
set_headers(format)
|
208
208
|
case(format)
|
209
209
|
when "csv"
|
210
|
-
text
|
210
|
+
text CSVDiffController.render_csv(options)
|
211
211
|
when "pdf"
|
212
|
-
text
|
212
|
+
text CSVDiffController.render_pdf(options.merge(:style => :justified))
|
213
213
|
when "txt"
|
214
|
-
text
|
214
|
+
text CSVDiffController.render_text(options)
|
215
215
|
else
|
216
216
|
text "no format!"
|
217
217
|
end
|
@@ -1,21 +1,21 @@
|
|
1
1
|
require "ruport"
|
2
2
|
|
3
|
-
#
|
3
|
+
# Controllers can be though of as control classes or interface builders.
|
4
4
|
# Essentially, they define the options that formatters should implement
|
5
5
|
# and the stages of rendering they should handle. Ruport's formatting
|
6
|
-
# system is very forgiving, and the
|
6
|
+
# system is very forgiving, and the controllers do not force their
|
7
7
|
# specs onto formatters that are attached to them.
|
8
8
|
#
|
9
|
-
class Document < Ruport::
|
9
|
+
class Document < Ruport::Controller
|
10
10
|
|
11
11
|
# Will throw an error if these options are not set at rendering time
|
12
12
|
required_option :text, :author
|
13
13
|
|
14
|
-
# The
|
14
|
+
# The controller will look for a build_document_body() method on the formatter,
|
15
15
|
# but silently skip this stage if it is missing
|
16
16
|
stage :document_body
|
17
17
|
|
18
|
-
# The
|
18
|
+
# The controller will look for a finalize_document() method on the formatter,
|
19
19
|
# but silently skip this stage if it is missing
|
20
20
|
finalize :document
|
21
21
|
end
|
@@ -59,11 +59,11 @@ class CenteredPDFTextBox < Ruport::Formatter::PDF
|
|
59
59
|
end
|
60
60
|
end
|
61
61
|
|
62
|
-
# All options passed to a
|
62
|
+
# All options passed to a controller will be written onto the options object.
|
63
63
|
# In the block form, you may use explicit accessors
|
64
64
|
# (i.e. r.text instead of r.options.text ) for only things that have
|
65
65
|
# either been defined with option / required_option methods,
|
66
|
-
# or have explicit accessors in the
|
66
|
+
# or have explicit accessors in the Controller.
|
67
67
|
#
|
68
68
|
a = Document.render_pdf( :heading => "a good quote",
|
69
69
|
:author => "Ralph Waldo Emerson") do |r|
|
data/examples/line_plotter.rb
CHANGED
@@ -8,14 +8,14 @@
|
|
8
8
|
|
9
9
|
require "ruport"
|
10
10
|
|
11
|
-
# only used for the titleize call in
|
11
|
+
# only used for the titleize call in ClientController#setup
|
12
12
|
# tweak as needed if you don't want to install AS.
|
13
13
|
require "active_support"
|
14
14
|
|
15
15
|
# This looks a little more messy than usual, but it addresses the
|
16
16
|
# concern of wanting to have a standard template for reports.
|
17
17
|
#
|
18
|
-
class
|
18
|
+
class ClientController < Ruport::Controller
|
19
19
|
prepare :standard_report
|
20
20
|
stage :company_header, :client_header, :client_body, :client_footer
|
21
21
|
finalize :standard_report
|
@@ -51,7 +51,7 @@ end
|
|
51
51
|
# Notice the footer is not implemented and it doesn't complain.
|
52
52
|
#
|
53
53
|
class ClientPDF < CompanyPDFBase
|
54
|
-
renders :pdf, :for =>
|
54
|
+
renders :pdf, :for => ClientController
|
55
55
|
|
56
56
|
def build_client_header
|
57
57
|
pad(10) do
|
@@ -68,5 +68,5 @@ end
|
|
68
68
|
table = Table([:a,:b,:c]) << [1,2,3] << [4,5,6]
|
69
69
|
|
70
70
|
File.open("example.pdf","w") do |f|
|
71
|
-
f <<
|
71
|
+
f << ClientController.render_pdf(:data => table,:example => "apple")
|
72
72
|
end
|
data/examples/png_embed.rb
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
require "rubygems"
|
2
2
|
require "ruport"
|
3
3
|
|
4
|
-
class
|
4
|
+
class RoadmapController < Ruport::Controller
|
5
5
|
stage :roadmap_image, :roadmap_text_body
|
6
6
|
finalize :roadmap
|
7
7
|
end
|
8
8
|
|
9
9
|
class HTMLRoadmap < Ruport::Formatter
|
10
10
|
|
11
|
-
renders :html, :for =>
|
11
|
+
renders :html, :for => RoadmapController
|
12
12
|
|
13
13
|
def layout
|
14
14
|
output << "<html><body>\n"
|
@@ -28,7 +28,7 @@ end
|
|
28
28
|
|
29
29
|
class PDFRoadmap < Ruport::Formatter::PDF
|
30
30
|
|
31
|
-
renders :pdf, :for =>
|
31
|
+
renders :pdf, :for => RoadmapController
|
32
32
|
|
33
33
|
def build_roadmap_image
|
34
34
|
center_image_in_box options.image_file, :x => 0, :y => 200,
|
@@ -49,6 +49,6 @@ end
|
|
49
49
|
|
50
50
|
formats = [:html, :pdf]
|
51
51
|
formats.each do |format|
|
52
|
-
|
52
|
+
RoadmapController.render(format, :image_file => "roadmap.png",
|
53
53
|
:file => "roadmap.#{format}")
|
54
54
|
end
|
data/examples/row_renderer.rb
CHANGED
@@ -1,12 +1,12 @@
|
|
1
1
|
require "ruport"
|
2
2
|
|
3
|
-
class CSV2Something < Ruport::
|
4
|
-
required_option :
|
3
|
+
class CSV2Something < Ruport::Controller
|
4
|
+
required_option :csv_file
|
5
5
|
stage :table_body
|
6
6
|
|
7
7
|
module Helpers
|
8
8
|
def table_feeder
|
9
|
-
Table(options.
|
9
|
+
Table(options.csv_file,:has_names => false) { |t,r| yield(r) }
|
10
10
|
end
|
11
11
|
end
|
12
12
|
|
@@ -36,4 +36,4 @@ class Text < Ruport::Formatter::Text
|
|
36
36
|
|
37
37
|
end
|
38
38
|
|
39
|
-
CSV2Something.render_html(:
|
39
|
+
CSV2Something.render_html(:csv_file => "example.csv",:io => STDOUT)
|
data/lib/ruport.rb
CHANGED
@@ -9,11 +9,23 @@
|
|
9
9
|
#
|
10
10
|
# See LICENSE and COPYING for details
|
11
11
|
#
|
12
|
+
|
13
|
+
|
14
|
+
if RUBY_VERSION > "1.9"
|
15
|
+
require "csv"
|
16
|
+
unless defined? FCSV
|
17
|
+
class Object
|
18
|
+
FCSV = CSV
|
19
|
+
alias_method :FCSV, :CSV
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
12
24
|
|
13
25
|
module Ruport #:nodoc:#
|
14
26
|
|
15
|
-
VERSION = "1.
|
16
|
-
|
27
|
+
VERSION = "1.6.0"
|
28
|
+
|
17
29
|
class FormatterError < RuntimeError #:nodoc:
|
18
30
|
end
|
19
31
|
|
@@ -102,7 +114,7 @@ module Ruport #:nodoc:#
|
|
102
114
|
end
|
103
115
|
|
104
116
|
require "enumerator"
|
105
|
-
require "ruport/
|
117
|
+
require "ruport/controller"
|
106
118
|
require "ruport/data"
|
107
119
|
require "ruport/formatter"
|
108
120
|
|
@@ -1,16 +1,16 @@
|
|
1
|
-
#
|
1
|
+
# controller.rb : General purpose control of formatted data for Ruby Reports
|
2
2
|
#
|
3
3
|
# Copyright December 2006, Gregory Brown. All Rights Reserved.
|
4
4
|
#
|
5
5
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
6
6
|
|
7
7
|
|
8
|
-
# This class implements the core
|
9
|
-
# designed to implement the low level tools necessary to build report
|
10
|
-
# for different kinds of tasks. See
|
11
|
-
#
|
8
|
+
# This class implements the core controller for Ruport's formatting system.
|
9
|
+
# It is designed to implement the low level tools necessary to build report
|
10
|
+
# controllers for different kinds of tasks. See Controller::Table for a
|
11
|
+
# tabular data controller.
|
12
12
|
#
|
13
|
-
class Ruport::
|
13
|
+
class Ruport::Controller
|
14
14
|
|
15
15
|
class RequiredOptionNotSet < RuntimeError #:nodoc:
|
16
16
|
end
|
@@ -18,16 +18,18 @@ class Ruport::Renderer
|
|
18
18
|
end
|
19
19
|
class StageAlreadyDefinedError < RuntimeError #:nodoc:
|
20
20
|
end
|
21
|
-
class
|
21
|
+
class ControllerNotSetError < RuntimeError #:nodoc:
|
22
22
|
end
|
23
23
|
|
24
24
|
require "ostruct"
|
25
25
|
|
26
|
-
# Structure for holding
|
26
|
+
# Structure for holding controller options.
|
27
27
|
# Simplified version of HashWithIndifferentAccess
|
28
28
|
class Options < OpenStruct
|
29
|
-
|
30
|
-
|
29
|
+
|
30
|
+
if RUBY_VERSION < "1.9"
|
31
|
+
private :id
|
32
|
+
end
|
31
33
|
|
32
34
|
# Returns a Hash object. Use this if you need methods other than []
|
33
35
|
def to_hash
|
@@ -57,23 +59,23 @@ class Ruport::Renderer
|
|
57
59
|
# structures, as well as the renders_with and renders_as_* helpers.
|
58
60
|
#
|
59
61
|
# You can actually use this with any data structure, it will look for a
|
60
|
-
# renderable_data(format) method to pass to the <tt>
|
62
|
+
# renderable_data(format) method to pass to the <tt>controller</tt> you
|
61
63
|
# specify, but if that is not defined, it will pass <tt>self</tt>.
|
62
64
|
#
|
63
65
|
# Examples:
|
64
66
|
#
|
65
|
-
# # Render Arrays with Ruport's Row
|
67
|
+
# # Render Arrays with Ruport's Row Controller
|
66
68
|
# class Array
|
67
|
-
# include Ruport::
|
69
|
+
# include Ruport::Controller::Hooks
|
68
70
|
# renders_as_row
|
69
71
|
# end
|
70
72
|
#
|
71
73
|
# # >> [1,2,3].as(:csv)
|
72
74
|
# # => "1,2,3\n"
|
73
75
|
#
|
74
|
-
# # Render Hashes with Ruport's Row
|
76
|
+
# # Render Hashes with Ruport's Row Controller
|
75
77
|
# class Hash
|
76
|
-
# include Ruport::
|
78
|
+
# include Ruport::Controller::Hooks
|
77
79
|
# renders_as_row
|
78
80
|
# attr_accessor :column_order
|
79
81
|
# def renderable_data(format)
|
@@ -88,24 +90,24 @@ class Ruport::Renderer
|
|
88
90
|
module Hooks
|
89
91
|
module ClassMethods
|
90
92
|
|
91
|
-
# Tells the class which
|
93
|
+
# Tells the class which controller as() will forward to.
|
92
94
|
#
|
93
95
|
# Usage:
|
94
96
|
#
|
95
97
|
# class MyStructure
|
96
|
-
# include
|
97
|
-
# renders_with
|
98
|
+
# include Controller::Hooks
|
99
|
+
# renders_with CustomController
|
98
100
|
# end
|
99
101
|
#
|
100
102
|
# You can also specify default rendering options, which will be used
|
101
103
|
# if they are not overriden by the options passed to as().
|
102
104
|
#
|
103
105
|
# class MyStructure
|
104
|
-
# include
|
105
|
-
# renders_with
|
106
|
+
# include Controller::Hooks
|
107
|
+
# renders_with CustomController, :font_size => 14
|
106
108
|
# end
|
107
|
-
def renders_with(
|
108
|
-
@
|
109
|
+
def renders_with(controller,opts={})
|
110
|
+
@controller = controller
|
109
111
|
@rendering_options=opts
|
110
112
|
end
|
111
113
|
|
@@ -114,39 +116,38 @@ class Ruport::Renderer
|
|
114
116
|
@rendering_options
|
115
117
|
end
|
116
118
|
|
117
|
-
# Shortcut for renders_with(Ruport::
|
118
|
-
# may wish to override this if you build a custom table
|
119
|
+
# Shortcut for renders_with(Ruport::Controller::Table), you
|
120
|
+
# may wish to override this if you build a custom table controller.
|
119
121
|
def renders_as_table(options={})
|
120
|
-
renders_with Ruport::
|
122
|
+
renders_with Ruport::Controller::Table,options
|
121
123
|
end
|
122
124
|
|
123
|
-
# Shortcut for renders_with(Ruport::
|
124
|
-
# may wish to override this if you build a custom row
|
125
|
+
# Shortcut for renders_with(Ruport::Controller::Row), you
|
126
|
+
# may wish to override this if you build a custom row controller.
|
125
127
|
def renders_as_row(options={})
|
126
|
-
renders_with Ruport::
|
128
|
+
renders_with Ruport::Controller::Row, options
|
127
129
|
end
|
128
130
|
|
129
|
-
# Shortcut for renders_with(Ruport::
|
130
|
-
# may wish to override this if you build a custom group
|
131
|
+
# Shortcut for renders_with(Ruport::Controller::Group), you
|
132
|
+
# may wish to override this if you build a custom group controller.
|
131
133
|
def renders_as_group(options={})
|
132
|
-
renders_with Ruport::
|
134
|
+
renders_with Ruport::Controller::Group,options
|
133
135
|
end
|
134
136
|
|
135
|
-
# Shortcut for renders_with(Ruport::
|
136
|
-
# may wish to override this if you build a custom grouping
|
137
|
+
# Shortcut for renders_with(Ruport::Controller::Grouping), you
|
138
|
+
# may wish to override this if you build a custom grouping controller.
|
137
139
|
def renders_as_grouping(options={})
|
138
|
-
renders_with Ruport::
|
140
|
+
renders_with Ruport::Controller::Grouping,options
|
139
141
|
end
|
140
142
|
|
141
|
-
# The class of the
|
143
|
+
# The class of the controller object for the base class.
|
142
144
|
#
|
143
145
|
# Example:
|
144
146
|
#
|
145
|
-
# >> Ruport::Data::Table.
|
146
|
-
# => Ruport::
|
147
|
-
def
|
148
|
-
|
149
|
-
@renderer.split("::").inject(Class) { |c,el| c.const_get(el) }
|
147
|
+
# >> Ruport::Data::Table.controller
|
148
|
+
# => Ruport::Controller::Table
|
149
|
+
def controller
|
150
|
+
@controller
|
150
151
|
end
|
151
152
|
end
|
152
153
|
|
@@ -154,22 +155,22 @@ class Ruport::Renderer
|
|
154
155
|
base.extend(ClassMethods)
|
155
156
|
end
|
156
157
|
|
157
|
-
# Uses the
|
158
|
+
# Uses the Controller specified by renders_with to generate formatted
|
158
159
|
# output. Passes the return value of the <tt>renderable_data(format)</tt>
|
159
160
|
# method if the method is defined, otherwise passes <tt>self</tt> as :data
|
160
161
|
#
|
161
|
-
# The remaining options are converted to a
|
162
|
-
# are accessible in both the
|
162
|
+
# The remaining options are converted to a Controller::Options object and
|
163
|
+
# are accessible in both the controller and formatter.
|
163
164
|
#
|
164
165
|
# Example:
|
165
166
|
#
|
166
167
|
# table.as(:csv, :show_table_headers => false)
|
167
168
|
def as(format,options={})
|
168
|
-
raise
|
169
|
-
unless self.class.
|
169
|
+
raise ControllerNotSetError unless self.class.controller
|
170
|
+
unless self.class.controller.formats.include?(format)
|
170
171
|
raise UnknownFormatError
|
171
172
|
end
|
172
|
-
self.class.
|
173
|
+
self.class.controller.render(format,
|
173
174
|
self.class.rendering_options.merge(options)) do |rend|
|
174
175
|
rend.data =
|
175
176
|
respond_to?(:renderable_data) ? renderable_data(format) : self
|
@@ -183,9 +184,105 @@ class Ruport::Renderer
|
|
183
184
|
as(format.to_sym, options.merge(:file => file))
|
184
185
|
end
|
185
186
|
end
|
187
|
+
|
186
188
|
|
187
189
|
|
188
190
|
class << self
|
191
|
+
|
192
|
+
# Returns a hash that maps format names to their formatter classes, for use
|
193
|
+
# with the formatter shortcut. Supported formats are :html, :csv, :pdf, and
|
194
|
+
# :text by default.
|
195
|
+
#
|
196
|
+
#
|
197
|
+
# Sample override:
|
198
|
+
#
|
199
|
+
# class MyController < Ruport::Controller
|
200
|
+
#
|
201
|
+
# def built_in_formats
|
202
|
+
# super.extend(:xml => MyXMLFormatter,
|
203
|
+
# :json => MyJSONFormatter)
|
204
|
+
# end
|
205
|
+
# end
|
206
|
+
#
|
207
|
+
# This would allow for:
|
208
|
+
#
|
209
|
+
# class ChildController < MyController
|
210
|
+
#
|
211
|
+
# formatter :xml do
|
212
|
+
# # ...
|
213
|
+
# end
|
214
|
+
#
|
215
|
+
# formatter :json do
|
216
|
+
# # ...
|
217
|
+
# end
|
218
|
+
# end
|
219
|
+
#
|
220
|
+
def built_in_formats
|
221
|
+
{ :html => Ruport::Formatter::HTML,
|
222
|
+
:csv => Ruport::Formatter::CSV,
|
223
|
+
:pdf => Ruport::Formatter::PDF,
|
224
|
+
:text => Ruport::Formatter::Text }
|
225
|
+
end
|
226
|
+
|
227
|
+
|
228
|
+
# Generates an anonymous formatter class and ties it to the Controller.
|
229
|
+
# This method looks up the built in formats in the hash returned by
|
230
|
+
# built_in_formats, but also explicitly specify a custom Formatter class to
|
231
|
+
# subclass from.
|
232
|
+
#
|
233
|
+
# Sample usage:
|
234
|
+
#
|
235
|
+
# class ControllerWithAnonymousFormatters < Ruport::Controller
|
236
|
+
#
|
237
|
+
# stage :report
|
238
|
+
#
|
239
|
+
# formatter :html do
|
240
|
+
# build :report do
|
241
|
+
# output << textile("h1. Hi there")
|
242
|
+
# end
|
243
|
+
# end
|
244
|
+
#
|
245
|
+
# formatter :csv do
|
246
|
+
# build :report do
|
247
|
+
# build_row([1,2,3])
|
248
|
+
# end
|
249
|
+
# end
|
250
|
+
#
|
251
|
+
# formatter :pdf do
|
252
|
+
# build :report do
|
253
|
+
# add_text "hello world"
|
254
|
+
# end
|
255
|
+
# end
|
256
|
+
#
|
257
|
+
# formatter :text do
|
258
|
+
# build :report do
|
259
|
+
# output << "Hello world"
|
260
|
+
# end
|
261
|
+
# end
|
262
|
+
#
|
263
|
+
# formatter :custom => CustomFormatter do
|
264
|
+
#
|
265
|
+
# build :report do
|
266
|
+
# output << "This is "
|
267
|
+
# custom_helper
|
268
|
+
# end
|
269
|
+
#
|
270
|
+
# end
|
271
|
+
#
|
272
|
+
# end
|
273
|
+
#
|
274
|
+
def formatter(*a,&b)
|
275
|
+
case a[0]
|
276
|
+
when Symbol
|
277
|
+
klass = Class.new(built_in_formats[a[0]])
|
278
|
+
klass.renders a[0], :for => self
|
279
|
+
when Hash
|
280
|
+
k,v = a[0].to_a[0]
|
281
|
+
klass = Class.new(v)
|
282
|
+
klass.renders k, :for => self
|
283
|
+
end
|
284
|
+
klass.class_eval(&b)
|
285
|
+
end
|
189
286
|
|
190
287
|
attr_accessor :first_stage,:final_stage,:required_options,:stages #:nodoc:
|
191
288
|
|
@@ -194,18 +291,18 @@ class Ruport::Renderer
|
|
194
291
|
#
|
195
292
|
# Usage:
|
196
293
|
#
|
197
|
-
# class
|
294
|
+
# class MyController < Ruport::Controller
|
198
295
|
# # other details omitted...
|
199
296
|
# finalize :apple
|
200
297
|
# end
|
201
298
|
#
|
202
299
|
# class MyFormatter < Ruport::Formatter
|
203
|
-
# renders :example, :for =>
|
300
|
+
# renders :example, :for => MyController
|
204
301
|
#
|
205
302
|
# # other details omitted...
|
206
303
|
#
|
207
304
|
# def finalize_apple
|
208
|
-
# # this method will be called when
|
305
|
+
# # this method will be called when MyController tries to render
|
209
306
|
# # the :example format
|
210
307
|
# end
|
211
308
|
# end
|
@@ -223,16 +320,16 @@ class Ruport::Renderer
|
|
223
320
|
#
|
224
321
|
# Usage:
|
225
322
|
#
|
226
|
-
# class
|
323
|
+
# class MyController < Ruport::Controller
|
227
324
|
# # other details omitted...
|
228
325
|
# prepare :apple
|
229
326
|
# end
|
230
327
|
#
|
231
328
|
# class MyFormatter < Ruport::Formatter
|
232
|
-
# renders :example, :for =>
|
329
|
+
# renders :example, :for => MyController
|
233
330
|
#
|
234
331
|
# def prepare_apple
|
235
|
-
# # this method will be called when
|
332
|
+
# # this method will be called when MyController tries to render
|
236
333
|
# # the :example format
|
237
334
|
# end
|
238
335
|
#
|
@@ -252,21 +349,21 @@ class Ruport::Renderer
|
|
252
349
|
#
|
253
350
|
# Usage:
|
254
351
|
#
|
255
|
-
# class
|
352
|
+
# class MyController < Ruport::Controller
|
256
353
|
# # other details omitted...
|
257
354
|
# stage :apple,:banana
|
258
355
|
# end
|
259
356
|
#
|
260
357
|
# class MyFormatter < Ruport::Formatter
|
261
|
-
# renders :example, :for =>
|
358
|
+
# renders :example, :for => MyController
|
262
359
|
#
|
263
360
|
# def build_apple
|
264
|
-
# # this method will be called when
|
361
|
+
# # this method will be called when MyController tries to render
|
265
362
|
# # the :example format
|
266
363
|
# end
|
267
364
|
#
|
268
365
|
# def build_banana
|
269
|
-
# # this method will be called when
|
366
|
+
# # this method will be called when MyController tries to render
|
270
367
|
# # the :example format
|
271
368
|
# end
|
272
369
|
#
|
@@ -281,13 +378,13 @@ class Ruport::Renderer
|
|
281
378
|
}
|
282
379
|
end
|
283
380
|
|
284
|
-
# Defines attribute writers for the
|
285
|
-
# between
|
381
|
+
# Defines attribute writers for the Controller::Options object shared
|
382
|
+
# between Controller and Formatter. Will throw an error if the user does
|
286
383
|
# not provide values for these options upon rendering.
|
287
384
|
#
|
288
385
|
# usage:
|
289
386
|
#
|
290
|
-
# class
|
387
|
+
# class MyController < Ruport::Controller
|
291
388
|
# required_option :employee_name, :address
|
292
389
|
# # other details omitted
|
293
390
|
# end
|
@@ -305,12 +402,12 @@ class Ruport::Renderer
|
|
305
402
|
end
|
306
403
|
end
|
307
404
|
|
308
|
-
# Lists the formatters that are currently registered on a
|
405
|
+
# Lists the formatters that are currently registered on a controller,
|
309
406
|
# as a hash keyed by format name.
|
310
407
|
#
|
311
408
|
# Example:
|
312
409
|
#
|
313
|
-
# >> Ruport::
|
410
|
+
# >> Ruport::Controller::Table.formats
|
314
411
|
# => {:html=>Ruport::Formatter::HTML,
|
315
412
|
# ?> :csv=>Ruport::Formatter::CSV,
|
316
413
|
# ?> :text=>Ruport::Formatter::Text,
|
@@ -319,20 +416,20 @@ class Ruport::Renderer
|
|
319
416
|
@formats ||= {}
|
320
417
|
end
|
321
418
|
|
322
|
-
# Builds up a
|
419
|
+
# Builds up a controller object, looks up the appropriate formatter,
|
323
420
|
# sets the data and options, and then does the following process:
|
324
421
|
#
|
325
|
-
# * If the
|
326
|
-
# * If a block is given, yield the
|
327
|
-
# * If a setup() method is defined on the
|
422
|
+
# * If the controller contains a module Helpers, mix it in to the instance.
|
423
|
+
# * If a block is given, yield the Controller instance.
|
424
|
+
# * If a setup() method is defined on the Controller, call it.
|
328
425
|
# * Call the run() method.
|
329
426
|
# * If the :file option is set to a file name, appends output to the file.
|
330
427
|
# * Return the results of formatter.output
|
331
428
|
#
|
332
|
-
# Please see the examples/ directory for custom
|
429
|
+
# Please see the examples/ directory for custom controller examples, because
|
333
430
|
# this is not nearly as complicated as it sounds in most cases.
|
334
|
-
def render(
|
335
|
-
rend = build(
|
431
|
+
def render(format, add_options=nil)
|
432
|
+
rend = build(format, add_options) { |r|
|
336
433
|
yield(r) if block_given?
|
337
434
|
r.setup if r.respond_to? :setup
|
338
435
|
}
|
@@ -348,7 +445,7 @@ class Ruport::Renderer
|
|
348
445
|
# options { |o| o.style = :justified }
|
349
446
|
#
|
350
447
|
def options
|
351
|
-
@options ||= Ruport::
|
448
|
+
@options ||= Ruport::Controller::Options.new
|
352
449
|
yield(@options) if block_given?
|
353
450
|
|
354
451
|
return @options
|
@@ -356,37 +453,37 @@ class Ruport::Renderer
|
|
356
453
|
|
357
454
|
private
|
358
455
|
|
359
|
-
# Creates a new instance of the
|
360
|
-
# formatter (by name). If a block is given, the
|
456
|
+
# Creates a new instance of the controller and sets it to use the specified
|
457
|
+
# formatter (by name). If a block is given, the controller instance is
|
361
458
|
# yielded.
|
362
459
|
#
|
363
|
-
# Returns the
|
460
|
+
# Returns the controller instance.
|
364
461
|
#
|
365
|
-
def build(
|
462
|
+
def build(format, add_options=nil)
|
366
463
|
rend = self.new
|
367
464
|
|
368
|
-
rend.send(:use_formatter,
|
465
|
+
rend.send(:use_formatter, format)
|
369
466
|
rend.send(:options=, options.dup)
|
370
467
|
if rend.class.const_defined? :Helpers
|
371
468
|
rend.formatter.extend(rend.class.const_get(:Helpers))
|
372
469
|
end
|
373
|
-
if
|
374
|
-
d =
|
470
|
+
if add_options.kind_of?(Hash)
|
471
|
+
d = add_options.delete(:data)
|
375
472
|
rend.data = d if d
|
376
|
-
|
473
|
+
add_options.each {|k,v| rend.options.send("#{k}=",v) }
|
377
474
|
end
|
378
475
|
|
379
476
|
yield(rend) if block_given?
|
380
477
|
return rend
|
381
478
|
end
|
382
479
|
|
383
|
-
# Allows you to register a format with the
|
480
|
+
# Allows you to register a format with the controller.
|
384
481
|
#
|
385
482
|
# Example:
|
386
483
|
#
|
387
484
|
# class MyFormatter < Ruport::Formatter
|
388
485
|
# # formatter code ...
|
389
|
-
#
|
486
|
+
# SomeController.add_format self, :my_formatter
|
390
487
|
# end
|
391
488
|
#
|
392
489
|
def add_format(format,name=nil)
|
@@ -408,23 +505,23 @@ class Ruport::Renderer
|
|
408
505
|
|
409
506
|
# Sets +data+ attribute on the active formatter.
|
410
507
|
def data=(val)
|
411
|
-
formatter.data = val
|
508
|
+
formatter.data = val
|
412
509
|
end
|
413
510
|
|
414
|
-
#
|
511
|
+
# Controller::Options object which is shared with the current formatter.
|
415
512
|
def options
|
416
513
|
yield(formatter.options) if block_given?
|
417
514
|
formatter.options
|
418
515
|
end
|
419
516
|
|
420
517
|
# Call the _run_ method. You can override this method in your custom
|
421
|
-
#
|
518
|
+
# controller if you need to define other actions.
|
422
519
|
def run
|
423
520
|
_run_
|
424
521
|
end
|
425
522
|
|
426
523
|
# If an IO object is given, Formatter#output will use it instead of
|
427
|
-
# the default String. For Ruport's core
|
524
|
+
# the default String. For Ruport's core controllers, we technically
|
428
525
|
# can use any object that supports the << method, but it's meant
|
429
526
|
# for IO objects such as File or STDOUT
|
430
527
|
#
|
@@ -456,7 +553,6 @@ class Ruport::Renderer
|
|
456
553
|
# Called automatically when the report is rendered. Uses the
|
457
554
|
# data collected from the earlier methods.
|
458
555
|
def _run_
|
459
|
-
# ensure all the required options have been set
|
460
556
|
unless self.class.required_options.nil?
|
461
557
|
self.class.required_options.each do |opt|
|
462
558
|
if options.__send__(opt).nil?
|
@@ -479,10 +575,10 @@ class Ruport::Renderer
|
|
479
575
|
end
|
480
576
|
|
481
577
|
finalize self.class.final_stage if self.class.final_stage
|
578
|
+
maybe :finalize
|
482
579
|
end
|
483
580
|
|
484
581
|
def execute_stages
|
485
|
-
# call each stage to build the report
|
486
582
|
unless self.class.stages.nil?
|
487
583
|
self.class.stages.each do |stage|
|
488
584
|
maybe("build_#{stage}")
|
@@ -516,5 +612,5 @@ class Ruport::Renderer
|
|
516
612
|
|
517
613
|
end
|
518
614
|
|
519
|
-
require "ruport/
|
520
|
-
require "ruport/
|
615
|
+
require "ruport/controller/table"
|
616
|
+
require "ruport/controller/grouping"
|