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
data/lib/ruport/formatter.rb
CHANGED
@@ -1,14 +1,70 @@
|
|
1
|
-
#
|
1
|
+
# Ruport : Extensible Reporting System
|
2
2
|
#
|
3
|
-
#
|
3
|
+
# formatter.rb provides a generalized base class for creating ruport formatters.
|
4
|
+
#
|
5
|
+
# Created By Gregory Brown
|
6
|
+
# Copyright (C) December 2006, All Rights Reserved.
|
4
7
|
#
|
5
|
-
# This is free software
|
6
|
-
|
7
|
-
module Ruport
|
8
|
+
# This is free software distributed under the same terms as Ruby 1.8
|
9
|
+
# See LICENSE and COPYING for details.
|
10
|
+
module Ruport
|
11
|
+
# Formatter is the base class for Ruport's format implementations.
|
12
|
+
#
|
13
|
+
# Typically, a Formatter will implement one or more output types,
|
14
|
+
# and be registered with one or more Renderer classes.
|
15
|
+
#
|
16
|
+
# This class provides all the necessary base functionality to make
|
17
|
+
# use of Ruport's rendering system, including option handling, data
|
18
|
+
# access, and basic output wrapping.
|
19
|
+
#
|
20
|
+
# The following example should provide a general idea of how formatters
|
21
|
+
# work, but see the built in formatters for reference implementations.
|
22
|
+
#
|
23
|
+
# A simple Renderer definition is included to help show the example in
|
24
|
+
# context, but you can also build your own custom interface to formatter
|
25
|
+
# if you wish.
|
26
|
+
#
|
27
|
+
# class ReverseRenderer < Ruport::Renderer
|
28
|
+
# stage :reversed_header, :reversed_body
|
29
|
+
# option :header_text
|
30
|
+
# end
|
31
|
+
#
|
32
|
+
# class ReversedText < Ruport::Formatter
|
33
|
+
#
|
34
|
+
# # Hooks formatter up to renderer
|
35
|
+
# renders :txt, :for => ReverseRenderer
|
36
|
+
#
|
37
|
+
# # Implements ReverseRenderer's :reversed_header hook
|
38
|
+
# # but can be used by any renderer
|
39
|
+
# def build_reversed_header
|
40
|
+
# output << "#{options.header_text}\n"
|
41
|
+
# output << "The reversed text will follow\n"
|
42
|
+
# end
|
43
|
+
#
|
44
|
+
# # Implements ReverseRenderer's :reversed_body hook
|
45
|
+
# # but can be used by any renderer
|
46
|
+
# def build_reversed_body
|
47
|
+
# output << data.reverse << "\n"
|
48
|
+
# end
|
49
|
+
#
|
50
|
+
# end
|
51
|
+
#
|
52
|
+
# puts ReverseRenderer.render_txt(:data => "apple",
|
53
|
+
# :header_text => "Hello Mike, Hello Joe!")
|
54
|
+
#
|
55
|
+
# -----
|
56
|
+
# OUTPUT:
|
57
|
+
#
|
58
|
+
# Hello Mike, Hello Joe!
|
59
|
+
# The reversed text will follow
|
60
|
+
# elppa
|
61
|
+
#
|
8
62
|
class Formatter
|
9
|
-
|
63
|
+
|
64
|
+
# Provides shortcuts so that you can use Ruport's default rendering
|
65
|
+
# capabilities within your custom formatters
|
66
|
+
#
|
10
67
|
module RenderingTools
|
11
|
-
|
12
68
|
# Iterates through <tt>data</tt> and passes
|
13
69
|
# each row to render_row with the given options
|
14
70
|
def render_data_by_row(options={},&block)
|
@@ -75,9 +131,15 @@ module Ruport
|
|
75
131
|
end
|
76
132
|
|
77
133
|
include RenderingTools
|
78
|
-
|
79
|
-
|
80
|
-
attr_accessor :
|
134
|
+
|
135
|
+
# Set by the <tt>:data</tt> attribute from Renderer#render
|
136
|
+
attr_accessor :data
|
137
|
+
|
138
|
+
# Set automatically by Renderer#render(format) or Renderer#render_format
|
139
|
+
attr_accessor :format
|
140
|
+
|
141
|
+
# Set automatically by Renderer#render as a Renderer::Options option built
|
142
|
+
# by the hash provided.
|
81
143
|
attr_writer :options
|
82
144
|
|
83
145
|
# Registers the formatter with one or more Renderers
|
@@ -116,7 +178,7 @@ module Ruport
|
|
116
178
|
@output ||= ""
|
117
179
|
end
|
118
180
|
|
119
|
-
# Provides a
|
181
|
+
# Provides a Renderer::Options object for storing formatting options
|
120
182
|
def options
|
121
183
|
@options ||= Renderer::Options.new
|
122
184
|
end
|
@@ -124,6 +186,19 @@ module Ruport
|
|
124
186
|
# Clears output.
|
125
187
|
def clear_output
|
126
188
|
@output.replace("")
|
189
|
+
end
|
190
|
+
|
191
|
+
# Evaluates the string using ERB and returns the results.
|
192
|
+
#
|
193
|
+
# If <tt>:binding</tt> is specified, it will evaluate the template
|
194
|
+
# in that context.
|
195
|
+
def erb(string,options={})
|
196
|
+
require "erb"
|
197
|
+
if string =~ /\.r\w+$/
|
198
|
+
ERB.new(File.read(string)).result(options[:binding]||binding)
|
199
|
+
else
|
200
|
+
ERB.new(string).result(options[:binding]||binding)
|
201
|
+
end
|
127
202
|
end
|
128
203
|
|
129
204
|
# Provides a shortcut for per format handlers.
|
data/lib/ruport/formatter/csv.rb
CHANGED
@@ -1,6 +1,32 @@
|
|
1
|
+
# Ruport : Extensible Reporting System
|
2
|
+
#
|
3
|
+
# formatter/csv.rb provides csv formatting for Ruport.
|
4
|
+
#
|
5
|
+
# Original code dates back to the earliest versions of Ruport in August 2005
|
6
|
+
# Extended over time, with much of the existing code being added around
|
7
|
+
# December 2006.
|
8
|
+
#
|
9
|
+
# Copyright (C) 2005-2007 Gregory Brown, 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.
|
13
|
+
#
|
1
14
|
module Ruport
|
2
15
|
|
3
|
-
# This formatter implements the CSV format for
|
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.
|
19
|
+
#
|
20
|
+
# === Rendering Options
|
21
|
+
#
|
22
|
+
# <tt>:style</tt> Used for grouping (:inline,:justified,:raw)
|
23
|
+
#
|
24
|
+
# <tt>:format_options</tt> A hash of FasterCSV options
|
25
|
+
#
|
26
|
+
# <tt>:show_table_headers</tt> True by default
|
27
|
+
#
|
28
|
+
# <tt>:show_group_headers</tt> True by default
|
29
|
+
#
|
4
30
|
class Formatter::CSV < Formatter
|
5
31
|
|
6
32
|
renders :csv, :for => [ Renderer::Row, Renderer::Table,
|
@@ -55,7 +81,8 @@ module Ruport
|
|
55
81
|
output << "#{data.grouped_by}," << grouping_columns
|
56
82
|
end
|
57
83
|
end
|
58
|
-
|
84
|
+
|
85
|
+
# determines the proper style to use and renders the Grouping.
|
59
86
|
def build_grouping_body
|
60
87
|
case style
|
61
88
|
when :inline
|
@@ -1,5 +1,25 @@
|
|
1
|
+
# Ruport : Extensible Reporting System
|
2
|
+
#
|
3
|
+
# formatter/html.rb provides html formatting for Ruport.
|
4
|
+
#
|
5
|
+
# Created by Gregory Brown, late 2005. Updated numerous times as needed to
|
6
|
+
# fit new formatting systems.
|
7
|
+
#
|
8
|
+
# Copyright (C) 2005-2007 Gregory Brown, All Rights Reserved.
|
9
|
+
#
|
10
|
+
# This is free software distributed under the same terms as Ruby 1.8
|
11
|
+
# See LICENSE and COPYING for details.
|
12
|
+
#
|
1
13
|
module Ruport
|
2
|
-
#
|
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
|
17
|
+
#
|
18
|
+
# === Rendering Options
|
19
|
+
#
|
20
|
+
# <tt>:show_table_headers</tt> True by default
|
21
|
+
#
|
22
|
+
# <tt>:show_group_headers</tt> True by default
|
3
23
|
#
|
4
24
|
class Formatter::HTML < Formatter
|
5
25
|
|
@@ -21,6 +41,8 @@ module Ruport
|
|
21
41
|
end
|
22
42
|
end
|
23
43
|
|
44
|
+
# Uses the Row renderer to build up the table body.
|
45
|
+
# Replaces nil and empty strings with " "
|
24
46
|
def build_table_body
|
25
47
|
render_data_by_row do |rend|
|
26
48
|
r = rend.data
|
data/lib/ruport/formatter/pdf.rb
CHANGED
@@ -1,19 +1,43 @@
|
|
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
|
+
#
|
1
15
|
module Ruport
|
2
16
|
|
3
|
-
# PDF
|
17
|
+
# This class provides PDF output for Ruport's Table, Group, and Grouping
|
18
|
+
# renderers. 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.
|
4
22
|
#
|
5
|
-
#
|
23
|
+
# Many methods forward options to PDF::Writer, so you may wish to consult
|
24
|
+
# its API docs.
|
25
|
+
#
|
26
|
+
# === Rendering Options
|
6
27
|
# General:
|
7
28
|
# * paper_size #=> "LETTER"
|
8
29
|
# * paper_orientation #=> :portrait
|
9
30
|
#
|
10
31
|
# Text:
|
11
|
-
# * text_format
|
32
|
+
# * text_format (sets options to be passed to add_text by default)
|
12
33
|
#
|
13
34
|
# Table:
|
14
35
|
# * table_format (a hash that can take any of the options available
|
15
36
|
# to PDF::SimpleTable)
|
16
|
-
# * table_format[:maximum_width] #=> 500
|
37
|
+
# * table_format[:maximum_width] #=> 500
|
38
|
+
#
|
39
|
+
# Grouping:
|
40
|
+
# * style (:inline,:justified,:separated,:offset)
|
17
41
|
#
|
18
42
|
class Formatter::PDF < Formatter
|
19
43
|
|
@@ -21,9 +45,7 @@ module Ruport
|
|
21
45
|
Renderer::Group, Renderer::Grouping ]
|
22
46
|
|
23
47
|
attr_writer :pdf_writer
|
24
|
-
|
25
|
-
attr_accessor :table_footer_proc
|
26
|
-
|
48
|
+
|
27
49
|
opt_reader :show_table_headers,
|
28
50
|
:style,
|
29
51
|
:table_format,
|
@@ -40,7 +62,7 @@ module Ruport
|
|
40
62
|
|
41
63
|
# Returns the current PDF::Writer object or creates a new one if it has not
|
42
64
|
# been set yet.
|
43
|
-
#
|
65
|
+
#
|
44
66
|
def pdf_writer
|
45
67
|
@pdf_writer ||= options.formatter ||
|
46
68
|
::PDF::Writer.new( :paper => paper_size || "LETTER",
|
@@ -60,15 +82,19 @@ module Ruport
|
|
60
82
|
def finalize_table
|
61
83
|
render_pdf unless options.skip_finalize_table
|
62
84
|
end
|
63
|
-
|
85
|
+
|
86
|
+
# Generates a header with the group name for Renderer::Group
|
64
87
|
def build_group_header
|
65
88
|
pad(10) { add_text data.name.to_s, :justification => :center }
|
66
89
|
end
|
67
|
-
|
90
|
+
|
91
|
+
# Renders the group as a table for Renderer::Group
|
68
92
|
def build_group_body
|
69
93
|
render_table data, options.to_hash.merge(:formatter => pdf_writer)
|
70
94
|
end
|
71
|
-
|
95
|
+
|
96
|
+
# Determines which style to use and renders the main body for
|
97
|
+
# Renderer::Grouping
|
72
98
|
def build_grouping_body
|
73
99
|
case style
|
74
100
|
when :inline
|
@@ -82,12 +108,21 @@ module Ruport
|
|
82
108
|
raise NotImplementedError, "Unknown style"
|
83
109
|
end
|
84
110
|
end
|
85
|
-
|
111
|
+
|
112
|
+
# calls <tt>render_pdf</tt>
|
86
113
|
def finalize_grouping
|
87
114
|
render_pdf
|
88
115
|
end
|
89
116
|
|
90
|
-
# Call PDF::Writer#text with the given arguments
|
117
|
+
# Call PDF::Writer#text with the given arguments, using <tt>text_format</tt>
|
118
|
+
# defaults, if they are defined.
|
119
|
+
#
|
120
|
+
# Example:
|
121
|
+
#
|
122
|
+
# options.text_format { :font_size => 14 }
|
123
|
+
#
|
124
|
+
# add_text("Hello Joe") #renders at 14pt
|
125
|
+
# add_text("Hello Mike",:font_size => 16) # renders at 16pt
|
91
126
|
def add_text(text, format_opts={})
|
92
127
|
format_opts = text_format.merge(format_opts) if text_format
|
93
128
|
pdf_writer.text(text, format_opts)
|
@@ -125,7 +160,22 @@ module Ruport
|
|
125
160
|
pdf_writer.add_image_from_file(path, x, y, img_width, img_height)
|
126
161
|
end
|
127
162
|
|
128
|
-
# Draws some text on the canvas, surrounded by a box with rounded
|
163
|
+
# Draws some text on the canvas, surrounded by a box with rounded corner
|
164
|
+
#
|
165
|
+
# Yields an OpenStruct which options can be defined on.
|
166
|
+
#
|
167
|
+
# Example:
|
168
|
+
#
|
169
|
+
# rounded_text_box(options.text) do |o|
|
170
|
+
# o.radius = 5
|
171
|
+
# o.width = options.width || 400
|
172
|
+
# o.height = options.height || 130
|
173
|
+
# o.font_size = options.font_size || 12
|
174
|
+
# o.heading = options.heading
|
175
|
+
#
|
176
|
+
# o.x = pdf_writer.absolute_x_middle - o.width/2
|
177
|
+
# o.y = 300
|
178
|
+
# end
|
129
179
|
#
|
130
180
|
def rounded_text_box(text)
|
131
181
|
opts = OpenStruct.new
|
@@ -167,34 +217,60 @@ module Ruport
|
|
167
217
|
pdf_writer.add_object(wm, :all_pages)
|
168
218
|
end
|
169
219
|
end
|
170
|
-
|
220
|
+
|
221
|
+
# adds n to pdf_writer.y, moving the vertical drawing position in the
|
222
|
+
# document
|
171
223
|
def move_cursor(n)
|
172
224
|
pdf_writer.y += n
|
173
225
|
end
|
174
|
-
|
226
|
+
|
227
|
+
# moves the cursor to a specific y coordinate in the document
|
175
228
|
def move_cursor_to(n)
|
176
229
|
pdf_writer.y = n
|
177
230
|
end
|
178
|
-
|
231
|
+
|
232
|
+
# puts a specified amount of whitespace above and below the code
|
233
|
+
# in your block. For example, if you want to surround the top and
|
234
|
+
# bottom of a line of text with 5 pixels of whitespace:
|
235
|
+
#
|
236
|
+
# pad(5) { add_text "This will be padded" }
|
179
237
|
def pad(y,&block)
|
180
238
|
move_cursor(-y)
|
181
239
|
block.call
|
182
240
|
move_cursor(-y)
|
183
241
|
end
|
184
|
-
|
242
|
+
|
243
|
+
# Adds a specified amount of whitespace above the code in your block.
|
244
|
+
# For example, if you want to add a 10 pixel buffer to the top of a
|
245
|
+
# line of text:
|
246
|
+
#
|
247
|
+
# pad_top(10) { add_text "This will be padded on top" }
|
185
248
|
def pad_top(y,&block)
|
186
249
|
move_cursor(-y)
|
187
250
|
block.call
|
188
251
|
end
|
189
|
-
|
252
|
+
|
253
|
+
# Adds a specified amount of whitespace below the code in your block.
|
254
|
+
# For example, if you want to add a 10 pixel buffer to the bottom of a
|
255
|
+
# line of text:
|
256
|
+
#
|
257
|
+
# pad_bottom(10) { add_text "This will be padded on top" }
|
190
258
|
def pad_bottom(y,&block)
|
191
259
|
block.call
|
192
260
|
move_cursor(-y)
|
193
261
|
end
|
194
|
-
|
262
|
+
|
263
|
+
# Draws a PDF::SimpleTable using the given data (usually a Data::Table)
|
264
|
+
# Takes all the options you can set on a PDF::SimpleTable object,
|
265
|
+
# see the PDF::Writer API docs for details, or check our quick reference
|
266
|
+
# at:
|
267
|
+
#
|
268
|
+
# http://stonecode.svnrepository.com/ruport/trac.cgi/wiki/PdfWriterQuickRef
|
195
269
|
def draw_table(table_data, format_opts={})
|
196
|
-
m = "
|
197
|
-
raise m if table_data.column_names.empty?
|
270
|
+
m = "PDF Formatter requires column_names to be defined"
|
271
|
+
raise FormatterError, m if table_data.column_names.empty?
|
272
|
+
|
273
|
+
table_data.rename_columns { |c| c.to_s }
|
198
274
|
|
199
275
|
format_opts = table_format.merge(format_opts) if table_format
|
200
276
|
|
@@ -210,38 +286,53 @@ module Ruport
|
|
210
286
|
table.render_on(pdf_writer)
|
211
287
|
end
|
212
288
|
end
|
213
|
-
|
289
|
+
|
290
|
+
# This module provides tools to simplify some common drawing operations
|
291
|
+
# it is included by default in the PDF formatter
|
292
|
+
#
|
214
293
|
module DrawingHelpers
|
215
|
-
|
294
|
+
|
295
|
+
# draws a horizontal line from x1 to x2
|
216
296
|
def horizontal_line(x1,x2)
|
217
297
|
pdf_writer.line(x1,cursor,x2,cursor)
|
218
298
|
pdf_writer.stroke
|
219
299
|
end
|
220
|
-
|
300
|
+
|
301
|
+
# draws a vertical line at x from y1 to y2
|
221
302
|
def vertical_line_at(x,y1,y2)
|
222
303
|
pdf_writer.line(x,y1,x,y2)
|
304
|
+
pdf_writer.stroke
|
223
305
|
end
|
224
|
-
|
306
|
+
|
307
|
+
# Alias for PDF::Writer#absolute_left_margin
|
225
308
|
def left_boundary
|
226
309
|
pdf_writer.absolute_left_margin
|
227
310
|
end
|
228
|
-
|
311
|
+
|
312
|
+
# Alias for PDF::Writer#absolute_right_margin
|
229
313
|
def right_boundary
|
230
314
|
pdf_writer.absolute_right_margin
|
231
315
|
end
|
232
|
-
|
316
|
+
|
317
|
+
# Alias for PDF::Writer#absolute_top_margin
|
233
318
|
def top_boundary
|
234
319
|
pdf_writer.absolute_top_margin
|
235
320
|
end
|
236
|
-
|
321
|
+
|
322
|
+
# Alias for PDF::Writer#absolute_bottom_margin
|
237
323
|
def bottom_boundary
|
238
324
|
pdf_writer.absolute_bottom_margin
|
239
325
|
end
|
240
|
-
|
326
|
+
|
327
|
+
# Alias for PDF::Writer#y
|
241
328
|
def cursor
|
242
329
|
pdf_writer.y
|
243
330
|
end
|
244
|
-
|
331
|
+
|
332
|
+
# Draws text at an absolute location, defined by
|
333
|
+
# :y, :x1|:left, :x2|:right
|
334
|
+
#
|
335
|
+
# All usual options to add_text are also supported
|
245
336
|
def draw_text(text,text_opts)
|
246
337
|
move_cursor_to(text_opts[:y]) if text_opts[:y]
|
247
338
|
add_text(text,
|
@@ -288,7 +379,7 @@ module Ruport
|
|
288
379
|
data.each do |name,group|
|
289
380
|
group_column = { data.grouped_by => "<b>#{name}</b>\n" }
|
290
381
|
group.each_with_index do |rec,i|
|
291
|
-
i == 0 ? table << group_column.merge(rec.
|
382
|
+
i == 0 ? table << group_column.merge(rec.to_hash) : table << rec
|
292
383
|
end
|
293
384
|
table << Array.new(grouping_columns.length,' ') if style == :separated
|
294
385
|
end
|