prawn-layout 0.1.0 → 0.2.0.1

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.
data/Rakefile CHANGED
@@ -4,7 +4,7 @@ require 'rake/testtask'
4
4
  require "rake/rdoctask"
5
5
  require "rake/gempackagetask"
6
6
 
7
- PRAWN_LAYOUT_VERSION = "0.1.0"
7
+ PRAWN_LAYOUT_VERSION = "0.2.0.1"
8
8
 
9
9
  task :default => [:test]
10
10
 
@@ -0,0 +1,23 @@
1
+ # encoding: utf-8
2
+
3
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
4
+ require "rubygems"
5
+ require "prawn"
6
+ require "prawn/layout"
7
+
8
+ Prawn::Document.generate('simple_grid.pdf') do |p|
9
+ p.define_grid(:columns => 5, :rows => 8, :gutter => 10)
10
+
11
+ p.grid.rows.times do |i|
12
+ p.grid.columns.times do |j|
13
+ b = p.grid(i,j)
14
+ p.bounding_box b.top_left, :width => b.width, :height => b.height do
15
+ p.text b.name
16
+ p.stroke do
17
+ p.rectangle(p.bounds.top_left, b.width, b.height)
18
+ end
19
+ end
20
+ end
21
+ end
22
+ end
23
+
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Multi-faceted example that demonstrates a document flowing between header
4
+ # and footer regions. At the moment, headers and footers in Prawn are run
5
+ # using the current font settings (among other things), for each page. This
6
+ # means that it is important to non-destructively set your desired styling
7
+ # within your headers and footers, as shown below.
8
+ #
9
+ # Future versions of Prawn may make this more convenient somehow.
10
+ #
11
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
12
+ require "rubygems"
13
+ require "prawn"
14
+ require "prawn/layout"
15
+
16
+ Prawn::Document.generate("flow_with_headers_and_footers.pdf") do
17
+
18
+ header margin_box.top_left do
19
+ font "Helvetica" do
20
+ text "Here's My Fancy Header", :size => 25, :align => :center
21
+ stroke_horizontal_rule
22
+ end
23
+ end
24
+
25
+ footer [margin_box.left, margin_box.bottom + 25] do
26
+ font "Helvetica" do
27
+ stroke_horizontal_rule
28
+ text "And here's a sexy footer", :size => 16
29
+ end
30
+ end
31
+
32
+ bounding_box([bounds.left, bounds.top - 50],
33
+ :width => bounds.width, :height => bounds.height - 100) do
34
+ text "this is some flowing text " * 200
35
+
36
+
37
+ end
38
+
39
+ end
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This example demonstrates Document#lazy_bounding_box, which is used for
4
+ # storing a set of drawing instructions to be executed later. This is used
5
+ # for header and footer support in Prawn, and can be used for repeating page
6
+ # elements in general.
7
+ #
8
+ # Note that once a lazy bounding box is positioned, it calculates its anchor
9
+ # relative to its parent bounding box. It will be positioned at this exact
10
+ # location each time it is redrawn, regardless of the bounds
11
+ # LazyBoundingBox#draw is in.
12
+ #
13
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
14
+ require "rubygems"
15
+ require "prawn"
16
+ require "prawn/layout"
17
+
18
+ file = "lazy_bounding_boxes.pdf"
19
+ Prawn::Document.generate(file, :skip_page_creation => true) do
20
+ point = [bounds.right-50, bounds.bottom + 25]
21
+ page_counter = lazy_bounding_box(point, :width => 50) do
22
+ text "Page: #{page_count}"
23
+ end
24
+
25
+ 10.times do
26
+ start_new_page
27
+ text "Some filler text for the page"
28
+ page_counter.draw
29
+ end
30
+ end
@@ -0,0 +1,26 @@
1
+ # encoding: utf-8
2
+ #
3
+ # Padded box is a kind of bounding box which places padding on all sides of
4
+ # the current bounds. This is easier to see than explain, so please run the
5
+ # example.
6
+ #
7
+ # Feature borrowed from Josh Knowle's pt at:
8
+ # http://github.com/joshknowles/pt/tree/master
9
+ #
10
+ $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', '..', 'lib'))
11
+ require "rubygems"
12
+ require "prawn"
13
+ require "prawn/layout"
14
+
15
+ Prawn::Document.generate('padded_box.pdf') do
16
+ stroke_bounds
17
+ text "Margin box"
18
+ padded_box(25) do
19
+ stroke_bounds
20
+ text "Bounding box padded by 25 on all sides from the margins"
21
+ padded_box(50) do
22
+ stroke_bounds
23
+ text "Bounding box padded by 50 on all sides from the parent bounds"
24
+ end
25
+ end
26
+ end
@@ -19,8 +19,8 @@ Prawn::Document.generate("cell.pdf") do
19
19
  :border_width => 3, :padding => 10,
20
20
  :text => "And that puppies are made of gravy", :document => self, :font_size => 9)
21
21
  cell3 = Prawn::Table::Cell.new(
22
- :border_width => 3, :padding => 10, :width => 100,
23
- :text => "This is simply the way of the world", :document => self)
22
+ :border_width => 3, :padding => 10, :width => 100,
23
+ :text => "This is simply the way of the world", :document => self, :font_style => :bold)
24
24
 
25
25
  3.times do
26
26
  cellblock = Prawn::Table::CellBlock.new(self)
@@ -1,4 +1,6 @@
1
1
  require "prawn/table"
2
+ require "prawn/layout/page"
3
+ require 'prawn/layout/grid'
2
4
 
3
5
  module Prawn
4
6
 
@@ -14,6 +16,6 @@ module Prawn
14
16
  end
15
17
 
16
18
  module Layout
17
- VERSION = "0.1.0"
19
+ VERSION = "0.2.0.1"
18
20
  end
19
21
  end
@@ -0,0 +1,238 @@
1
+ module Prawn
2
+ class Document
3
+ # Defines the grid system for a particular document. Takes the number of rows and columns and the
4
+ # width to use for the gutter as the keys :rows, :columns, :gutter
5
+ #
6
+ def define_grid(options = {})
7
+ @grid = Grid.new(self, options)
8
+ end
9
+
10
+ # A method that can either be used to access a particular grid on the page or interogate the grid
11
+ # system directly.
12
+ #
13
+ # @pdf.grid # Get the Grid directly
14
+ # @pdf.grid([0,1]) # Get the box at [0,1]
15
+ # @pdf.grid([0,1], [1,2]) # Get a multi-box spanning from [0,1] to [1,2]
16
+ def grid(*args)
17
+ @boxes ||= {}
18
+ @boxes[args] ||= if args.empty?
19
+ @grid
20
+ else
21
+ g1, g2 = args
22
+ if(g1.class == Array && g2.class == Array &&
23
+ g1.length == 2 && g2.length == 2)
24
+ multi_box(single_box(*g1), single_box(*g2))
25
+ else
26
+ single_box(g1, g2)
27
+ end
28
+ end
29
+ end
30
+
31
+ # A Grid represents the entire grid system of a Page and calculates the column width and row height
32
+ # of the base box.
33
+ class Grid
34
+ attr_reader :pdf, :columns, :rows, :gutter
35
+ # :nodoc
36
+ def initialize(pdf, options = {})
37
+ Prawn.verify_options([:columns, :rows, :gutter], options)
38
+
39
+ @pdf = pdf
40
+ @columns = options[:columns]
41
+ @rows = options[:rows]
42
+ @gutter = options[:gutter].to_f
43
+ end
44
+
45
+ # Calculates the base width of boxes.
46
+ def column_width
47
+ @column_width ||= subdivide(pdf.bounds.width, columns)
48
+ end
49
+
50
+ # Calculates the base height of boxes.
51
+ def row_height
52
+ @row_height ||= subdivide(pdf.bounds.height, rows)
53
+ end
54
+
55
+ # Diagnostic tool to show all of the grids. Defaults to gray.
56
+ def show_all(color = "CCCCCC")
57
+ self.rows.times do |i|
58
+ self.columns.times do |j|
59
+ pdf.grid(i,j).show(color)
60
+ end
61
+ end
62
+ end
63
+
64
+ private
65
+ def subdivide(total, num)
66
+ (total.to_f - (gutter * (num - 1).to_f)) / num.to_f
67
+ end
68
+ end
69
+
70
+ # A Box is a class that represents a bounded area of a page. A Grid object has methods that allow
71
+ # easy access to the coordinates of its corners, which can be plugged into most existing prawn
72
+ # methods.
73
+ #
74
+ class Box
75
+ attr_reader :pdf
76
+
77
+ def initialize(pdf, i, j)
78
+ @pdf = pdf
79
+ @i = i
80
+ @j = j
81
+ end
82
+
83
+ # Mostly diagnostic method that outputs the name of a box as col_num, row_num
84
+ def name
85
+ "#{@i.to_s},#{@j.to_s}"
86
+ end
87
+
88
+ # :nodoc
89
+ def total_height
90
+ pdf.bounds.height.to_f
91
+ end
92
+
93
+ # Width of a box
94
+ def width
95
+ grid.column_width.to_f
96
+ end
97
+
98
+ # Height of a box
99
+ def height
100
+ grid.row_height.to_f
101
+ end
102
+
103
+ # Width of the gutter
104
+ def gutter
105
+ grid.gutter.to_f
106
+ end
107
+
108
+ # x-coordinate of left side
109
+ def left
110
+ @left ||= (width + gutter) * @j.to_f
111
+ end
112
+
113
+ # x-coordinate of right side
114
+ def right
115
+ @right ||= left + width
116
+ end
117
+
118
+ # y-coordinate of the top
119
+ def top
120
+ @top ||= total_height - ((height + gutter) * @i.to_f)
121
+ end
122
+
123
+ # y-coordinate of the bottom
124
+ def bottom
125
+ @bottom ||= top - height
126
+ end
127
+
128
+ # x,y coordinates of top left corner
129
+ def top_left
130
+ [left, top]
131
+ end
132
+
133
+ # x,y coordinates of top right corner
134
+ def top_right
135
+ [right, top]
136
+ end
137
+
138
+ # x,y coordinates of bottom left corner
139
+ def bottom_left
140
+ [left, bottom]
141
+ end
142
+
143
+ # x,y coordinates of bottom right corner
144
+ def bottom_right
145
+ [right, bottom]
146
+ end
147
+
148
+ # Creates a standard bounding box based on the grid box.
149
+ def bounding_box(&blk)
150
+ pdf.bounding_box(top_left, :width => width, :height => height, &blk)
151
+ end
152
+
153
+ # Diagnostic method
154
+ def show(grid_color = "CCCCCC")
155
+ self.bounding_box do
156
+ pdf.stroke_color = grid_color
157
+ pdf.text self.name
158
+ pdf.stroke_bounds
159
+ end
160
+ end
161
+
162
+ private
163
+ def grid
164
+ pdf.grid
165
+ end
166
+ end
167
+
168
+ # A MultiBox is specified by 2 Boxes and spans the areas between.
169
+ class MultiBox < Box
170
+ def initialize(pdf, b1, b2)
171
+ @pdf = pdf
172
+ @bs = [b1, b2]
173
+ end
174
+
175
+ def name
176
+ @bs.map {|b| b.name}.join(":")
177
+ end
178
+
179
+ def total_height
180
+ @bs[0].total_height
181
+ end
182
+
183
+ def width
184
+ right_box.right - left_box.left
185
+ end
186
+
187
+ def height
188
+ top_box.top - bottom_box.bottom
189
+ end
190
+
191
+ def gutter
192
+ @bs[0].gutter
193
+ end
194
+
195
+ def left
196
+ left_box.left
197
+ end
198
+
199
+ def right
200
+ right_box.right
201
+ end
202
+
203
+ def top
204
+ top_box.top
205
+ end
206
+
207
+ def bottom
208
+ bottom_box.bottom
209
+ end
210
+
211
+ private
212
+ def left_box
213
+ @left_box ||= @bs.min {|a,b| a.left <=> b.left}
214
+ end
215
+
216
+ def right_box
217
+ @right_box ||= @bs.max {|a,b| a.right <=> b.right}
218
+ end
219
+
220
+ def top_box
221
+ @top_box ||= @bs.max {|a,b| a.top <=> b.top}
222
+ end
223
+
224
+ def bottom_box
225
+ @bottom_box ||= @bs.min {|a,b| a.bottom <=> b.bottom}
226
+ end
227
+ end
228
+
229
+ private
230
+ def single_box(i, j)
231
+ Box.new(self, i, j)
232
+ end
233
+
234
+ def multi_box(b1, b2)
235
+ MultiBox.new(self, b1, b2)
236
+ end
237
+ end
238
+ end
@@ -0,0 +1,116 @@
1
+ # encoding: utf-8
2
+
3
+ # layout/page.rb : Provides helpers for page layout
4
+ #
5
+ # Copyright January 2009, Gregory Brown. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ module Prawn
10
+ class Document
11
+ # A LazyBoundingBox is simply a BoundingBox with an action tied to it to be
12
+ # executed later. The lazy_bounding_box method takes the same arguments as
13
+ # bounding_box, but returns a LazyBoundingBox object instead of executing
14
+ # the code block directly.
15
+ #
16
+ # You can then call LazyBoundingBox#draw at any time (or multiple times if
17
+ # you wish), and the contents of the block will then be run. This can be
18
+ # useful for assembling repeating page elements or reusable components.
19
+ #
20
+ # file = "lazy_bounding_boxes.pdf"
21
+ # Prawn::Document.generate(file, :skip_page_creation => true) do
22
+ # point = [bounds.right-50, bounds.bottom + 25]
23
+ # page_counter = lazy_bounding_box(point, :width => 50) do
24
+ # text "Page: #{page_count}"
25
+ # end
26
+ #
27
+ # 10.times do
28
+ # start_new_page
29
+ # text "Some text"
30
+ # page_counter.draw
31
+ # end
32
+ # end
33
+ #
34
+ def lazy_bounding_box(*args,&block)
35
+ translate!(args[0])
36
+ box = LazyBoundingBox.new(self,*args)
37
+ box.action(&block)
38
+ return box
39
+ end
40
+
41
+ # A bounding box with the same dimensions of its parents, minus a margin
42
+ # on all sides
43
+ #
44
+ def padded_box(margin, &block)
45
+ bounding_box [bounds.left + margin, bounds.top - margin],
46
+ :width => bounds.width - (margin * 2),
47
+ :height => bounds.height - (margin * 2), &block
48
+ end
49
+
50
+ # A header is a LazyBoundingBox drawn relative to the margins that can be
51
+ # repeated on every page of the document.
52
+ #
53
+ # Unless <tt>:width</tt> or <tt>:height</tt> are specified, the margin_box
54
+ # width and height are used.
55
+ #
56
+ # header margin_box.top_left do
57
+ # text "Here's My Fancy Header", :size => 25, :align => :center
58
+ # stroke_horizontal_rule
59
+ # end
60
+ #
61
+ def header(top_left,options={},&block)
62
+ @header = repeating_page_element(top_left,options,&block)
63
+ end
64
+
65
+ # A footer is a LazyBoundingBox drawn relative to the margins that can be
66
+ # repeated on every page of the document.
67
+ #
68
+ # Unless <tt>:width</tt> or <tt>:height</tt> are specified, the margin_box
69
+ # width and height are used.
70
+ #
71
+ # footer [margin_box.left, margin_box.bottom + 25] do
72
+ # stroke_horizontal_rule
73
+ # text "And here's a sexy footer", :size => 16
74
+ # end
75
+ #
76
+ def footer(top_left,options={},&block)
77
+ @footer = repeating_page_element(top_left,options,&block)
78
+ end
79
+
80
+ private
81
+
82
+ def repeating_page_element(top_left,options={},&block)
83
+ r = LazyBoundingBox.new(self, translate(top_left),
84
+ :width => options[:width] || margin_box.width,
85
+ :height => options[:height] || margin_box.height )
86
+ r.action(&block)
87
+ return r
88
+ end
89
+
90
+ class LazyBoundingBox < BoundingBox
91
+
92
+ # Defines the block to be executed by LazyBoundingBox#draw.
93
+ # Usually, this will be used via a higher level interface.
94
+ # See the documentation for Document#lazy_bounding_box, Document#header,
95
+ # and Document#footer
96
+ #
97
+ def action(&block)
98
+ @action = block
99
+ end
100
+
101
+ # Sets Document#bounds to use the LazyBoundingBox for its bounds,
102
+ # runs the block specified by LazyBoundingBox#action,
103
+ # and then restores the original bounds of the document.
104
+ #
105
+ def draw
106
+ @parent.mask(:y) do
107
+ parent_box = @parent.bounds
108
+ @parent.bounds = self
109
+ @parent.y = absolute_top
110
+ @action.call
111
+ @parent.bounds = parent_box
112
+ end
113
+ end
114
+ end
115
+ end
116
+ end
@@ -42,7 +42,7 @@ module Prawn
42
42
  # Will raise <tt>Prawn::Errors::EmptyTable</tt> given
43
43
  # a nil or empty <tt>data</tt> paramater.
44
44
  #
45
- def table(data,options={})
45
+ def table(data, options={})
46
46
  if data.nil? || data.empty?
47
47
  raise Prawn::Errors::EmptyTable,
48
48
  "data must be a non-empty, non-nil, two dimensional array of Prawn::Cells or strings"
@@ -107,7 +107,6 @@ module Prawn
107
107
  # <tt>:column_widths:</tt> A hash of indices and widths in PDF points. E.g. <tt>{ 0 => 50, 1 => 100 }</tt>
108
108
  # <tt>:row_colors</tt>:: An array of row background colors which are used cyclicly.
109
109
  # <tt>:align</tt>:: Alignment of text in columns, for entire table (<tt>:center</tt>) or by column (<tt>{ 0 => :left, 1 => :center}</tt>)
110
- # <tt>:minimum_rows</tt>:: The minimum rows to display on a page, including header.
111
110
  #
112
111
  # Row colors are specified as html encoded values, e.g.
113
112
  # ["ffffff","aaaaaa","ccaaff"]. You can also specify
@@ -117,7 +116,7 @@ module Prawn
117
116
  # See Document#table for typical usage, as directly using this class is
118
117
  # not recommended unless you know why you want to do it.
119
118
  #
120
- def initialize(data, document,options={})
119
+ def initialize(data, document, options={})
121
120
  unless data.all? { |e| Array === e }
122
121
  raise Prawn::Errors::InvalidTableData,
123
122
  "data must be a two dimensional array of Prawn::Cells or strings"
@@ -190,15 +189,28 @@ module Prawn
190
189
  def calculate_column_widths(manual_widths=nil, width=nil)
191
190
  @column_widths = [0] * @data[0].inject(0){ |acc, e|
192
191
  acc += (e.is_a?(Hash) && e.has_key?(:colspan)) ? e[:colspan] : 1 }
192
+
193
193
  renderable_data.each do |row|
194
+ colspan = 0
194
195
  row.each_with_index do |cell,i|
195
- length = cell.to_s.lines.map { |e|
196
- @document.font.width_of(e, :size => C(:font_size)) }.max.to_f +
196
+ cell_text = cell.is_a?(Hash) ? cell[:text] : cell.to_s
197
+ length = cell_text.lines.map { |e|
198
+ @document.width_of(e, :size => C(:font_size)) }.max.to_f +
197
199
  2*C(:horizontal_padding)
198
- @column_widths[i] = length.ceil if length > @column_widths[i]
200
+ if length > @column_widths[i+colspan]
201
+ @column_widths[i+colspan] = length.ceil
202
+ end
203
+
204
+ if cell.is_a?(Hash) && cell[:colspan]
205
+ colspan += cell[:colspan] - 1
206
+ end
199
207
  end
200
208
  end
201
209
 
210
+ fit_within_bounds(manual_widths, width)
211
+ end
212
+
213
+ def fit_within_bounds(manual_widths, width)
202
214
  manual_width = 0
203
215
  manual_widths.each { |k,v|
204
216
  @column_widths[k] = v; manual_width += v } if manual_widths
@@ -227,6 +239,7 @@ module Prawn
227
239
  end
228
240
  end
229
241
 
242
+
230
243
  def renderable_data
231
244
  C(:headers) ? [C(:headers)] + @data : @data
232
245
  end
@@ -270,15 +283,18 @@ module Prawn
270
283
  @column_widths[col_index]
271
284
  end
272
285
 
273
- c << Prawn::Table::Cell.new(
274
- :document => @document,
286
+ cell_options = {:document => @document,
275
287
  :text => text,
276
288
  :width => width,
277
289
  :horizontal_padding => C(:horizontal_padding),
278
290
  :vertical_padding => C(:vertical_padding),
279
291
  :border_width => C(:border_width),
280
292
  :border_style => :sides,
281
- :align => align )
293
+ :align => align}
294
+ cell_options[:font_style] = e[:font_style] if e.is_a?(Hash) && e.has_key?(:font_style)
295
+ cell_options[:font_size] = e[:font_size] if e.is_a?(Hash) && e.has_key?(:font_size)
296
+
297
+ c << Prawn::Table::Cell.new(cell_options)
282
298
  end
283
299
 
284
300
  col_index += (e.is_a?(Hash) && e.has_key?(:colspan)) ? e[:colspan] : 1
@@ -52,6 +52,7 @@ module Prawn
52
52
  # <tt>:border_style</tt>:: One of <tt>:all</tt>, <tt>:no_top</tt>, <tt>:no_bottom</tt>, <tt>:sides</tt>, <tt>:none</tt>, <tt>:bottom_only</tt>. Defaults to :all.
53
53
  # <tt>:border_color</tt>:: The color of the cell border.
54
54
  # <tt>:font_size</tt>:: The font size for the cell text.
55
+ # <tt>:font_style</tt>:: The font style for the cell text.
55
56
  #
56
57
  def initialize(options={})
57
58
  @point = options[:point]
@@ -67,6 +68,7 @@ module Prawn
67
68
  @background_color = options[:background_color]
68
69
  @align = options[:align] || :left
69
70
  @font_size = options[:font_size]
71
+ @font_style = options[:font_style]
70
72
 
71
73
  @horizontal_padding = options[:horizontal_padding] || 0
72
74
  @vertical_padding = options[:vertical_padding] || 0
@@ -78,7 +80,7 @@ module Prawn
78
80
 
79
81
  attr_accessor :point, :border_style, :border_width, :background_color,
80
82
  :document, :horizontal_padding, :vertical_padding, :align,
81
- :borders, :text_color, :border_color
83
+ :borders, :text_color, :border_color, :font_size, :font_style
82
84
 
83
85
  attr_writer :height, :width #:nodoc:
84
86
 
@@ -97,7 +99,7 @@ module Prawn
97
99
  # The width of the cell in PDF points
98
100
  #
99
101
  def width
100
- @width || (@document.font.width_of(@text, :size => @font_size)) + 2*@horizontal_padding
102
+ @width || (@document.width_of(@text, :size => @font_size)) + 2*@horizontal_padding
101
103
  end
102
104
 
103
105
  # The height of the cell in PDF points
@@ -109,7 +111,15 @@ module Prawn
109
111
  # The height of the text area excluding the vertical padding
110
112
  #
111
113
  def text_area_height
112
- @document.height_of(@text, text_area_width)
114
+ text_height = 0
115
+ if @font_size
116
+ @document.font_size(@font_size) do
117
+ text_height = @document.height_of(@text, text_area_width)
118
+ end
119
+ else
120
+ text_height = @document.height_of(@text, text_area_width)
121
+ end
122
+ text_height
113
123
  end
114
124
 
115
125
  # Draws the cell onto the PDF document
@@ -173,6 +183,7 @@ module Prawn
173
183
  options = {:align => @align, :final_gap => false}
174
184
 
175
185
  options[:size] = @font_size if @font_size
186
+ options[:style] = @font_style if @font_style
176
187
 
177
188
  @document.mask(:fill_color) do
178
189
  @document.fill_color @text_color if @text_color
@@ -0,0 +1,61 @@
1
+ # encoding: utf-8
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
3
+
4
+ describe "A document's grid" do
5
+ before do
6
+ @pdf = Prawn::Document.new
7
+ end
8
+
9
+ it "should allow definition of a grid" do
10
+ @pdf.define_grid(:columns => 5, :rows => 8, :gutter => 0.1)
11
+ @pdf.grid.columns.should == 5
12
+ @pdf.grid.rows.should == 8
13
+ @pdf.grid.gutter.should == 0.1
14
+ end
15
+
16
+ describe "when a grid is defined" do
17
+ before do
18
+ @num_columns = 5
19
+ @num_rows = 8
20
+ @gutter = 10.0
21
+ @pdf.define_grid(
22
+ :columns => @num_columns,
23
+ :rows => @num_rows,
24
+ :gutter => @gutter
25
+ )
26
+ end
27
+
28
+ it "should compute the column width" do
29
+ (@pdf.grid.column_width * @num_columns.to_f +
30
+ @gutter * (@num_columns - 1).to_f).should == @pdf.bounds.width
31
+ end
32
+
33
+ it "should compute the row height" do
34
+ (@pdf.grid.row_height * @num_rows.to_f +
35
+ @gutter * (@num_rows - 1).to_f).should == @pdf.bounds.height
36
+ end
37
+
38
+ it "should give the edges of a grid box" do
39
+ grid_width = (@pdf.bounds.width.to_f -
40
+ (@gutter * (@num_columns - 1).to_f )) / @num_columns.to_f
41
+ grid_height = (@pdf.bounds.height.to_f -
42
+ (@gutter * (@num_rows - 1).to_f ))/ @num_rows.to_f
43
+
44
+ exp_tl_x = (grid_width + @gutter.to_f) * 4.0
45
+ exp_tl_y = @pdf.bounds.height.to_f - (grid_height + @gutter.to_f)
46
+
47
+ @pdf.grid(1,4).top_left.should == [exp_tl_x, exp_tl_y]
48
+ @pdf.grid(1,4).top_right.should == [exp_tl_x + grid_width, exp_tl_y]
49
+ @pdf.grid(1,4).bottom_left.should == [exp_tl_x, exp_tl_y - grid_height]
50
+ @pdf.grid(1,4).bottom_right.should == [exp_tl_x + grid_width, exp_tl_y - grid_height]
51
+ end
52
+
53
+ it "should give the edges of a multiple grid boxes" do
54
+ # Hand verified. Cheating a bit. Don't tell.
55
+ @pdf.grid([1,3], [2,5]).top_left.should == [330.0, 628.75]
56
+ @pdf.grid([1,3], [2,5]).top_right.should == [650.0, 628.75]
57
+ @pdf.grid([1,3], [2,5]).bottom_left.should == [330.0, 456.25]
58
+ @pdf.grid([1,3], [2,5]).bottom_right.should == [650.0, 456.25]
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,41 @@
1
+ # encoding: utf-8
2
+ require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
3
+
4
+ describe "When beginning each new page" do
5
+
6
+ it "should execute codeblock given to Document#header" do
7
+ call_count = 0
8
+
9
+ pdf = Prawn::Document.new
10
+ pdf.header(pdf.margin_box.top_left) do
11
+ call_count += 1
12
+ end
13
+
14
+ pdf.start_new_page
15
+ pdf.start_new_page
16
+ pdf.render
17
+
18
+ call_count.should == 3
19
+ end
20
+
21
+ end
22
+
23
+ describe "When ending each page" do
24
+
25
+ it "should execute codeblock given to Document#footer" do
26
+
27
+ call_count = 0
28
+
29
+ pdf = Prawn::Document.new
30
+ pdf.footer([pdf.margin_box.left, pdf.margin_box.bottom + 50]) do
31
+ call_count += 1
32
+ end
33
+
34
+ pdf.start_new_page
35
+ pdf.start_new_page
36
+ pdf.render
37
+
38
+ call_count.should == 3
39
+ end
40
+
41
+ end
@@ -5,7 +5,7 @@ puts "Prawn specs: Running on Ruby Version: #{RUBY_VERSION}"
5
5
  require "rubygems"
6
6
  require "test/spec"
7
7
  require "mocha"
8
- $LOAD_PATH << File.join(File.dirname(__FILE__), '..', 'lib')
8
+ $LOAD_PATH.unshift File.join(File.dirname(__FILE__), '..', 'lib')
9
9
 
10
10
  require "prawn"
11
11
  require "prawn/layout"
@@ -10,6 +10,25 @@ describe "A table's width" do
10
10
 
11
11
  table.width.should == 300
12
12
  end
13
+ it "should calculate unspecified column widths even " +
14
+ "with colspan cells declared" do
15
+ pdf = Prawn::Document.new
16
+ hpad, fs = 3, 5
17
+ columns = 3
18
+
19
+ data = [ [ { :text => 'foo', :colspan => 2 }, "foobar" ],
20
+ [ "foo", "foo", "foo" ] ]
21
+ table = Prawn::Table.new( data, pdf,
22
+ :horizontal_padding => hpad,
23
+ :font_size => fs )
24
+
25
+ col0_width = pdf.width_of("foo", :size => fs) # cell 1, 0
26
+ col1_width = pdf.width_of("foo", :size => fs) # cell 1, 1
27
+ col2_width = pdf.width_of("foobar", :size => fs) # cell 0, 1 (at col 2)
28
+
29
+ table.width.should == col0_width.ceil + col1_width.ceil +
30
+ col2_width.ceil + 2*columns*hpad
31
+ end
13
32
 
14
33
  it "should calculate unspecified column widths as "+
15
34
  "(max(string_width).ceil + 2*horizontal_padding)" do
@@ -19,8 +38,8 @@ describe "A table's width" do
19
38
  table = Prawn::Table.new( [%w[ foo b ], %w[d foobar]], pdf,
20
39
  :horizontal_padding => hpad, :font_size => fs)
21
40
 
22
- col0_width = pdf.font.width_of("foo", :size => fs)
23
- col1_width = pdf.font.width_of("foobar", :size => fs)
41
+ col0_width = pdf.width_of("foo", :size => fs)
42
+ col1_width = pdf.width_of("foobar", :size => fs)
24
43
 
25
44
  table.width.should == col0_width.ceil + col1_width.ceil + 2*columns*hpad
26
45
  end
@@ -33,8 +52,8 @@ describe "A table's width" do
33
52
  stretchy_columns = 2
34
53
 
35
54
  col0_width = 50
36
- col1_width = pdf.font.width_of("foo", :size => fs)
37
- col2_width = pdf.font.width_of("foobar", :size => fs)
55
+ col1_width = pdf.width_of("foo", :size => fs)
56
+ col2_width = pdf.width_of("foobar", :size => fs)
38
57
  col3_width = 150
39
58
 
40
59
  table = Prawn::Table.new( [%w[snake foo b apple],
@@ -54,7 +73,9 @@ describe "A table's width" do
54
73
  expected_width = pdf.margin_box.width
55
74
 
56
75
  data = [
57
- ['This is a column with a lot of text that should comfortably exceed the width of a normal document margin_box width', 'Some more text', 'and then some more', 'Just a bit more to be extra sure']
76
+ ['This is a column with a lot of text that should comfortably exceed '+
77
+ 'the width of a normal document margin_box width', 'Some more text',
78
+ 'and then some more', 'Just a bit more to be extra sure']
58
79
  ]
59
80
 
60
81
  table = Prawn::Table.new(data, pdf)
@@ -69,9 +90,12 @@ describe "A table's width" do
69
90
  expected_width = pdf.margin_box.width
70
91
 
71
92
  data = [
72
- ['This is a column with a lot of text that should comfortably exceed the width of a normal document margin_box width', 'Some more text', 'and then some more', 'Just a bit more to be extra sure']
93
+ ['This is a column with a lot of text that should comfortably exceed '+
94
+ 'the width of a normal document margin_box width', 'Some more text',
95
+ 'and then some more', 'Just a bit more to be extra sure']
73
96
  ]
74
97
 
98
+
75
99
  table = Prawn::Table.new(data, pdf, :column_widths => { 1 => 100 })
76
100
 
77
101
  table.width.should == expected_width
@@ -98,7 +122,9 @@ describe "A table's width" do
98
122
  expected_width = 400
99
123
 
100
124
  data = [
101
- ['This is a column with a lot of text that should comfortably exceed the width of a normal document margin_box width', 'Some more text', 'and then some more', 'Just a bit more to be extra sure']
125
+ ['This is a column with a lot of text that should comfortably exceed '+
126
+ 'the width of a normal document margin_box width', 'Some more text',
127
+ 'and then some more', 'Just a bit more to be extra sure']
102
128
  ]
103
129
 
104
130
  table = Prawn::Table.new(data, pdf, :width => expected_width)
@@ -113,7 +139,9 @@ describe "A table's width" do
113
139
  expected_width = 400
114
140
 
115
141
  data = [
116
- ['This is a column with a lot of text that should comfortably exceed the width of a normal document margin_box width', 'Some more text', 'and then some more', 'Just a bit more to be extra sure']
142
+ ['This is a column with a lot of text that should comfortably exceed '+
143
+ 'the width of a normal document margin_box width', 'Some more text',
144
+ 'and then some more', 'Just a bit more to be extra sure']
117
145
  ]
118
146
 
119
147
  table = Prawn::Table.new(data, pdf, :column_widths => { 1 => 100 }, :width => expected_width)
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: prawn-layout
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Gregory Brown
@@ -9,11 +9,11 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-01-17 00:00:00 -05:00
12
+ date: 2009-06-15 00:00:00 -04:00
13
13
  default_executable:
14
14
  dependencies: []
15
15
 
16
- description: An extension to Prawn that provides table support and other layout functionality
16
+ description: " An extension to Prawn that provides table support and other layout functionality\n"
17
17
  email: " gregory.t.brown@gmail.com"
18
18
  executables: []
19
19
 
@@ -22,7 +22,10 @@ extensions: []
22
22
  extra_rdoc_files: []
23
23
 
24
24
  files:
25
- - examples/table
25
+ - examples/grid/simple_grid.rb
26
+ - examples/page_layout/flowing_text_with_header_and_footer.rb
27
+ - examples/page_layout/lazy_bounding_boxes.rb
28
+ - examples/page_layout/padded_box.rb
26
29
  - examples/table/addressbook.csv
27
30
  - examples/table/cell.rb
28
31
  - examples/table/currency.csv
@@ -34,16 +37,20 @@ files:
34
37
  - examples/table/table_header_color.rb
35
38
  - examples/table/table_header_underline.rb
36
39
  - examples/table/table_widths.rb
37
- - lib/prawn
40
+ - lib/prawn/layout/grid.rb
41
+ - lib/prawn/layout/page.rb
38
42
  - lib/prawn/layout.rb
39
- - lib/prawn/table
40
43
  - lib/prawn/table/cell.rb
41
44
  - lib/prawn/table.rb
45
+ - spec/grid_spec.rb
46
+ - spec/page_layout_spec.rb
42
47
  - spec/spec_helper.rb
43
48
  - spec/table_spec.rb
44
49
  - Rakefile
45
50
  has_rdoc: true
46
51
  homepage: http://prawn.majesticseacreature.com
52
+ licenses: []
53
+
47
54
  post_install_message:
48
55
  rdoc_options:
49
56
  - --title
@@ -65,9 +72,9 @@ required_rubygems_version: !ruby/object:Gem::Requirement
65
72
  requirements: []
66
73
 
67
74
  rubyforge_project: prawn
68
- rubygems_version: 1.3.1
75
+ rubygems_version: 1.3.4
69
76
  signing_key:
70
- specification_version: 2
77
+ specification_version: 3
71
78
  summary: An extension to Prawn that provides table support and other layout functionality
72
79
  test_files: []
73
80