ruport 0.10.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|