ruport 0.10.0 → 0.11.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/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
|