prawn 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data.tar.gz.sig +0 -0
  4. data/Rakefile +2 -31
  5. data/lib/prawn.rb +1 -0
  6. data/lib/prawn/document.rb +20 -15
  7. data/lib/prawn/document/bounding_box.rb +10 -2
  8. data/lib/prawn/document/span.rb +2 -1
  9. data/lib/prawn/font.rb +6 -4
  10. data/lib/prawn/font_metric_cache.rb +7 -6
  11. data/lib/prawn/fonts/afm.rb +18 -16
  12. data/lib/prawn/fonts/ttf.rb +55 -29
  13. data/lib/prawn/graphics.rb +11 -11
  14. data/lib/prawn/graphics/color.rb +18 -16
  15. data/lib/prawn/graphics/join_style.rb +1 -1
  16. data/lib/prawn/graphics/patterns.rb +57 -49
  17. data/lib/prawn/graphics/transformation.rb +3 -3
  18. data/lib/prawn/grid.rb +36 -1
  19. data/lib/prawn/images.rb +29 -27
  20. data/lib/prawn/images/jpg.rb +4 -1
  21. data/lib/prawn/images/png.rb +2 -1
  22. data/lib/prawn/outline.rb +6 -5
  23. data/lib/prawn/repeater.rb +1 -1
  24. data/lib/prawn/security.rb +39 -36
  25. data/lib/prawn/text.rb +18 -18
  26. data/lib/prawn/text/box.rb +10 -9
  27. data/lib/prawn/text/formatted/arranger.rb +38 -19
  28. data/lib/prawn/text/formatted/box.rb +20 -15
  29. data/lib/prawn/text/formatted/line_wrap.rb +18 -16
  30. data/lib/prawn/text/formatted/parser.rb +28 -26
  31. data/lib/prawn/text/formatted/wrap.rb +15 -11
  32. data/lib/prawn/version.rb +1 -1
  33. data/lib/prawn/view.rb +2 -2
  34. data/manual/basic_concepts/measurement.rb +1 -1
  35. data/manual/bounding_box/canvas.rb +3 -3
  36. data/manual/bounding_box/nesting.rb +1 -1
  37. data/manual/document_and_page_options/background.rb +6 -2
  38. data/manual/document_and_page_options/document_and_page_options.rb +3 -3
  39. data/manual/document_and_page_options/print_scaling.rb +2 -1
  40. data/manual/graphics/common_lines.rb +1 -1
  41. data/manual/graphics/fill_and_stroke.rb +1 -1
  42. data/manual/graphics/fill_rules.rb +4 -3
  43. data/manual/graphics/helper.rb +11 -4
  44. data/manual/graphics/lines_and_curves.rb +1 -1
  45. data/manual/graphics/stroke_dash.rb +5 -5
  46. data/manual/graphics/translate.rb +2 -1
  47. data/manual/images/horizontal.rb +2 -2
  48. data/manual/images/scale.rb +3 -3
  49. data/manual/images/vertical.rb +6 -3
  50. data/manual/images/width_and_height.rb +3 -3
  51. data/manual/layout/content.rb +2 -2
  52. data/manual/outline/outline.rb +1 -1
  53. data/manual/security/permissions.rb +4 -2
  54. data/manual/security/security.rb +1 -1
  55. data/manual/text/alignment.rb +2 -2
  56. data/manual/text/column_box.rb +2 -2
  57. data/manual/text/font_style.rb +5 -2
  58. data/manual/text/formatted_callbacks.rb +17 -12
  59. data/manual/text/formatted_text.rb +7 -4
  60. data/manual/text/free_flowing_text.rb +3 -3
  61. data/manual/text/kerning_and_character_spacing.rb +4 -4
  62. data/manual/text/paragraph_indentation.rb +4 -5
  63. data/manual/text/rendering_and_color.rb +1 -1
  64. data/manual/text/right_to_left_text.rb +6 -6
  65. data/manual/text/rotation.rb +8 -3
  66. data/manual/text/text_box_extensions.rb +1 -1
  67. data/manual/text/text_box_overflow.rb +11 -9
  68. data/manual/text/win_ansi_charset.rb +9 -9
  69. data/prawn.gemspec +4 -10
  70. data/spec/prawn/document/bounding_box_spec.rb +82 -78
  71. data/spec/prawn/document/security_spec.rb +1 -1
  72. data/spec/prawn/document_span_spec.rb +14 -6
  73. data/spec/prawn/document_spec.rb +29 -26
  74. data/spec/prawn/font_spec.rb +16 -14
  75. data/spec/prawn/graphics_spec.rb +79 -44
  76. data/spec/prawn/images_spec.rb +13 -8
  77. data/spec/prawn/outline_spec.rb +127 -27
  78. data/spec/prawn/repeater_spec.rb +9 -8
  79. data/spec/prawn/soft_mask_spec.rb +1 -1
  80. data/spec/prawn/stamp_spec.rb +3 -2
  81. data/spec/prawn/text/box_spec.rb +57 -59
  82. data/spec/prawn/text/formatted/arranger_spec.rb +10 -10
  83. data/spec/prawn/text/formatted/box_spec.rb +8 -5
  84. data/spec/prawn/text/formatted/line_wrap_spec.rb +2 -1
  85. data/spec/prawn/text_draw_text_spec.rb +9 -8
  86. data/spec/prawn/text_spacing_spec.rb +2 -2
  87. data/spec/prawn/text_spec.rb +9 -9
  88. data/spec/prawn/text_with_inline_formatting_spec.rb +1 -1
  89. data/spec/prawn_manual_spec.rb +4 -4
  90. metadata +14 -98
  91. metadata.gz.sig +0 -0
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1dd091ffaaed7c69fe8a0353317736d1f145e91f3f133a6d04ed0cffd7b5eb37
4
- data.tar.gz: 98d1b0c973c9bf1947681ea971240fe9c351a9bcc1a74c91e7f8f677510eb11c
3
+ metadata.gz: d64c2da1e4be48e40f4fa6fa4de35e04c75debf0119e8c59b3fba9d944c112db
4
+ data.tar.gz: 393bbdd1a5df657d5c6190d4bd10ecd7353522e714b2f60c8d9c5f70e5bc1ce9
5
5
  SHA512:
6
- metadata.gz: 9b75677d2586bf8a812549075cc9532bc02f78dc18b0e0db99711ad1087586f4fef6ae2f244e96a73366172410357d19e9371ac7b7eacf4a3bcbf85292ffb028
7
- data.tar.gz: 138ac861e5016c49836a882c8beda2d2ed250e63959307ffe720624d322fd92b21ca71945e9cf58d0439851f8ebec515d13fb5f1d1660a3c9f4c996c5d04e701
6
+ metadata.gz: c4980639ca24796d577be790ed0f6fa85c985f1a6eb147e4c5db1df261c5d50afe8a466f06b65588b71a897e22e8d2b7b01daceed1714f6164124057154d2d28
7
+ data.tar.gz: e0fd560d4a80f2827736d599266bcb2e2fe19abedcde639520fba8bd19a2f12fe2cf0e8a60a91b87dbac4336d25c680f94b2341e5f9ce3d6d24f2e65f24e24a3
Binary file
data.tar.gz.sig CHANGED
Binary file
data/Rakefile CHANGED
@@ -1,23 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'rake'
4
- require 'rspec/core/rake_task'
5
- require 'yard'
6
- require 'rubygems/package_task'
7
- require 'rubocop/rake_task'
3
+ GEMSPEC = File.expand_path('prawn.gemspec', __dir__)
4
+ require 'prawn/dev/tasks'
8
5
 
9
6
  task default: %i[spec rubocop]
10
7
 
11
- desc 'Run all rspec files'
12
- RSpec::Core::RakeTask.new('spec') do |c|
13
- c.rspec_opts = '-t ~unresolved'
14
- end
15
-
16
- YARD::Rake::YardocTask.new do |t|
17
- t.options = ['--output-dir', 'doc/html']
18
- end
19
- task docs: :yard
20
-
21
8
  desc "Generate the 'Prawn by Example' manual"
22
9
  task :manual do
23
10
  puts 'Building manual...'
@@ -26,12 +13,6 @@ task :manual do
26
13
  puts 'The Prawn manual is available at manual.pdf. Happy Prawning!'
27
14
  end
28
15
 
29
- spec = Gem::Specification.load 'prawn.gemspec'
30
- Gem::PackageTask.new(spec) do |pkg|
31
- pkg.need_zip = true
32
- pkg.need_tar = true
33
- end
34
-
35
16
  desc 'Run a console with Prawn loaded'
36
17
  task :console do
37
18
  require 'irb'
@@ -42,13 +23,3 @@ task :console do
42
23
  ARGV.clear
43
24
  IRB.start
44
25
  end
45
-
46
- RuboCop::RakeTask.new
47
-
48
- task :checksum do
49
- require 'digest/sha2'
50
- built_gem_path = "prawn-#{Prawn::VERSION}.gem"
51
- checksum = Digest::SHA512.new.hexdigest(File.read(built_gem_path))
52
- checksum_path = "checksums/#{built_gem_path}.sha512"
53
- File.write(checksum_path, checksum)
54
- end
@@ -32,6 +32,7 @@ module Prawn
32
32
  #
33
33
  # @private
34
34
  attr_accessor :debug
35
+
35
36
  module_function :debug, :debug=
36
37
 
37
38
  module_function
@@ -98,6 +98,7 @@ module Prawn
98
98
 
99
99
  # @private
100
100
  def self.inherited(base)
101
+ super
101
102
  extensions.each { |e| base.extensions << e }
102
103
  end
103
104
 
@@ -570,11 +571,12 @@ module Prawn
570
571
  opts = options.dup
571
572
  start_count_at = opts.delete(:start_count_at).to_i
572
573
 
573
- page_filter = if opts.key?(:page_filter)
574
- opts.delete(:page_filter)
575
- else
576
- :all
577
- end
574
+ page_filter =
575
+ if opts.key?(:page_filter)
576
+ opts.delete(:page_filter)
577
+ else
578
+ :all
579
+ end
578
580
 
579
581
  total_pages = opts.delete(:total_pages)
580
582
  txtcolor = opts.delete(:color)
@@ -585,12 +587,13 @@ module Prawn
585
587
  pseudopage = 0
586
588
  (1..page_count).each do |p|
587
589
  unless start_count
588
- pseudopage = case start_count_at
589
- when 0
590
- 1
591
- else
592
- start_count_at.to_i
593
- end
590
+ pseudopage =
591
+ case start_count_at
592
+ when 0
593
+ 1
594
+ else
595
+ start_count_at.to_i
596
+ end
594
597
  end
595
598
  if page_match?(page_filter, p)
596
599
  go_to_page(p)
@@ -668,9 +671,9 @@ module Prawn
668
671
  # and then restores the original values after the block has executed.
669
672
  # -- I will remove the nodoc if/when this feature is a little less hacky
670
673
  stored = {}
671
- fields.each { |f| stored[f] = send(f) }
674
+ fields.each { |f| stored[f] = public_send(f) }
672
675
  yield
673
- fields.each { |f| send("#{f}=", stored[f]) }
676
+ fields.each { |f| public_send("#{f}=", stored[f]) }
674
677
  end
675
678
 
676
679
  # @group Extension API
@@ -737,8 +740,10 @@ module Prawn
737
740
 
738
741
  # Treat :margin as CSS shorthand with 1-4 values.
739
742
  positions = {
740
- 4 => [0, 1, 2, 3], 3 => [0, 1, 2, 1],
741
- 2 => [0, 1, 0, 1], 1 => [0, 0, 0, 0],
743
+ 4 => [0, 1, 2, 3],
744
+ 3 => [0, 1, 2, 1],
745
+ 2 => [0, 1, 0, 1],
746
+ 1 => [0, 0, 0, 0],
742
747
  0 => []
743
748
  }[margin.length]
744
749
 
@@ -173,7 +173,9 @@ module Prawn
173
173
  init_bounding_box(block, hold_position: true) do |_|
174
174
  # Canvas bbox acts like margin_box in that its parent bounds are unset.
175
175
  @bounding_box = BoundingBox.new(
176
- self, nil, [0, page.dimensions[3]],
176
+ self,
177
+ nil,
178
+ [0, page.dimensions[3]],
177
179
  width: page.dimensions[2],
178
180
  height: page.dimensions[3]
179
181
  )
@@ -221,6 +223,12 @@ module Prawn
221
223
  # is used for.
222
224
  #
223
225
  class BoundingBox
226
+ class NoReferenceBounds < StandardError
227
+ def initialize(message = "Can't find reference bounds: my parent is unset")
228
+ super
229
+ end
230
+ end
231
+
224
232
  # @private
225
233
  def initialize(document, parent, point, options = {})
226
234
  unless options[:width]
@@ -504,7 +512,7 @@ module Prawn
504
512
  #
505
513
  def reference_bounds
506
514
  if stretchy?
507
- raise "Can't find reference bounds: my parent is unset" unless @parent
515
+ raise NoReferenceBounds unless @parent
508
516
 
509
517
  @parent.reference_bounds
510
518
  else
@@ -51,7 +51,8 @@ module Prawn
51
51
  [
52
52
  left_boundary,
53
53
  margin_box.absolute_top
54
- ], width: width
54
+ ],
55
+ width: width
55
56
  ) do
56
57
  self.y = original_position
57
58
  yield
@@ -318,10 +318,10 @@ module Prawn
318
318
  return options.fetch(:format, 'ttf') if src.respond_to? :read
319
319
 
320
320
  case src.to_s
321
- when /\.ttf$/i then 'ttf'
322
- when /\.otf$/i then 'otf'
321
+ when /\.ttf$/i then 'ttf'
322
+ when /\.otf$/i then 'otf'
323
323
  when /\.dfont$/i then 'dfont'
324
- when /\.ttc$/i then 'ttc'
324
+ when /\.ttc$/i then 'ttc'
325
325
  else 'afm'
326
326
  end
327
327
  end
@@ -420,7 +420,7 @@ module Prawn
420
420
  #
421
421
  def eql?(other) #:nodoc:
422
422
  self.class == other.class && name == other.name &&
423
- family == other.family && size == other.send(:size)
423
+ family == other.family && size == other.size
424
424
  end
425
425
 
426
426
  private
@@ -445,6 +445,8 @@ module Prawn
445
445
  end
446
446
  end
447
447
 
448
+ protected
449
+
448
450
  def size
449
451
  @document.font_size
450
452
  end
@@ -22,12 +22,13 @@ module Prawn
22
22
  end
23
23
 
24
24
  def width_of(string, options)
25
- f = if options[:style]
26
- # override style with :style => :bold
27
- @document.find_font(@document.font.family, style: options[:style])
28
- else
29
- @document.font
30
- end
25
+ f =
26
+ if options[:style]
27
+ # override style with :style => :bold
28
+ @document.find_font(@document.font.family, style: options[:style])
29
+ else
30
+ @document.font
31
+ end
31
32
 
32
33
  encoded_string = f.normalize_encoding(string)
33
34
 
@@ -31,16 +31,17 @@ module Prawn
31
31
  end
32
32
 
33
33
  def self.metrics_path
34
- @metrics_path ||= if ENV['METRICS']
35
- ENV['METRICS'].split(':')
36
- else
37
- [
38
- '.', '/usr/lib/afm',
39
- '/usr/local/lib/afm',
40
- '/usr/openwin/lib/fonts/afm',
41
- Prawn::DATADIR + '/fonts'
42
- ]
43
- end
34
+ @metrics_path ||=
35
+ if ENV['METRICS']
36
+ ENV['METRICS'].split(':')
37
+ else
38
+ [
39
+ '.', '/usr/lib/afm',
40
+ '/usr/local/lib/afm',
41
+ '/usr/openwin/lib/fonts/afm',
42
+ "#{Prawn::DATADIR}/fonts"
43
+ ]
44
+ end
44
45
  end
45
46
 
46
47
  attr_reader :attributes #:nodoc:
@@ -88,7 +89,7 @@ module Prawn
88
89
 
89
90
  if options[:kerning]
90
91
  strings, numbers = kern(string).partition { |e| e.is_a?(String) }
91
- total_kerning_offset = numbers.inject(0.0) { |a, e| a + e }
92
+ total_kerning_offset = numbers.sum
92
93
  (unscaled_width_of(strings.join) - total_kerning_offset) * scale
93
94
  else
94
95
  unscaled_width_of(string) * scale
@@ -176,7 +177,7 @@ module Prawn
176
177
  rescue NoMethodError
177
178
  raise Prawn::Errors::UnknownFont,
178
179
  "Couldn't find the font: #{file} in any of:\n" +
179
- self.class.metrics_path.join("\n")
180
+ self.class.metrics_path.join("\n")
180
181
  end
181
182
 
182
183
  def parse_afm(file_name)
@@ -220,9 +221,10 @@ module Prawn
220
221
 
221
222
  # process data parsed from AFM file to build tables which
222
223
  # will be used when measuring and kerning text
223
- data[:glyph_table] = (0..255).map do |i|
224
- data[:glyph_widths][Encoding::WinAnsi::CHARACTERS[i]].to_i
225
- end
224
+ data[:glyph_table] =
225
+ (0..255).map do |i|
226
+ data[:glyph_widths][Encoding::WinAnsi::CHARACTERS[i]].to_i
227
+ end
226
228
 
227
229
  character_hash = Hash[
228
230
  Encoding::WinAnsi::CHARACTERS.zip(
@@ -281,7 +283,7 @@ module Prawn
281
283
  end
282
284
 
283
285
  def unscaled_width_of(string)
284
- string.bytes.inject(0) do |s, r|
286
+ string.bytes.reduce(0) do |s, r|
285
287
  s + @glyph_table[r]
286
288
  end
287
289
  end
@@ -14,6 +14,29 @@ module Prawn
14
14
  module Fonts
15
15
  # @private
16
16
  class TTF < Font
17
+ class Error < StandardError
18
+ DEFAULT_MESSAGE = 'TTF font error'
19
+ MESSAGE_WITH_FONT = 'TTF font error in font %<font>s'
20
+
21
+ def initialize(message = DEFAULT_MESSAGE, font: nil)
22
+ if font && message == DEFAULT_MESSAGE
23
+ super format(MESSAGE_WITH_FONT, font: font)
24
+ else
25
+ super message
26
+ end
27
+ end
28
+ end
29
+
30
+ class NoUnicodeCMap < Error
31
+ DEFAULT_MESSAGE = 'No unicode cmap found in font'
32
+ MESSAGE_WITH_FONT = 'No unicode cmap found in font %<font>s'
33
+ end
34
+
35
+ class NoPostscriptName < Error
36
+ DEFAULT_MESSAGE = 'Can not detect a postscript name'
37
+ MESSAGE_WITH_FONT = 'Can not detect a postscript name in font %<font>s'
38
+ end
39
+
17
40
  attr_reader :ttf, :subsets
18
41
 
19
42
  def unicode?
@@ -41,15 +64,15 @@ module Prawn
41
64
  def compute_width_of(string, options = {}) #:nodoc:
42
65
  scale = (options[:size] || size) / 1000.0
43
66
  if options[:kerning]
44
- kern(string).inject(0) do |s, r|
67
+ kern(string).reduce(0) do |s, r|
45
68
  if r.is_a?(Numeric)
46
69
  s - r
47
70
  else
48
- r.inject(s) { |a, e| a + character_width_by_code(e) }
71
+ r.reduce(s) { |a, e| a + character_width_by_code(e) }
49
72
  end
50
73
  end * scale
51
74
  else
52
- string.codepoints.inject(0) do |s, r|
75
+ string.codepoints.reduce(0) do |s, r|
53
76
  s + character_width_by_code(r)
54
77
  end * scale
55
78
  end
@@ -82,7 +105,7 @@ module Prawn
82
105
 
83
106
  if options[:kerning]
84
107
  last_subset = nil
85
- kern(text).inject([]) do |result, element|
108
+ kern(text).reduce([]) do |result, element|
86
109
  if element.is_a?(Numeric)
87
110
  unless result.last[1].is_a?(Array)
88
111
  result.last[1] = [result.last[1]]
@@ -136,10 +159,11 @@ module Prawn
136
159
  end
137
160
 
138
161
  def cap_height
139
- @cap_height ||= begin
140
- height = @ttf.os2.exists? && @ttf.os2.cap_height || 0
141
- height.zero? ? @ascender : height
142
- end
162
+ @cap_height ||=
163
+ begin
164
+ height = @ttf.os2.exists? && @ttf.os2.cap_height || 0
165
+ height.zero? ? @ascender : height
166
+ end
143
167
  end
144
168
 
145
169
  def x_height
@@ -161,23 +185,24 @@ module Prawn
161
185
  end
162
186
 
163
187
  def pdf_flags
164
- @pdf_flags ||= begin
165
- flags = 0
166
- flags |= 0x0001 if @ttf.postscript.fixed_pitch?
167
- flags |= 0x0002 if serif?
168
- flags |= 0x0008 if script?
169
- flags |= 0x0040 if italic_angle != 0
170
- # Assume the font contains at least some non-latin characters
171
- flags | 0x0004
172
- end
188
+ @pdf_flags ||=
189
+ begin
190
+ flags = 0
191
+ flags |= 0x0001 if @ttf.postscript.fixed_pitch?
192
+ flags |= 0x0002 if serif?
193
+ flags |= 0x0008 if script?
194
+ flags |= 0x0040 if italic_angle != 0
195
+ # Assume the font contains at least some non-latin characters
196
+ flags | 0x0004
197
+ end
173
198
  end
174
199
 
175
200
  def normalize_encoding(text)
176
201
  text.encode(::Encoding::UTF_8)
177
202
  rescue StandardError => e
178
203
  puts e
179
- raise Prawn::Errors::IncompatibleStringEncoding, 'Encoding ' \
180
- "#{text.encoding} can not be transparently converted to UTF-8. " \
204
+ raise Prawn::Errors::IncompatibleStringEncoding,
205
+ "Encoding #{text.encoding} can not be transparently converted to UTF-8. " \
181
206
  'Please ensure the encoding of the string you are attempting ' \
182
207
  'to use is set correctly'
183
208
  end
@@ -200,7 +225,7 @@ module Prawn
200
225
  private
201
226
 
202
227
  def cmap
203
- (@cmap ||= @ttf.cmap.unicode.first) || raise('no unicode cmap for font')
228
+ (@cmap ||= @ttf.cmap.unicode.first) || raise(NoUnicodeCMap.new(font: name))
204
229
  end
205
230
 
206
231
  # +string+ must be UTF8-encoded.
@@ -275,7 +300,7 @@ module Prawn
275
300
  # if their font name is more than 33 bytes long. Strange. But true.
276
301
  basename = font.name.postscript_name[0, 33].delete("\0")
277
302
 
278
- raise "Can't detect a postscript name for #{file}" if basename.nil?
303
+ raise NoPostscriptName.new(font: font) if basename.nil?
279
304
 
280
305
  fontfile = @document.ref!(Length1: font_content.size)
281
306
  fontfile.stream << font_content
@@ -313,7 +338,7 @@ module Prawn
313
338
  map = @subsets[subset].to_unicode_map
314
339
 
315
340
  ranges = [[]]
316
- map.keys.sort.inject('') do |_s, code|
341
+ map.keys.sort.reduce('') do |_s, code|
317
342
  ranges << [] if ranges.last.length >= 100
318
343
  unicode = map[code]
319
344
  ranges.last << format(
@@ -323,13 +348,14 @@ module Prawn
323
348
  )
324
349
  end
325
350
 
326
- range_blocks = ranges.inject(+'') do |s, list|
327
- s << format(
328
- "%<lenght>d beginbfchar\n%<list>s\nendbfchar\n",
329
- lenght: list.length,
330
- list: list.join("\n")
331
- )
332
- end
351
+ range_blocks =
352
+ ranges.reduce(+'') do |s, list|
353
+ s << format(
354
+ "%<lenght>d beginbfchar\n%<list>s\nendbfchar\n",
355
+ lenght: list.length,
356
+ list: list.join("\n")
357
+ )
358
+ end
333
359
 
334
360
  to_unicode_cmap = UNICODE_CMAP_TEMPLATE % range_blocks.strip
335
361