ruport 0.10.0 → 0.11.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (59) hide show
  1. data/LICENSE +55 -9
  2. data/Rakefile +3 -5
  3. data/examples/line_plotter.rb +3 -0
  4. data/examples/pdf_complex_report.rb +0 -1
  5. data/examples/pdf_report_with_common_base.rb +72 -0
  6. data/examples/pdf_styles.rb +16 -0
  7. data/examples/simple_pdf_lines.rb +0 -1
  8. data/lib/ruport.rb +5 -66
  9. data/lib/ruport/acts_as_reportable.rb +122 -51
  10. data/lib/ruport/data/grouping.rb +30 -13
  11. data/lib/ruport/data/record.rb +26 -25
  12. data/lib/ruport/data/table.rb +91 -34
  13. data/lib/ruport/formatter.rb +86 -11
  14. data/lib/ruport/formatter/csv.rb +29 -2
  15. data/lib/ruport/formatter/html.rb +23 -1
  16. data/lib/ruport/formatter/pdf.rb +123 -32
  17. data/lib/ruport/formatter/text.rb +62 -6
  18. data/lib/ruport/query.rb +75 -39
  19. data/lib/ruport/renderer.rb +250 -35
  20. data/lib/ruport/renderer/grouping.rb +2 -2
  21. data/test/html_formatter_test.rb +4 -1
  22. data/test/pdf_formatter_test.rb +30 -7
  23. data/test/query_test.rb +12 -0
  24. data/test/renderer_test.rb +33 -2
  25. data/test/table_test.rb +8 -2
  26. data/test/text_formatter_test.rb +11 -1
  27. metadata +53 -107
  28. data/bin/rope +0 -12
  29. data/examples/rope_examples/itunes/README +0 -12
  30. data/examples/rope_examples/itunes/Rakefile +0 -39
  31. data/examples/rope_examples/itunes/config/environment.rb +0 -4
  32. data/examples/rope_examples/itunes/data/mix.txt +0 -1
  33. data/examples/rope_examples/itunes/lib/helpers.rb +0 -0
  34. data/examples/rope_examples/itunes/lib/init.rb +0 -39
  35. data/examples/rope_examples/itunes/lib/reports.rb +0 -1
  36. data/examples/rope_examples/itunes/lib/reports/playlist.rb +0 -17
  37. data/examples/rope_examples/itunes/log/ruport.log +0 -1
  38. data/examples/rope_examples/itunes/test/test_playlist.rb +0 -8
  39. data/examples/rope_examples/itunes/util/build +0 -96
  40. data/examples/rope_examples/itunes/util/sql_exec +0 -5
  41. data/examples/rope_examples/sales_report/README +0 -4
  42. data/examples/rope_examples/sales_report/Rakefile +0 -39
  43. data/examples/rope_examples/sales_report/config/environment.rb +0 -4
  44. data/examples/rope_examples/sales_report/lib/helpers.rb +0 -0
  45. data/examples/rope_examples/sales_report/lib/init.rb +0 -39
  46. data/examples/rope_examples/sales_report/lib/reports.rb +0 -1
  47. data/examples/rope_examples/sales_report/lib/reports/sales.rb +0 -132
  48. data/examples/rope_examples/sales_report/log/ruport.log +0 -1
  49. data/examples/rope_examples/sales_report/output/books.pdf +0 -170
  50. data/examples/rope_examples/sales_report/output/books.txt +0 -11
  51. data/examples/rope_examples/sales_report/test/test_sales.rb +0 -8
  52. data/examples/rope_examples/sales_report/util/build +0 -96
  53. data/examples/rope_examples/sales_report/util/sql_exec +0 -5
  54. data/examples/sample.rb +0 -16
  55. data/lib/ruport/generator.rb +0 -294
  56. data/lib/ruport/report.rb +0 -262
  57. data/setup.rb +0 -1585
  58. data/test/report_test.rb +0 -218
  59. data/test/samples/foo.rtxt +0 -3
@@ -1,11 +1,55 @@
1
- module Ruport
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 DBI. It supports
9
- # returning result sets in either Ruport's native Data::Table, or in their
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
- # It offers basic caching support, the ability to instantiate a generator
13
- # for a result set, and the ability to quickly and easily swap between data
14
- # sources.
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>:raw_data</tt></b>:: When set to true, DBI::Rows will be
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",:origin => :file)
68
+ # Ruport::Query.new(:file => "foo")
60
69
  #
61
- def initialize(sql, options={})
62
- options = { :source => :default, :origin => :string }.merge(options)
63
- options[:origin] = :file if sql =~ /.sql$/
64
- @statements = SqlSplit.new(get_query(options[:origin],sql))
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
@@ -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; end
18
- class UnknownFormatError < RuntimeError; end
19
- class StageAlreadyDefinedError < RuntimeError; end
20
- class RendererNotSetError < RuntimeError; end
21
-
22
- require "ostruct"
23
- class Options < OpenStruct #:nodoc:
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 Hooks #:nodoc:
36
- module ClassMethods
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
- def stage(*stage_list)
156
- self.stages ||= []
157
- stage_list.each { |stage|
158
- self.stages << stage.to_s
159
- }
160
- end
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
- attr_accessor :format
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