prawn 0.14.0 → 0.15.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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +2 -1
  3. data/Rakefile +12 -0
  4. data/lib/prawn.rb +9 -21
  5. data/lib/prawn/document.rb +95 -68
  6. data/lib/prawn/document/bounding_box.rb +22 -4
  7. data/lib/prawn/document/column_box.rb +2 -0
  8. data/lib/prawn/document/graphics_state.rb +1 -1
  9. data/lib/prawn/document/internals.rb +2 -2
  10. data/lib/prawn/document/snapshot.rb +2 -1
  11. data/lib/prawn/document/span.rb +2 -0
  12. data/lib/prawn/encoding.rb +1 -1
  13. data/lib/prawn/font.rb +89 -75
  14. data/lib/prawn/font/afm.rb +3 -0
  15. data/lib/prawn/font/dfont.rb +1 -0
  16. data/lib/prawn/font/ttf.rb +2 -0
  17. data/lib/prawn/font_metric_cache.rb +3 -1
  18. data/lib/prawn/graphics.rb +2 -14
  19. data/lib/prawn/graphics/cap_style.rb +1 -0
  20. data/lib/prawn/graphics/color.rb +1 -0
  21. data/lib/prawn/graphics/dash.rb +3 -2
  22. data/lib/prawn/graphics/join_style.rb +2 -0
  23. data/lib/prawn/graphics/patterns.rb +1 -0
  24. data/lib/prawn/graphics/transformation.rb +1 -0
  25. data/lib/prawn/graphics/transparency.rb +2 -0
  26. data/lib/prawn/image_handler.rb +2 -0
  27. data/lib/prawn/images.rb +5 -0
  28. data/lib/prawn/images/image.rb +1 -0
  29. data/lib/prawn/images/jpg.rb +3 -0
  30. data/lib/prawn/images/png.rb +2 -0
  31. data/lib/prawn/layout.rb +8 -13
  32. data/lib/prawn/layout/grid.rb +15 -3
  33. data/lib/prawn/measurement_extensions.rb +4 -0
  34. data/lib/prawn/measurements.rb +2 -0
  35. data/lib/prawn/outline.rb +3 -1
  36. data/lib/prawn/repeater.rb +3 -1
  37. data/lib/prawn/security.rb +15 -7
  38. data/lib/prawn/security/arcfour.rb +52 -0
  39. data/lib/prawn/soft_mask.rb +3 -1
  40. data/lib/prawn/stamp.rb +2 -0
  41. data/lib/prawn/table.rb +2 -0
  42. data/lib/prawn/table/cell.rb +4 -1
  43. data/lib/prawn/table/cell/image.rb +1 -2
  44. data/lib/prawn/table/cell/in_table.rb +2 -0
  45. data/lib/prawn/table/cell/span_dummy.rb +1 -0
  46. data/lib/prawn/table/cells.rb +7 -2
  47. data/lib/prawn/table/column_width_calculator.rb +8 -2
  48. data/lib/prawn/text.rb +4 -2
  49. data/lib/prawn/text/box.rb +3 -0
  50. data/lib/prawn/text/formatted/arranger.rb +2 -0
  51. data/lib/prawn/text/formatted/box.rb +55 -50
  52. data/lib/prawn/text/formatted/fragment.rb +2 -0
  53. data/lib/prawn/text/formatted/line_wrap.rb +1 -0
  54. data/lib/prawn/text/formatted/parser.rb +2 -0
  55. data/lib/prawn/text/formatted/wrap.rb +2 -0
  56. data/lib/prawn/utilities.rb +5 -3
  57. data/manual/graphics/common_lines.rb +2 -0
  58. data/manual/text/group.rb +2 -0
  59. data/manual/text/text.rb +1 -1
  60. data/prawn.gemspec +4 -3
  61. data/spec/grid_spec.rb +11 -0
  62. data/spec/object_store_spec.rb +1 -96
  63. data/spec/reference_spec.rb +0 -57
  64. data/spec/spec_helper.rb +7 -0
  65. data/spec/table_spec.rb +26 -0
  66. metadata +172 -185
  67. data/lib/pdf/core.rb +0 -35
  68. data/lib/pdf/core/annotations.rb +0 -60
  69. data/lib/pdf/core/byte_string.rb +0 -9
  70. data/lib/pdf/core/destinations.rb +0 -90
  71. data/lib/pdf/core/document_state.rb +0 -79
  72. data/lib/pdf/core/filter_list.rb +0 -51
  73. data/lib/pdf/core/filters.rb +0 -36
  74. data/lib/pdf/core/graphics_state.rb +0 -89
  75. data/lib/pdf/core/literal_string.rb +0 -16
  76. data/lib/pdf/core/name_tree.rb +0 -177
  77. data/lib/pdf/core/object_store.rb +0 -311
  78. data/lib/pdf/core/outline.rb +0 -315
  79. data/lib/pdf/core/page.rb +0 -212
  80. data/lib/pdf/core/page_geometry.rb +0 -126
  81. data/lib/pdf/core/pdf_object.rb +0 -99
  82. data/lib/pdf/core/reference.rb +0 -103
  83. data/lib/pdf/core/stream.rb +0 -98
  84. data/lib/pdf/core/text.rb +0 -275
  85. data/lib/prawn/templates.rb +0 -75
  86. data/spec/filters_spec.rb +0 -34
  87. data/spec/name_tree_spec.rb +0 -112
  88. data/spec/pdf_object_spec.rb +0 -172
  89. data/spec/stream_spec.rb +0 -58
  90. data/spec/template_spec_obsolete.rb +0 -352
@@ -8,7 +8,8 @@
8
8
 
9
9
  require "zlib"
10
10
 
11
- require_relative "../pdf/core/text"
11
+ require "pdf/core/text"
12
+
12
13
  require_relative "text/formatted"
13
14
  require_relative "text/box"
14
15
 
@@ -25,6 +26,8 @@ module Prawn
25
26
  # Soft Hyphen (invisible, except when causing a line break)
26
27
  Prawn::Text::SHY = "­"
27
28
 
29
+ # @group Stable API
30
+
28
31
  # If you want text to flow onto a new page or between columns, this is the
29
32
  # method to use. If, instead, if you want to place bounded text outside of
30
33
  # the flow of a document (for captions, labels, charts, etc.), use Text::Box
@@ -170,7 +173,6 @@ module Prawn
170
173
  formatted_text(array, options)
171
174
  end
172
175
 
173
-
174
176
  # Draws formatted text to the page.
175
177
  # Formatted text is comprised of an array of hashes, where each hash defines
176
178
  # text and format information. See Text::Formatted#formatted_text_box for
@@ -11,6 +11,7 @@ require_relative "formatted/box"
11
11
 
12
12
  module Prawn
13
13
  module Text
14
+ # @group Stable API
14
15
 
15
16
  # Draws the requested text into a box. When the text overflows
16
17
  # the rectangle, you shrink to fit, or truncate the text. Text
@@ -121,6 +122,8 @@ module Prawn
121
122
  box.render
122
123
  end
123
124
 
125
+ # @group Experimental API
126
+
124
127
  # Generally, one would use the Prawn::Text#text_box convenience
125
128
  # method. However, using Text::Box.new in conjunction with
126
129
  # #render(:dry_run=> true) enables one to do look-ahead calculations prior
@@ -11,6 +11,8 @@ module Prawn
11
11
  module Text
12
12
  module Formatted #:nodoc:
13
13
 
14
+ # @private
15
+
14
16
  class Arranger #:nodoc:
15
17
  attr_reader :max_line_height
16
18
  attr_reader :max_descender
@@ -10,7 +10,8 @@
10
10
  module Prawn
11
11
  module Text
12
12
  module Formatted
13
-
13
+ # @group Stable API
14
+
14
15
  # Draws the requested formatted text into a box. When the text overflows
15
16
  # the rectangle shrink to fit or truncate the text. Text boxes are
16
17
  # independent of the document y position.
@@ -100,19 +101,7 @@ module Prawn
100
101
  class Box
101
102
  include Prawn::Text::Formatted::Wrap
102
103
 
103
- def valid_options
104
- PDF::Core::Text::VALID_OPTIONS + [:at, :height, :width,
105
- :align, :valign,
106
- :rotate, :rotate_around,
107
- :overflow, :min_font_size,
108
- :leading, :character_spacing,
109
- :mode, :single_line,
110
- :skip_encoding,
111
- :document,
112
- :direction,
113
- :fallback_fonts,
114
- :draw_text_callback]
115
- end
104
+ # @group Experimental API
116
105
 
117
106
  # The text that was successfully printed (or, if <tt>dry_run</tt> was
118
107
  # used, the text that would have been successfully printed)
@@ -145,42 +134,6 @@ module Prawn
145
134
  line_height - (ascender + descender)
146
135
  end
147
136
 
148
- #
149
- # Example (see Prawn::Text::Core::Formatted::Wrap for what is required
150
- # of the wrap method if you want to override the default wrapping
151
- # algorithm):
152
- #
153
- #
154
- # module MyWrap
155
- #
156
- # def wrap(array)
157
- # initialize_wrap([{ :text => 'all your base are belong to us' }])
158
- # @line_wrap.wrap_line(:document => @document,
159
- # :kerning => @kerning,
160
- # :width => 10000,
161
- # :arranger => @arranger)
162
- # fragment = @arranger.retrieve_fragment
163
- # format_and_draw_fragment(fragment, 0, @line_wrap.width, 0)
164
- # []
165
- # end
166
- #
167
- # end
168
- #
169
- # Prawn::Text::Formatted::Box.extensions << MyWrap
170
- #
171
- # box = Prawn::Text::Formatted::Box.new('hello world')
172
- # box.render('why can't I print anything other than' +
173
- # '"all your base are belong to us"?')
174
- #
175
- #
176
- def self.extensions
177
- @extensions ||= []
178
- end
179
-
180
- def self.inherited(base) #:nodoc:
181
- extensions.each { |e| base.extensions << e }
182
- end
183
-
184
137
  # See Prawn::Text#text_box for valid options
185
138
  #
186
139
  def initialize(formatted_text, options={})
@@ -339,6 +292,58 @@ module Prawn
339
292
  end
340
293
  end
341
294
 
295
+ # @group Extension API
296
+
297
+ # Example (see Prawn::Text::Core::Formatted::Wrap for what is required
298
+ # of the wrap method if you want to override the default wrapping
299
+ # algorithm):
300
+ #
301
+ #
302
+ # module MyWrap
303
+ #
304
+ # def wrap(array)
305
+ # initialize_wrap([{ :text => 'all your base are belong to us' }])
306
+ # @line_wrap.wrap_line(:document => @document,
307
+ # :kerning => @kerning,
308
+ # :width => 10000,
309
+ # :arranger => @arranger)
310
+ # fragment = @arranger.retrieve_fragment
311
+ # format_and_draw_fragment(fragment, 0, @line_wrap.width, 0)
312
+ # []
313
+ # end
314
+ #
315
+ # end
316
+ #
317
+ # Prawn::Text::Formatted::Box.extensions << MyWrap
318
+ #
319
+ # box = Prawn::Text::Formatted::Box.new('hello world')
320
+ # box.render('why can't I print anything other than' +
321
+ # '"all your base are belong to us"?')
322
+ #
323
+ #
324
+ def self.extensions
325
+ @extensions ||= []
326
+ end
327
+
328
+ # @private
329
+ def self.inherited(base)
330
+ extensions.each { |e| base.extensions << e }
331
+ end
332
+
333
+ def valid_options
334
+ PDF::Core::Text::VALID_OPTIONS + [:at, :height, :width,
335
+ :align, :valign,
336
+ :rotate, :rotate_around,
337
+ :overflow, :min_font_size,
338
+ :leading, :character_spacing,
339
+ :mode, :single_line,
340
+ :skip_encoding,
341
+ :document,
342
+ :direction,
343
+ :fallback_fonts,
344
+ :draw_text_callback]
345
+ end
346
+
342
347
  private
343
348
 
344
349
  def original_text
@@ -10,9 +10,11 @@ module Prawn
10
10
  module Text
11
11
  module Formatted
12
12
 
13
+
13
14
  # Prawn::Text::Formatted::Fragment is a state store for a formatted text
14
15
  # fragment. It does not render anything.
15
16
  #
17
+ # @private
16
18
  class Fragment
17
19
 
18
20
  attr_reader :format_state, :text
@@ -12,6 +12,7 @@ module Prawn
12
12
  module Text
13
13
  module Formatted #:nodoc:
14
14
 
15
+ # @private
15
16
  class LineWrap #:nodoc:
16
17
 
17
18
  # The width of the last wrapped line
@@ -13,6 +13,8 @@ module Prawn
13
13
  module Formatted
14
14
 
15
15
  class Parser
16
+ # @group Extension API
17
+
16
18
  PARSER_REGEX = begin
17
19
  regex_string = "\n|" +
18
20
  "<b>|</b>|" +
@@ -4,6 +4,8 @@ require_relative "arranger"
4
4
  module Prawn
5
5
  module Text
6
6
  module Formatted #:nodoc:
7
+ # @private
8
+
7
9
  module Wrap #:nodoc:
8
10
 
9
11
  def initialize(array, options)
@@ -16,7 +16,8 @@ module Prawn
16
16
  # But at the same time, we don't want to throw away thread safety
17
17
  # We have two interchangeable thread-safe cache implementations:
18
18
 
19
- class SynchronizedCache
19
+ # @private
20
+ class SynchronizedCache
20
21
  # As an optimization, this could access the hash directly on VMs with a global interpreter lock (like MRI)
21
22
  def initialize
22
23
  @cache = {}
@@ -29,8 +30,9 @@ module Prawn
29
30
  @mutex.synchronize { @cache[key] = value }
30
31
  end
31
32
  end
32
-
33
- class ThreadLocalCache
33
+
34
+ # @private
35
+ class ThreadLocalCache
34
36
  def initialize
35
37
  @cache_id = "cache_#{self.object_id}".to_sym
36
38
  end
@@ -15,6 +15,8 @@ require File.expand_path(File.join(File.dirname(__FILE__),
15
15
  filename = File.basename(__FILE__).gsub('.rb', '.pdf')
16
16
  Prawn::Example.generate(filename) do
17
17
  stroke_axis
18
+
19
+ stroke_color "ff0000"
18
20
 
19
21
  stroke do
20
22
  # just lower the current y position
@@ -1,5 +1,7 @@
1
1
  # encoding: utf-8
2
2
  #
3
+ # <strong>NOTE: This feature is currently not working correctly</strong>
4
+ #
3
5
  # Sometimes free flowing text might look ugly, specially when a paragraph is
4
6
  # split between two pages. Using a positioned text box just to overcome this
5
7
  # nuisance is not the right choice.
@@ -14,7 +14,7 @@ Prawn::Example.generate("text.pdf", :page_size => "FOLIO") do
14
14
  s.example "positioned_text"
15
15
  s.example "text_box_overflow"
16
16
  s.example "text_box_excess"
17
- s.example "group"
17
+ s.example "group", :eval_source => false
18
18
  s.example "column_box"
19
19
  end
20
20
 
@@ -20,9 +20,8 @@ Gem::Specification.new do |spec|
20
20
  spec.rubyforge_project = "prawn"
21
21
  spec.licenses = ['RUBY', 'GPL-2', 'GPL-3']
22
22
 
23
- spec.add_dependency('pdf-reader', '~>1.2')
24
- spec.add_dependency('ttfunk', '~>1.0.3')
25
- spec.add_dependency('ruby-rc4')
23
+ spec.add_dependency('ttfunk', '~> 1.1.0')
24
+ spec.add_dependency('pdf-core', "~> 0.1.3")
26
25
 
27
26
  spec.add_development_dependency('pdf-inspector', '~> 1.1.0')
28
27
  spec.add_development_dependency('coderay', '~> 1.0.7')
@@ -30,6 +29,8 @@ Gem::Specification.new do |spec|
30
29
  spec.add_development_dependency('rspec')
31
30
  spec.add_development_dependency('mocha')
32
31
  spec.add_development_dependency('rake')
32
+ spec.add_development_dependency('simplecov')
33
+ spec.add_development_dependency('pdf-reader', '~>1.2')
33
34
 
34
35
  spec.homepage = "http://prawn.majesticseacreature.com"
35
36
  spec.description = <<END_DESC
@@ -13,6 +13,17 @@ describe "A document's grid" do
13
13
  @pdf.grid.gutter.should == 0.1
14
14
  end
15
15
 
16
+ it "should allow re-definition of a grid" do
17
+ @pdf.define_grid(:columns => 5, :rows => 8, :gutter => 0.1)
18
+ @pdf.grid.columns.should == 5
19
+ @pdf.grid.rows.should == 8
20
+ @pdf.grid.gutter.should == 0.1
21
+ @pdf.define_grid(:columns => 3, :rows => 6, :gutter => 0.1)
22
+ @pdf.grid.columns.should == 3
23
+ @pdf.grid.rows.should == 6
24
+ @pdf.grid.gutter.should == 0.1
25
+ end
26
+
16
27
  describe "when a grid is defined" do
17
28
  before do
18
29
  @num_columns = 5
@@ -15,49 +15,7 @@ describe "Prawn::ObjectStore" do
15
15
  store.root.data[:Pages].should == store.pages
16
16
  end
17
17
 
18
- it "should import objects from an existing PDF" do
19
- filename = "#{Prawn::BASEDIR}/spec/data/curves.pdf"
20
- store = PDF::Core::ObjectStore.new(:template => filename)
21
- store.size.should == 5
22
- end
23
-
24
- it "should point to existing roots when importing objects from an existing PDF" do
25
- filename = "#{Prawn::BASEDIR}/spec/data/curves.pdf"
26
- store = PDF::Core::ObjectStore.new(:template => filename)
27
- store.info.class.should == PDF::Core::Reference
28
- store.root.class.should == PDF::Core::Reference
29
- end
30
-
31
- it "should initialize with pages when importing objects from an existing PDF" do
32
- filename = "#{Prawn::BASEDIR}/spec/data/curves.pdf"
33
- store = PDF::Core::ObjectStore.new(:template => filename)
34
- store.pages.data[:Count].should == 1
35
- end
36
-
37
- it "should import all objects from a PDF that has an indirect reference in a stream dict" do
38
- filename = "#{Prawn::DATADIR}/pdfs/indirect_reference.pdf"
39
- store = PDF::Core::ObjectStore.new(:template => filename)
40
- store.size.should == 8
41
- end
42
-
43
- it "should raise_error ArgumentError when given a file that doesn exist as a template" do
44
- filename = "not_really_there.pdf"
45
-
46
- lambda { PDF::Core::ObjectStore.new(:template => filename) }.should raise_error(ArgumentError)
47
- end
48
-
49
- it "should raise_error PDF::Core::Errors::TemplateError when given a non PDF as a template" do
50
- filename = "#{Prawn::DATADIR}/images/dice.png"
51
-
52
- lambda { PDF::Core::ObjectStore.new(:template => filename) }.should raise_error(PDF::Core::Errors::TemplateError)
53
- end
54
-
55
- it "should raise_error PDF::Core::Errors::TemplateError when given an encrypted PDF as a template" do
56
- filename = "#{Prawn::DATADIR}/pdfs/encrypted.pdf"
57
-
58
- lambda { PDF::Core::ObjectStore.new(:template => filename) }.should raise_error(PDF::Core::Errors::TemplateError)
59
- end
60
-
18
+
61
19
  it "should add to its objects when ref() is called" do
62
20
  count = @store.size
63
21
  @store.ref("blah")
@@ -121,56 +79,3 @@ describe "Prawn::ObjectStore#compact" do
121
79
  store.map{ |o| o.identifier }.should == (1..store.size).to_a
122
80
  end
123
81
  end
124
-
125
- describe "Prawn::ObjectStorie#object_id_for_page" do
126
- it "should return the object ID of an imported template page" do
127
- filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
128
- store = PDF::Core::ObjectStore.new(:template => filename)
129
- store.object_id_for_page(0).should == 4
130
- end
131
-
132
- it "should return the object ID of the first imported template page" do
133
- filename = "#{Prawn::DATADIR}/pdfs/two_hexagons.pdf"
134
- store = PDF::Core::ObjectStore.new(:template => filename)
135
- store.object_id_for_page(1).should == 4
136
- end
137
-
138
- it "should return the object ID of the last imported template page" do
139
- filename = "#{Prawn::DATADIR}/pdfs/two_hexagons.pdf"
140
- store = PDF::Core::ObjectStore.new(:template => filename)
141
- store.object_id_for_page(-1).should == 6
142
- end
143
-
144
- it "should return the object ID of the first page of a template that uses nested Pages" do
145
- filename = "#{Prawn::DATADIR}/pdfs/nested_pages.pdf"
146
- store = PDF::Core::ObjectStore.new(:template => filename)
147
- store.object_id_for_page(1).should == 5
148
- end
149
-
150
- it "should return the object ID of the last page of a template that uses nested Pages" do
151
- filename = "#{Prawn::DATADIR}/pdfs/nested_pages.pdf"
152
- store = PDF::Core::ObjectStore.new(:template => filename)
153
- store.object_id_for_page(-1).should == 8
154
- end
155
-
156
- it "should return nil if given an invalid page number" do
157
- filename = "#{Prawn::DATADIR}/pdfs/hexagon.pdf"
158
- store = PDF::Core::ObjectStore.new(:template => filename)
159
- store.object_id_for_page(10).should == nil
160
- end
161
-
162
- it "should return nil if given an invalid page number" do
163
- store = PDF::Core::ObjectStore.new
164
- store.object_id_for_page(10).should == nil
165
- end
166
-
167
- it "should accept a stream instead of a filename" do
168
- example = Prawn::Document.new()
169
- example.text "An example doc, created in memory"
170
- example.start_new_page
171
- StringIO.open(example.render) do |stream|
172
- @pdf = PDF::Core::ObjectStore.new(:template => stream)
173
- end
174
- @pdf.page_count.should == 2
175
- end
176
- end
@@ -3,63 +3,6 @@
3
3
  require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
4
4
 
5
5
  describe "A Reference object" do
6
- it "should produce a PDF reference on #to_s call" do
7
- ref = PDF::Core::Reference(1,true)
8
- ref.to_s.should == "1 0 R"
9
- end
10
-
11
- it "should allow changing generation number" do
12
- ref = PDF::Core::Reference(1,true)
13
- ref.gen = 1
14
- ref.to_s.should == "1 1 R"
15
- end
16
-
17
- it "should generate a valid PDF object for the referenced data" do
18
- ref = PDF::Core::Reference(2,[1,"foo"])
19
- ref.object.should == "2 0 obj\n#{PDF::Core::PdfObject([1,"foo"])}\nendobj\n"
20
- end
21
-
22
- it "should include stream fileds in dictionary when serializing" do
23
- ref = PDF::Core::Reference(1, {})
24
- ref.stream << 'Hello'
25
- ref.object.should == "1 0 obj\n<< /Length 5\n>>\nstream\nHello\nendstream\nendobj\n"
26
- end
27
-
28
- it "should append data to stream when #<< is used" do
29
- ref = PDF::Core::Reference(1, {})
30
- ref << "BT\n/F1 12 Tf\n72 712 Td\n( A stream ) Tj\nET"
31
- ref.object.should == "1 0 obj\n<< /Length 41\n>>\nstream"+
32
- "\nBT\n/F1 12 Tf\n72 712 Td\n( A stream ) Tj\nET" +
33
- "\nendstream\nendobj\n"
34
- end
35
-
36
- it "should copy the data and stream from another ref on #replace" do
37
- from = PDF::Core::Reference(3, {:foo => 'bar'})
38
- from << "has a stream too"
39
-
40
- to = PDF::Core::Reference(4, {:foo => 'baz'})
41
- to.replace from
42
-
43
- # should preserve identifier but copy data and stream
44
- to.identifier.should == 4
45
- to.data.should == from.data
46
- to.stream.should == from.stream
47
- end
48
-
49
- it "should copy a compressed stream from a compressed ref on #replace" do
50
- from = PDF::Core::Reference(5, {:foo => 'bar'})
51
- from << "has a stream too " * 20
52
- from.stream.compress!
53
-
54
- to = PDF::Core::Reference(6, {:foo => 'baz'})
55
- to.replace from
56
-
57
- to.identifier.should == 6
58
- to.data.should == from.data
59
- to.stream.should == from.stream
60
- to.stream.compressed?.should == true
61
- end
62
-
63
6
  describe "generated via Prawn::Document" do
64
7
  it "should return a proper reference on ref!" do
65
8
  pdf = Prawn::Document.new