ruport 0.10.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- data/LICENSE +55 -9
- data/Rakefile +3 -5
- data/examples/line_plotter.rb +3 -0
- data/examples/pdf_complex_report.rb +0 -1
- data/examples/pdf_report_with_common_base.rb +72 -0
- data/examples/pdf_styles.rb +16 -0
- data/examples/simple_pdf_lines.rb +0 -1
- data/lib/ruport.rb +5 -66
- data/lib/ruport/acts_as_reportable.rb +122 -51
- data/lib/ruport/data/grouping.rb +30 -13
- data/lib/ruport/data/record.rb +26 -25
- data/lib/ruport/data/table.rb +91 -34
- data/lib/ruport/formatter.rb +86 -11
- data/lib/ruport/formatter/csv.rb +29 -2
- data/lib/ruport/formatter/html.rb +23 -1
- data/lib/ruport/formatter/pdf.rb +123 -32
- data/lib/ruport/formatter/text.rb +62 -6
- data/lib/ruport/query.rb +75 -39
- data/lib/ruport/renderer.rb +250 -35
- data/lib/ruport/renderer/grouping.rb +2 -2
- data/test/html_formatter_test.rb +4 -1
- data/test/pdf_formatter_test.rb +30 -7
- data/test/query_test.rb +12 -0
- data/test/renderer_test.rb +33 -2
- data/test/table_test.rb +8 -2
- data/test/text_formatter_test.rb +11 -1
- metadata +53 -107
- data/bin/rope +0 -12
- data/examples/rope_examples/itunes/README +0 -12
- data/examples/rope_examples/itunes/Rakefile +0 -39
- data/examples/rope_examples/itunes/config/environment.rb +0 -4
- data/examples/rope_examples/itunes/data/mix.txt +0 -1
- data/examples/rope_examples/itunes/lib/helpers.rb +0 -0
- data/examples/rope_examples/itunes/lib/init.rb +0 -39
- data/examples/rope_examples/itunes/lib/reports.rb +0 -1
- data/examples/rope_examples/itunes/lib/reports/playlist.rb +0 -17
- data/examples/rope_examples/itunes/log/ruport.log +0 -1
- data/examples/rope_examples/itunes/test/test_playlist.rb +0 -8
- data/examples/rope_examples/itunes/util/build +0 -96
- data/examples/rope_examples/itunes/util/sql_exec +0 -5
- data/examples/rope_examples/sales_report/README +0 -4
- data/examples/rope_examples/sales_report/Rakefile +0 -39
- data/examples/rope_examples/sales_report/config/environment.rb +0 -4
- data/examples/rope_examples/sales_report/lib/helpers.rb +0 -0
- data/examples/rope_examples/sales_report/lib/init.rb +0 -39
- data/examples/rope_examples/sales_report/lib/reports.rb +0 -1
- data/examples/rope_examples/sales_report/lib/reports/sales.rb +0 -132
- data/examples/rope_examples/sales_report/log/ruport.log +0 -1
- data/examples/rope_examples/sales_report/output/books.pdf +0 -170
- data/examples/rope_examples/sales_report/output/books.txt +0 -11
- data/examples/rope_examples/sales_report/test/test_sales.rb +0 -8
- data/examples/rope_examples/sales_report/util/build +0 -96
- data/examples/rope_examples/sales_report/util/sql_exec +0 -5
- data/examples/sample.rb +0 -16
- data/lib/ruport/generator.rb +0 -294
- data/lib/ruport/report.rb +0 -262
- data/setup.rb +0 -1585
- data/test/report_test.rb +0 -218
- data/test/samples/foo.rtxt +0 -3
@@ -1,11 +1,55 @@
|
|
1
|
-
|
1
|
+
# Ruport : Extensible Reporting System
|
2
|
+
#
|
3
|
+
# formatter/text.rb provides text formatting for Ruport.
|
4
|
+
#
|
5
|
+
# Created by Gregory Brown, some time around Spring 2006.
|
6
|
+
# Copyright (C) 2006-2007, All Rights Reserved.
|
7
|
+
#
|
8
|
+
# Mathijs Mohlmann and Marshall T. Vandegrift have provided some patches for
|
9
|
+
# this class, see AUTHORS file for details.
|
10
|
+
#
|
11
|
+
# This is free software distributed under the same terms as Ruby 1.8
|
12
|
+
# See LICENSE and COPYING for details.
|
13
|
+
module Ruport
|
14
|
+
# This class provides text output for Ruport's Row,Table,Group, and Grouping
|
15
|
+
# renderers
|
16
|
+
#
|
17
|
+
# It handles things like automatically truncating tables that go off the
|
18
|
+
# edge of the screen in the console, proper column alignment, and pretty
|
19
|
+
# output that looks something like this:
|
20
|
+
#
|
21
|
+
# +-----------------------------+
|
22
|
+
# | apple | banana | strawberry |
|
23
|
+
# +-----------------------------+
|
24
|
+
# | yes | no | yes |
|
25
|
+
# | yes | yes | god yes |
|
26
|
+
# | what | the | f? |
|
27
|
+
# +-----------------------------+
|
28
|
+
#
|
29
|
+
# === Supported Options
|
30
|
+
#
|
31
|
+
# <tt>:max_col_width:</tt> Ordinal array of column widths. Set automatically
|
32
|
+
# but can be overridden
|
33
|
+
#
|
34
|
+
# <tt>:alignment:</tt> Defaults to left justify text and right justify numbers.
|
35
|
+
# centers all fields when set to :center
|
36
|
+
#
|
37
|
+
# <tt>:table_width:</tt> Will truncate rows at this limit.
|
38
|
+
#
|
39
|
+
# <tt>:show_table_headers:</tt> Defaults to true
|
40
|
+
#
|
41
|
+
# <tt>:show_group_headers:</tt> Defaults to true
|
42
|
+
#
|
43
|
+
# <tt>:ignore_table_width:</tt> When set to true, outputs full table without
|
44
|
+
# truncating it. Useful for file output
|
2
45
|
class Formatter::Text < Formatter
|
3
46
|
|
4
47
|
renders :text, :for => [ Renderer::Row, Renderer::Table,
|
5
48
|
Renderer::Group, Renderer::Grouping ]
|
6
49
|
|
7
50
|
opt_reader :max_col_width, :alignment, :table_width,
|
8
|
-
:show_table_headers, :show_group_headers
|
51
|
+
:show_table_headers, :show_group_headers,
|
52
|
+
:ignore_table_width
|
9
53
|
|
10
54
|
# Checks to ensure the table is not empty and then calls
|
11
55
|
# calculate_max_col_widths
|
@@ -47,13 +91,22 @@ module Ruport
|
|
47
91
|
rend.options do |o|
|
48
92
|
o.max_col_width = max_col_width
|
49
93
|
o.alignment = alignment
|
50
|
-
o.table_width = table_width
|
94
|
+
o.table_width = table_width
|
95
|
+
o.ignore_table_width = ignore_table_width
|
51
96
|
end
|
52
97
|
end
|
53
98
|
|
54
99
|
output << fit_to_width(hr)
|
55
100
|
end
|
56
|
-
|
101
|
+
|
102
|
+
# Generates a formatted text row.
|
103
|
+
#
|
104
|
+
# Defaults to numeric values being right justified, and other values being
|
105
|
+
# left justified. Can be changed to support centering of output by
|
106
|
+
# setting options.alignment to :center
|
107
|
+
#
|
108
|
+
# Uses fit_to_width to truncate table if necessary.
|
109
|
+
#
|
57
110
|
def build_row
|
58
111
|
max_col_widths_for_row(data) unless max_col_width
|
59
112
|
|
@@ -113,7 +166,8 @@ module Ruport
|
|
113
166
|
end
|
114
167
|
|
115
168
|
# Truncates a string so that it does not exceed Text#width
|
116
|
-
def fit_to_width(s)
|
169
|
+
def fit_to_width(s)
|
170
|
+
return s if options.ignore_table_width
|
117
171
|
# workaround for Rails setting terminal_width to 1
|
118
172
|
max_width = width < 2 ? 80 : width
|
119
173
|
|
@@ -137,7 +191,9 @@ module Ruport
|
|
137
191
|
|
138
192
|
data.each { |r| max_col_widths_for_row(r) }
|
139
193
|
end
|
140
|
-
|
194
|
+
|
195
|
+
# used to calculate the <tt>max_col_widths</tt> array.
|
196
|
+
# Override this to tweak the automatic column size adjustments.
|
141
197
|
def max_col_widths_for_row(row)
|
142
198
|
options.max_col_width ||= []
|
143
199
|
row.each_with_index do |f,i|
|
data/lib/ruport/query.rb
CHANGED
@@ -1,3 +1,15 @@
|
|
1
|
+
# Ruport : Extensible Reporting System
|
2
|
+
#
|
3
|
+
# query.rb provides a basic wrapper around RubyDBI for SQL interaction
|
4
|
+
#
|
5
|
+
# Original work began by Gregory Brown based on ideas from James Edward Gray II
|
6
|
+
# in August, 2005.
|
7
|
+
#
|
8
|
+
# Copyright (C) 2005-2007, Gregory Brown
|
9
|
+
# All Rights Reserved.
|
10
|
+
#
|
11
|
+
# This is free software distributed under the same terms as Ruby 1.8
|
12
|
+
# See LICENSE and COPYING for details.
|
1
13
|
require "generator"
|
2
14
|
require "ruport/query/sql_split"
|
3
15
|
|
@@ -5,17 +17,18 @@ module Ruport
|
|
5
17
|
|
6
18
|
# === Overview
|
7
19
|
#
|
8
|
-
# Query offers a way to interact with databases via
|
9
|
-
# returning result sets in either Ruport's
|
20
|
+
# Query offers a way to interact with databases via RubyDBI. It supports
|
21
|
+
# returning result sets in either Ruport's Data::Table, or in their
|
10
22
|
# raw form as DBI::Rows.
|
11
23
|
#
|
12
|
-
#
|
13
|
-
#
|
14
|
-
#
|
24
|
+
# Query allows you to treat your result sets as an Enumerable data structure
|
25
|
+
# that plays well with the rest of Ruport.
|
26
|
+
#
|
27
|
+
# If you are using ActiveRecord, you might prefer our acts_as_reportable
|
28
|
+
# extension.
|
15
29
|
#
|
16
30
|
class Query
|
17
|
-
|
18
|
-
|
31
|
+
|
19
32
|
include Enumerable
|
20
33
|
|
21
34
|
# Ruport::Query provides an interface for dealing with raw SQL queries.
|
@@ -33,12 +46,8 @@ module Ruport
|
|
33
46
|
# be set with this option.
|
34
47
|
# <b><tt>:password</tt></b>:: If a DSN is specified, the password
|
35
48
|
# can be set with this option.
|
36
|
-
# <b><tt>:
|
37
|
-
# returned instead of a Data::Table
|
38
|
-
# <b><tt>:cache_enabled</tt></b>:: When set to true, Query will download
|
39
|
-
# results only once, and then return
|
40
|
-
# cached values until the cache has been
|
41
|
-
# cleared.
|
49
|
+
# <b><tt>:row_type</tt></b>:: When set to :raw, DBI::Rows will be
|
50
|
+
# returned instead of a Data::Table
|
42
51
|
#
|
43
52
|
# Examples:
|
44
53
|
#
|
@@ -56,12 +65,19 @@ module Ruport
|
|
56
65
|
# Ruport::Query.new("my_query.sql")
|
57
66
|
#
|
58
67
|
# # explicitly use a file, even if it doesn't end in .sql
|
59
|
-
# Ruport::Query.new("foo"
|
68
|
+
# Ruport::Query.new(:file => "foo")
|
60
69
|
#
|
61
|
-
def initialize(sql, options={})
|
62
|
-
|
63
|
-
|
64
|
-
|
70
|
+
def initialize(sql, options={})
|
71
|
+
if sql.kind_of?(Hash)
|
72
|
+
options = { :source => :default }.merge(sql)
|
73
|
+
sql = options[:file] || options[:string]
|
74
|
+
else
|
75
|
+
options = { :source => :default, :string => sql }.merge(options)
|
76
|
+
options[:file] = sql if sql =~ /.sql$/
|
77
|
+
end
|
78
|
+
origin = options[:file] ? :file : :string
|
79
|
+
|
80
|
+
@statements = SqlSplit.new(get_query(origin,sql))
|
65
81
|
@sql = @statements.join
|
66
82
|
|
67
83
|
if options[:dsn]
|
@@ -76,28 +92,43 @@ module Ruport
|
|
76
92
|
@raw_data = options[:row_type].eql?(:raw)
|
77
93
|
@params = options[:params]
|
78
94
|
end
|
79
|
-
|
95
|
+
|
96
|
+
# Returns an OpenStruct with the configuration options for the default
|
97
|
+
# database source.
|
98
|
+
#
|
80
99
|
def self.default_source
|
81
100
|
sources[:default]
|
82
101
|
end
|
83
|
-
|
102
|
+
|
103
|
+
# Returns a hash of database sources, keyed by label.
|
84
104
|
def self.sources
|
85
105
|
@sources ||= {}
|
86
106
|
end
|
87
|
-
|
107
|
+
|
108
|
+
# Allows you to add a labeled DBI source configuration.
|
109
|
+
#
|
110
|
+
# Query objects will use the source labeled <tt>:default</tt>,
|
111
|
+
# unless another source is specified.
|
112
|
+
#
|
113
|
+
# Examples:
|
114
|
+
#
|
115
|
+
# # a connection to a MySQL database foo with user root, pass chunkybacon
|
116
|
+
# Query.add_source :default, :dsn => "dbi:mysql:foo",
|
117
|
+
# :user => "root",
|
118
|
+
# :password => "chunkybacon"
|
119
|
+
#
|
120
|
+
#
|
121
|
+
# # a second connection to a MySQL database bar
|
122
|
+
# Query.add_source :test, :dsn => "dbi:mysql:bar",
|
123
|
+
# :user => "tester",
|
124
|
+
# :password => "blinky"
|
125
|
+
#
|
126
|
+
#
|
88
127
|
def self.add_source(name,options={})
|
89
128
|
sources[name] = OpenStruct.new(options)
|
90
129
|
check_source(sources[name],name)
|
91
130
|
end
|
92
131
|
|
93
|
-
private
|
94
|
-
|
95
|
-
def self.check_source(settings,label) # :nodoc:
|
96
|
-
raise ArgumentError unless settings.dsn
|
97
|
-
end
|
98
|
-
|
99
|
-
public
|
100
|
-
|
101
132
|
attr_accessor :raw_data
|
102
133
|
|
103
134
|
# The original SQL for the Query object
|
@@ -112,20 +143,20 @@ module Ruport
|
|
112
143
|
@password = Ruport::Query.sources[label].password
|
113
144
|
end
|
114
145
|
|
146
|
+
# Yields result set by row.
|
115
147
|
def each(&action)
|
116
148
|
raise(LocalJumpError, "No block given!") unless action
|
117
149
|
fetch(&action)
|
118
150
|
self
|
119
151
|
end
|
120
152
|
|
153
|
+
# Runs the SQL query and returns the result set
|
121
154
|
def result; fetch; end
|
122
155
|
|
123
156
|
# Runs the query without returning its results.
|
124
157
|
def execute; fetch; nil; end
|
125
158
|
|
126
159
|
# Returns a Data::Table, even if in <tt>raw_data</tt> mode.
|
127
|
-
# This doesn't work with raw data if the cache is enabled and filled.
|
128
|
-
#
|
129
160
|
def to_table
|
130
161
|
data_flag, @raw_data = @raw_data, false
|
131
162
|
data = fetch; @raw_data = data_flag; return data
|
@@ -176,14 +207,6 @@ module Ruport
|
|
176
207
|
type.eql?(:file) ? load_file( query ) : query
|
177
208
|
end
|
178
209
|
|
179
|
-
def load_file(query_file)
|
180
|
-
begin
|
181
|
-
File.read( query_file ).strip
|
182
|
-
rescue
|
183
|
-
raise LoadError, "Could not open #{query_file}"
|
184
|
-
end
|
185
|
-
end
|
186
|
-
|
187
210
|
def fetch(&block)
|
188
211
|
data = nil
|
189
212
|
final = @statements.size - 1
|
@@ -192,5 +215,18 @@ module Ruport
|
|
192
215
|
end
|
193
216
|
return data
|
194
217
|
end
|
218
|
+
|
219
|
+
def load_file(query_file)
|
220
|
+
begin
|
221
|
+
File.read( query_file ).strip
|
222
|
+
rescue
|
223
|
+
raise LoadError, "Could not open #{query_file}"
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
def self.check_source(settings,label) # :nodoc:
|
228
|
+
raise ArgumentError unless settings.dsn
|
229
|
+
end
|
230
|
+
|
195
231
|
end
|
196
232
|
end
|
data/lib/ruport/renderer.rb
CHANGED
@@ -13,62 +13,156 @@
|
|
13
13
|
# This class can easily be extended to build custom formatting systems, but if
|
14
14
|
# you do not need that, it may not be relevant to study for your use of Ruport.
|
15
15
|
class Ruport::Renderer
|
16
|
-
|
17
|
-
class RequiredOptionNotSet < RuntimeError
|
18
|
-
|
19
|
-
class
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
class
|
16
|
+
|
17
|
+
class RequiredOptionNotSet < RuntimeError #:nodoc:
|
18
|
+
end
|
19
|
+
class UnknownFormatError < RuntimeError #:nodoc:
|
20
|
+
end
|
21
|
+
class StageAlreadyDefinedError < RuntimeError #:nodoc:
|
22
|
+
end
|
23
|
+
class RendererNotSetError < RuntimeError #:nodoc:
|
24
|
+
end
|
25
|
+
|
26
|
+
require "ostruct"
|
27
|
+
|
28
|
+
# Structure for holding renderer options.
|
29
|
+
# Simplified version of HashWithIndifferentAccess
|
30
|
+
class Options < OpenStruct
|
31
|
+
# returns a Hash object. Use this if you need methods other than []
|
24
32
|
def to_hash
|
25
33
|
@table
|
26
|
-
end
|
34
|
+
end
|
35
|
+
# indifferent lookup of an attribute, e.g.
|
36
|
+
#
|
37
|
+
# options[:foo] == options["foo"]
|
27
38
|
def [](key)
|
28
39
|
send(key)
|
29
|
-
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Sets an attribute, with indifferent access.
|
43
|
+
#
|
44
|
+
# options[:foo] = "bar"
|
45
|
+
#
|
46
|
+
# options[:foo] == options["foo"] #=> true
|
47
|
+
# options["foo"] == options.foo #=> true
|
48
|
+
# options.foo #=> "bar"
|
30
49
|
def []=(key,value)
|
31
50
|
send("#{key}=",value)
|
32
51
|
end
|
33
52
|
end
|
34
|
-
|
35
|
-
module
|
36
|
-
|
53
|
+
|
54
|
+
# This module provides hooks into Ruport's formatting system.
|
55
|
+
# It is used to implement the as() method for all of Ruport's datastructures,
|
56
|
+
# as well as the renders_with and renders_as_* helpers.
|
57
|
+
#
|
58
|
+
# You can actually use this with any data structure, it will look for a
|
59
|
+
# renderable_data method to pass to the <tt>renderer</tt> you specify,
|
60
|
+
# but if that is not defined, it will pass <tt>self</tt>
|
61
|
+
#
|
62
|
+
# Examples:
|
63
|
+
#
|
64
|
+
# # Render Arrays with Ruport's Row Renderer
|
65
|
+
# class Array
|
66
|
+
# include Ruport::Renderer::Hooks
|
67
|
+
# renders_as_row
|
68
|
+
# end
|
69
|
+
#
|
70
|
+
# # >> [1,2,3].as(:csv)
|
71
|
+
# # => "1,2,3\n"
|
72
|
+
#
|
73
|
+
# # Render Hashes with Ruport's Row Renderer
|
74
|
+
# class Hash
|
75
|
+
# include Ruport::Renderer::Hooks
|
76
|
+
# renders_as_row
|
77
|
+
# attr_accessor :column_order
|
78
|
+
# def renderable_data
|
79
|
+
# column_order.map { |c| self[c] }
|
80
|
+
# end
|
81
|
+
# end
|
82
|
+
#
|
83
|
+
# # >> a = { :a => 1, :b => 2, :c => 3 }
|
84
|
+
# # >> a.column_order = [:b,:a,:c]
|
85
|
+
# # >> a.as(:csv)
|
86
|
+
# # => "2,1,3\n"
|
87
|
+
module Hooks
|
88
|
+
module ClassMethods
|
89
|
+
|
90
|
+
# Tells the class which renderer as() will forward to.
|
91
|
+
#
|
92
|
+
# usage:
|
93
|
+
#
|
94
|
+
# class MyStructure
|
95
|
+
# include Renderer::Hooks
|
96
|
+
# renders_with CustomRenderer
|
97
|
+
# end
|
98
|
+
#
|
99
|
+
# You can also specify default rendering options, which will be used
|
100
|
+
# if they are not overriden by the options passed to as()
|
101
|
+
#
|
102
|
+
# class MyStructure
|
103
|
+
# include Renderer::Hooks
|
104
|
+
# renders_with CustomRenderer, :font_size => 14
|
105
|
+
# end
|
37
106
|
def renders_with(renderer,opts={})
|
38
107
|
@renderer = renderer.name
|
39
108
|
@rendering_options=opts
|
40
109
|
end
|
41
|
-
|
110
|
+
|
111
|
+
# The default rendering options for a class, stored as a hash.
|
42
112
|
def rendering_options
|
43
113
|
@rendering_options
|
44
114
|
end
|
45
|
-
|
115
|
+
|
116
|
+
# Shortcut for renders_with(Ruport::Renderer::Table), you
|
117
|
+
# may wish to override this if you build a custom table renderer.
|
46
118
|
def renders_as_table(options={})
|
47
119
|
renders_with Ruport::Renderer::Table,options
|
48
120
|
end
|
49
|
-
|
121
|
+
|
122
|
+
# Shortcut for renders_with(Ruport::Renderer::Row), you
|
123
|
+
# may wish to override this if you build a custom row renderer.
|
50
124
|
def renders_as_row(options={})
|
51
125
|
renders_with Ruport::Renderer::Row, options
|
52
126
|
end
|
53
|
-
|
127
|
+
|
128
|
+
# Shortcut for renders_with(Ruport::Renderer::Group), you
|
129
|
+
# may wish to override this if you build a custom group renderer.
|
54
130
|
def renders_as_group(options={})
|
55
131
|
renders_with Ruport::Renderer::Group,options
|
56
132
|
end
|
57
133
|
|
134
|
+
# Shortcut for renders_with(Ruport::Renderer::Grouping), you
|
135
|
+
# may wish to override this if you build a custom grouping renderer.
|
58
136
|
def renders_as_grouping(options={})
|
59
137
|
renders_with Ruport::Renderer::Grouping,options
|
60
138
|
end
|
61
|
-
|
139
|
+
|
140
|
+
# The class of the renderer object for the base class.
|
141
|
+
#
|
142
|
+
# Example
|
143
|
+
#
|
144
|
+
# >> Ruport::Data::Table.renderer
|
145
|
+
# => Ruport::Renderer::Table
|
62
146
|
def renderer
|
63
147
|
return unless @renderer
|
64
148
|
@renderer.split("::").inject(Class) { |c,el| c.const_get(el) }
|
65
149
|
end
|
66
150
|
end
|
67
151
|
|
68
|
-
def self.included(base)
|
152
|
+
def self.included(base) #:nodoc:
|
69
153
|
base.extend(ClassMethods)
|
70
154
|
end
|
71
|
-
|
155
|
+
|
156
|
+
# Uses the Renderer specified by renders_with to generate formatted
|
157
|
+
# output. Passes the return value of the <tt>renderable_data</tt> method if
|
158
|
+
# the method is defined, otherwise passes <tt>self</tt> as :data
|
159
|
+
#
|
160
|
+
# The remaining options are converted to a Renderer::Options object and
|
161
|
+
# accessible in both the renderer and formatter.
|
162
|
+
#
|
163
|
+
# Example:
|
164
|
+
#
|
165
|
+
# table.as(:csv, :show_table_headers => false)
|
72
166
|
def as(format,options={})
|
73
167
|
raise RendererNotSetError unless self.class.renderer
|
74
168
|
unless self.class.renderer.formats.include?(format)
|
@@ -122,28 +216,125 @@ class Ruport::Renderer
|
|
122
216
|
class << self
|
123
217
|
|
124
218
|
attr_accessor :first_stage,:final_stage,:required_options,:stages #:nodoc:
|
125
|
-
|
219
|
+
|
220
|
+
# Registers a hook to look for in the Formatter object when the render()
|
221
|
+
# method is called.
|
222
|
+
#
|
223
|
+
# Usage:
|
224
|
+
#
|
225
|
+
# class MyRenderer < Ruport::Renderer
|
226
|
+
# # other details omitted...
|
227
|
+
# finalize :apple
|
228
|
+
# end
|
229
|
+
#
|
230
|
+
# class MyFormatter < Ruport::Formatter
|
231
|
+
# renders :example, :for => MyRenderer
|
232
|
+
#
|
233
|
+
# # other details omitted...
|
234
|
+
#
|
235
|
+
# def finalize_apple
|
236
|
+
# # this method will be called when MyRenderer tries to render
|
237
|
+
# # the :example format
|
238
|
+
# end
|
239
|
+
# end
|
240
|
+
#
|
241
|
+
# If a formatter does not implement this hook, it is simply ignored.
|
126
242
|
def finalize(stage)
|
127
243
|
if final_stage
|
128
244
|
raise StageAlreadyDefinedError, 'final stage already defined'
|
129
245
|
end
|
130
246
|
self.final_stage = stage
|
131
247
|
end
|
132
|
-
|
248
|
+
|
249
|
+
# Registers a hook to look for in the Formatter object when the render()
|
250
|
+
# method is called.
|
251
|
+
#
|
252
|
+
# Usage:
|
253
|
+
#
|
254
|
+
# class MyRenderer < Ruport::Renderer
|
255
|
+
# # other details omitted...
|
256
|
+
# prepare :apple
|
257
|
+
# end
|
258
|
+
#
|
259
|
+
# class MyFormatter < Ruport::Formatter
|
260
|
+
# renders :example, :for => MyRenderer
|
261
|
+
#
|
262
|
+
# def prepare_apple
|
263
|
+
# # this method will be called when MyRenderer tries to render
|
264
|
+
# # the :example format
|
265
|
+
# end
|
266
|
+
#
|
267
|
+
# # other details omitted...
|
268
|
+
# end
|
269
|
+
#
|
270
|
+
# If a formatter does not implement this hook, it is simply ignored.
|
133
271
|
def prepare(stage)
|
134
272
|
if first_stage
|
135
273
|
raise StageAlreadyDefinedError, "prepare stage already defined"
|
136
274
|
end
|
137
275
|
self.first_stage = stage
|
138
276
|
end
|
139
|
-
|
277
|
+
|
278
|
+
# Registers hooks to look for in the Formatter object when the render()
|
279
|
+
# method is called.
|
280
|
+
#
|
281
|
+
# Usage:
|
282
|
+
#
|
283
|
+
# class MyRenderer < Ruport::Renderer
|
284
|
+
# # other details omitted...
|
285
|
+
# stage :apple,:banana
|
286
|
+
# end
|
287
|
+
#
|
288
|
+
# class MyFormatter < Ruport::Formatter
|
289
|
+
# renders :example, :for => MyRenderer
|
290
|
+
#
|
291
|
+
# def build_apple
|
292
|
+
# # this method will be called when MyRenderer tries to render
|
293
|
+
# # the :example format
|
294
|
+
# end
|
295
|
+
#
|
296
|
+
# def build_banana
|
297
|
+
# # this method will be called when MyRenderer tries to render
|
298
|
+
# # the :example format
|
299
|
+
# end
|
300
|
+
#
|
301
|
+
# # other details omitted...
|
302
|
+
# end
|
303
|
+
#
|
304
|
+
# If a formatter does not implement these hooks, they are simply ignored.
|
305
|
+
def stage(*stage_list)
|
306
|
+
self.stages ||= []
|
307
|
+
stage_list.each { |stage|
|
308
|
+
self.stages << stage.to_s
|
309
|
+
}
|
310
|
+
end
|
311
|
+
|
312
|
+
# Defines attribute writers for the Renderer::Options object shared
|
313
|
+
# between Renderer and Formatter
|
314
|
+
#
|
315
|
+
# usage:
|
316
|
+
#
|
317
|
+
# class MyRenderer < Ruport::Renderer
|
318
|
+
# option :font_size, :font_style
|
319
|
+
# # other details omitted
|
320
|
+
# end
|
140
321
|
def option(*opts)
|
141
322
|
opts.each do |opt|
|
142
323
|
opt = "#{opt}="
|
143
324
|
define_method(opt) {|t| options.send(opt, t) }
|
144
325
|
end
|
145
326
|
end
|
146
|
-
|
327
|
+
|
328
|
+
# Defines attribute writers for the Renderer::Options object shared
|
329
|
+
# between Renderer and Formatter. Will throw an error if the user does
|
330
|
+
# not provide values for these options upon rendering.
|
331
|
+
#
|
332
|
+
# usage:
|
333
|
+
#
|
334
|
+
# class MyRenderer < Ruport::Renderer
|
335
|
+
# required_option :employee_name, :address
|
336
|
+
# # other details omitted
|
337
|
+
# end
|
147
338
|
def required_option(*opts)
|
148
339
|
self.required_options ||= []
|
149
340
|
opts.each do |opt|
|
@@ -151,18 +342,38 @@ class Ruport::Renderer
|
|
151
342
|
option opt
|
152
343
|
end
|
153
344
|
end
|
345
|
+
|
154
346
|
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
347
|
+
# Lists the formatters that are currently registered on a renderer,
|
348
|
+
# as a hash keyed by format name.
|
349
|
+
#
|
350
|
+
# Example:
|
351
|
+
#
|
352
|
+
# >> Ruport::Renderer::Table.formats
|
353
|
+
# => {:html=>Ruport::Formatter::HTML,
|
354
|
+
# ?> :csv=>Ruport::Formatter::CSV,
|
355
|
+
# ?> :text=>Ruport::Formatter::Text,
|
356
|
+
# ?> :pdf=>Ruport::Formatter::PDF}
|
162
357
|
def formats
|
163
358
|
@formats ||= {}
|
164
359
|
end
|
165
|
-
|
360
|
+
|
361
|
+
# Builds up a renderer object, looks up the appropriate formatter,
|
362
|
+
# sets the data and options, and then does the following process:
|
363
|
+
#
|
364
|
+
# * If the renderer contains a module Helpers, mix it in to the instance.
|
365
|
+
# * If a setup() method is defined on the Renderer, call it
|
366
|
+
# * If a block is given, yield the Renderer instance
|
367
|
+
# * If the renderer has defined a run() method, call it, otherwise,
|
368
|
+
# include Renderer::AutoRunner. (you usually won't need a run() method )
|
369
|
+
# * call _run_ if it exists (This is provided by default, by AutoRunner)
|
370
|
+
# * return the results of formatter.output
|
371
|
+
#
|
372
|
+
# Note that the only time you will need a run() method is if you can't
|
373
|
+
# do what you need to via a helpers module or via setup()
|
374
|
+
#
|
375
|
+
# Please see the examples/ directory for custom renderer examples, because
|
376
|
+
# this is not nearly as complicated as it sounds in most cases.
|
166
377
|
def render(*args)
|
167
378
|
rend = build(*args) { |r|
|
168
379
|
r.setup if r.respond_to? :setup
|
@@ -230,10 +441,14 @@ class Ruport::Renderer
|
|
230
441
|
end
|
231
442
|
|
232
443
|
end
|
233
|
-
|
234
|
-
|
444
|
+
|
445
|
+
# The name of format being used
|
446
|
+
attr_accessor :format
|
447
|
+
|
448
|
+
# The formatter object being used
|
235
449
|
attr_writer :formatter
|
236
|
-
|
450
|
+
|
451
|
+
# The +data+ that has been passed to the active formatter.
|
237
452
|
def data
|
238
453
|
formatter.data
|
239
454
|
end
|