prawn 1.0.0 → 1.1.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.
- 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
|