prawn 0.14.0 → 0.15.0

Sign up to get free protection for your applications and to get access to all the features.
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