prawn-layout 0.1.0 → 0.2.0.1

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