prawn 0.11.1.pre → 0.11.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. data/COPYING +2 -340
  2. data/HACKING +1 -1
  3. data/LICENSE +3 -3
  4. data/Rakefile +17 -6
  5. data/data/encodings/win_ansi.txt +1 -1
  6. data/data/images/prawn.png +0 -0
  7. data/data/pdfs/form.pdf +820 -0
  8. data/data/pdfs/multipage_template.pdf +127 -0
  9. data/examples/bounding_box/bounding_boxes.rb +4 -3
  10. data/examples/bounding_box/indentation.rb +2 -1
  11. data/examples/bounding_box/russian_boxes.rb +3 -2
  12. data/examples/bounding_box/stretched_nesting.rb +2 -1
  13. data/examples/general/background.rb +2 -1
  14. data/examples/general/canvas.rb +2 -1
  15. data/examples/general/context_sensitive_headers.rb +2 -1
  16. data/examples/general/float.rb +2 -1
  17. data/examples/general/margin.rb +2 -1
  18. data/examples/general/measurement_units.rb +2 -1
  19. data/examples/general/metadata-info.rb +2 -1
  20. data/examples/general/multi_page_layout.rb +2 -1
  21. data/examples/general/outlines.rb +2 -1
  22. data/examples/general/page_geometry.rb +2 -1
  23. data/examples/general/page_numbering.rb +27 -2
  24. data/examples/general/page_templates.rb +20 -0
  25. data/examples/general/repeaters.rb +2 -1
  26. data/examples/general/stamp.rb +4 -3
  27. data/examples/general/templates.rb +2 -1
  28. data/examples/graphics/basic_images.rb +2 -1
  29. data/examples/graphics/cmyk.rb +2 -1
  30. data/examples/graphics/curves.rb +4 -3
  31. data/examples/graphics/gradient.rb +23 -0
  32. data/examples/graphics/hexagon.rb +3 -2
  33. data/examples/graphics/image_fit.rb +3 -2
  34. data/examples/graphics/image_flow.rb +2 -1
  35. data/examples/graphics/image_position.rb +3 -2
  36. data/examples/graphics/line.rb +2 -1
  37. data/examples/graphics/png_types.rb +3 -2
  38. data/examples/graphics/polygons.rb +3 -2
  39. data/examples/graphics/remote_images.rb +2 -1
  40. data/examples/graphics/rounded_polygons.rb +2 -1
  41. data/examples/graphics/rounded_rectangle.rb +2 -1
  42. data/examples/graphics/ruport_style_helpers.rb +3 -2
  43. data/examples/graphics/stroke_bounds.rb +2 -1
  44. data/examples/graphics/stroke_cap_and_join.rb +2 -1
  45. data/examples/graphics/stroke_dash.rb +2 -1
  46. data/examples/graphics/transformations.rb +2 -1
  47. data/examples/graphics/transparency.rb +4 -3
  48. data/examples/grid/bounding_boxes.rb +2 -1
  49. data/examples/grid/column_gutter_grid.rb +2 -1
  50. data/examples/grid/multi_boxes.rb +2 -1
  51. data/examples/grid/show_grid.rb +2 -1
  52. data/examples/grid/simple_grid.rb +2 -1
  53. data/examples/m17n/chinese_text_wrapping.rb +2 -1
  54. data/examples/m17n/euro.rb +3 -2
  55. data/examples/m17n/full_win_ansi_character_list.rb +20 -0
  56. data/examples/m17n/sjis.rb +2 -1
  57. data/examples/m17n/utf8.rb +3 -2
  58. data/examples/m17n/win_ansi_charset.rb +2 -1
  59. data/examples/security/hello_foo.rb +2 -1
  60. data/examples/table/bill.rb +2 -1
  61. data/examples/table/borders.rb +25 -0
  62. data/examples/table/cell.rb +3 -2
  63. data/examples/table/checkerboard.rb +2 -1
  64. data/examples/table/header.rb +3 -2
  65. data/examples/table/inline_format_table.rb +2 -1
  66. data/examples/table/multi_page_table.rb +2 -1
  67. data/examples/table/simple_table.rb +2 -1
  68. data/examples/table/subtable.rb +2 -1
  69. data/examples/table/widths.rb +2 -1
  70. data/examples/text/alignment.rb +2 -1
  71. data/examples/text/character_spacing.rb +2 -1
  72. data/examples/text/dfont.rb +2 -1
  73. data/examples/text/family_based_styling.rb +3 -2
  74. data/examples/text/font_calculations.rb +2 -1
  75. data/examples/text/font_size.rb +2 -1
  76. data/examples/text/hyphenation.rb +2 -2
  77. data/examples/text/indent_paragraphs.rb +7 -5
  78. data/examples/text/inline_format.rb +7 -6
  79. data/examples/text/kerning.rb +2 -1
  80. data/examples/text/rendering_mode.rb +21 -0
  81. data/examples/text/rotated.rb +2 -1
  82. data/examples/text/shaped_text_box.rb +2 -1
  83. data/examples/text/simple_text.rb +2 -1
  84. data/examples/text/simple_text_ttf.rb +2 -1
  85. data/examples/text/span.rb +3 -2
  86. data/examples/text/text_box.rb +7 -5
  87. data/examples/text/text_box_returning_excess.rb +4 -3
  88. data/examples/text/text_flow.rb +2 -1
  89. data/lib/prawn.rb +1 -1
  90. data/lib/prawn/core/object_store.rb +42 -14
  91. data/lib/prawn/core/page.rb +22 -8
  92. data/lib/prawn/core/text.rb +141 -13
  93. data/lib/prawn/core/text/formatted/arranger.rb +39 -12
  94. data/lib/prawn/core/text/formatted/line_wrap.rb +205 -60
  95. data/lib/prawn/core/text/formatted/wrap.rb +72 -35
  96. data/lib/prawn/document.rb +174 -70
  97. data/lib/prawn/document/bounding_box.rb +122 -83
  98. data/lib/prawn/document/column_box.rb +113 -0
  99. data/lib/prawn/document/graphics_state.rb +90 -2
  100. data/lib/prawn/document/internals.rb +5 -3
  101. data/lib/prawn/errors.rb +5 -0
  102. data/lib/prawn/font.rb +4 -4
  103. data/lib/prawn/font/afm.rb +11 -0
  104. data/lib/prawn/font/ttf.rb +5 -0
  105. data/lib/prawn/graphics.rb +77 -14
  106. data/lib/prawn/graphics/cap_style.rb +13 -5
  107. data/lib/prawn/graphics/color.rb +54 -35
  108. data/lib/prawn/graphics/dash.rb +27 -16
  109. data/lib/prawn/graphics/gradient.rb +84 -0
  110. data/lib/prawn/graphics/join_style.rb +12 -3
  111. data/lib/prawn/graphics/transparency.rb +4 -4
  112. data/lib/prawn/images.rb +18 -160
  113. data/lib/prawn/images/jpg.rb +39 -0
  114. data/lib/prawn/images/png.rb +130 -0
  115. data/lib/prawn/repeater.rb +6 -13
  116. data/lib/prawn/security.rb +6 -1
  117. data/lib/prawn/stamp.rb +12 -4
  118. data/lib/prawn/table.rb +36 -4
  119. data/lib/prawn/table/cell.rb +224 -63
  120. data/lib/prawn/table/cell/text.rb +20 -10
  121. data/lib/prawn/table/cells.rb +23 -6
  122. data/lib/prawn/text.rb +54 -91
  123. data/lib/prawn/text/box.rb +29 -283
  124. data/lib/prawn/text/formatted/box.rb +349 -24
  125. data/lib/prawn/text/formatted/fragment.rb +63 -2
  126. data/lib/prawn/text/formatted/parser.rb +2 -1
  127. data/prawn.gemspec +21 -5
  128. data/spec/bounding_box_spec.rb +61 -28
  129. data/spec/cell_spec.rb +168 -30
  130. data/spec/document_spec.rb +187 -3
  131. data/spec/extensions/mocha.rb +45 -0
  132. data/spec/font_spec.rb +32 -1
  133. data/spec/formatted_text_arranger_spec.rb +35 -40
  134. data/spec/formatted_text_box_spec.rb +287 -443
  135. data/spec/formatted_text_fragment_spec.rb +87 -0
  136. data/spec/graphics_spec.rb +128 -12
  137. data/spec/grid_spec.rb +1 -1
  138. data/spec/images_spec.rb +11 -3
  139. data/spec/inline_formatted_text_parser_spec.rb +8 -0
  140. data/spec/line_wrap_spec.rb +200 -208
  141. data/spec/object_store_spec.rb +10 -0
  142. data/spec/outline_spec.rb +7 -3
  143. data/spec/repeater_spec.rb +58 -10
  144. data/spec/security_spec.rb +6 -0
  145. data/spec/spec_helper.rb +12 -8
  146. data/spec/stamp_spec.rb +52 -1
  147. data/spec/stroke_styles_spec.rb +30 -0
  148. data/spec/table_spec.rb +93 -3
  149. data/spec/template_spec.rb +132 -6
  150. data/spec/text_at_spec.rb +14 -4
  151. data/spec/text_box_spec.rb +309 -70
  152. data/spec/text_rendering_mode_spec.rb +45 -0
  153. data/spec/text_spec.rb +60 -17
  154. data/spec/text_with_inline_formatting_spec.rb +4 -162
  155. metadata +241 -241
  156. data/lib/prawn/core/text/line_wrap.rb +0 -211
  157. data/lib/prawn/core/text/wrap.rb +0 -82
  158. data/vendor/pdf-inspector/README +0 -18
  159. data/vendor/pdf-inspector/lib/pdf/inspector.rb +0 -26
  160. data/vendor/pdf-inspector/lib/pdf/inspector/extgstate.rb +0 -18
  161. data/vendor/pdf-inspector/lib/pdf/inspector/graphics.rb +0 -131
  162. data/vendor/pdf-inspector/lib/pdf/inspector/page.rb +0 -25
  163. data/vendor/pdf-inspector/lib/pdf/inspector/text.rb +0 -46
  164. data/vendor/pdf-inspector/lib/pdf/inspector/xobject.rb +0 -19
  165. data/vendor/ttfunk/data/fonts/DejaVuSans.ttf +0 -0
  166. data/vendor/ttfunk/data/fonts/comicsans.ttf +0 -0
  167. data/vendor/ttfunk/example.rb +0 -45
  168. data/vendor/ttfunk/lib/ttfunk.rb +0 -102
  169. data/vendor/ttfunk/lib/ttfunk/directory.rb +0 -17
  170. data/vendor/ttfunk/lib/ttfunk/encoding/mac_roman.rb +0 -88
  171. data/vendor/ttfunk/lib/ttfunk/encoding/windows_1252.rb +0 -69
  172. data/vendor/ttfunk/lib/ttfunk/reader.rb +0 -44
  173. data/vendor/ttfunk/lib/ttfunk/resource_file.rb +0 -78
  174. data/vendor/ttfunk/lib/ttfunk/subset.rb +0 -18
  175. data/vendor/ttfunk/lib/ttfunk/subset/base.rb +0 -141
  176. data/vendor/ttfunk/lib/ttfunk/subset/mac_roman.rb +0 -50
  177. data/vendor/ttfunk/lib/ttfunk/subset/unicode.rb +0 -48
  178. data/vendor/ttfunk/lib/ttfunk/subset/unicode_8bit.rb +0 -63
  179. data/vendor/ttfunk/lib/ttfunk/subset/windows_1252.rb +0 -55
  180. data/vendor/ttfunk/lib/ttfunk/subset_collection.rb +0 -72
  181. data/vendor/ttfunk/lib/ttfunk/table.rb +0 -46
  182. data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +0 -34
  183. data/vendor/ttfunk/lib/ttfunk/table/cmap/format00.rb +0 -54
  184. data/vendor/ttfunk/lib/ttfunk/table/cmap/format04.rb +0 -126
  185. data/vendor/ttfunk/lib/ttfunk/table/cmap/subtable.rb +0 -79
  186. data/vendor/ttfunk/lib/ttfunk/table/glyf.rb +0 -64
  187. data/vendor/ttfunk/lib/ttfunk/table/glyf/compound.rb +0 -81
  188. data/vendor/ttfunk/lib/ttfunk/table/glyf/simple.rb +0 -37
  189. data/vendor/ttfunk/lib/ttfunk/table/head.rb +0 -44
  190. data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +0 -41
  191. data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +0 -47
  192. data/vendor/ttfunk/lib/ttfunk/table/kern.rb +0 -79
  193. data/vendor/ttfunk/lib/ttfunk/table/kern/format0.rb +0 -62
  194. data/vendor/ttfunk/lib/ttfunk/table/loca.rb +0 -43
  195. data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +0 -40
  196. data/vendor/ttfunk/lib/ttfunk/table/name.rb +0 -125
  197. data/vendor/ttfunk/lib/ttfunk/table/os2.rb +0 -78
  198. data/vendor/ttfunk/lib/ttfunk/table/post.rb +0 -91
  199. data/vendor/ttfunk/lib/ttfunk/table/post/format10.rb +0 -43
  200. data/vendor/ttfunk/lib/ttfunk/table/post/format20.rb +0 -35
  201. data/vendor/ttfunk/lib/ttfunk/table/post/format25.rb +0 -23
  202. data/vendor/ttfunk/lib/ttfunk/table/post/format30.rb +0 -17
  203. data/vendor/ttfunk/lib/ttfunk/table/post/format40.rb +0 -17
  204. data/vendor/ttfunk/lib/ttfunk/table/simple.rb +0 -14
@@ -318,13 +318,23 @@ describe "The mask() feature" do
318
318
  end
319
319
 
320
320
  describe "The group() feature" do
321
+ it "should return a true value if the content fits on one page" do
322
+ pdf = Prawn::Document.new do
323
+ val = group { text "Hello"; text "World" }
324
+ (!!val).should == true
325
+ end
326
+ end
327
+
321
328
  it "should group a simple block on a single page" do
322
329
  pdf = Prawn::Document.new do
323
330
  self.y = 50
324
- group do
331
+ val = group do
325
332
  text "Hello"
326
333
  text "World"
327
334
  end
335
+
336
+ # group should return a false value since a new page was started
337
+ (!!val).should == false
328
338
  end
329
339
  pages = PDF::Inspector::Page.analyze(pdf.render).pages
330
340
  pages.size.should == 2
@@ -341,6 +351,25 @@ describe "The group() feature" do
341
351
  end.render
342
352
  }.should.raise(Prawn::Errors::CannotGroup)
343
353
  end
354
+
355
+ it "should group within individual column boxes" do
356
+ pdf = Prawn::Document.new do
357
+ # Set up columns with grouped blocks of 0..49. 0 to 49 is slightly short
358
+ # of the height of one page / column, so each column should get its own
359
+ # group (every column should start with zero).
360
+ column_box([0, bounds.top], :width => bounds.width, :columns => 7) do
361
+ 10.times do
362
+ group { 50.times { |i| text(i.to_s) } }
363
+ end
364
+ end
365
+ end
366
+
367
+ # Second page should start with a 0 because it's a new group.
368
+ pages = PDF::Inspector::Page.analyze(pdf.render).pages
369
+ pages.size.should == 2
370
+ pages[1][:strings].first.should == '0'
371
+ end
372
+
344
373
  end
345
374
 
346
375
  describe "The render() feature" do
@@ -373,6 +402,14 @@ describe "The render() feature" do
373
402
  render_body.call(StringIO.new)
374
403
  pdf.render
375
404
  end
405
+
406
+ it "should be idempotent" do
407
+ pdf = Prawn::Document.new
408
+
409
+ contents = pdf.render
410
+ contents2 = pdf.render
411
+ contents2.should == contents
412
+ end
376
413
  end
377
414
 
378
415
  describe "The :optimize_objects option" do
@@ -454,7 +491,7 @@ describe "content stream characteristics" do
454
491
  @pdf = Prawn::Document.new
455
492
  @pdf.text "James"
456
493
  output = StringIO.new(@pdf.render)
457
- hash = PDF::Hash.new(output)
494
+ hash = PDF::Reader::ObjectHash.new(output)
458
495
 
459
496
  streams = hash.values.select { |obj| obj.kind_of?(PDF::Reader::Stream) }
460
497
 
@@ -467,10 +504,157 @@ describe "content stream characteristics" do
467
504
  @pdf.go_to_page(1)
468
505
  @pdf.text "Healy"
469
506
  output = StringIO.new(@pdf.render)
470
- hash = PDF::Hash.new(output)
507
+ hash = PDF::Reader::ObjectHash.new(output)
471
508
 
472
509
  streams = hash.values.select { |obj| obj.kind_of?(PDF::Reader::Stream) }
473
510
 
474
511
  streams.size.should == 1
475
512
  end
476
513
  end
514
+
515
+ describe "The number_pages method" do
516
+ before do
517
+ @pdf = Prawn::Document.new(:skip_page_creation => true)
518
+ end
519
+
520
+ it "replaces the '<page>' string with the proper page number" do
521
+ @pdf.start_new_page
522
+ @pdf.expects(:text_box).with("1, test", { :height => 50 })
523
+ @pdf.number_pages "<page>, test", {:page_filter => :all}
524
+ end
525
+
526
+ it "replaces the '<total>' string with the total page count" do
527
+ @pdf.start_new_page
528
+ @pdf.expects(:text_box).with("test, 1", { :height => 50 })
529
+ @pdf.number_pages "test, <total>", {:page_filter => :all}
530
+ end
531
+
532
+ it "must print the page if the page number matches" do
533
+ 10.times { @pdf.start_new_page }
534
+ @pdf.expects(:text_box).at_least_once
535
+ @pdf.number_pages "test", {:page_filter => :all}
536
+ end
537
+
538
+ it "must not print the page number without a filter" do
539
+ 10.times { @pdf.start_new_page }
540
+ @pdf.expects(:text_box).never
541
+ @pdf.number_pages "test", {:page_filter => nil}
542
+ end
543
+
544
+ context "start_count_at option" do
545
+ [1, 2].each do |startat|
546
+ context "equal to #{startat}" do
547
+ it "increments the pages" do
548
+ 2.times { @pdf.start_new_page }
549
+ options = {:page_filter => :all, :start_count_at => startat}
550
+ @pdf.expects(:text_box).with("#{startat} 2", { :height => 50 })
551
+ @pdf.expects(:text_box).with("#{startat+1} 2", { :height => 50 })
552
+ @pdf.number_pages "<page> <total>", options
553
+ end
554
+ end
555
+ end
556
+
557
+ [0, nil].each do |val|
558
+ context "equal to #{val}" do
559
+ it "defaults to start at page 1" do
560
+ 3.times { @pdf.start_new_page }
561
+ options = {:page_filter => :all, :start_count_at => val}
562
+ @pdf.expects(:text_box).with("1 3", { :height => 50 })
563
+ @pdf.expects(:text_box).with("2 3", { :height => 50 })
564
+ @pdf.expects(:text_box).with("3 3", { :height => 50 })
565
+ @pdf.number_pages "<page> <total>", options
566
+ end
567
+ end
568
+ end
569
+ end
570
+
571
+ context "total_pages option" do
572
+ it "allows the total pages count to be overridden" do
573
+ 2.times { @pdf.start_new_page }
574
+ @pdf.expects(:text_box).with("1 10", { :height => 50 })
575
+ @pdf.expects(:text_box).with("2 10", { :height => 50 })
576
+ @pdf.number_pages "<page> <total>", :page_filter => :all, :total_pages => 10
577
+ end
578
+ end
579
+
580
+ context "special page filter" do
581
+ context "such as :odd" do
582
+ it "increments the pages" do
583
+ 3.times { @pdf.start_new_page }
584
+ @pdf.expects(:text_box).with("1 3", { :height => 50 })
585
+ @pdf.expects(:text_box).with("3 3", { :height => 50 })
586
+ @pdf.expects(:text_box).with("2 3", { :height => 50 }).never
587
+ @pdf.number_pages "<page> <total>", :page_filter => :odd
588
+ end
589
+ end
590
+ context "missing" do
591
+ it "does not print any page numbers" do
592
+ 3.times { @pdf.start_new_page }
593
+ @pdf.expects(:text_box).never
594
+ @pdf.number_pages "<page> <total>", :page_filter => nil
595
+ end
596
+ end
597
+ end
598
+
599
+ context "given both a special page filter and a start_count_at parameter" do
600
+ context "such as :odd and 7" do
601
+ it "increments the pages" do
602
+ 3.times { @pdf.start_new_page }
603
+ @pdf.expects(:text_box).with("1 3", { :height => 50 }).never
604
+ @pdf.expects(:text_box).with("5 3", { :height => 50 }) # page 1
605
+ @pdf.expects(:text_box).with("6 3", { :height => 50 }).never # page 2
606
+ @pdf.expects(:text_box).with("7 3", { :height => 50 }) # page 3
607
+ @pdf.number_pages "<page> <total>", :page_filter => :odd, :start_count_at => 5
608
+ end
609
+ end
610
+ context "some crazy proc and 2" do
611
+ it "increments the pages" do
612
+ 6.times { @pdf.start_new_page }
613
+ options = {:page_filter => lambda {|p| p != 2 && p != 5}, :start_count_at => 4}
614
+ @pdf.expects(:text_box).with("4 6", { :height => 50 }) # page 1
615
+ @pdf.expects(:text_box).with("5 6", { :height => 50 }).never # page 2
616
+ @pdf.expects(:text_box).with("6 6", { :height => 50 }) # page 3
617
+ @pdf.expects(:text_box).with("7 6", { :height => 50 }) # page 4
618
+ @pdf.expects(:text_box).with("8 6", { :height => 50 }).never # page 5
619
+ @pdf.expects(:text_box).with("9 6", { :height => 50 }) # page 6
620
+ @pdf.number_pages "<page> <total>", options
621
+ end
622
+ end
623
+ end
624
+ end
625
+
626
+ describe "The page_match? method" do
627
+ before do
628
+ @pdf = Prawn::Document.new(:skip_page_creation => true)
629
+ 10.times {@pdf.start_new_page}
630
+ end
631
+
632
+ it "returns nil given no filter" do
633
+ assert ! @pdf.page_match?(:nil, 1)
634
+ end
635
+
636
+ it "must provide an :all filter" do
637
+ assert (1..@pdf.page_count).all? { |i| @pdf.page_match?(:all, i) }
638
+ end
639
+
640
+ it "must provide an :odd filter" do
641
+ odd, even = (1..@pdf.page_count).partition { |e| e % 2 == 1 }
642
+ assert odd.all? { |i| @pdf.page_match?(:odd, i) }
643
+ assert ! even.any? { |i| @pdf.page_match?(:odd, i) }
644
+ end
645
+
646
+ it "must be able to filter by an array of page numbers" do
647
+ fltr = [1,2,7]
648
+ assert_equal [1,2,7], (1..10).select { |i| @pdf.page_match?(fltr, i) }
649
+ end
650
+
651
+ it "must be able to filter by a range of page numbers" do
652
+ fltr = 2..4
653
+ assert_equal [2,3,4], (1..10).select { |i| @pdf.page_match?(fltr, i) }
654
+ end
655
+
656
+ it "must be able to filter by an arbitrary proc" do
657
+ fltr = lambda { |x| x == 1 or x % 3 == 0 }
658
+ assert_equal [1,3,6,9], (1..10).select { |i| @pdf.page_match?(fltr, i) }
659
+ end
660
+ end
@@ -0,0 +1,45 @@
1
+ # Allow speccing things when an expectation matcher runs. Similar to #with, but
2
+ # always succeeds.
3
+ #
4
+ # @pdf.expects(:stroke_line).checking do |from, to|
5
+ # @pdf.map_to_absolute(from).should == [0, 0]
6
+ # end
7
+ #
8
+ # Note that the outer expectation does *not* fail only because the inner one
9
+ # does; in the above example, the outer expectation would only fail if
10
+ # stroke_line were not called.
11
+
12
+ class ParameterChecker < Mocha::ParametersMatcher
13
+ def initialize(&matching_block)
14
+ @matching_block = matching_block
15
+ @run_matching_block = false
16
+ end
17
+
18
+ def match?(actual_parameters = [])
19
+ @matching_block.call(*actual_parameters) unless @run_matching_block
20
+ @run_matching_block = true
21
+
22
+ true # always succeed
23
+ end
24
+ end
25
+
26
+ class Mocha::Expectation
27
+ def checking(&block)
28
+ @parameters_matcher = ParameterChecker.new(&block)
29
+ self
30
+ end
31
+ end
32
+
33
+
34
+ # Equivalent to expects(method_name).at_least(0). More useful when combined
35
+ # with parameter matchers to ignore certain calls for the sake of parameter
36
+ # matching.
37
+ #
38
+ # @pdf.ignores(:stroke_color=).with("000000")
39
+ # @pdf.expects(:stroke_color=).with("ff0000")
40
+ #
41
+ module Mocha::ObjectMethods
42
+ def ignores(method_name)
43
+ expects(method_name).at_least(0)
44
+ end
45
+ end
data/spec/font_spec.rb CHANGED
@@ -206,6 +206,33 @@ describe "AFM fonts" do
206
206
 
207
207
  end
208
208
 
209
+ describe "#glyph_present" do
210
+ before(:each) { create_pdf }
211
+
212
+ it "should return true when present in an AFM font" do
213
+ font = @pdf.find_font("Helvetica")
214
+ font.glyph_present?("H").should.be true
215
+ end
216
+
217
+ it "should return false when absent in an AFM font" do
218
+ font = @pdf.find_font("Helvetica")
219
+ font.glyph_present?("再").should.be false
220
+ end
221
+
222
+ it "should return true when present in a TTF font" do
223
+ font = @pdf.find_font("#{Prawn::BASEDIR}/data/fonts/Activa.ttf")
224
+ font.glyph_present?("H").should.be true
225
+ end
226
+
227
+ it "should return false when absent in a TTF font" do
228
+ font = @pdf.find_font("#{Prawn::BASEDIR}/data/fonts/Activa.ttf")
229
+ font.glyph_present?("再").should.be false
230
+
231
+ font = @pdf.find_font("#{Prawn::BASEDIR}/data/fonts/gkai00mp.ttf")
232
+ font.glyph_present?("€").should.be false
233
+ end
234
+ end
235
+
209
236
  describe "TTF fonts" do
210
237
 
211
238
  setup do
@@ -224,7 +251,11 @@ describe "TTF fonts" do
224
251
 
225
252
  it "should encode text without kerning by default" do
226
253
  @activa.encode_text("To").should == [[0, "To"]]
227
- @activa.encode_text("Télé").should == [[0, "T\216l\216"]]
254
+
255
+ tele = (RUBY_VERSION < '1.9') ? "T\216l\216" :
256
+ "T\216l\216".force_encoding("US-ASCII")
257
+ @activa.encode_text("Télé").should == [[0, tele]]
258
+
228
259
  @activa.encode_text("Technology").should == [[0, "Technology"]]
229
260
  @activa.encode_text("Technology...").should == [[0, "Technology..."]]
230
261
  @activa.encode_text("Teχnology...").should == [[0, "Te"], [1, "!"], [0, "nology..."]]
@@ -178,12 +178,26 @@ describe "Core::Text::Formatted::Arranger#update_last_string" do
178
178
  arranger.format_array = array
179
179
  while string = arranger.next_string
180
180
  end
181
- arranger.update_last_string(" you", " now?")
181
+ arranger.update_last_string(" you", " now?", nil)
182
182
  arranger.consumed[3].should == { :text => " you",
183
- :styles => [:bold, :italic] }
183
+ :styles => [:bold, :italic] }
184
184
  arranger.unconsumed.should == [{ :text => " now?",
185
- :styles => [:bold, :italic] }]
185
+ :styles => [:bold, :italic] }]
186
186
  end
187
+ it "should set the format state to the previously processed fragment" do
188
+ create_pdf
189
+ arranger = Prawn::Core::Text::Formatted::Arranger.new(@pdf)
190
+ array = [{ :text => "hello " },
191
+ { :text => "world how ", :styles => [:bold] },
192
+ { :text => "are", :styles => [:bold, :italic] },
193
+ { :text => " you now?" }]
194
+ arranger.format_array = array
195
+ 3.times { arranger.next_string }
196
+ arranger.current_format_state.should == { :styles => [:bold, :italic] }
197
+ arranger.update_last_string("", "are", "-")
198
+ arranger.current_format_state.should == { :styles => [:bold] }
199
+ end
200
+
187
201
  context "when the entire string was used" do
188
202
  it "should not push empty string onto unconsumed" do
189
203
  create_pdf
@@ -195,7 +209,7 @@ describe "Core::Text::Formatted::Arranger#update_last_string" do
195
209
  arranger.format_array = array
196
210
  while string = arranger.next_string
197
211
  end
198
- arranger.update_last_string(" you now?", "")
212
+ arranger.update_last_string(" you now?", "", nil)
199
213
  arranger.unconsumed.should == []
200
214
  end
201
215
  end
@@ -223,7 +237,8 @@ describe "Core::Text::Formatted::Arranger#space_count" do
223
237
  end
224
238
  end
225
239
  describe "Core::Text::Formatted::Arranger#finalize_line" do
226
- it "should make it so the last consumed fragment ends with non-white-space" do
240
+ it "should make it so that all trailing white space fragments " +
241
+ "exclude trailing white space" do
227
242
  create_pdf
228
243
  arranger = Prawn::Core::Text::Formatted::Arranger.new(@pdf)
229
244
  array = [{ :text => "hello " },
@@ -233,9 +248,16 @@ describe "Core::Text::Formatted::Arranger#finalize_line" do
233
248
  while string = arranger.next_string
234
249
  end
235
250
  arranger.finalize_line
236
- arranger.fragments.length.should == 2
237
- arranger.retrieve_fragment.text
238
- arranger.retrieve_fragment.text.should == "world how"
251
+ arranger.fragments.length.should == 3
252
+
253
+ fragment = arranger.retrieve_fragment
254
+ fragment.text.should == "hello "
255
+
256
+ fragment = arranger.retrieve_fragment
257
+ fragment.text.should == "world how"
258
+
259
+ fragment = arranger.retrieve_fragment
260
+ fragment.text.should == ""
239
261
  end
240
262
  end
241
263
 
@@ -343,7 +365,7 @@ describe "Core::Text::Formatted::Arranger#finished" do
343
365
  arranger.format_array = array
344
366
  while string = arranger.next_string
345
367
  end
346
- arranger.update_last_string(" you", "now?")
368
+ arranger.update_last_string(" you", "now?", nil)
347
369
  arranger.should.not.be.finished
348
370
  end
349
371
  it "should be false if everything was printed" do
@@ -360,47 +382,20 @@ describe "Core::Text::Formatted::Arranger#finished" do
360
382
  end
361
383
  end
362
384
 
363
- describe "Core::Text::Formatted::Arranger#unfinished" do
364
- it "should be false if anything was not printed" do
365
- create_pdf
366
- arranger = Prawn::Core::Text::Formatted::Arranger.new(@pdf)
367
- array = [{ :text => "hello " },
368
- { :text => "world how ", :styles => [:bold] },
369
- { :text => "are", :styles => [:bold, :italic] },
370
- { :text => " you now?" }]
371
- arranger.format_array = array
372
- while string = arranger.next_string
373
- end
374
- arranger.update_last_string(" you", "now?")
375
- arranger.should.be.unfinished
376
- end
377
- it "should be false if everything was printed" do
378
- create_pdf
379
- arranger = Prawn::Core::Text::Formatted::Arranger.new(@pdf)
380
- array = [{ :text => "hello " },
381
- { :text => "world how ", :styles => [:bold] },
382
- { :text => "are", :styles => [:bold, :italic] },
383
- { :text => " you now?" }]
384
- arranger.format_array = array
385
- while string = arranger.next_string
386
- end
387
- arranger.should.not.be.unfinished
388
- end
389
- end
390
-
391
385
  describe "Core::Text::Formatted::Arranger.max_line_height" do
392
386
  it "should be the height of the maximum consumed fragment" do
393
387
  create_pdf
394
388
  arranger = Prawn::Core::Text::Formatted::Arranger.new(@pdf)
395
389
  array = [{ :text => "hello " },
396
390
  { :text => "world how ", :styles => [:bold] },
397
- { :text => "are", :styles => [:bold, :italic] },
391
+ { :text => "are", :styles => [:bold, :italic],
392
+ :size => 28 },
398
393
  { :text => " you now?" }]
399
394
  arranger.format_array = array
400
395
  while string = arranger.next_string
401
396
  end
402
- arranger.update_last_string(" you", "now?")
403
- arranger.should.be.unfinished
397
+ arranger.finalize_line
398
+ arranger.max_line_height.should.be.close(33.32, 0.0001)
404
399
  end
405
400
  end
406
401