prawn 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/Rakefile +4 -2
- data/lib/prawn.rb +5 -3
- data/lib/prawn/document.rb +7 -7
- data/lib/prawn/document/bounding_box.rb +1 -1
- data/lib/prawn/document/column_box.rb +3 -3
- data/lib/prawn/document/internals.rb +1 -1
- data/lib/prawn/font.rb +24 -8
- data/lib/prawn/font/afm.rb +4 -4
- data/lib/prawn/font_metric_cache.rb +1 -1
- data/lib/prawn/grid.rb +3 -1
- data/lib/prawn/image_handler.rb +3 -1
- data/lib/prawn/images/jpg.rb +1 -1
- data/lib/prawn/measurement_extensions.rb +1 -1
- data/lib/prawn/outline.rb +3 -1
- data/lib/prawn/security.rb +1 -1
- data/lib/prawn/security/arcfour.rb +4 -2
- data/lib/prawn/table.rb +14 -2
- data/lib/prawn/table/cell.rb +1 -1
- data/lib/prawn/table/cells.rb +1 -50
- data/lib/prawn/table/column_width_calculator.rb +131 -10
- data/lib/prawn/text.rb +1 -1
- data/lib/prawn/text/formatted.rb +2 -0
- data/lib/prawn/text/formatted/arranger.rb +1 -1
- data/lib/prawn/text/formatted/box.rb +5 -5
- data/lib/prawn/text/formatted/line_wrap.rb +1 -1
- data/lib/prawn/text/formatted/wrap.rb +2 -0
- data/lib/prawn/utilities.rb +3 -3
- data/manual/absolute_position.pdf +0 -0
- data/manual/basic_concepts/adding_pages.rb +3 -3
- data/manual/basic_concepts/basic_concepts.rb +6 -6
- data/manual/basic_concepts/cursor.rb +5 -5
- data/manual/basic_concepts/measurement.rb +2 -2
- data/manual/basic_concepts/origin.rb +3 -3
- data/manual/basic_concepts/other_cursor_helpers.rb +6 -6
- data/manual/bounding_box/bounding_box.rb +6 -6
- data/manual/bounding_box/bounds.rb +6 -6
- data/manual/bounding_box/canvas.rb +2 -2
- data/manual/bounding_box/creation.rb +3 -3
- data/manual/bounding_box/indentation.rb +9 -9
- data/manual/bounding_box/nesting.rb +8 -8
- data/manual/bounding_box/russian_boxes.rb +1 -1
- data/manual/bounding_box/stretchy.rb +8 -8
- data/manual/{manual/manual.rb → contents.rb} +6 -9
- data/manual/{manual/cover.rb → cover.rb} +6 -6
- data/manual/document_and_page_options/background.rb +2 -2
- data/manual/document_and_page_options/document_and_page_options.rb +4 -4
- data/manual/document_and_page_options/metadata.rb +2 -2
- data/manual/document_and_page_options/page_margins.rb +2 -2
- data/manual/document_and_page_options/page_size.rb +3 -3
- data/manual/example_helper.rb +5 -409
- data/manual/graphics/circle_and_ellipse.rb +4 -4
- data/manual/graphics/color.rb +4 -4
- data/manual/graphics/common_lines.rb +5 -5
- data/manual/graphics/fill_and_stroke.rb +5 -5
- data/manual/graphics/fill_rules.rb +1 -1
- data/manual/graphics/gradients.rb +1 -1
- data/manual/graphics/graphics.rb +8 -8
- data/manual/graphics/helper.rb +1 -1
- data/manual/graphics/line_width.rb +5 -5
- data/manual/graphics/lines_and_curves.rb +5 -5
- data/manual/graphics/polygon.rb +4 -4
- data/manual/graphics/rectangle.rb +3 -3
- data/manual/graphics/rotate.rb +5 -5
- data/manual/graphics/scale.rb +5 -5
- data/manual/graphics/soft_masks.rb +1 -1
- data/manual/graphics/stroke_cap.rb +3 -3
- data/manual/graphics/stroke_dash.rb +1 -1
- data/manual/graphics/stroke_join.rb +4 -4
- data/manual/graphics/translate.rb +5 -5
- data/manual/graphics/transparency.rb +5 -5
- data/manual/{manual/how_to_read_this_manual.rb → how_to_read_this_manual.rb} +16 -17
- data/manual/images/absolute_position.rb +3 -3
- data/manual/images/fit.rb +2 -2
- data/manual/images/horizontal.rb +3 -3
- data/manual/images/images.rb +7 -7
- data/manual/images/plain_image.rb +1 -1
- data/manual/images/scale.rb +3 -3
- data/manual/images/vertical.rb +3 -3
- data/manual/images/width_and_height.rb +3 -3
- data/manual/layout/boxes.rb +4 -4
- data/manual/layout/content.rb +3 -3
- data/manual/layout/layout.rb +5 -5
- data/manual/layout/simple_grid.rb +2 -2
- data/manual/outline/add_subsection_to.rb +7 -7
- data/manual/outline/insert_section_after.rb +5 -5
- data/manual/outline/outline.rb +6 -6
- data/manual/outline/sections_and_pages.rb +9 -9
- data/manual/repeatable_content/page_numbering.rb +3 -3
- data/manual/repeatable_content/repeatable_content.rb +5 -5
- data/manual/repeatable_content/repeater.rb +4 -4
- data/manual/repeatable_content/stamp.rb +4 -4
- data/manual/security/encryption.rb +2 -2
- data/manual/security/permissions.rb +2 -2
- data/manual/security/security.rb +5 -5
- data/manual/table/basic_block.rb +5 -5
- data/manual/table/before_rendering_page.rb +1 -1
- data/manual/table/cell_border_lines.rb +4 -4
- data/manual/table/cell_borders_and_bg.rb +4 -4
- data/manual/table/cell_dimensions.rb +3 -3
- data/manual/table/cell_text.rb +6 -6
- data/manual/table/column_widths.rb +4 -4
- data/manual/table/content_and_subtables.rb +5 -5
- data/manual/table/creation.rb +2 -2
- data/manual/table/filtering.rb +6 -6
- data/manual/table/flow_and_header.rb +2 -2
- data/manual/table/image_cells.rb +1 -1
- data/manual/table/position.rb +1 -1
- data/manual/table/row_colors.rb +3 -3
- data/manual/table/span.rb +1 -1
- data/manual/table/style.rb +3 -3
- data/manual/table/table.rb +7 -7
- data/manual/table/width.rb +3 -3
- data/manual/text/alignment.rb +1 -1
- data/manual/text/color.rb +1 -1
- data/manual/text/column_box.rb +1 -1
- data/manual/text/fallback_fonts.rb +3 -3
- data/manual/text/font.rb +7 -7
- data/manual/text/font_size.rb +9 -9
- data/manual/text/font_style.rb +3 -3
- data/manual/text/formatted_callbacks.rb +3 -3
- data/manual/text/formatted_text.rb +3 -3
- data/manual/text/free_flowing_text.rb +6 -6
- data/manual/text/inline.rb +5 -5
- data/manual/text/kerning_and_character_spacing.rb +7 -7
- data/manual/text/leading.rb +4 -4
- data/manual/text/line_wrapping.rb +4 -4
- data/manual/text/paragraph_indentation.rb +3 -3
- data/manual/text/positioned_text.rb +3 -3
- data/manual/text/registering_families.rb +6 -6
- data/manual/text/rendering_and_color.rb +2 -2
- data/manual/text/right_to_left_text.rb +2 -2
- data/manual/text/rotation.rb +4 -4
- data/manual/text/single_usage.rb +3 -3
- data/manual/text/text.rb +9 -9
- data/manual/text/text_box_excess.rb +2 -2
- data/manual/text/text_box_extensions.rb +3 -3
- data/manual/text/text_box_overflow.rb +4 -4
- data/manual/text/utf8.rb +5 -5
- data/manual/text/win_ansi_charset.rb +1 -1
- data/prawn.gemspec +5 -3
- data/spec/acceptance/png.rb +5 -3
- data/spec/cell_spec.rb +1 -0
- data/spec/column_box_spec.rb +1 -1
- data/spec/extensions/encoding_helpers.rb +2 -0
- data/spec/extensions/mocha.rb +2 -0
- data/spec/font_spec.rb +15 -0
- data/spec/measurement_units_spec.rb +2 -0
- data/spec/repeater_spec.rb +2 -0
- data/spec/soft_mask_spec.rb +2 -0
- data/spec/stamp_spec.rb +2 -0
- data/spec/table_spec.rb +103 -10
- data/spec/text_spec.rb +1 -1
- data/spec/transparency_spec.rb +2 -0
- metadata +42 -18
- data/lib/prawn/layout.rb +0 -17
- data/manual/example_file.rb +0 -111
- data/manual/example_package.rb +0 -53
- data/manual/example_section.rb +0 -46
- data/manual/syntax_highlight.rb +0 -52
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 8492b319da06bf93faa4e58cfa4932b46fd8a474
|
4
|
+
data.tar.gz: ba94547a9eda37f13c91b7293203a12df99b9815
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d898304c9f63ac7826f49b3802106ec84e36fb8a0efcb07d85b2b88d0e7a2f3016f722655fea9e4992e028a8a740ef5d29a5ee9e7287164f6768d9435179891c
|
7
|
+
data.tar.gz: 0127f4e217c2588fe196665712cb1fe7e3914a49d3ba4e0b248e1a7bd3615f52e6c97e2288c4c7fb9295383e48c03ad48557c137e8d1f822841c65d1a8f77d62
|
data/Rakefile
CHANGED
@@ -5,8 +5,9 @@ require 'rake'
|
|
5
5
|
require 'rspec/core/rake_task'
|
6
6
|
require 'yard'
|
7
7
|
require 'rubygems/package_task'
|
8
|
+
require 'rubocop/rake_task'
|
8
9
|
|
9
|
-
task :default => [:spec]
|
10
|
+
task :default => [:rubocop, :spec]
|
10
11
|
|
11
12
|
desc "Run all rspec files"
|
12
13
|
RSpec::Core::RakeTask.new("spec") do |c|
|
@@ -31,7 +32,7 @@ desc "Generate the 'Prawn by Example' manual"
|
|
31
32
|
task :manual do
|
32
33
|
puts "Building manual..."
|
33
34
|
require File.expand_path(File.join(File.dirname(__FILE__),
|
34
|
-
%w[manual
|
35
|
+
%w[manual contents]))
|
35
36
|
puts "The Prawn manual is available at manual.pdf. Happy Prawning!"
|
36
37
|
end
|
37
38
|
|
@@ -52,3 +53,4 @@ task :console do
|
|
52
53
|
IRB.start
|
53
54
|
end
|
54
55
|
|
56
|
+
Rubocop::RakeTask.new
|
data/lib/prawn.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
# Welcome to Prawn, the best PDF Generation library ever.
|
2
4
|
# This documentation covers user level functionality.
|
3
5
|
#
|
@@ -7,7 +9,7 @@ require 'ttfunk'
|
|
7
9
|
require "pdf/core"
|
8
10
|
|
9
11
|
module Prawn
|
10
|
-
VERSION = "1.
|
12
|
+
VERSION = "1.1.0"
|
11
13
|
|
12
14
|
extend self
|
13
15
|
|
@@ -20,7 +22,7 @@ module Prawn
|
|
20
22
|
#
|
21
23
|
BASEDIR = File.expand_path(File.join(dir, '..'))
|
22
24
|
DATADIR = File.expand_path(File.join(dir, '..', 'data'))
|
23
|
-
|
25
|
+
|
24
26
|
FLOAT_PRECISION = 1.0e-9
|
25
27
|
|
26
28
|
# Whe set to true, Prawn will verify hash options to ensure only valid keys
|
@@ -81,7 +83,7 @@ require_relative "prawn/encoding"
|
|
81
83
|
require_relative "prawn/measurements"
|
82
84
|
require_relative "prawn/repeater"
|
83
85
|
require_relative "prawn/outline"
|
84
|
-
require_relative "prawn/
|
86
|
+
require_relative "prawn/grid"
|
85
87
|
|
86
88
|
require_relative "prawn/image_handler"
|
87
89
|
|
data/lib/prawn/document.rb
CHANGED
@@ -97,7 +97,7 @@ module Prawn
|
|
97
97
|
end
|
98
98
|
|
99
99
|
# @private
|
100
|
-
def self.inherited(base)
|
100
|
+
def self.inherited(base)
|
101
101
|
extensions.each { |e| base.extensions << e }
|
102
102
|
end
|
103
103
|
|
@@ -148,7 +148,7 @@ module Prawn
|
|
148
148
|
# Creates a new PDF Document. The following options are available (with
|
149
149
|
# the default values marked in [])
|
150
150
|
#
|
151
|
-
# <tt>:page_size</tt>:: One of the
|
151
|
+
# <tt>:page_size</tt>:: One of the PDF::Core::PageGeometry sizes [LETTER]
|
152
152
|
# <tt>:page_layout</tt>:: Either <tt>:portrait</tt> or <tt>:landscape</tt>
|
153
153
|
# <tt>:margin</tt>:: Sets the margin on all sides in points [0.5 inch]
|
154
154
|
# <tt>:left_margin</tt>:: Sets the left margin in points [0.5 inch]
|
@@ -587,7 +587,7 @@ module Prawn
|
|
587
587
|
#
|
588
588
|
# @private
|
589
589
|
def group(*a, &b)
|
590
|
-
raise NotImplementedError,
|
590
|
+
raise NotImplementedError,
|
591
591
|
"Document#group has been disabled because its implementation "+
|
592
592
|
"lead to corrupted documents whenever a page boundary was "+
|
593
593
|
"crossed. We will try to work on reimplementing it in a "+
|
@@ -596,7 +596,7 @@ module Prawn
|
|
596
596
|
|
597
597
|
# @private
|
598
598
|
def transaction
|
599
|
-
raise NotImplementedError,
|
599
|
+
raise NotImplementedError,
|
600
600
|
"Document#transaction has been disabled because its implementation "+
|
601
601
|
"lead to corrupted documents whenever a page boundary was "+
|
602
602
|
"crossed. We will try to work on reimplementing it in a "+
|
@@ -629,8 +629,8 @@ module Prawn
|
|
629
629
|
end
|
630
630
|
|
631
631
|
# @private
|
632
|
-
|
633
|
-
def mask(*fields)
|
632
|
+
|
633
|
+
def mask(*fields)
|
634
634
|
# Stores the current state of the named attributes, executes the block, and
|
635
635
|
# then restores the original values after the block has executed.
|
636
636
|
# -- I will remove the nodoc if/when this feature is a little less hacky
|
@@ -696,7 +696,7 @@ module Prawn
|
|
696
696
|
|
697
697
|
# we must update bounding box if not flowing from the previous page
|
698
698
|
#
|
699
|
-
@bounding_box = @margin_box unless @bounding_box && @bounding_box.parent
|
699
|
+
@bounding_box = @margin_box unless @bounding_box && @bounding_box.parent
|
700
700
|
end
|
701
701
|
|
702
702
|
def apply_margin_options(options)
|
@@ -20,12 +20,12 @@ module Prawn
|
|
20
20
|
#
|
21
21
|
# column_box accepts the same parameters as bounding_box, as well as the
|
22
22
|
# number of :columns and a :spacer (in points) between columns. If resetting
|
23
|
-
# the top margin is desired on a new page (e.g. to allow for initial page
|
23
|
+
# the top margin is desired on a new page (e.g. to allow for initial page
|
24
24
|
# wide column titles) the option :reflow_margins => true can be set.
|
25
25
|
#
|
26
|
-
# Defaults are :columns = 3, :spacer = font_size, and
|
26
|
+
# Defaults are :columns = 3, :spacer = font_size, and
|
27
27
|
# :reflow_margins => false
|
28
|
-
#
|
28
|
+
#
|
29
29
|
# Under PDF::Writer, "spacer" was known as "gutter"
|
30
30
|
#
|
31
31
|
def column_box(*args, &block)
|
@@ -15,7 +15,7 @@ module Prawn
|
|
15
15
|
# are you won't need anything you find here.
|
16
16
|
#
|
17
17
|
# @private
|
18
|
-
module Internals
|
18
|
+
module Internals
|
19
19
|
# Creates a new Prawn::Reference and adds it to the Document's object
|
20
20
|
# list. The +data+ argument is anything that Prawn::PdfObject() can convert.
|
21
21
|
#
|
data/lib/prawn/font.rb
CHANGED
@@ -237,7 +237,15 @@ module Prawn
|
|
237
237
|
end
|
238
238
|
end
|
239
239
|
key = "#{name}:#{options[:font] || 0}"
|
240
|
-
|
240
|
+
|
241
|
+
if name.is_a? Prawn::Font
|
242
|
+
font_registry[key] = name
|
243
|
+
else
|
244
|
+
font_registry[key] ||= Font.load( self,
|
245
|
+
name,
|
246
|
+
options.merge(family: family)
|
247
|
+
)
|
248
|
+
end
|
241
249
|
end
|
242
250
|
|
243
251
|
# Hash of Font objects keyed by names
|
@@ -279,13 +287,21 @@ module Prawn
|
|
279
287
|
# Shortcut interface for constructing a font object. Filenames of the form
|
280
288
|
# *.ttf will call Font::TTF.new, *.dfont Font::DFont.new, and anything else
|
281
289
|
# will be passed through to Font::AFM.new()
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
when
|
286
|
-
|
287
|
-
|
288
|
-
|
290
|
+
def self.load(document, src, options={})
|
291
|
+
case font_format(src, options)
|
292
|
+
when 'ttf' then TTF.new(document, src, options)
|
293
|
+
when 'dfont' then DFont.new(document, src, options)
|
294
|
+
else AFM.new(document, src, options)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
def self.font_format(src, options)
|
299
|
+
return options.fetch(:format, 'ttf') if src.respond_to? :read
|
300
|
+
|
301
|
+
case src.to_s
|
302
|
+
when /\.ttf$/i then return 'ttf'
|
303
|
+
when /\.dfont$/i then return 'dfont'
|
304
|
+
else return 'afm'
|
289
305
|
end
|
290
306
|
end
|
291
307
|
|
data/lib/prawn/font/afm.rb
CHANGED
@@ -157,7 +157,7 @@ module Prawn
|
|
157
157
|
end
|
158
158
|
|
159
159
|
def parse_afm(file_name)
|
160
|
-
data = {:glyph_widths => {}, :bounding_boxes => {}, :kern_pairs => {}, :attributes => {}}
|
160
|
+
data = {:glyph_widths => {}, :bounding_boxes => {}, :kern_pairs => {}, :attributes => {}}
|
161
161
|
section = []
|
162
162
|
|
163
163
|
File.foreach(file_name) do |line|
|
@@ -187,7 +187,7 @@ module Prawn
|
|
187
187
|
parse_generic_afm_attribute(line, data)
|
188
188
|
end
|
189
189
|
end
|
190
|
-
|
190
|
+
|
191
191
|
# process data parsed from AFM file to build tables which
|
192
192
|
# will be used when measuring and kerning text
|
193
193
|
data[:glyph_table] = (0..255).map do |i|
|
@@ -234,9 +234,9 @@ module Prawn
|
|
234
234
|
e.respond_to?(:force_encoding) ? e.force_encoding(::Encoding::Windows_1252) : e
|
235
235
|
}
|
236
236
|
end
|
237
|
-
|
237
|
+
|
238
238
|
private
|
239
|
-
|
239
|
+
|
240
240
|
def unscaled_width_of(string)
|
241
241
|
string.bytes.inject(0) do |s,r|
|
242
242
|
s + @glyph_table[r]
|
data/lib/prawn/grid.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
# grid.rb: Provides a basic grid layout system for Prawn
|
2
4
|
#
|
3
5
|
# Contributed by Andrew O'Brien in March 2009
|
@@ -14,7 +16,7 @@ module Prawn
|
|
14
16
|
#
|
15
17
|
# Note that a completely new grid object is built each time define_grid()
|
16
18
|
# is called. This means that all subsequent calls to grid() will use
|
17
|
-
# the newly defined Grid object -- grids are not nestable like
|
19
|
+
# the newly defined Grid object -- grids are not nestable like
|
18
20
|
# bounding boxes are.
|
19
21
|
|
20
22
|
def define_grid(options = {})
|
data/lib/prawn/image_handler.rb
CHANGED
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
# ImageHandler provides a way to register image processors with Prawn
|
2
4
|
#
|
3
5
|
# Contributed by Evan Sharp in November 2013.
|
@@ -6,7 +8,7 @@
|
|
6
8
|
|
7
9
|
module Prawn
|
8
10
|
# @group Extension API
|
9
|
-
|
11
|
+
|
10
12
|
def self.image_handler
|
11
13
|
@image_handler ||= ImageHandler.new
|
12
14
|
end
|
data/lib/prawn/images/jpg.rb
CHANGED
data/lib/prawn/outline.rb
CHANGED
data/lib/prawn/security.rb
CHANGED
@@ -213,7 +213,7 @@ module PDF
|
|
213
213
|
# from the indirect object referencing obj.
|
214
214
|
#
|
215
215
|
# @private
|
216
|
-
def EncryptedPdfObject(obj, key, id, gen, in_content_stream=false)
|
216
|
+
def EncryptedPdfObject(obj, key, id, gen, in_content_stream=false)
|
217
217
|
case obj
|
218
218
|
when Array
|
219
219
|
"[" << obj.map { |e|
|
@@ -1,3 +1,5 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
# Implementation of the "ARCFOUR" algorithm ("alleged RC4 (tm)"). Implemented
|
2
4
|
# as described at:
|
3
5
|
# http://www.mozilla.org/projects/security/pki/nss/draft-kaukonen-cipher-arcfour-03.txt
|
@@ -17,7 +19,7 @@ class Arcfour
|
|
17
19
|
# 1. Allocate an 256 element array of 8 bit bytes to be used as an S-box
|
18
20
|
# 2. Initialize the S-box. Fill each entry first with it's index
|
19
21
|
@sbox = (0..255).to_a
|
20
|
-
|
22
|
+
|
21
23
|
# 3. Fill another array of the same size (256) with the key, repeating
|
22
24
|
# bytes as necessary.
|
23
25
|
s2 = []
|
@@ -39,7 +41,7 @@ class Arcfour
|
|
39
41
|
def encrypt(string)
|
40
42
|
string.unpack('c*').map{|byte| byte ^ key_byte}.pack('c*')
|
41
43
|
end
|
42
|
-
|
44
|
+
|
43
45
|
private
|
44
46
|
|
45
47
|
# Produces the next byte of key material in the stream (3.2 Stream Generation)
|
data/lib/prawn/table.rb
CHANGED
@@ -43,6 +43,16 @@ module Prawn
|
|
43
43
|
|
44
44
|
end
|
45
45
|
|
46
|
+
module Errors
|
47
|
+
# This error is raised when table data is malformed
|
48
|
+
#
|
49
|
+
InvalidTableData = Class.new(StandardError)
|
50
|
+
|
51
|
+
# This error is raised when an empty or nil table is rendered
|
52
|
+
#
|
53
|
+
EmptyTable = Class.new(StandardError)
|
54
|
+
end
|
55
|
+
|
46
56
|
# Next-generation table drawing for Prawn.
|
47
57
|
#
|
48
58
|
# = Data
|
@@ -320,7 +330,9 @@ module Prawn
|
|
320
330
|
c = Cells.new(cells_this_page.map { |ci, _| ci })
|
321
331
|
@before_rendering_page.call(c)
|
322
332
|
end
|
323
|
-
|
333
|
+
if @header_row.nil? || cells_this_page.size > @header_row.size
|
334
|
+
Cell.draw_cells(cells_this_page)
|
335
|
+
end
|
324
336
|
cells_this_page = []
|
325
337
|
|
326
338
|
# start a new page or column
|
@@ -527,7 +539,7 @@ module Prawn
|
|
527
539
|
rows_to_operate_on = @header_row.rows(row_of_header) if row_of_header
|
528
540
|
rows_to_operate_on.each do |cell|
|
529
541
|
cell.row = row
|
530
|
-
cell.dummy_cells.each {|c| c.row = row }
|
542
|
+
cell.dummy_cells.each {|c| c.row = row + c.row }
|
531
543
|
page_of_cells << [cell, [cell.x + x_offset, y]]
|
532
544
|
end
|
533
545
|
rows_to_operate_on.height
|
data/lib/prawn/table/cell.rb
CHANGED
@@ -153,7 +153,7 @@ module Prawn
|
|
153
153
|
# this span group. They know their own width / height, but do not draw
|
154
154
|
# anything.
|
155
155
|
#
|
156
|
-
attr_reader :dummy_cells
|
156
|
+
attr_reader :dummy_cells
|
157
157
|
|
158
158
|
# Instantiates a Cell based on the given options. The particular class of
|
159
159
|
# cell returned depends on the :content argument. See the Prawn::Table
|
data/lib/prawn/table/cells.rb
CHANGED
@@ -228,56 +228,7 @@ module Prawn
|
|
228
228
|
# each cell, grouped by +row_or_column+.
|
229
229
|
#
|
230
230
|
def aggregate_cell_values(row_or_column, meth, aggregate)
|
231
|
-
|
232
|
-
|
233
|
-
#calculate values for all cells that do not span accross multiple cells
|
234
|
-
#this ensures that we don't have a problem if the first line includes
|
235
|
-
#a cell that spans across multiple cells
|
236
|
-
each do |cell|
|
237
|
-
#don't take spanned cells
|
238
|
-
if cell.colspan == 1 and cell.class != Prawn::Table::Cell::SpanDummy
|
239
|
-
index = cell.send(row_or_column)
|
240
|
-
values[index] = [values[index], cell.send(meth)].compact.send(aggregate)
|
241
|
-
end
|
242
|
-
end
|
243
|
-
|
244
|
-
#if there are only colspanned or rowspanned cells in a table
|
245
|
-
spanned_width_needs_fixing = true
|
246
|
-
|
247
|
-
each do |cell|
|
248
|
-
index = cell.send(row_or_column)
|
249
|
-
if cell.colspan > 1
|
250
|
-
#calculate current (old) return value before we do anything
|
251
|
-
old_sum = 0
|
252
|
-
cell.colspan.times { |i|
|
253
|
-
old_sum += values[index+i] unless values[index+i].nil?
|
254
|
-
}
|
255
|
-
|
256
|
-
#calculate future return value
|
257
|
-
new_sum = cell.send(meth) * cell.colspan
|
258
|
-
|
259
|
-
#due to float rounding errors we need to ignore a small difference in the new
|
260
|
-
#and the old sum the same had to be done in
|
261
|
-
#the column_width_calculator#natural_width
|
262
|
-
spanned_width_needs_fixing = ((new_sum - old_sum) > Prawn::FLOAT_PRECISION)
|
263
|
-
|
264
|
-
if spanned_width_needs_fixing
|
265
|
-
#not entirely sure why we need this line, but with it the tests pass
|
266
|
-
values[index] = [values[index], cell.send(meth)].compact.send(aggregate)
|
267
|
-
#overwrite the old values with the new ones, but only if all entries existed
|
268
|
-
entries_exist = true
|
269
|
-
cell.colspan.times { |i| entries_exist = false if values[index+i].nil? }
|
270
|
-
cell.colspan.times { |i|
|
271
|
-
values[index+i] = cell.send(meth) if entries_exist
|
272
|
-
}
|
273
|
-
end
|
274
|
-
else
|
275
|
-
if spanned_width_needs_fixing && cell.class == Prawn::Table::Cell::SpanDummy
|
276
|
-
values[index] = [values[index], cell.send(meth)].compact.send(aggregate)
|
277
|
-
end
|
278
|
-
end
|
279
|
-
end
|
280
|
-
values.values.inject(0, &:+)
|
231
|
+
ColumnWidthCalculator.new(self).aggregate_cell_values(row_or_column, meth, aggregate)
|
281
232
|
end
|
282
233
|
|
283
234
|
# Transforms +spec+, a column / row specification, into an object that
|
@@ -1,48 +1,104 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
1
3
|
module Prawn
|
2
4
|
class Table
|
3
5
|
# @private
|
4
|
-
class ColumnWidthCalculator
|
6
|
+
class ColumnWidthCalculator
|
5
7
|
def initialize(cells)
|
6
8
|
@cells = cells
|
7
9
|
|
8
10
|
@widths_by_column = Hash.new(0)
|
9
11
|
@rows_with_a_span_dummy = Hash.new(false)
|
10
|
-
end
|
11
12
|
|
12
|
-
|
13
|
+
#calculate for each row if it includes a Cell:SpanDummy
|
13
14
|
@cells.each do |cell|
|
14
15
|
@rows_with_a_span_dummy[cell.row] = true if cell.is_a?(Cell::SpanDummy)
|
15
16
|
end
|
17
|
+
end
|
18
|
+
|
19
|
+
# does this row include a Cell:SpanDummy?
|
20
|
+
#
|
21
|
+
# @param row - the row that should be checked for Cell:SpanDummy elements
|
22
|
+
#
|
23
|
+
def has_a_span_dummy?(row)
|
24
|
+
@rows_with_a_span_dummy[row]
|
25
|
+
end
|
26
|
+
|
27
|
+
# helper method
|
28
|
+
# column widths are stored in the values array
|
29
|
+
# a cell may span cells whose value is only partly given
|
30
|
+
# this function handles this special case
|
31
|
+
#
|
32
|
+
# @param values - The columns widths calculated up until now
|
33
|
+
# @param cell - The current cell
|
34
|
+
# @param index - The current column
|
35
|
+
# @param meth - Meth (min/max); used to calculate values to be filled
|
36
|
+
#
|
37
|
+
def fill_values_if_needed(values, cell, index, meth)
|
38
|
+
#have all spanned indices been filled with a value?
|
39
|
+
#e.g. values[0], values[1] and values[2] don't return nil given a index of 0 and a colspan of 3
|
40
|
+
number_of_nil_values = 0
|
41
|
+
cell.colspan.times do |i|
|
42
|
+
number_of_nil_values += 1 if values[index+i].nil?
|
43
|
+
end
|
44
|
+
|
45
|
+
#nothing to do? because
|
46
|
+
#a) all values are filled
|
47
|
+
return values if number_of_nil_values == 0
|
48
|
+
#b) no values are filled
|
49
|
+
return values if number_of_nil_values == cell.colspan
|
50
|
+
#c) I am not sure why this line is needed FIXXME
|
51
|
+
#some test cases manage to this line even though there is no dummy cell in the row
|
52
|
+
#I'm not sure if this is a sign for a further underlying bug.
|
53
|
+
return values unless has_a_span_dummy?(cell.row)
|
54
|
+
#fill up the values array
|
55
|
+
|
56
|
+
#calculate the new sum
|
57
|
+
new_sum = cell.send(meth) * cell.colspan
|
58
|
+
#substract any calculated values
|
59
|
+
cell.colspan.times do |i|
|
60
|
+
new_sum -= values[index+i] unless values[index+i].nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
#calculate value for the remaining - not yet filled - cells.
|
64
|
+
new_value = new_sum.to_f / number_of_nil_values
|
65
|
+
#fill the not yet filled cells
|
66
|
+
cell.colspan.times do |i|
|
67
|
+
values[index+i] = new_value if values[index+i].nil?
|
68
|
+
end
|
69
|
+
return values
|
70
|
+
end
|
16
71
|
|
72
|
+
def natural_widths
|
17
73
|
#calculate natural column width for all rows that do not include a span dummy
|
18
74
|
@cells.each do |cell|
|
19
|
-
unless
|
20
|
-
@widths_by_column[cell.column] =
|
75
|
+
unless has_a_span_dummy?(cell.row)
|
76
|
+
@widths_by_column[cell.column] =
|
21
77
|
[@widths_by_column[cell.column], cell.width.to_f].max
|
22
78
|
end
|
23
79
|
end
|
24
80
|
|
25
81
|
#integrate natural column widths for all rows that do include a span dummy
|
26
82
|
@cells.each do |cell|
|
27
|
-
next unless
|
83
|
+
next unless has_a_span_dummy?(cell.row)
|
28
84
|
#the width of a SpanDummy cell will be calculated by the "mother" cell
|
29
85
|
next if cell.is_a?(Cell::SpanDummy)
|
30
86
|
|
31
87
|
if cell.colspan == 1
|
32
|
-
@widths_by_column[cell.column] =
|
88
|
+
@widths_by_column[cell.column] =
|
33
89
|
[@widths_by_column[cell.column], cell.width.to_f].max
|
34
90
|
else
|
35
91
|
#calculate the current with of all cells that will be spanned by the current cell
|
36
|
-
current_width_of_spanned_cells =
|
92
|
+
current_width_of_spanned_cells =
|
37
93
|
@widths_by_column.to_a[cell.column..(cell.column + cell.colspan - 1)]
|
38
94
|
.collect{|key, value| value}.inject(0, :+)
|
39
95
|
|
40
96
|
#update the Hash only if the new with is at least equal to the old one
|
41
97
|
#due to arithmetic errors we need to ignore a small difference in the new and the old sum
|
42
98
|
#the same had to be done in the column_widht_calculator#natural_width
|
43
|
-
update_hash = ((cell.width.to_f - current_width_of_spanned_cells) >
|
99
|
+
update_hash = ((cell.width.to_f - current_width_of_spanned_cells) >
|
44
100
|
Prawn::FLOAT_PRECISION)
|
45
|
-
|
101
|
+
|
46
102
|
if update_hash
|
47
103
|
# Split the width of colspanned cells evenly by columns
|
48
104
|
width_per_column = cell.width.to_f / cell.colspan
|
@@ -56,6 +112,71 @@ module Prawn
|
|
56
112
|
|
57
113
|
@widths_by_column.sort_by { |col, _| col }.map { |_, w| w }
|
58
114
|
end
|
115
|
+
|
116
|
+
# get column widths (either min or max depending on meth)
|
117
|
+
# used in cells.rb
|
118
|
+
#
|
119
|
+
# @param row_or_column - you may call this on either rows or columns
|
120
|
+
# @param meth - min/max
|
121
|
+
# @param aggregate - functions from cell.rb to be used to aggregate e.g. avg_spanned_min_width
|
122
|
+
#
|
123
|
+
def aggregate_cell_values(row_or_column, meth, aggregate)
|
124
|
+
values = {}
|
125
|
+
|
126
|
+
#calculate values for all cells that do not span accross multiple cells
|
127
|
+
#this ensures that we don't have a problem if the first line includes
|
128
|
+
#a cell that spans across multiple cells
|
129
|
+
@cells.each do |cell|
|
130
|
+
#don't take spanned cells
|
131
|
+
if cell.colspan == 1 and cell.class != Prawn::Table::Cell::SpanDummy
|
132
|
+
index = cell.send(row_or_column)
|
133
|
+
values[index] = [values[index], cell.send(meth)].compact.send(aggregate)
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
# if there are only colspanned or rowspanned cells in a table
|
138
|
+
spanned_width_needs_fixing = true
|
139
|
+
|
140
|
+
@cells.each do |cell|
|
141
|
+
index = cell.send(row_or_column)
|
142
|
+
if cell.colspan > 1
|
143
|
+
#special treatment if some but not all spanned indices in the values array have been calculated
|
144
|
+
#only applies to rows
|
145
|
+
values = fill_values_if_needed(values, cell, index, meth) if row_or_column == :column
|
146
|
+
#calculate current (old) return value before we do anything
|
147
|
+
old_sum = 0
|
148
|
+
cell.colspan.times { |i|
|
149
|
+
old_sum += values[index+i] unless values[index+i].nil?
|
150
|
+
}
|
151
|
+
|
152
|
+
#calculate future return value
|
153
|
+
new_sum = cell.send(meth) * cell.colspan
|
154
|
+
|
155
|
+
#due to float rounding errors we need to ignore a small difference in the new
|
156
|
+
#and the old sum the same had to be done in
|
157
|
+
#the column_width_calculator#natural_width
|
158
|
+
spanned_width_needs_fixing = ((new_sum - old_sum) > Prawn::FLOAT_PRECISION)
|
159
|
+
|
160
|
+
if spanned_width_needs_fixing
|
161
|
+
#not entirely sure why we need this line, but with it the tests pass
|
162
|
+
values[index] = [values[index], cell.send(meth)].compact.send(aggregate)
|
163
|
+
#overwrite the old values with the new ones, but only if all entries existed
|
164
|
+
entries_exist = true
|
165
|
+
cell.colspan.times { |i| entries_exist = false if values[index+i].nil? }
|
166
|
+
cell.colspan.times { |i|
|
167
|
+
values[index+i] = cell.send(meth) if entries_exist
|
168
|
+
}
|
169
|
+
end
|
170
|
+
else
|
171
|
+
if spanned_width_needs_fixing && cell.class == Prawn::Table::Cell::SpanDummy
|
172
|
+
values[index] = [values[index], cell.send(meth)].compact.send(aggregate)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
return values.values.inject(0, &:+)
|
178
|
+
end
|
59
179
|
end
|
180
|
+
|
60
181
|
end
|
61
182
|
end
|