tn_pdf 0.0.2 → 0.0.8
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.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/.rvmrc +1 -0
- data/Gemfile +3 -0
- data/Gemfile.lock +29 -20
- data/Rakefile +3 -4
- data/lib/prawn/table_fix.rb +11 -0
- data/lib/tn_pdf/box.rb +27 -10
- data/lib/tn_pdf/configuration.rb +84 -22
- data/lib/tn_pdf/page_section.rb +14 -7
- data/lib/tn_pdf/report.rb +149 -22
- data/lib/tn_pdf/table.rb +290 -38
- data/lib/tn_pdf/table_column.rb +134 -25
- data/lib/tn_pdf/version.rb +1 -1
- data/lib/tn_pdf.rb +4 -1
- data/spec/tn_pdf/box_spec.rb +4 -4
- data/spec/tn_pdf/table_spec.rb +13 -9
- data/tn_pdf.gemspec +1 -1
- metadata +65 -83
data/lib/tn_pdf/table.rb
CHANGED
@@ -1,28 +1,51 @@
|
|
1
1
|
require 'tn_pdf/table_column'
|
2
|
-
require 'prawn'
|
3
2
|
|
4
3
|
module TnPDF
|
4
|
+
# A representation {Report}'s table. It's an abstraction above a Prawn
|
5
|
+
# table that that 'defaultizes' a commonly used structure - a table that is a
|
6
|
+
# {#collection} of elements displayed as {#rows}, on which each of the {#columns}
|
7
|
+
# is a property of an object.
|
8
|
+
#
|
9
|
+
# Through {Table::Column}, it also provides many configurable
|
10
|
+
# column 'types', such as currency and float, to ease the pain of formatting
|
11
|
+
# the table on a consistent manner.
|
12
|
+
#
|
13
|
+
# Above that, it also provides a very useful feature that Prawn misses:
|
14
|
+
# column spanning (although currently only on footers).
|
15
|
+
#
|
16
|
+
# == Table footers
|
17
|
+
#
|
18
|
+
# Table footers are special rows that are often used to make a summary of
|
19
|
+
# the table data.
|
20
|
+
#
|
21
|
+
# The main differences between a footer row and a ordinary row are:
|
22
|
+
# [Column spanning]
|
23
|
+
# Normal row's cells can't span across multiple columns,
|
24
|
+
# while a footer cell can.
|
25
|
+
# [Calculation]
|
26
|
+
# In a normal row, the cells' values are automatically
|
27
|
+
# calculated using the provided method, while in a footer
|
28
|
+
# row the displayed value should be directly passed.
|
29
|
+
# [Scope]
|
30
|
+
# A footer row acts in the scope of the whole collection, while
|
31
|
+
# a normal row represents a single object.
|
32
|
+
# [Format]
|
33
|
+
# Footer rows can be formatted in a differente manner, through
|
34
|
+
# the use of the +table_footer_*+ properties on {Configuration}
|
5
35
|
class Table
|
6
36
|
attr_accessor *Configuration.table_properties_names
|
7
37
|
|
8
|
-
def initialize
|
38
|
+
def initialize(document)
|
9
39
|
Configuration.table_properties_names.each do |property|
|
10
40
|
send("#{property}=", Configuration["table_#{property}"])
|
11
41
|
end
|
42
|
+
@document = document
|
12
43
|
end
|
13
44
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
hash
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def columns_headers
|
23
|
-
columns.map(&:header)
|
24
|
-
end
|
25
|
-
|
45
|
+
# The collection of objects to be represented by the table.
|
46
|
+
# @return [Array]
|
47
|
+
# @raise [ArgumentError] If the passed value isn't an Array
|
48
|
+
attr_accessor :collection
|
26
49
|
def collection
|
27
50
|
@collection ||= Array.new
|
28
51
|
end
|
@@ -32,13 +55,48 @@ module TnPDF
|
|
32
55
|
@collection = collection
|
33
56
|
end
|
34
57
|
|
58
|
+
# The columns already set on this table. Despite of being first provided
|
59
|
+
# as Arrays, the members of this collection are instances of {Column}.
|
60
|
+
# @return [Array]
|
61
|
+
attr_reader :columns
|
62
|
+
def columns(type = :all)
|
63
|
+
@columns ||= []
|
64
|
+
if type == :all
|
65
|
+
@columns
|
66
|
+
else
|
67
|
+
@columns.select { |c| c.column_width_type == type }
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# Adds a column to the table. The argument should be a {Column}, or an
|
72
|
+
# argument that {Column#initialize} accepts.
|
73
|
+
# @param [Column] (see Column#initialize)
|
35
74
|
def add_column(column)
|
36
75
|
unless column.kind_of? Column
|
37
76
|
column = Column.new(column)
|
38
77
|
end
|
78
|
+
column.index = columns.count
|
79
|
+
column.max_width = document_width
|
39
80
|
columns << column
|
40
81
|
end
|
41
82
|
|
83
|
+
def remove_column(column)
|
84
|
+
if column.kind_of? Column
|
85
|
+
columns.delete(column)
|
86
|
+
elsif column.kind_of? Fixnum
|
87
|
+
columns.delete_at(column)
|
88
|
+
else
|
89
|
+
raise ArgumentError, "Unrecognized argument '#{column.inspect}'"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def reset_columns
|
94
|
+
@columns = []
|
95
|
+
end
|
96
|
+
|
97
|
+
# The already computed rows of the table. Needs {#columns} and
|
98
|
+
# {#collection} to be already set to return something meaningful.
|
99
|
+
# @return [Array] An array containing the rows to be rendered.
|
42
100
|
def rows
|
43
101
|
collection.map do |object|
|
44
102
|
columns.map do |column|
|
@@ -47,45 +105,239 @@ module TnPDF
|
|
47
105
|
end
|
48
106
|
end
|
49
107
|
|
50
|
-
def render(
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
table.row(0).background_color = self.header_color
|
108
|
+
def render(max_height)
|
109
|
+
x_pos = x_pos_on(document, document_width)
|
110
|
+
|
111
|
+
initialize_generated_widths
|
112
|
+
total_width = self.column_widths.sum
|
56
113
|
|
57
|
-
columns.each_with_index do |column, index|
|
58
|
-
style = column.style.reject { |k, v| [:format, :decimal].include? k }
|
59
|
-
table.columns(index).style(style)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
x_pos = x_pos_on(document, table.width)
|
63
114
|
document.bounding_box([x_pos, document.cursor],
|
64
|
-
:width =>
|
115
|
+
:width => total_width,
|
65
116
|
:height => max_height) do
|
66
|
-
|
117
|
+
|
118
|
+
table_data = [[header_table]]
|
119
|
+
table_data += minitables
|
120
|
+
table_data += footer_tables
|
121
|
+
|
122
|
+
document.text *([text_before].flatten)
|
123
|
+
document.font_size self.font_size
|
124
|
+
|
125
|
+
document.table(table_data, :column_widths => [total_width],
|
126
|
+
:width => total_width) do |table|
|
127
|
+
|
128
|
+
table.header = self.multipage_headers
|
129
|
+
stylize_table(table)
|
130
|
+
end
|
131
|
+
|
132
|
+
document.text *([text_after].flatten)
|
67
133
|
end
|
68
134
|
end
|
69
135
|
|
70
|
-
|
71
|
-
|
136
|
+
# Adds a footer row to the table.
|
137
|
+
#
|
138
|
+
# The argument to this method should be an Array (or a block that returns
|
139
|
+
# an Array) in which each member is a cell in the format:
|
140
|
+
# [content, colspan, style]
|
141
|
+
# where:
|
142
|
+
# [*content*]
|
143
|
+
# Is the content of the cell. May be a label, a sum of some values
|
144
|
+
# from the collection etc.
|
145
|
+
# [*colspan*]
|
146
|
+
# A number representing how many columns of the table this cell is going
|
147
|
+
# to span across. Be warned that the sum of all the colspans on a given
|
148
|
+
# footer row should always match the number of columns in the table, or
|
149
|
+
# an exception will be raised.
|
150
|
+
# [*style*]
|
151
|
+
# The formatting style of the cell. Refer to {Column#style Column#style}
|
152
|
+
# for details.
|
153
|
+
# @example
|
154
|
+
# # On a table that has 2 columns
|
155
|
+
# table.add_footer [
|
156
|
+
# ["Total", 1, :text],
|
157
|
+
# [12345, 1, :number]
|
158
|
+
# ]
|
159
|
+
# @example
|
160
|
+
# # On a table that has 3 columns
|
161
|
+
# table.add_footer do |collection|
|
162
|
+
# calculation = collection.map(&:value).sum
|
163
|
+
# [
|
164
|
+
# ["Calculation", 1, :text],
|
165
|
+
# [calculation, 2, :number]
|
166
|
+
# ]
|
167
|
+
# end
|
168
|
+
def add_footer(row=nil, &block)
|
169
|
+
unless block_given? or row.kind_of? Array
|
170
|
+
raise ArgumentError, "No block or array was passed"
|
171
|
+
end
|
172
|
+
|
173
|
+
row = block.call(collection) if block_given?
|
174
|
+
|
175
|
+
# [content, colspan, style]
|
176
|
+
row = row.map do |field|
|
177
|
+
field[2] ||= :text
|
178
|
+
content = Column.format_value(field[0],
|
179
|
+
Column.style_for(field[2]))
|
180
|
+
|
181
|
+
OpenStruct.new(:content => content,
|
182
|
+
:colspan => field[1],
|
183
|
+
:style => Column.prawn_style_for(field[2]) )
|
184
|
+
end
|
185
|
+
|
186
|
+
row.inject(0) do |first_column, field|
|
187
|
+
final_column = first_column+field.colspan-1
|
188
|
+
field.colspan_range = (first_column..final_column)
|
189
|
+
final_column+1
|
190
|
+
end
|
191
|
+
|
192
|
+
total_colspan = row.map(&:colspan).inject(:+)
|
193
|
+
unless total_colspan == columns.length
|
194
|
+
raise ArgumentError,
|
195
|
+
"Total colspan value '#{total_colspan}' differs from the "+
|
196
|
+
"table's columns number '#{columns.length}'"
|
197
|
+
end
|
198
|
+
|
199
|
+
footer_rows << row
|
200
|
+
end
|
201
|
+
|
202
|
+
def row_color(row_number)
|
203
|
+
row_number % 2 == 0 ?
|
204
|
+
self.even_row_color:
|
205
|
+
self.odd_row_color
|
206
|
+
end
|
207
|
+
|
208
|
+
def column_widths(type = :all)
|
209
|
+
selected_columns = columns(type)
|
210
|
+
selected_columns.sort_by(&:index).map(&:width)
|
72
211
|
end
|
73
212
|
|
74
213
|
private
|
75
214
|
|
215
|
+
def columns_headers
|
216
|
+
columns.map(&:header)
|
217
|
+
end
|
218
|
+
|
76
219
|
def x_pos_on(document, table_width)
|
77
220
|
case align
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
221
|
+
when :left
|
222
|
+
0
|
223
|
+
when :center
|
224
|
+
(document.bounds.right - table_width)/2.0
|
225
|
+
when :right
|
226
|
+
document.bounds.right - table_width
|
227
|
+
else
|
228
|
+
0
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
def document
|
233
|
+
@document
|
234
|
+
end
|
235
|
+
|
236
|
+
def prawn_table
|
237
|
+
if @prev_headers != columns_headers or
|
238
|
+
@prev_rows != rows
|
239
|
+
|
240
|
+
@prawn_table = nil
|
241
|
+
@prev_headers = columns_headers
|
242
|
+
@prev_rows = rows
|
243
|
+
end
|
244
|
+
|
245
|
+
@prawn_table ||= begin
|
246
|
+
document.make_table([columns_headers]+rows) do |table|
|
247
|
+
document.font_size = self.font_size
|
248
|
+
stylize_table(table)
|
249
|
+
end
|
86
250
|
end
|
87
251
|
end
|
88
252
|
|
253
|
+
def minitables
|
254
|
+
row_number = 0 # I hate this as much as you do
|
255
|
+
rows.map do |row|
|
256
|
+
minitable = document.make_table([row],
|
257
|
+
:column_widths => column_widths) do |table|
|
258
|
+
columns.each_with_index do |column, index|
|
259
|
+
table.columns(index).style(column.prawn_style)
|
260
|
+
end
|
261
|
+
table.rows(0..-1).size = self.font_size
|
262
|
+
row_number += 1
|
263
|
+
stylize_table(table)
|
264
|
+
table.cells.background_color = self.row_color(row_number)
|
265
|
+
end
|
266
|
+
[minitable]
|
267
|
+
end
|
268
|
+
end
|
269
|
+
|
270
|
+
def header_table
|
271
|
+
document.make_table([columns_headers],
|
272
|
+
:column_widths => column_widths) do |table|
|
273
|
+
header_row = table.row(0)
|
274
|
+
header_row.background_color = self.header_color
|
275
|
+
header_row.font_style = self.header_font_style
|
276
|
+
header_row.size = self.header_font_size
|
277
|
+
header_row.font = self.header_font
|
278
|
+
header_row.align = :center
|
279
|
+
|
280
|
+
stylize_table(table)
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def stylize_table(table)
|
285
|
+
table.cells.borders = borders || []
|
286
|
+
end
|
287
|
+
|
288
|
+
def footer_rows
|
289
|
+
@footer_rows ||= []
|
290
|
+
end
|
291
|
+
|
292
|
+
def footer_tables
|
293
|
+
footer_rows.map do |row|
|
294
|
+
[footer_table_for(row)]
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def footer_table_for(row)
|
299
|
+
row_array = [row.map(&:content)]
|
300
|
+
footer_column_widths = row.map do |field|
|
301
|
+
column_widths[field.colspan_range].inject(:+)
|
302
|
+
end
|
303
|
+
|
304
|
+
document.make_table(row_array,
|
305
|
+
:column_widths => footer_column_widths) do |table|
|
306
|
+
|
307
|
+
footer_row = table.row(0)
|
308
|
+
footer_row.background_color = self.footer_color
|
309
|
+
footer_row.font_style = self.footer_font_style
|
310
|
+
footer_row.size = self.footer_font_size
|
311
|
+
footer_row.font = self.footer_font
|
312
|
+
|
313
|
+
row.each_with_index do |field, index|
|
314
|
+
table.columns(index).style(field.style)
|
315
|
+
end
|
316
|
+
stylize_table(table)
|
317
|
+
end
|
318
|
+
end
|
319
|
+
|
320
|
+
def initialize_generated_widths
|
321
|
+
columns(:generated).each do |column|
|
322
|
+
index = column.index
|
323
|
+
column.width = prawn_table.columns(index).width
|
324
|
+
end
|
325
|
+
generated_widths_sum = column_widths(:generated).sum
|
326
|
+
|
327
|
+
fixed_widths_sum = column_widths(:fixed).sum
|
328
|
+
percentage_widths_sum = column_widths(:percentage).sum
|
329
|
+
remaining_space = document_width - percentage_widths_sum - fixed_widths_sum
|
330
|
+
|
331
|
+
columns(:generated).each do |column|
|
332
|
+
width = column.width
|
333
|
+
column.width = (width/generated_widths_sum)*remaining_space
|
334
|
+
column.column_width_type = :fixed
|
335
|
+
end
|
336
|
+
end
|
337
|
+
|
338
|
+
def document_width
|
339
|
+
document.bounds.width
|
340
|
+
end
|
89
341
|
end
|
90
342
|
|
91
343
|
end
|
data/lib/tn_pdf/table_column.rb
CHANGED
@@ -1,49 +1,130 @@
|
|
1
1
|
module TnPDF
|
2
2
|
class Table
|
3
|
-
|
3
|
+
# Represents a column of a table. Typically not used directly, but through
|
4
|
+
# {Table#add_column Table#add_column} and friends.
|
4
5
|
class Column
|
5
|
-
|
6
|
+
# Is a String that contains the column header
|
7
|
+
# @return [String]
|
8
|
+
attr_reader :header
|
9
|
+
|
10
|
+
# Is an object that responds to to_proc, typically a Symbol or a Proc.
|
11
|
+
# It represents the procedure used to extract the information from the
|
12
|
+
# object.
|
13
|
+
# @example
|
14
|
+
# column.proc = :full_name
|
15
|
+
# @example
|
16
|
+
# myProc = Proc.new do |person|
|
17
|
+
# "#{person.id} - #{person.name}"
|
18
|
+
# end
|
19
|
+
# column.proc = myProc
|
20
|
+
# @return [#to_proc]
|
21
|
+
attr_reader :proc
|
22
|
+
|
23
|
+
# Defines how the formatting of the result will occur. Typically used
|
24
|
+
# for formatting currencies, numbers etc, but can be anything defined
|
25
|
+
# on {Configuration}, the {TnPDF::Configuration.load_from YAML Configuration file}
|
26
|
+
# or a Hash that contains (at least) the :format key.
|
27
|
+
# It defaults to the :text style.
|
28
|
+
# @example
|
29
|
+
# column.style = :currency
|
30
|
+
# @example
|
31
|
+
# column.style = { :format => "%.2f",
|
32
|
+
# :decimal => ",",
|
33
|
+
# :align => :right }
|
34
|
+
# @return [Symbol, Hash]
|
35
|
+
attr_reader :style
|
36
|
+
|
37
|
+
# Defines the (visual) width of the column. May be defined in PDF
|
38
|
+
# points (1/72 inch), a String "in" the cm or mm units, or a String
|
39
|
+
# representing a percentage.
|
40
|
+
#
|
41
|
+
# It is important to note that, in the case of a percentage-based
|
42
|
+
# column, it represents a percentage of the *page* on which the table
|
43
|
+
# will be rendered, not of the table.
|
44
|
+
# @example
|
45
|
+
# width = 1234.45
|
46
|
+
# @example
|
47
|
+
# width = "1.5cm"
|
48
|
+
# @example
|
49
|
+
# width = "14mm"
|
50
|
+
# @example
|
51
|
+
# width = "20%"
|
52
|
+
# @return [Double, String]
|
53
|
+
attr_accessor :width
|
6
54
|
|
7
55
|
alias_method :to_proc, :proc
|
56
|
+
|
57
|
+
attr_accessor :column_width_type
|
58
|
+
# Creates a new Column
|
59
|
+
#
|
60
|
+
# The parameter has to be an Array in the form:
|
61
|
+
# [header, procedure, style, width]
|
62
|
+
# where:
|
63
|
+
# [{#header header} (required)]
|
64
|
+
# {include:#header}
|
65
|
+
# [{#proc procedure} (required)]
|
66
|
+
# {include:#proc}
|
67
|
+
# [{#style style} (optional)]
|
68
|
+
# {include:#style}
|
69
|
+
# [{#width width} (optional)]
|
70
|
+
# {include:#width}
|
71
|
+
# @example
|
72
|
+
# Column.new [ "Full name", :full_name ]
|
73
|
+
# @example
|
74
|
+
# sum = Proc.new { |obj| obj.value_a + obj.value_b }
|
75
|
+
# Column.new [ "Sum", sum, :number, "15%" ]
|
8
76
|
def initialize(arguments)
|
9
77
|
raise ArgumentError unless valid_column_args?(arguments)
|
10
78
|
@header = arguments[0].to_s
|
11
79
|
@proc = arguments[1].to_proc
|
12
|
-
@style
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
collection.map do |object|
|
17
|
-
value_for(object)
|
80
|
+
@style = Column.style_for(arguments[2])
|
81
|
+
@width = Configuration.perform_conversions arguments[3]
|
82
|
+
if @width.nil?
|
83
|
+
column_width_type = :generated
|
18
84
|
end
|
19
85
|
end
|
20
86
|
|
21
87
|
def value_for(object)
|
22
88
|
value = @proc.call(object)
|
23
|
-
|
24
|
-
|
25
|
-
elsif value.respond_to?(:sprintf)
|
26
|
-
value.method(:sprintf)
|
27
|
-
else
|
28
|
-
method(:sprintf)
|
29
|
-
end
|
30
|
-
string = method.arity == 1 ?
|
31
|
-
method.call(style[:format]) :
|
32
|
-
method.call(style[:format], value)
|
89
|
+
Column.format_value(value, style)
|
90
|
+
end
|
33
91
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
92
|
+
def prawn_style
|
93
|
+
style.reject { |k, v| [:format, :decimal].include? k }
|
94
|
+
end
|
95
|
+
|
96
|
+
def width
|
97
|
+
if column_width_type == :percentage
|
98
|
+
unless max_width
|
99
|
+
raise ArgumentError, "Maximum width should be set for percentage-based widths!"
|
100
|
+
end
|
101
|
+
match = @width.scan(/(\d+\.?\d*)%/)
|
102
|
+
|
103
|
+
number = match[0][0].to_f/100.0
|
104
|
+
number*max_width
|
105
|
+
else
|
106
|
+
@width
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
def column_width_type
|
111
|
+
@column_width_type ||=
|
112
|
+
if @width.kind_of? String
|
113
|
+
(@width =~ /(\d+\.?\d*)%/) ? :percentage : :fixed
|
114
|
+
elsif @width.kind_of? Numeric
|
115
|
+
:fixed
|
116
|
+
else
|
117
|
+
:generated
|
118
|
+
end
|
39
119
|
end
|
40
120
|
|
121
|
+
attr_accessor :index, :max_width
|
41
122
|
private
|
42
123
|
|
43
124
|
def valid_column_args?(column_args)
|
44
125
|
validity = true
|
45
126
|
validity &= column_args.kind_of? Array
|
46
|
-
validity &=
|
127
|
+
validity &= (2..4).include? column_args.count
|
47
128
|
validity &= column_args[0].respond_to?(:to_s)
|
48
129
|
validity &= column_args[1].respond_to?(:to_proc)
|
49
130
|
rescue NoMethodError
|
@@ -52,7 +133,7 @@ module TnPDF
|
|
52
133
|
return validity
|
53
134
|
end
|
54
135
|
|
55
|
-
def style_for(type)
|
136
|
+
def self.style_for(type)
|
56
137
|
if type.nil?
|
57
138
|
{:format => "%s"}
|
58
139
|
elsif type.kind_of? Symbol
|
@@ -61,6 +142,34 @@ module TnPDF
|
|
61
142
|
type
|
62
143
|
end
|
63
144
|
end
|
145
|
+
|
146
|
+
def self.prawn_style_for(type)
|
147
|
+
style_for(type).reject { |k, v| [:format, :decimal].include? k }
|
148
|
+
end
|
149
|
+
|
150
|
+
def self.format_value(value, style)
|
151
|
+
formatting_method = formatting_method_for(value)
|
152
|
+
string = formatting_method.call(style[:format])
|
153
|
+
|
154
|
+
string.gsub!(".", style[:decimal]) if style[:decimal]
|
155
|
+
return string
|
156
|
+
rescue TypeError, ArgumentError
|
157
|
+
puts "WARNING: Bad format '#{style[:format]}' for value '#{value.inspect}'"
|
158
|
+
return value.to_s
|
159
|
+
end
|
160
|
+
|
161
|
+
def self.formatting_method_for(value)
|
162
|
+
if value.respond_to?(:strftime)
|
163
|
+
lambda { |format| value.strftime(format) }
|
164
|
+
elsif value.respond_to?(:sprintf)
|
165
|
+
lambda { |format| value.sprintf(format) }
|
166
|
+
elsif value.nil?
|
167
|
+
lambda { |_| "" }
|
168
|
+
else
|
169
|
+
lambda { |format| sprintf(format, value) }
|
170
|
+
end
|
171
|
+
end
|
172
|
+
private_class_method :formatting_method_for
|
64
173
|
end
|
65
174
|
|
66
175
|
end
|
data/lib/tn_pdf/version.rb
CHANGED
data/lib/tn_pdf.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
1
|
require 'rubygems'
|
2
|
-
require 'active_support' # Because of to_options!
|
3
2
|
require 'prawn'
|
4
3
|
require 'prawn/measurement_extensions'
|
4
|
+
require 'ostruct'
|
5
|
+
require 'backports'
|
6
|
+
|
7
|
+
load 'prawn/table_fix.rb'
|
5
8
|
|
6
9
|
require 'tn_pdf/configuration'
|
7
10
|
require 'tn_pdf/report'
|
data/spec/tn_pdf/box_spec.rb
CHANGED
@@ -19,17 +19,17 @@ module TnPDF
|
|
19
19
|
|
20
20
|
it "accepts extra text options to prawn by passing hashes" do
|
21
21
|
document = Prawn::Document.new
|
22
|
-
box = Box.new( :text => {:text => "text", :font => "
|
22
|
+
box = Box.new( :text => {:text => "text", :font => "Courier"} )
|
23
23
|
|
24
|
-
document.should_receive(:text).with("text", hash_including(:font => "
|
24
|
+
document.should_receive(:text).with("text", hash_including(:font => "Courier") )
|
25
25
|
box.render(document, [0,0], 100)
|
26
26
|
end
|
27
27
|
|
28
28
|
it "accepts extra image options to prawn by passing hashes" do
|
29
29
|
document = Prawn::Document.new
|
30
|
-
box = Box.new( :image => {:
|
30
|
+
box = Box.new( :image => {:file => "./image.jpg", :width => 1.cm } )
|
31
31
|
|
32
|
-
document.should_receive(:image).with("image.jpg", hash_including(:width => 1.cm) )
|
32
|
+
document.should_receive(:image).with("./image.jpg", hash_including(:width => 1.cm) )
|
33
33
|
box.render(document, [0,0], 100)
|
34
34
|
end
|
35
35
|
end
|
data/spec/tn_pdf/table_spec.rb
CHANGED
@@ -5,7 +5,10 @@ module TnPDF
|
|
5
5
|
const_set("Column",EmptyClass) unless const_defined?("Column")
|
6
6
|
end
|
7
7
|
|
8
|
+
|
8
9
|
describe Table do
|
10
|
+
let(:subject) { Table.new(stub('Document')) }
|
11
|
+
|
9
12
|
describe "#columns_hash" do
|
10
13
|
it "is a kind of Hash" do
|
11
14
|
subject.columns_hash.should be_kind_of(Hash)
|
@@ -71,30 +74,31 @@ module TnPDF
|
|
71
74
|
|
72
75
|
describe "#rows" do
|
73
76
|
it "returns the values of the objects for each column" do
|
74
|
-
subject = Table.new # Just to be explicit
|
77
|
+
subject = Table.new(stub('Document')) # Just to be explicit
|
75
78
|
subject.add_column( ["String", :to_s] )
|
76
79
|
subject.add_column( ["Integer", :to_i] )
|
77
80
|
subject.add_column( ["Doubled", Proc.new { |x| x*2 } ] )
|
78
81
|
|
79
82
|
subject.collection = [1, 2, 3]
|
80
|
-
subject.rows.should == [ ["1", 1, 2],
|
81
|
-
["2", 2, 4],
|
82
|
-
["3", 3, 6] ]
|
83
|
+
subject.rows.should == [ ["1", "1", "2"],
|
84
|
+
["2", "2", "4"],
|
85
|
+
["3", "3", "6"] ]
|
83
86
|
end
|
84
87
|
end
|
85
88
|
|
86
89
|
describe "#render" do
|
87
|
-
let(:document) do
|
88
|
-
mock("Prawn::Document").as_null_object
|
89
|
-
end
|
90
|
-
|
91
90
|
let(:table) do
|
92
91
|
mock("Prawn::Table").as_null_object
|
93
92
|
end
|
94
93
|
|
94
|
+
let(:document) do
|
95
|
+
mock("Prawn::Document").as_null_object
|
96
|
+
end
|
97
|
+
|
95
98
|
it "instantiates a Prawn::Table instance" do
|
96
99
|
document.should_receive(:make_table).and_return(table)
|
97
|
-
subject.
|
100
|
+
subject = Table.new(document)
|
101
|
+
subject.render(0)
|
98
102
|
end
|
99
103
|
end
|
100
104
|
end
|
data/tn_pdf.gemspec
CHANGED