prawn 2.3.0 → 2.4.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.
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
@@ -264,11 +264,12 @@ module Prawn
264
264
  counting_parent = parent
265
265
  while counting_parent
266
266
  counting_parent.data.count += 1
267
- counting_parent = if counting_parent == root
268
- nil
269
- else
270
- counting_parent.data.parent
271
- end
267
+ counting_parent =
268
+ if counting_parent == root
269
+ nil
270
+ else
271
+ counting_parent.data.parent
272
+ end
272
273
  end
273
274
  end
274
275
 
@@ -115,7 +115,7 @@ module Prawn
115
115
  @document.stamp(@stamp_name) if match?(page_number)
116
116
  elsif @block && match?(page_number)
117
117
  @document.save_graphics_state(@graphic_state) do
118
- @document.send(:freeze_stamp_graphics)
118
+ @document.__send__(:freeze_stamp_graphics)
119
119
  @block.call
120
120
  end
121
121
  end
@@ -124,8 +124,8 @@ module Prawn
124
124
  def encryption_dictionary
125
125
  {
126
126
  Filter: :Standard, # default PDF security handler
127
- V: 1, # "Algorithm 3.1", PDF reference 1.3
128
- R: 2, # Revision 2 of the algorithm
127
+ V: 1, # "Algorithm 3.1", PDF reference 1.3
128
+ R: 2, # Revision 2 of the algorithm
129
129
  O: PDF::Core::ByteString.new(owner_password_hash),
130
130
  U: PDF::Core::ByteString.new(user_password_hash),
131
131
  P: permissions_value
@@ -181,21 +181,23 @@ module Prawn
181
181
  end
182
182
 
183
183
  def user_encryption_key
184
- @user_encryption_key ||= begin
185
- md5 = Digest::MD5.new
186
- md5 << pad_password(@user_password)
187
- md5 << owner_password_hash
188
- md5 << [permissions_value].pack('V')
189
- md5.digest[0, 5]
190
- end
184
+ @user_encryption_key ||=
185
+ begin
186
+ md5 = Digest::MD5.new
187
+ md5 << pad_password(@user_password)
188
+ md5 << owner_password_hash
189
+ md5 << [permissions_value].pack('V')
190
+ md5.digest[0, 5]
191
+ end
191
192
  end
192
193
 
193
194
  # The O (owner) value in the encryption dictionary. Algorithm 3.3.
194
195
  def owner_password_hash
195
- @owner_password_hash ||= begin
196
- key = Digest::MD5.digest(pad_password(@owner_password))[0, 5]
197
- Arcfour.new(key).encrypt(pad_password(@user_password))
198
- end
196
+ @owner_password_hash ||=
197
+ begin
198
+ key = Digest::MD5.digest(pad_password(@owner_password))[0, 5]
199
+ Arcfour.new(key).encrypt(pad_password(@user_password))
200
+ end
199
201
  end
200
202
 
201
203
  # The U (user) value in the encryption dictionary. Algorithm 3.4.
@@ -219,19 +221,22 @@ module PDF
219
221
  def encrypted_pdf_object(obj, key, id, gen, in_content_stream = false)
220
222
  case obj
221
223
  when Array
222
- '[' + obj.map do |e|
224
+ array_content = obj.map do |e|
223
225
  encrypted_pdf_object(e, key, id, gen, in_content_stream)
224
- end.join(' ') + ']'
226
+ end.join(' ')
227
+ "[#{array_content}]"
225
228
  when LiteralString
226
- obj = ByteString.new(
227
- Prawn::Document::Security.encrypt_string(obj, key, id, gen)
228
- ).gsub(/[\\\n\(\)]/) { |m| "\\#{m}" }
229
+ obj =
230
+ ByteString.new(
231
+ Prawn::Document::Security.encrypt_string(obj, key, id, gen)
232
+ ).gsub(/[\\\n()]/) { |m| "\\#{m}" }
229
233
  "(#{obj})"
230
234
  when Time
231
- obj = obj.strftime('D:%Y%m%d%H%M%S%z').chop.chop + "'00'"
232
- obj = ByteString.new(
233
- Prawn::Document::Security.encrypt_string(obj, key, id, gen)
234
- ).gsub(/[\\\n\(\)]/) { |m| "\\#{m}" }
235
+ obj = "#{obj.strftime('D:%Y%m%d%H%M%S%z').chop.chop}'00'"
236
+ obj =
237
+ ByteString.new(
238
+ Prawn::Document::Security.encrypt_string(obj, key, id, gen)
239
+ ).gsub(/[\\\n()]/) { |m| "\\#{m}" }
235
240
  "(#{obj})"
236
241
  when String
237
242
  pdf_object(
@@ -241,19 +246,16 @@ module PDF
241
246
  in_content_stream
242
247
  )
243
248
  when ::Hash
244
- '<< ' +
245
- obj.map do |k, v|
246
- unless k.is_a?(String) || k.is_a?(Symbol)
247
- raise PDF::Core::Errors::FailedObjectConversion,
248
- 'A PDF Dictionary must be keyed by names'
249
- end
250
- pdf_object(k.to_sym, in_content_stream) + ' ' +
251
- encrypted_pdf_object(v, key, id, gen, in_content_stream) + "\n"
252
- end.join('') +
253
- '>>'
249
+ hash_content = obj.map do |k, v|
250
+ unless k.is_a?(String) || k.is_a?(Symbol)
251
+ raise PDF::Core::Errors::FailedObjectConversion,
252
+ 'A PDF Dictionary must be keyed by names'
253
+ end
254
+ "#{pdf_object(k.to_sym, in_content_stream)} #{encrypted_pdf_object(v, key, id, gen, in_content_stream)}\n"
255
+ end.join('')
256
+ "<< #{hash_content}>>"
254
257
  when NameTree::Value
255
- pdf_object(obj.name) + ' ' +
256
- encrypted_pdf_object(obj.value, key, id, gen, in_content_stream)
258
+ "#{pdf_object(obj.name)} #{encrypted_pdf_object(obj.value, key, id, gen, in_content_stream)}"
257
259
  when PDF::Core::OutlineRoot, PDF::Core::OutlineItem
258
260
  encrypted_pdf_object(obj.to_hash, key, id, gen, in_content_stream)
259
261
  else # delegate back to pdf_object
@@ -265,10 +267,11 @@ module PDF
265
267
  class Stream
266
268
  def encrypted_object(key, id, gen)
267
269
  if filtered_stream
268
- "stream\n" +
270
+ "stream\n#{
269
271
  Prawn::Document::Security.encrypt_string(
270
272
  filtered_stream, key, id, gen
271
- ) + "\nendstream\n"
273
+ )
274
+ }\nendstream\n"
272
275
  else
273
276
  ''
274
277
  end
@@ -192,21 +192,19 @@ module Prawn
192
192
 
193
193
  color = options.delete(:color)
194
194
  if color
195
- array = array.map do |fragment|
196
- fragment[:color] ? fragment : fragment.merge(color: color)
197
- end
195
+ array =
196
+ array.map do |fragment|
197
+ fragment[:color] ? fragment : fragment.merge(color: color)
198
+ end
198
199
  end
199
200
 
200
201
  if @indent_paragraphs
201
202
  text_formatter.array_paragraphs(array).each do |paragraph|
202
203
  remaining_text = draw_indented_formatted_line(paragraph, options)
203
204
 
204
- if @no_text_printed
205
- # unless this paragraph was an empty line
206
- unless @all_text_printed
207
- @bounding_box.move_past_bottom
208
- remaining_text = draw_indented_formatted_line(paragraph, options)
209
- end
205
+ if @no_text_printed && !@all_text_printed
206
+ @bounding_box.move_past_bottom
207
+ remaining_text = draw_indented_formatted_line(paragraph, options)
210
208
  end
211
209
 
212
210
  unless @all_text_printed
@@ -337,8 +335,8 @@ module Prawn
337
335
  #
338
336
  def height_of_formatted(array, options = {})
339
337
  if options[:indent_paragraphs]
340
- raise NotImplementedError, ':indent_paragraphs option not available' \
341
- 'with height_of'
338
+ raise NotImplementedError,
339
+ ':indent_paragraphs option not available with height_of'
342
340
  end
343
341
  process_final_gap_option(options)
344
342
  box = Text::Formatted::Box.new(
@@ -364,11 +362,12 @@ module Prawn
364
362
  end
365
363
 
366
364
  def draw_indented_formatted_line(string, options)
367
- gap = if options.fetch(:direction, text_direction) == :ltr
368
- [@indent_paragraphs, 0]
369
- else
370
- [0, @indent_paragraphs]
371
- end
365
+ gap =
366
+ if options.fetch(:direction, text_direction) == :ltr
367
+ [@indent_paragraphs, 0]
368
+ else
369
+ [0, @indent_paragraphs]
370
+ end
372
371
 
373
372
  indent(*gap) do
374
373
  fill_formatted_text_box(string, options.dup.merge(single_line: true))
@@ -421,8 +420,9 @@ module Prawn
421
420
 
422
421
  def inspect_options_for_text(options)
423
422
  if options[:at]
424
- raise ArgumentError, ':at is no longer a valid option with text.' \
425
- 'use draw_text or text_box instead'
423
+ raise ArgumentError,
424
+ ':at is no longer a valid option with text.' \
425
+ 'use draw_text or text_box instead'
426
426
  end
427
427
  process_final_gap_option(options)
428
428
  process_indent_paragraphs_option(options)
@@ -107,14 +107,15 @@ module Prawn
107
107
  options = options.dup
108
108
  options[:document] = self
109
109
 
110
- box = if options[:inline_format]
111
- p = options.delete(:inline_format)
112
- p = [] unless p.is_a?(Array)
113
- array = text_formatter.format(string, *p)
114
- Text::Formatted::Box.new(array, options)
115
- else
116
- Text::Box.new(string, options)
117
- end
110
+ box =
111
+ if options[:inline_format]
112
+ p = options.delete(:inline_format)
113
+ p = [] unless p.is_a?(Array)
114
+ array = text_formatter.format(string, *p)
115
+ Text::Formatted::Box.new(array, options)
116
+ else
117
+ Text::Box.new(string, options)
118
+ end
118
119
 
119
120
  box.render
120
121
  end
@@ -134,7 +135,7 @@ module Prawn
134
135
 
135
136
  def render(flags = {})
136
137
  leftover = super(flags)
137
- leftover.collect { |hash| hash[:text] }.join
138
+ leftover.map { |hash| hash[:text] }.join
138
139
  end
139
140
  end
140
141
  end
@@ -13,6 +13,25 @@ module Prawn
13
13
  # @private
14
14
 
15
15
  class Arranger #:nodoc:
16
+ class NotFinalized < StandardError
17
+ DEFAULT_MESSAGE = 'Lines must be finalized'
18
+ MESSAGE_WITH_METHOD = 'Lines must be finalized before calling #%<method>s'
19
+
20
+ def initialize(message = DEFAULT_MESSAGE, method: nil)
21
+ if method && message == DEFAULT_MESSAGE
22
+ super format(MESSAGE_WITH_METHOD, method: method)
23
+ else
24
+ super message
25
+ end
26
+ end
27
+ end
28
+
29
+ class BadFontFamily < StandardError
30
+ def initialize(message = 'Bad font family')
31
+ super
32
+ end
33
+ end
34
+
16
35
  attr_reader :max_line_height
17
36
  attr_reader :max_descender
18
37
  attr_reader :max_ascender
@@ -33,30 +52,30 @@ module Prawn
33
52
 
34
53
  def space_count
35
54
  unless finalized
36
- raise 'Lines must be finalized before calling #space_count'
55
+ raise NotFinalized.new(method: 'space_count')
37
56
  end
38
57
 
39
- @fragments.inject(0) do |sum, fragment|
58
+ @fragments.reduce(0) do |sum, fragment|
40
59
  sum + fragment.space_count
41
60
  end
42
61
  end
43
62
 
44
63
  def line_width
45
64
  unless finalized
46
- raise 'Lines must be finalized before calling #line_width'
65
+ raise raise NotFinalized.new(method: 'line_width')
47
66
  end
48
67
 
49
- @fragments.inject(0) do |sum, fragment|
68
+ @fragments.reduce(0) do |sum, fragment|
50
69
  sum + fragment.width
51
70
  end
52
71
  end
53
72
 
54
73
  def line
55
74
  unless finalized
56
- raise 'Lines must be finalized before calling #line'
75
+ raise NotFinalized.new(method: 'line')
57
76
  end
58
77
 
59
- @fragments.collect do |fragment|
78
+ @fragments.map do |fragment|
60
79
  fragment.text.dup.encode(::Encoding::UTF_8)
61
80
  rescue ::Encoding::InvalidByteSequenceError,
62
81
  ::Encoding::UndefinedConversionError
@@ -110,7 +129,7 @@ module Prawn
110
129
 
111
130
  def next_string
112
131
  if finalized
113
- raise 'Lines must not be finalized when calling #next_string'
132
+ raise NotFinalized.new(method: 'next_string')
114
133
  end
115
134
 
116
135
  next_unconsumed_hash = @unconsumed.shift
@@ -163,7 +182,7 @@ module Prawn
163
182
 
164
183
  @document.character_spacing(character_spacing) do
165
184
  if font || font_style != :normal
166
- raise 'Bad font family' unless @document.font.family
185
+ raise BadFontFamily unless @document.font.family
167
186
 
168
187
  @document.font(
169
188
  font || @document.font.family, style: font_style
@@ -197,7 +216,7 @@ module Prawn
197
216
 
198
217
  def retrieve_fragment
199
218
  unless finalized
200
- raise 'Lines must be finalized before fragments can be retrieved'
219
+ raise NotFinalized, 'Lines must be finalized before fragments can be retrieved'
201
220
  end
202
221
 
203
222
  @fragments.shift
@@ -215,9 +234,8 @@ module Prawn
215
234
  end
216
235
 
217
236
  def font_style(styles)
218
- if styles.nil?
219
- :normal
220
- elsif styles.include?(:bold) && styles.include?(:italic)
237
+ styles = Array(styles)
238
+ if styles.include?(:bold) && styles.include?(:italic)
221
239
  :bold_italic
222
240
  elsif styles.include?(:bold)
223
241
  :bold
@@ -240,19 +258,20 @@ module Prawn
240
258
  end
241
259
  end
242
260
 
243
- def apply_font_size(size, styles)
261
+ def apply_font_size(size, styles, &block)
244
262
  if subscript?(styles) || superscript?(styles)
245
263
  relative_size = 0.583
246
- size = if size.nil?
247
- @document.font_size * relative_size
248
- else
249
- size * relative_size
250
- end
264
+ size =
265
+ if size.nil?
266
+ @document.font_size * relative_size
267
+ else
268
+ size * relative_size
269
+ end
251
270
  end
252
271
  if size.nil?
253
272
  yield
254
273
  else
255
- @document.font_size(size) { yield }
274
+ @document.font_size(size, &block)
256
275
  end
257
276
  end
258
277
 
@@ -222,11 +222,12 @@ module Prawn
222
222
  shrink_to_fit(text) if @overflow == :shrink_to_fit
223
223
  process_vertical_alignment(text)
224
224
  @inked = true unless flags[:dry_run]
225
- unprinted_text = if @rotate != 0 && @inked
226
- render_rotated(text)
227
- else
228
- wrap(text)
229
- end
225
+ unprinted_text =
226
+ if @rotate != 0 && @inked
227
+ render_rotated(text)
228
+ else
229
+ wrap(text)
230
+ end
230
231
  @inked = false
231
232
  end
232
233
  end
@@ -265,11 +266,12 @@ module Prawn
265
266
  when :right
266
267
  x = @at[0] + @width - line_width
267
268
  when :justify
268
- x = if @direction == :ltr
269
- @at[0]
270
- else
271
- @at[0] + @width - line_width
272
- end
269
+ x =
270
+ if @direction == :ltr
271
+ @at[0]
272
+ else
273
+ @at[0] + @width - line_width
274
+ end
273
275
  else
274
276
  raise ArgumentError,
275
277
  'align must be one of :left, :right, :center or :justify symbols'
@@ -290,13 +292,15 @@ module Prawn
290
292
  @document.word_spacing(word_spacing) do
291
293
  if @draw_text_callback
292
294
  @draw_text_callback.call(
293
- fragment.text, at: [x, y],
294
- kerning: @kerning
295
+ fragment.text,
296
+ at: [x, y],
297
+ kerning: @kerning
295
298
  )
296
299
  else
297
300
  @document.draw_text!(
298
- fragment.text, at: [x, y],
299
- kerning: @kerning
301
+ fragment.text,
302
+ at: [x, y],
303
+ kerning: @kerning
300
304
  )
301
305
  end
302
306
  end
@@ -340,6 +344,7 @@ module Prawn
340
344
 
341
345
  # @private
342
346
  def self.inherited(base)
347
+ super
343
348
  extensions.each { |e| base.extensions << e }
344
349
  end
345
350
 
@@ -371,7 +376,7 @@ module Prawn
371
376
  end
372
377
 
373
378
  def original_text
374
- @original_array.collect(&:dup)
379
+ @original_array.map(&:dup)
375
380
  end
376
381
 
377
382
  def original_text=(formatted_text)
@@ -86,18 +86,20 @@ module Prawn
86
86
  # the line
87
87
  #
88
88
  def add_fragment_to_line(fragment)
89
- if fragment == ''
89
+ case fragment
90
+ when ''
90
91
  true
91
- elsif fragment == "\n"
92
+ when "\n"
92
93
  @newline_encountered = true
93
94
  false
94
95
  else
95
96
  tokenize(fragment).each do |segment|
96
- segment_width = if segment == zero_width_space(segment.encoding)
97
- 0
98
- else
99
- @document.width_of(segment, kerning: @kerning)
100
- end
97
+ segment_width =
98
+ if segment == zero_width_space(segment.encoding)
99
+ 0
100
+ else
101
+ @document.width_of(segment, kerning: @kerning)
102
+ end
101
103
 
102
104
  if @accumulated_width + segment_width <= @width
103
105
  @accumulated_width += segment_width
@@ -151,9 +153,10 @@ module Prawn
151
153
  # word breaking is needed
152
154
  #
153
155
  def word_division_scan_pattern(encoding = ::Encoding::UTF_8)
154
- common_whitespaces = ["\t", "\n", "\v", "\r", ' '].map do |c|
155
- c.encode(encoding)
156
- end
156
+ common_whitespaces =
157
+ ["\t", "\n", "\v", "\r", ' '].map do |c|
158
+ c.encode(encoding)
159
+ end
157
160
 
158
161
  Regexp.union(
159
162
  common_whitespaces +
@@ -254,12 +257,11 @@ module Prawn
254
257
 
255
258
  def pull_preceding_fragment_to_join_this_one?(current_fragment)
256
259
  if @fragment_output.empty? && !current_fragment.empty? &&
257
- @line_contains_more_than_one_word
258
- unless previous_fragment_ended_with_breakable? ||
259
- fragment_begins_with_breakable?(current_fragment)
260
- @fragment_output = @previous_fragment_output_without_last_word
261
- update_output_based_on_last_fragment(@previous_fragment)
262
- end
260
+ @line_contains_more_than_one_word &&
261
+ !(previous_fragment_ended_with_breakable? ||
262
+ fragment_begins_with_breakable?(current_fragment))
263
+ @fragment_output = @previous_fragment_output_without_last_word
264
+ update_output_based_on_last_fragment(@previous_fragment)
263
265
  end
264
266
  end
265
267