ruport 1.6.3 → 1.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (57) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +11 -0
  3. data/CHANGELOG.md +38 -0
  4. data/HACKING +1 -17
  5. data/README.md +97 -0
  6. data/Rakefile +9 -50
  7. data/examples/add_row_table.rb +46 -0
  8. data/examples/data/wine.csv +255 -0
  9. data/examples/pdf_grouping.rb +39 -0
  10. data/examples/pdf_table.rb +28 -0
  11. data/examples/pdf_table_from_csv.rb +26 -0
  12. data/examples/pdf_table_prawn.rb +30 -0
  13. data/examples/pdf_table_simple.rb +13 -0
  14. data/examples/row_renderer.rb +1 -1
  15. data/examples/simple_pdf_lines.rb +1 -1
  16. data/examples/trac_ticket_status.rb +1 -1
  17. data/lib/ruport/controller.rb +17 -21
  18. data/lib/ruport/data/feeder.rb +2 -2
  19. data/lib/ruport/data/grouping.rb +8 -8
  20. data/lib/ruport/data/record.rb +4 -4
  21. data/lib/ruport/data/table.rb +318 -206
  22. data/lib/ruport/formatter/csv.rb +6 -7
  23. data/lib/ruport/formatter/html.rb +13 -11
  24. data/lib/ruport/formatter/markdown.rb +105 -0
  25. data/lib/ruport/formatter/prawn_pdf.rb +159 -0
  26. data/lib/ruport/formatter/template.rb +1 -1
  27. data/lib/ruport/formatter/text.rb +1 -1
  28. data/lib/ruport/formatter.rb +54 -54
  29. data/lib/ruport/version.rb +1 -1
  30. data/lib/ruport.rb +7 -23
  31. data/test/controller_test.rb +201 -225
  32. data/test/csv_formatter_test.rb +36 -36
  33. data/test/data_feeder_test.rb +64 -64
  34. data/test/expected_outputs/prawn_pdf_formatter/pdf_basic.pdf.test +265 -0
  35. data/test/grouping_test.rb +103 -102
  36. data/test/helpers.rb +29 -10
  37. data/test/html_formatter_test.rb +46 -46
  38. data/test/markdown_formatter_test.rb +142 -0
  39. data/test/prawn_pdf_formatter_test.rb +108 -0
  40. data/test/record_test.rb +91 -91
  41. data/test/samples/sales.csv +21 -0
  42. data/test/table_pivot_test.rb +77 -26
  43. data/test/table_test.rb +376 -354
  44. data/test/template_test.rb +13 -13
  45. data/test/text_formatter_test.rb +52 -52
  46. data/util/bench/data/table/bench_column_manip.rb +0 -1
  47. data/util/bench/data/table/bench_dup.rb +0 -1
  48. data/util/bench/data/table/bench_init.rb +1 -2
  49. data/util/bench/data/table/bench_manip.rb +0 -1
  50. data/util/bench/formatter/bench_csv.rb +0 -1
  51. data/util/bench/formatter/bench_html.rb +0 -1
  52. data/util/bench/formatter/bench_pdf.rb +0 -1
  53. data/util/bench/formatter/bench_text.rb +0 -1
  54. metadata +131 -82
  55. data/README +0 -114
  56. data/lib/ruport/formatter/pdf.rb +0 -591
  57. data/test/pdf_formatter_test.rb +0 -354
data/README DELETED
@@ -1,114 +0,0 @@
1
- # -----------------------------------------------------------------
2
- # Contents:
3
- #
4
- # + What Ruport Is
5
- # + Installation
6
- # + Resources
7
- # + Hacking
8
- #
9
- # = What Ruport Is
10
- #
11
- # Ruby Reports (Ruport) is an extensible reporting system.
12
- #
13
- # It aims to be as lightweight as possible while still providing core support
14
- # for data aggregation and manipulation as well as multi-format rendering
15
- # of reports.
16
- #
17
- # Ruport provides tools for using a number of data sources, including CSV files,
18
- # ActiveRecord models, and raw SQL connections via RubyDBI (through ruport-util).
19
- #
20
- # Data manipulation is easy as there are standard structures that support
21
- # record, table, and grouping operations. These all can be extended to
22
- # implement custom behavior as needed.
23
- #
24
- # For common tasks, Ruport provides formatters for CSV, HTML, PDF, and text-
25
- # based reports. However, the real power lies in building custom report
26
- # controllers and formatters. The base formatting libraries provide a number
27
- # of helper functions that will let you build complex reports while maintaining
28
- # a DRY and consistent interface.
29
- #
30
- # To get a quick feel for what you can accomplish with Ruport, take a look at
31
- # a few simple examples provided on our web site.
32
- #
33
- # http://rubyreports.org/examples.html
34
- #
35
- # Since Ruport's core support is intentionally minimalistic, you may be looking
36
- # for some higher level support for specific needs such as graphing, invoices,
37
- # report mailing support, etc. For this, you may wish to take a look at the
38
- # ruport-util package, which contains some generally useful tools and libraries
39
- # to extend Ruport's capabilities.
40
- #
41
- # = Installation
42
- #
43
- # To install ruport via rubygems:
44
- #
45
- # sudo gem install ruport
46
- #
47
- # Check to see if it installed properly:
48
- #
49
- # ruby -rubygems -e "require 'ruport'; puts Ruport::VERSION"
50
- #
51
- # If you get an error, please let us know on our mailing list.
52
- #
53
- # Dependencies Details:
54
- #
55
- # -- formatting
56
- #
57
- # Ruport relies on PDF::Writer and FasterCSV for its formatting support.
58
- # If you want to make use of textile helpers, you'll also need RedCloth.
59
- #
60
- # -- database interaction
61
- #
62
- # If you wish to use Ruport to report against a rails project,
63
- # a camping project, or do standalone acts_as_reportable reports, you'll need
64
- # ActiveRecord and the acts_as_reportable gem.
65
- #
66
- # If you want to use Ruport::Query for raw SQL support, you'll need to
67
- # install ruport-util, RubyDBI and whatever database drivers you might need.
68
- #
69
- # = Resources
70
- #
71
- # Our developers have published a free-content book about all things
72
- # Ruport, including complete coverage of acts_as_reportable and some of
73
- # ruport-util's features. This book serves as the definitive guide to
74
- # Ruport, so all users should become acquainted with it:
75
- #
76
- # http://ruportbook.com
77
- #
78
- # The next best way to get help and make suggestions is the Ruport mailing list.
79
- # This software is on the move, so the list is the most reliable way of getting
80
- # up to date information.
81
- #
82
- # - You can sign up and/or view the archives here:
83
- # http://groups.google.com/group/ruby-reports
84
- #
85
- # If you are looking to dig a little deeper, there are a couple more resources
86
- # that may be helpful to you.
87
- #
88
- # - The latest stable API documentation is available at:
89
- # http://api.rubyreports.org
90
- #
91
- # - Our Trac is at: http://code.rubyreports.org/ruport
92
- # You may use the username ruport and password blinky to file tickets.
93
- #
94
- # = Hacking
95
- #
96
- # If you'd like to contribute code to Ruport, please join our development
97
- # mailing list, and let us know what you'd like to do!
98
- #
99
- # http://groups.google.com/group/ruport-dev
100
- #
101
- # It also may be worthwhile to join this list if you plan on running edge
102
- # versions of Ruport, as this is where we make announcements about major
103
- # breakage in trunk.
104
- #
105
- # We are very responsive to contributors, and review every patch we receive
106
- # fairly quickly. Most contributors who successfully get a patch or two applied
107
- # are given write access to the repositories and invited to join Ruport's
108
- # development team. Since we view every user as potential contributor, this
109
- # approach works well for us.
110
- #
111
- # So if you want to help out with Ruport, we'll happy accept your efforts!
112
-
113
-
114
-
@@ -1,591 +0,0 @@
1
- # Ruport : Extensible Reporting System
2
- #
3
- # formatter/pdf.rb provides text formatting for Ruport.
4
- #
5
- # Created by Gregory Brown, February 2006
6
- # Extended by James Healy, Fall 2006
7
- # Copyright (C) 2006-2007 Gregory Brown / James Healy, All Rights Reserved.
8
- #
9
- # Initially inspired by some ideas and code from Simon Claret,
10
- # with many improvements from James Healy and Michael Milner over time.
11
- #
12
- # This is free software distributed under the same terms as Ruby 1.8
13
- # See LICENSE and COPYING for details.
14
- #
15
- module Ruport
16
-
17
- # This class provides PDF output for Ruport's Table, Group, and Grouping
18
- # controllers. It wraps Austin Ziegler's PDF::Writer to provide a higher
19
- # level interface and provides a number of helpers designed to make
20
- # generating PDF reports much easier. You will typically want to build
21
- # subclasses of this formatter to customize it as needed.
22
- #
23
- # Many methods forward options to PDF::Writer, so you may wish to consult
24
- # its API docs.
25
- #
26
- # === Rendering Options
27
- # General:
28
- # * paper_size #=> "LETTER"
29
- # * paper_orientation #=> :portrait
30
- #
31
- # Text:
32
- # * text_format (sets options to be passed to add_text by default)
33
- #
34
- # Table:
35
- # * table_format (a hash that can take any of the options available
36
- # to PDF::SimpleTable)
37
- # * table_format[:maximum_width] #=> 500
38
- #
39
- # Grouping:
40
- # * style (:inline,:justified,:separated,:offset)
41
- #
42
- class Formatter::PDF < Formatter
43
-
44
- module PDFWriterProxy #:nodoc:
45
- def method_missing(id,*args)
46
- super(id,*args)
47
- rescue
48
- pdf_writer.send(id,*args)
49
- end
50
- end
51
-
52
- renders :pdf, :for => [ Controller::Row, Controller::Table,
53
- Controller::Group, Controller::Grouping ]
54
-
55
- attr_writer :pdf_writer
56
-
57
-
58
- # If you use this macro in your formatter, Ruport will automatically forward
59
- # calls to the underlying PDF::Writer, for any methods that are not wrapped
60
- # or redefined.
61
- def self.proxy_to_pdf_writer
62
- include PDFWriterProxy
63
- end
64
-
65
- save_as_binary_file
66
-
67
- def initialize
68
- Ruport.quiet do
69
- require "pdf/writer"
70
- require "pdf/simpletable"
71
- end
72
- end
73
-
74
- # Hook for setting available options using a template. See the template
75
- # documentation for the available options and their format.
76
- def apply_template
77
- apply_page_format_template(template.page)
78
- apply_text_format_template(template.text)
79
- apply_table_format_template(template.table)
80
- apply_column_format_template(template.column)
81
- apply_heading_format_template(template.heading)
82
- apply_grouping_format_template(template.grouping)
83
- end
84
-
85
- # Returns the current PDF::Writer object or creates a new one if it has not
86
- # been set yet.
87
- #
88
- def pdf_writer
89
- @pdf_writer ||= options.formatter ||
90
- ::PDF::Writer.new( :paper => options.paper_size || "LETTER",
91
- :orientation => options.paper_orientation || :portrait)
92
- end
93
-
94
- # Calls the draw_table method.
95
- #
96
- def build_table_body
97
- draw_table(data)
98
- end
99
-
100
- # Appends the results of PDF::Writer#render to output for your
101
- # <tt>pdf_writer</tt> object.
102
- #
103
- def finalize_table
104
- render_pdf unless options.skip_finalize_table
105
- end
106
-
107
- # Generates a header with the group name for Controller::Group.
108
- def build_group_header
109
- pad(10) { add_text data.name.to_s, :justification => :center }
110
- end
111
-
112
- # Renders the group as a table for Controller::Group.
113
- def build_group_body
114
- render_table data, options.to_hash.merge(:formatter => pdf_writer)
115
- end
116
-
117
- # Determines which style to use and renders the main body for
118
- # Controller::Grouping.
119
- def build_grouping_body
120
- case options.style
121
- when :inline
122
- render_inline_grouping(options.to_hash.merge(:formatter => pdf_writer,
123
- :skip_finalize_table => true))
124
- when :justified, :separated
125
- render_justified_or_separated_grouping
126
- when :offset
127
- render_offset_grouping
128
- else
129
- raise NotImplementedError, "Unknown style"
130
- end
131
- end
132
-
133
- # Calls <tt>render_pdf</tt>.
134
- def finalize_grouping
135
- render_pdf
136
- end
137
-
138
- # Call PDF::Writer#text with the given arguments, using
139
- # <tt>text_format</tt> defaults, if they are defined.
140
- #
141
- # Example:
142
- #
143
- # options.text_format { :font_size => 14 }
144
- #
145
- # add_text("Hello Joe") #renders at 14pt
146
- # add_text("Hello Mike",:font_size => 16) # renders at 16pt
147
- def add_text(text, format_opts={})
148
- format_opts = options.text_format.merge(format_opts) if options.text_format
149
- pdf_writer.text(text, format_opts)
150
- end
151
-
152
- # Calls PDF::Writer#render and appends to <tt>output</tt>.
153
- def render_pdf
154
- output << pdf_writer.render
155
- end
156
-
157
- # - If the image is bigger than the box, it will be scaled down until
158
- # it fits.
159
- # - If the image is smaller than the box, it won't be resized.
160
- #
161
- # options:
162
- # - :x: left bound of box
163
- # - :y: bottom bound of box
164
- # - :width: width of box
165
- # - :height: height of box
166
- #
167
- def center_image_in_box(path, image_opts={})
168
- x = image_opts[:x]
169
- y = image_opts[:y]
170
- width = image_opts[:width]
171
- height = image_opts[:height]
172
- info = ::PDF::Writer::Graphics::ImageInfo.new(File.open(path, "rb"))
173
-
174
- # reduce the size of the image until it fits into the requested box
175
- img_width, img_height =
176
- fit_image_in_box(info.width,width,info.height,height)
177
-
178
- # if the image is smaller than the box, calculate the white space buffer
179
- x, y = add_white_space(x,y,img_width,width,img_height,height)
180
-
181
- pdf_writer.add_image_from_file(path, x, y, img_width, img_height)
182
- end
183
-
184
- # Draws some text on the canvas, surrounded by a box with rounded corners.
185
- #
186
- # Yields an OpenStruct which options can be defined on.
187
- #
188
- # Example:
189
- #
190
- # rounded_text_box(options.text) do |o|
191
- # o.radius = 5
192
- # o.width = options.width || 400
193
- # o.height = options.height || 130
194
- # o.font_size = options.font_size || 12
195
- # o.heading = options.heading
196
- #
197
- # o.x = pdf_writer.absolute_x_middle - o.width/2
198
- # o.y = 300
199
- # end
200
- #
201
- def rounded_text_box(text)
202
- opts = OpenStruct.new
203
- yield(opts)
204
-
205
- resize_text_to_box(text, opts)
206
-
207
- pdf_writer.save_state
208
- draw_box(opts.x, opts.y, opts.width, opts.height, opts.radius,
209
- opts.fill_color, opts.stroke_color)
210
- add_text_with_bottom_border(opts.heading, opts.x, opts.y,
211
- opts.width, opts.font_size) if opts.heading
212
- pdf_writer.restore_state
213
-
214
- start_position = opts.heading ? opts.y - 20 : opts.y
215
- draw_text(text, :y => start_position,
216
- :left => opts.x,
217
- :right => opts.x + opts.width,
218
- :justification => opts.justification || :center,
219
- :font_size => opts.font_size)
220
- move_cursor_to(opts.y - opts.height)
221
- end
222
-
223
- # Adds n to pdf_writer.y, moving the vertical drawing position in the
224
- # document.
225
- def move_cursor(n)
226
- pdf_writer.y += n
227
- end
228
-
229
- # Moves the cursor to a specific y coordinate in the document.
230
- def move_cursor_to(n)
231
- pdf_writer.y = n
232
- end
233
-
234
- # Moves the vertical drawing position in the document upwards by n.
235
- def move_up(n)
236
- pdf_writer.y += n
237
- end
238
-
239
- def move_down(n)
240
- pdf_writer.y -= n
241
- end
242
-
243
- # Adds a specified amount of whitespace above and below the code
244
- # in your block. For example, if you want to surround the top and
245
- # bottom of a line of text with 5 pixels of whitespace:
246
- #
247
- # pad(5) { add_text "This will be padded top and bottom" }
248
- def pad(y,&block)
249
- move_cursor(-y)
250
- block.call
251
- move_cursor(-y)
252
- end
253
-
254
- # Adds a specified amount of whitespace above the code in your block.
255
- # For example, if you want to add a 10 pixel buffer to the top of a
256
- # line of text:
257
- #
258
- # pad_top(10) { add_text "This will be padded on top" }
259
- def pad_top(y,&block)
260
- move_cursor(-y)
261
- block.call
262
- end
263
-
264
- # Adds a specified amount of whitespace below the code in your block.
265
- # For example, if you want to add a 10 pixel buffer to the bottom of a
266
- # line of text:
267
- #
268
- # pad_bottom(10) { add_text "This will be padded on bottom" }
269
- def pad_bottom(y,&block)
270
- block.call
271
- move_cursor(-y)
272
- end
273
-
274
- # Draws a PDF::SimpleTable using the given data (usually a Data::Table).
275
- # Takes all the options you can set on a PDF::SimpleTable object,
276
- # see the PDF::Writer API docs for details, or check our quick reference
277
- # at:
278
- #
279
- # http://stonecode.svnrepository.com/ruport/trac.cgi/wiki/PdfWriterQuickRef
280
- def draw_table(table_data, format_opts={})
281
- m = "PDF Formatter requires column_names to be defined"
282
- raise FormatterError, m if table_data.column_names.empty?
283
-
284
- table_data.rename_columns { |c| c.to_s }
285
-
286
- if options.table_format
287
- format_opts =
288
- Marshal.load(Marshal.dump(options.table_format.merge(format_opts)))
289
- end
290
-
291
- old = pdf_writer.font_size
292
-
293
- ::PDF::SimpleTable.new do |table|
294
- table.maximum_width = 500
295
- table.column_order = table_data.column_names
296
- table.data = table_data
297
- table.data = [{}] if table.data.empty?
298
- apply_pdf_table_column_opts(table,table_data,format_opts)
299
-
300
- format_opts.each {|k,v| table.send("#{k}=", v) }
301
- table.render_on(pdf_writer)
302
- end
303
-
304
- pdf_writer.font_size = old
305
- end
306
-
307
- # This module provides tools to simplify some common drawing operations.
308
- # It is included by default in the PDF formatter.
309
- #
310
- module DrawingHelpers
311
-
312
- # Draws a horizontal line from x1 to x2
313
- def horizontal_line(x1,x2)
314
- pdf_writer.line(x1,cursor,x2,cursor)
315
- pdf_writer.stroke
316
- end
317
-
318
- # Draws a horizontal line from left_boundary to right_boundary
319
- def horizontal_rule
320
- horizontal_line(left_boundary,right_boundary)
321
- end
322
-
323
- alias_method :hr, :horizontal_rule
324
-
325
- # Draws a vertical line at x from y1 to y2
326
- def vertical_line_at(x,y1,y2)
327
- pdf_writer.line(x,y1,x,y2)
328
- pdf_writer.stroke
329
- end
330
-
331
- # Alias for PDF::Writer#absolute_left_margin
332
- def left_boundary
333
- pdf_writer.absolute_left_margin
334
- end
335
-
336
- # Alias for PDF::Writer#absolute_right_margin
337
- def right_boundary
338
- pdf_writer.absolute_right_margin
339
- end
340
-
341
- # Alias for PDF::Writer#absolute_top_margin
342
- def top_boundary
343
- pdf_writer.absolute_top_margin
344
- end
345
-
346
- # Alias for PDF::Writer#absolute_bottom_margin
347
- def bottom_boundary
348
- pdf_writer.absolute_bottom_margin
349
- end
350
-
351
- # Alias for PDF::Writer#y
352
- def cursor
353
- pdf_writer.y
354
- end
355
-
356
- # Draws text at an absolute location, defined by
357
- # :y, :x1|:left, :x2|:right
358
- #
359
- # All options to add_text are also supported.
360
- def draw_text(text,text_opts)
361
- ypos = cursor
362
- move_cursor_to(text_opts[:y]) if text_opts[:y]
363
- add_text(text,
364
- text_opts.merge(:absolute_left => text_opts[:x1] || text_opts[:left],
365
- :absolute_right => text_opts[:x2] || text_opts[:right]))
366
- move_cursor_to(ypos)
367
- end
368
-
369
- # Draws text at an absolute location, defined by
370
- # :y, :x1|:left
371
- #
372
- # The x position defaults to the left margin and the
373
- # y position defaults to the current cursor location.
374
- #
375
- # Uses PDF::Writer#add_text, so it will ignore any options not supported
376
- # by that method.
377
- def draw_text!(text,text_opts)
378
- ypos = cursor
379
- pdf_writer.add_text(text_opts[:x1] || text_opts[:left] || left_boundary,
380
- text_opts[:y] || ypos,
381
- text,
382
- text_opts[:font_size],
383
- text_opts[:angle] || 0)
384
- move_cursor_to(ypos)
385
- end
386
-
387
- def finalize
388
- render_pdf
389
- end
390
- end
391
-
392
- include DrawingHelpers
393
-
394
- private
395
-
396
- def apply_pdf_table_column_opts(table,table_data,format_opts)
397
- column_opts = format_opts.delete(:column_options)
398
-
399
- if column_opts
400
- heading_opts = column_opts.delete(:heading)
401
- if column_opts[:justification]
402
- heading_opts ||= {}
403
- heading_opts = {
404
- :justification => column_opts[:justification]
405
- }.merge(heading_opts)
406
- end
407
- specific = get_specific_column_options(table_data.column_names,
408
- column_opts)
409
- columns = table_data.column_names.inject({}) { |s,c|
410
- s.merge( c => ::PDF::SimpleTable::Column.new(c) { |col|
411
- col.heading = create_heading(heading_opts)
412
- column_opts.each { |k,v| col.send("#{k}=",v) }
413
- # use the specific column names now
414
- specific[c].each { |k,v| col.send("#{k}=",v) }
415
- })
416
- }
417
- table.columns = columns
418
- end
419
- end
420
-
421
- def get_specific_column_options(column_names,column_opts)
422
- column_names.inject({}) do |s,c|
423
- opts = column_opts.delete(c) || {}
424
- if opts[:heading]
425
- opts = opts.merge(:heading => create_heading(opts[:heading]))
426
- end
427
- s.merge(c => opts)
428
- end
429
- end
430
-
431
- def create_heading(heading_opts)
432
- heading_opts ||= {}
433
- ::PDF::SimpleTable::Column::Heading.new {|head|
434
- heading_opts.each {|k,v| head.send("#{k}=",v) }
435
- }
436
- end
437
-
438
- def grouping_columns
439
- data.data.to_a[0][1].column_names.dup.unshift(data.grouped_by)
440
- end
441
-
442
- def table_with_grouped_by_column
443
- Ruport::Data::Table.new(:column_names => grouping_columns)
444
- end
445
-
446
- def render_justified_or_separated_grouping
447
- table = table_with_grouped_by_column
448
- data.each do |name,group|
449
- group.each_with_index do |r,i|
450
- if i == 0
451
- table << { data.grouped_by => "<b>#{name}</b>" }.merge(r.to_hash)
452
- else
453
- table << r
454
- end
455
- end
456
- table << [" "] if options.style == :separated
457
- end
458
- render_table table, options.to_hash.merge(:formatter => pdf_writer)
459
- end
460
-
461
- def render_offset_grouping
462
- table = table_with_grouped_by_column
463
- data.each do |name,group|
464
- table << ["<b>#{name}</b>"]
465
- group.each {|r| table << r }
466
- end
467
- render_table table, options.to_hash.merge(:formatter => pdf_writer)
468
- end
469
-
470
- def image_fits_in_box?(img_width,box_width,img_height,box_height)
471
- !(img_width > box_width || img_height > box_height)
472
- end
473
-
474
- def fit_image_in_box(img_width,box_width,img_height,box_height)
475
- img_ratio = img_height.to_f / img_width.to_f
476
- until image_fits_in_box?(img_width,box_width,img_height,box_height)
477
- img_width -= 1
478
- img_height = img_width * img_ratio
479
- end
480
- return img_width, img_height
481
- end
482
-
483
- def add_white_space(x,y,img_width,box_width,img_height,box_height)
484
- if img_width < box_width
485
- white_space = box_width - img_width
486
- x = x + (white_space / 2)
487
- end
488
- if img_height < box_height
489
- white_space = box_height - img_height
490
- y = y + (white_space / 2)
491
- end
492
- return x, y
493
- end
494
-
495
- def resize_text_to_box(text,opts)
496
- loop do
497
- sz = pdf_writer.text_width(text, opts.font_size)
498
- opts.x + sz > opts.x + opts.width or break
499
- opts.font_size -= 1
500
- end
501
- end
502
-
503
- def draw_box(x,y,width,height,radius,fill_color=nil,stroke_color=nil)
504
- pdf_writer.fill_color(fill_color || Color::RGB::White)
505
- pdf_writer.stroke_color(stroke_color || Color::RGB::Black)
506
- pdf_writer.rounded_rectangle(x, y, width, height, radius).fill_stroke
507
- end
508
-
509
- def add_text_with_bottom_border(text,x,y,width,font_size)
510
- pdf_writer.line( x, y - 20,
511
- x + width, y - 20).stroke
512
- pdf_writer.fill_color(Color::RGB::Black)
513
- move_cursor_to(y - 3)
514
- add_text("<b>#{text}</b>",
515
- :absolute_left => x, :absolute_right => x + width,
516
- :justification => :center, :font_size => font_size)
517
- end
518
-
519
- def apply_page_format_template(t)
520
- t = (t || {}).merge(options.page_format || {})
521
- options.paper_size ||= t[:size]
522
- options.paper_orientation ||= t[:layout]
523
- end
524
-
525
- def apply_text_format_template(t)
526
- t = (t || {}).merge(options.text_format || {})
527
- options.text_format = t unless t.empty?
528
- end
529
-
530
- def apply_table_format_template(t)
531
- t = (t || {}).merge(options.table_format || {})
532
- options.table_format = t unless t.empty?
533
- end
534
-
535
- def apply_column_format_template(t)
536
- t = (t || {}).merge(options.column_format || {})
537
- column_opts = {}
538
- column_opts.merge!(:justification => t[:alignment]) if t[:alignment]
539
- column_opts.merge!(:width => t[:width]) if t[:width]
540
- unless column_opts.empty?
541
- if options.table_format
542
- if options.table_format[:column_options]
543
- options.table_format[:column_options] =
544
- column_opts.merge(options.table_format[:column_options])
545
- else
546
- options.table_format.merge!(:column_options => column_opts)
547
- end
548
- else
549
- options.table_format = { :column_options => column_opts }
550
- end
551
- end
552
- end
553
-
554
- def apply_heading_format_template(t)
555
- t = (t || {}).merge(options.heading_format || {})
556
- heading_opts = {}
557
- heading_opts.merge!(:justification => t[:alignment]) if t[:alignment]
558
- heading_opts.merge!(:bold => t[:bold]) unless t[:bold].nil?
559
- heading_opts.merge!(:title => t[:title]) if t[:title]
560
- unless heading_opts.empty?
561
- if options.table_format
562
- if options.table_format[:column_options]
563
- if options.table_format[:column_options][:heading]
564
- options.table_format[:column_options][:heading] =
565
- heading_opts.merge(
566
- options.table_format[:column_options][:heading]
567
- )
568
- else
569
- options.table_format[:column_options].merge!(
570
- :heading => heading_opts
571
- )
572
- end
573
- else
574
- options.table_format.merge!(
575
- :column_options => { :heading => heading_opts }
576
- )
577
- end
578
- else
579
- options.table_format = {
580
- :column_options => { :heading => heading_opts }
581
- }
582
- end
583
- end
584
- end
585
-
586
- def apply_grouping_format_template(t)
587
- t = (t || {}).merge(options.grouping_format || {})
588
- options.style ||= t[:style]
589
- end
590
- end
591
- end