ruport 1.0.2 → 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -66,7 +66,7 @@ module Ruport
66
66
  #
67
67
  module RenderingTools
68
68
  # Iterates through <tt>data</tt> and passes
69
- # each row to render_row with the given options
69
+ # each row to render_row with the given options.
70
70
  def render_data_by_row(options={},&block)
71
71
  data.each do |r|
72
72
  render_row(r,options,&block)
@@ -124,7 +124,9 @@ module Ruport
124
124
  def render_helper(rend_klass, source_data,options={},&block)
125
125
  options = {:data => source_data,
126
126
  :io => output,
127
- :layout => false }.merge(options)
127
+ :layout => false }.merge(options)
128
+
129
+ options[:io] = "" if self.class.kind_of?(Ruport::Formatter::PDF)
128
130
  rend_klass.render(format,options) do |rend|
129
131
  block[rend] if block
130
132
  end
@@ -140,11 +142,11 @@ module Ruport
140
142
  # Set automatically by Renderer#render(format) or Renderer#render_format
141
143
  attr_accessor :format
142
144
 
143
- # Set automatically by Renderer#render as a Renderer::Options option built
145
+ # Set automatically by Renderer#render as a Renderer::Options object built
144
146
  # by the hash provided.
145
147
  attr_writer :options
146
148
 
147
- # Registers the formatter with one or more Renderers
149
+ # Registers the formatter with one or more Renderers.
148
150
  #
149
151
  # renders :pdf, :for => MyRenderer
150
152
  # render :text, :for => [MyRenderer,YourRenderer]
@@ -172,6 +174,11 @@ module Ruport
172
174
  # Gives a list of formats registered for this formatter.
173
175
  def self.formats
174
176
  @formats ||= []
177
+ end
178
+
179
+ # Returns the template currently set for this formatter.
180
+ def template
181
+ Template[options.template]
175
182
  end
176
183
 
177
184
  # Stores a string used for outputting formatted data.
@@ -180,15 +187,20 @@ module Ruport
180
187
  @output ||= ""
181
188
  end
182
189
 
183
- # Provides a Renderer::Options object for storing formatting options
190
+ # Provides a Renderer::Options object for storing formatting options.
184
191
  def options
185
192
  @options ||= Renderer::Options.new
186
193
  end
187
194
 
188
- # Clears output.
195
+ # Clears the output.
189
196
  def clear_output
190
197
  @output.replace("")
191
- end
198
+ end
199
+
200
+ # Saves the output to a file.
201
+ def save_output(filename)
202
+ File.open(filename,"w") {|f| f << output }
203
+ end
192
204
 
193
205
  # Evaluates the string using ERB and returns the results.
194
206
  #
@@ -203,7 +215,7 @@ module Ruport
203
215
  end
204
216
  end
205
217
 
206
- # Provides a shortcut for per format handlers.
218
+ # Provides a shortcut for per-format handlers.
207
219
  #
208
220
  # Example:
209
221
  #
@@ -218,8 +230,9 @@ module Ruport
218
230
  end
219
231
  end
220
232
  end
221
- end
233
+ end
222
234
 
235
+ require "ruport/formatter/template"
223
236
  require "ruport/formatter/csv"
224
237
  require "ruport/formatter/html"
225
238
  require "ruport/formatter/text"
@@ -14,8 +14,8 @@
14
14
  module Ruport
15
15
 
16
16
  # This formatter implements the CSV format for Ruport's Row, Table, Group
17
- # and Grouping renderers. It is a light wrapper around James Edward Gray II's
18
- # FasterCSV.
17
+ # and Grouping renderers. It is a light wrapper around
18
+ # James Edward Gray II's FasterCSV.
19
19
  #
20
20
  # === Rendering Options
21
21
  #
@@ -37,6 +37,16 @@ module Ruport
37
37
  :show_group_headers,
38
38
  :style
39
39
 
40
+ # Hook for setting available options using a template. See the template
41
+ # documentation for the available options and their format.
42
+ def apply_template
43
+ apply_table_format_template(template.table_format)
44
+ apply_grouping_format_template(template.grouping_format)
45
+
46
+ options.format_options = template.format_options if
47
+ template.format_options
48
+ end
49
+
40
50
  # Generates table header by turning column_names into a CSV row.
41
51
  # Uses the row renderer to generate the actual formatted output
42
52
  #
@@ -82,7 +92,7 @@ module Ruport
82
92
  end
83
93
  end
84
94
 
85
- # determines the proper style to use and renders the Grouping.
95
+ # Determines the proper style to use and renders the Grouping.
86
96
  def build_grouping_body
87
97
  case style
88
98
  when :inline
@@ -110,5 +120,19 @@ module Ruport
110
120
  output << "\n"
111
121
  end
112
122
  end
123
+
124
+ def apply_table_format_template(t)
125
+ t = t || {}
126
+ options.show_table_headers = t[:show_headings] unless
127
+ t[:show_headings].nil?
128
+ end
129
+
130
+ def apply_grouping_format_template(t)
131
+ t = t || {}
132
+ options.style = t[:style] if t[:style]
133
+ options.show_group_headers = t[:show_headings] unless
134
+ t[:show_headings].nil?
135
+ end
136
+
113
137
  end
114
138
  end
@@ -11,9 +11,9 @@
11
11
  # See LICENSE and COPYING for details.
12
12
  #
13
13
  module Ruport
14
- # This class produces HTML output for Ruport's Row,Table,Group, and Grouping
15
- # renderers. It can be used as a subclass, as it has some helper methods
16
- # that might be useful for custom output
14
+ # This class produces HTML output for Ruport's Row, Table, Group, and
15
+ # Grouping renderers. It can be subclassed, as it has some helper methods
16
+ # that might be useful for custom output.
17
17
  #
18
18
  # === Rendering Options
19
19
  #
@@ -30,10 +30,17 @@ module Ruport
30
30
 
31
31
  opt_reader :show_table_headers, :show_group_headers, :style
32
32
 
33
+ # Hook for setting available options using a template. See the template
34
+ # documentation for the available options and their format.
35
+ def apply_template
36
+ apply_table_format_template(template.table_format)
37
+ apply_grouping_format_template(template.grouping_format)
38
+ end
39
+
33
40
  # Generates table headers based on the column names of your Data::Table.
34
41
  #
35
- # This method does not do anything if options.show_table_headers is false or
36
- # the Data::Table has no column names.
42
+ # This method does not do anything if options.show_table_headers is false
43
+ # or the Data::Table has no column names.
37
44
  def build_table_header
38
45
  output << "\t<table>\n"
39
46
  unless data.column_names.empty? || !show_table_headers
@@ -57,7 +64,7 @@ module Ruport
57
64
  output << "\t</table>"
58
65
  end
59
66
 
60
- # Renders individual rows for the table
67
+ # Renders individual rows for the table.
61
68
  def build_row
62
69
  output <<
63
70
  "\t\t<tr>\n\t\t\t<td>" +
@@ -139,6 +146,19 @@ module Ruport
139
146
  def grouping_columns
140
147
  data.data.to_a[0][1].column_names
141
148
  end
149
+
150
+ def apply_table_format_template(t)
151
+ t = t || {}
152
+ options.show_table_headers = t[:show_headings] unless
153
+ t[:show_headings].nil?
154
+ end
155
+
156
+ def apply_grouping_format_template(t)
157
+ t = t || {}
158
+ options.style = t[:style] if t[:style]
159
+ options.show_group_headers = t[:show_headings] unless
160
+ t[:show_headings].nil?
161
+ end
142
162
 
143
163
  end
144
164
  end
@@ -54,9 +54,9 @@ module Ruport
54
54
  #p "this actually gets called"
55
55
  max_width = PDF::Writer::OHash.new(-1)
56
56
 
57
- # Find the maximum cell widths based on the data and the headings.
58
- # Passing through the data multiple times is unavoidable as we must do
59
- # some analysis first.
57
+ # Find the maximum cell widths based on the data and the headings.
58
+ # Passing through the data multiple times is unavoidable as we must
59
+ # do some analysis first.
60
60
  @data.each do |row|
61
61
  @cols.each do |name, column|
62
62
  w = pdf.text_width(row[name].to_s, @font_size)
@@ -82,8 +82,7 @@ module Ruport
82
82
 
83
83
  attr_writer :pdf_writer
84
84
 
85
- opt_reader :show_table_headers,
86
- :style,
85
+ opt_reader :style,
87
86
  :table_format,
88
87
  :text_format,
89
88
  :paper_size,
@@ -95,6 +94,17 @@ module Ruport
95
94
  require "pdf/simpletable"
96
95
  end
97
96
  end
97
+
98
+ # Hook for setting available options using a template. See the template
99
+ # documentation for the available options and their format.
100
+ def apply_template
101
+ apply_page_format_template(template.page_format)
102
+ apply_text_format_template(template.text_format)
103
+ apply_table_format_template(template.table_format)
104
+ apply_column_format_template(template.column_format)
105
+ apply_heading_format_template(template.heading_format)
106
+ apply_grouping_format_template(template.grouping_format)
107
+ end
98
108
 
99
109
  # Returns the current PDF::Writer object or creates a new one if it has not
100
110
  # been set yet.
@@ -119,18 +129,18 @@ module Ruport
119
129
  render_pdf unless options.skip_finalize_table
120
130
  end
121
131
 
122
- # Generates a header with the group name for Renderer::Group
132
+ # Generates a header with the group name for Renderer::Group.
123
133
  def build_group_header
124
134
  pad(10) { add_text data.name.to_s, :justification => :center }
125
135
  end
126
136
 
127
- # Renders the group as a table for Renderer::Group
137
+ # Renders the group as a table for Renderer::Group.
128
138
  def build_group_body
129
139
  render_table data, options.to_hash.merge(:formatter => pdf_writer)
130
140
  end
131
141
 
132
142
  # Determines which style to use and renders the main body for
133
- # Renderer::Grouping
143
+ # Renderer::Grouping.
134
144
  def build_grouping_body
135
145
  case style
136
146
  when :inline
@@ -145,13 +155,13 @@ module Ruport
145
155
  end
146
156
  end
147
157
 
148
- # calls <tt>render_pdf</tt>
158
+ # Calls <tt>render_pdf</tt>.
149
159
  def finalize_grouping
150
160
  render_pdf
151
161
  end
152
162
 
153
- # Call PDF::Writer#text with the given arguments, using <tt>text_format</tt>
154
- # defaults, if they are defined.
163
+ # Call PDF::Writer#text with the given arguments, using
164
+ # <tt>text_format</tt> defaults, if they are defined.
155
165
  #
156
166
  # Example:
157
167
  #
@@ -164,7 +174,7 @@ module Ruport
164
174
  pdf_writer.text(text, format_opts)
165
175
  end
166
176
 
167
- # Calls PDF::Writer#render and appends to <tt>output</tt>
177
+ # Calls PDF::Writer#render and appends to <tt>output</tt>.
168
178
  def render_pdf
169
179
  output << pdf_writer.render
170
180
  end
@@ -196,7 +206,7 @@ module Ruport
196
206
  pdf_writer.add_image_from_file(path, x, y, img_width, img_height)
197
207
  end
198
208
 
199
- # Draws some text on the canvas, surrounded by a box with rounded corner
209
+ # Draws some text on the canvas, surrounded by a box with rounded corners.
200
210
  #
201
211
  # Yields an OpenStruct which options can be defined on.
202
212
  #
@@ -254,22 +264,22 @@ module Ruport
254
264
  end
255
265
  end
256
266
 
257
- # adds n to pdf_writer.y, moving the vertical drawing position in the
258
- # document
267
+ # Adds n to pdf_writer.y, moving the vertical drawing position in the
268
+ # document.
259
269
  def move_cursor(n)
260
270
  pdf_writer.y += n
261
271
  end
262
272
 
263
- # moves the cursor to a specific y coordinate in the document
273
+ # Moves the cursor to a specific y coordinate in the document.
264
274
  def move_cursor_to(n)
265
275
  pdf_writer.y = n
266
276
  end
267
277
 
268
- # puts a specified amount of whitespace above and below the code
278
+ # Adds a specified amount of whitespace above and below the code
269
279
  # in your block. For example, if you want to surround the top and
270
280
  # bottom of a line of text with 5 pixels of whitespace:
271
281
  #
272
- # pad(5) { add_text "This will be padded" }
282
+ # pad(5) { add_text "This will be padded top and bottom" }
273
283
  def pad(y,&block)
274
284
  move_cursor(-y)
275
285
  block.call
@@ -290,13 +300,13 @@ module Ruport
290
300
  # For example, if you want to add a 10 pixel buffer to the bottom of a
291
301
  # line of text:
292
302
  #
293
- # pad_bottom(10) { add_text "This will be padded on top" }
303
+ # pad_bottom(10) { add_text "This will be padded on bottom" }
294
304
  def pad_bottom(y,&block)
295
305
  block.call
296
306
  move_cursor(-y)
297
307
  end
298
308
 
299
- # Draws a PDF::SimpleTable using the given data (usually a Data::Table)
309
+ # Draws a PDF::SimpleTable using the given data (usually a Data::Table).
300
310
  # Takes all the options you can set on a PDF::SimpleTable object,
301
311
  # see the PDF::Writer API docs for details, or check our quick reference
302
312
  # at:
@@ -327,25 +337,30 @@ module Ruport
327
337
  pdf_writer.font_size = old
328
338
  end
329
339
 
330
- # This module provides tools to simplify some common drawing operations
331
- # it is included by default in the PDF formatter
340
+ # Save the output to a file.
341
+ def save_output(filename)
342
+ File.open(filename,"wb") {|f| f << output }
343
+ end
344
+
345
+ # This module provides tools to simplify some common drawing operations.
346
+ # It is included by default in the PDF formatter.
332
347
  #
333
348
  module DrawingHelpers
334
349
 
335
- # draws a horizontal line from x1 to x2
350
+ # Draws a horizontal line from x1 to x2
336
351
  def horizontal_line(x1,x2)
337
352
  pdf_writer.line(x1,cursor,x2,cursor)
338
353
  pdf_writer.stroke
339
354
  end
340
355
 
341
- # draws a horizontal line from left_boundary to right_boundary
356
+ # Draws a horizontal line from left_boundary to right_boundary
342
357
  def horizontal_rule
343
358
  horizontal_line(left_boundary,right_boundary)
344
359
  end
345
360
 
346
361
  alias_method :hr, :horizontal_rule
347
362
 
348
- # draws a vertical line at x from y1 to y2
363
+ # Draws a vertical line at x from y1 to y2
349
364
  def vertical_line_at(x,y1,y2)
350
365
  pdf_writer.line(x,y1,x,y2)
351
366
  pdf_writer.stroke
@@ -377,33 +392,82 @@ module Ruport
377
392
  end
378
393
 
379
394
  # Draws text at an absolute location, defined by
380
- # :y, :x1|:left, :x2|:right
395
+ # :y, :x1|:left, :x2|:right
381
396
  #
382
- # All usual options to add_text are also supported
397
+ # All options to add_text are also supported.
383
398
  def draw_text(text,text_opts)
399
+ ypos = cursor
384
400
  move_cursor_to(text_opts[:y]) if text_opts[:y]
385
401
  add_text(text,
386
402
  text_opts.merge(:absolute_left => text_opts[:x1] || text_opts[:left],
387
403
  :absolute_right => text_opts[:x2] || text_opts[:right]))
404
+ move_cursor_to(ypos)
388
405
  end
389
406
 
407
+ # Draws text at an absolute location, defined by
408
+ # :y, :x1|:left
409
+ #
410
+ # The x position defaults to the left margin and the
411
+ # y position defaults to the current cursor location.
412
+ #
413
+ # Uses PDF::Writer#add_text, so it will ignore any options not supported
414
+ # by that method.
415
+ def draw_text!(text,text_opts)
416
+ ypos = cursor
417
+ pdf_writer.add_text(text_opts[:x1] || text_opts[:left] || left_boundary,
418
+ text_opts[:y] || ypos,
419
+ text,
420
+ text_opts[:font_size],
421
+ text_opts[:angle] || 0)
422
+ move_cursor_to(ypos)
423
+ end
390
424
  end
391
425
 
392
426
  include DrawingHelpers
393
427
 
394
- private
428
+ private
395
429
 
396
430
  def apply_pdf_table_column_opts(table,table_data,format_opts)
397
- column_opts = format_opts.delete(:column_options)
398
- if column_opts
399
- columns = table_data.column_names.inject({}) { |s,c|
400
- s.merge( c => ::PDF::SimpleTable::Column.new(c) { |col|
401
- column_opts.each { |k,v| col.send("#{k}=",v) }
431
+ column_opts = format_opts.delete(:column_options)
432
+
433
+ if column_opts
434
+ heading_opts = column_opts.delete(:heading)
435
+ if column_opts[:justification]
436
+ heading_opts ||= {}
437
+ heading_opts = {
438
+ :justification => column_opts[:justification]
439
+ }.merge(heading_opts)
440
+ end
441
+ specific = get_specific_column_options(table_data.column_names,
442
+ column_opts)
443
+ columns = table_data.column_names.inject({}) { |s,c|
444
+ s.merge( c => ::PDF::SimpleTable::Column.new(c) { |col|
445
+ col.heading = create_heading(heading_opts)
446
+ column_opts.each { |k,v| col.send("#{k}=",v) }
447
+ # use the specific column names now
448
+ specific[c].each { |k,v| col.send("#{k}=",v) }
402
449
  })
403
- }
450
+ }
404
451
  table.columns = columns
405
- end
406
- end
452
+ end
453
+ end
454
+
455
+ def get_specific_column_options(column_names,column_opts)
456
+ column_names.inject({}) do |s,c|
457
+ opts = column_opts.delete(c) || {}
458
+ if opts[:heading]
459
+ opts = opts.merge(:heading => create_heading(opts[:heading]))
460
+ end
461
+ s.merge(c => opts)
462
+ end
463
+ end
464
+
465
+ def create_heading(heading_opts)
466
+ heading_opts ||= {}
467
+ ::PDF::SimpleTable::Column::Heading.new {|head|
468
+ heading_opts.each {|k,v| head.send("#{k}=",v) }
469
+ }
470
+ end
407
471
 
408
472
  def grouping_columns
409
473
  data.data.to_a[0][1].column_names.dup.unshift(data.grouped_by)
@@ -487,5 +551,74 @@ module Ruport
487
551
  :justification => :center, :font_size => font_size)
488
552
  end
489
553
 
554
+ def apply_page_format_template(t)
555
+ t = t || {}
556
+ options.paper_size = t[:size] if t[:size]
557
+ options.paper_orientation = t[:layout] if t[:layout]
558
+ end
559
+
560
+ def apply_text_format_template(t)
561
+ options.text_format = template.text_format if t
562
+ end
563
+
564
+ def apply_table_format_template(t)
565
+ options.table_format = template.table_format.dup if t
566
+ end
567
+
568
+ def apply_column_format_template(t)
569
+ t = t || {}
570
+ column_opts = {}
571
+ column_opts.merge!(:justification => t[:alignment]) if t[:alignment]
572
+ column_opts.merge!(:width => t[:width]) if t[:width]
573
+ unless column_opts.empty?
574
+ if options.table_format
575
+ if options.table_format[:column_options]
576
+ options.table_format[:column_options] =
577
+ column_opts.merge(options.table_format[:column_options])
578
+ else
579
+ options.table_format.merge!(:column_options => column_opts)
580
+ end
581
+ else
582
+ options.table_format = { :column_options => column_opts }
583
+ end
584
+ end
585
+ end
586
+
587
+ def apply_heading_format_template(t)
588
+ t = t || {}
589
+ heading_opts = {}
590
+ heading_opts.merge!(:justification => t[:alignment]) if t[:alignment]
591
+ heading_opts.merge!(:bold => t[:bold]) unless t[:bold].nil?
592
+ heading_opts.merge!(:title => t[:title]) if t[:title]
593
+ unless heading_opts.empty?
594
+ if options.table_format
595
+ if options.table_format[:column_options]
596
+ if options.table_format[:column_options][:heading]
597
+ options.table_format[:column_options][:heading] =
598
+ heading_opts.merge(
599
+ options.table_format[:column_options][:heading]
600
+ )
601
+ else
602
+ options.table_format[:column_options].merge!(
603
+ :heading => heading_opts
604
+ )
605
+ end
606
+ else
607
+ options.table_format.merge!(
608
+ :column_options => { :heading => heading_opts }
609
+ )
610
+ end
611
+ else
612
+ options.table_format = {
613
+ :column_options => { :heading => heading_opts }
614
+ }
615
+ end
616
+ end
617
+ end
618
+
619
+ def apply_grouping_format_template(t)
620
+ t = t || {}
621
+ options.style = t[:style] if t[:style]
622
+ end
490
623
  end
491
624
  end