prawn 1.1.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +4 -4
  2. data/VERSION +1 -0
  3. data/lib/prawn.rb +2 -2
  4. data/lib/prawn/text/box.rb +2 -0
  5. data/lib/prawn/text/formatted/box.rb +46 -21
  6. data/lib/prawn/text/formatted/line_wrap.rb +8 -2
  7. data/lib/prawn/text/formatted/wrap.rb +3 -1
  8. data/manual/contents.rb +1 -1
  9. data/manual/example_helper.rb +0 -1
  10. data/manual/table.rb +16 -0
  11. data/manual/text/text_box_overflow.rb +4 -0
  12. data/prawn.gemspec +2 -3
  13. data/spec/formatted_text_box_spec.rb +22 -0
  14. data/spec/line_wrap_spec.rb +4 -0
  15. data/spec/text_box_spec.rb +28 -0
  16. data/spec/text_spec.rb +19 -0
  17. metadata +6 -50
  18. data/lib/prawn/table.rb +0 -644
  19. data/lib/prawn/table/cell.rb +0 -772
  20. data/lib/prawn/table/cell/image.rb +0 -69
  21. data/lib/prawn/table/cell/in_table.rb +0 -33
  22. data/lib/prawn/table/cell/span_dummy.rb +0 -93
  23. data/lib/prawn/table/cell/subtable.rb +0 -66
  24. data/lib/prawn/table/cell/text.rb +0 -154
  25. data/lib/prawn/table/cells.rb +0 -255
  26. data/lib/prawn/table/column_width_calculator.rb +0 -182
  27. data/manual/table/basic_block.rb +0 -53
  28. data/manual/table/before_rendering_page.rb +0 -26
  29. data/manual/table/cell_border_lines.rb +0 -24
  30. data/manual/table/cell_borders_and_bg.rb +0 -31
  31. data/manual/table/cell_dimensions.rb +0 -30
  32. data/manual/table/cell_text.rb +0 -38
  33. data/manual/table/column_widths.rb +0 -30
  34. data/manual/table/content_and_subtables.rb +0 -39
  35. data/manual/table/creation.rb +0 -27
  36. data/manual/table/filtering.rb +0 -36
  37. data/manual/table/flow_and_header.rb +0 -17
  38. data/manual/table/image_cells.rb +0 -33
  39. data/manual/table/position.rb +0 -29
  40. data/manual/table/row_colors.rb +0 -20
  41. data/manual/table/span.rb +0 -30
  42. data/manual/table/style.rb +0 -22
  43. data/manual/table/table.rb +0 -52
  44. data/manual/table/width.rb +0 -27
  45. data/spec/cell_spec.rb +0 -629
  46. data/spec/table/span_dummy_spec.rb +0 -17
  47. data/spec/table_spec.rb +0 -1527
@@ -1,69 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # image.rb: Table image cells.
4
- #
5
- # Copyright September 2010, Brad Ediger. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
- module Prawn
9
- class Table
10
- class Cell
11
-
12
- # @private
13
- class Image < Cell
14
-
15
- def initialize(pdf, point, options={})
16
- @image_options = {}
17
- super
18
-
19
- @pdf_object, @image_info = @pdf.build_image_object(@file)
20
- @natural_width, @natural_height = @image_info.calc_image_dimensions(
21
- @image_options)
22
- end
23
-
24
- def image=(file)
25
- @file = file
26
- end
27
-
28
- def scale=(s)
29
- @image_options[:scale] = s
30
- end
31
-
32
- def fit=(f)
33
- @image_options[:fit] = f
34
- end
35
-
36
- def image_height=(h)
37
- @image_options[:height] = h
38
- end
39
-
40
- def image_width=(w)
41
- @image_options[:width] = w
42
- end
43
-
44
- def position=(p)
45
- @image_options[:position] = p
46
- end
47
-
48
- def vposition=(vp)
49
- @image_options[:vposition] = vp
50
- end
51
-
52
- def natural_content_width
53
- @natural_width
54
- end
55
-
56
- def natural_content_height
57
- @natural_height
58
- end
59
-
60
- # Draw the image on the page.
61
- #
62
- def draw_content
63
- @pdf.embed_image(@pdf_object, @image_info, @image_options)
64
- end
65
-
66
- end
67
- end
68
- end
69
- end
@@ -1,33 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # Accessors for using a Cell inside a Table.
4
- #
5
- # Contributed by Brad Ediger.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
-
9
- module Prawn
10
- class Table
11
-
12
- class Cell
13
-
14
- # This module extends Cell objects when they are used in a table (as
15
- # opposed to standalone). Its properties apply to cells-in-tables but not
16
- # cells themselves.
17
- #
18
- # @private
19
- module InTable
20
-
21
- # Row number (0-based).
22
- #
23
- attr_accessor :row
24
-
25
- # Column number (0-based).
26
- #
27
- attr_accessor :column
28
-
29
- end
30
-
31
- end
32
- end
33
- end
@@ -1,93 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # span_dummy.rb: Placeholder for non-master spanned cells.
4
- #
5
- # Copyright December 2011, Brad Ediger. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
- module Prawn
9
- class Table
10
- class Cell
11
-
12
- # A Cell object used to represent all but the topmost cell in a span
13
- # group.
14
- #
15
- # @private
16
- class SpanDummy < Cell
17
- def initialize(pdf, master_cell)
18
- super(pdf, [0, pdf.cursor])
19
- @master_cell = master_cell
20
- @padding = [0, 0, 0, 0]
21
- end
22
-
23
- # By default, a span dummy will never increase the height demand.
24
- #
25
- def natural_content_height
26
- 0
27
- end
28
-
29
- # By default, a span dummy will never increase the width demand.
30
- #
31
- def natural_content_width
32
- 0
33
- end
34
-
35
- def avg_spanned_min_width
36
- @master_cell.avg_spanned_min_width
37
- end
38
-
39
- # Dummy cells have nothing to draw.
40
- #
41
- def draw_borders(pt)
42
- end
43
-
44
- # Dummy cells have nothing to draw.
45
- #
46
- def draw_bounded_content(pt)
47
- end
48
-
49
- def padding_right=(val)
50
- @master_cell.padding_right = val if rightmost?
51
- end
52
-
53
- def padding_bottom=(val)
54
- @master_cell.padding_bottom = val if bottommost?
55
- end
56
-
57
- def border_right_color=(val)
58
- @master_cell.border_right_color = val if rightmost?
59
- end
60
-
61
- def border_bottom_color=(val)
62
- @master_cell.border_bottom_color = val if bottommost?
63
- end
64
-
65
- def border_right_width=(val)
66
- @master_cell.border_right_width = val if rightmost?
67
- end
68
-
69
- def border_bottom_width=(val)
70
- @master_cell.border_bottom_width = val if bottommost?
71
- end
72
-
73
- def background_color
74
- @master_cell.background_color
75
- end
76
-
77
- private
78
-
79
- # Are we on the right border of the span?
80
- #
81
- def rightmost?
82
- @column == @master_cell.column + @master_cell.colspan - 1
83
- end
84
-
85
- # Are we on the bottom border of the span?
86
- #
87
- def bottommost?
88
- @row == @master_cell.row + @master_cell.rowspan - 1
89
- end
90
- end
91
- end
92
- end
93
- end
@@ -1,66 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # subtable.rb: Yo dawg.
4
- #
5
- # Copyright January 2010, Brad Ediger. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
- module Prawn
9
- class Table
10
- class Cell
11
-
12
- # A Cell that contains another table.
13
- #
14
- # @private
15
- class Subtable < Cell
16
-
17
- attr_reader :subtable
18
-
19
- def initialize(pdf, point, options={})
20
- super
21
- @subtable = options[:content]
22
-
23
- # Subtable padding defaults to zero
24
- @padding = [0, 0, 0, 0]
25
- end
26
-
27
- # Sets the text color of the entire subtable.
28
- #
29
- def text_color=(color)
30
- @subtable.cells.text_color = color
31
- end
32
-
33
- # Proxied to subtable.
34
- #
35
- def natural_content_width
36
- @subtable.cells.width
37
- end
38
-
39
- # Proxied to subtable.
40
- #
41
- def min_width
42
- @subtable.cells.min_width
43
- end
44
-
45
- # Proxied to subtable.
46
- #
47
- def max_width
48
- @subtable.cells.max_width
49
- end
50
-
51
- # Proxied to subtable.
52
- #
53
- def natural_content_height
54
- @subtable.cells.height
55
- end
56
-
57
- # Draws the subtable.
58
- #
59
- def draw_content
60
- @subtable.draw
61
- end
62
-
63
- end
64
- end
65
- end
66
- end
@@ -1,154 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # text.rb: Text table cells.
4
- #
5
- # Copyright December 2009, Gregory Brown and Brad Ediger. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
- module Prawn
9
- class Table
10
- class Cell
11
-
12
- # A Cell that contains text. Has some limited options to set font family,
13
- # size, and style.
14
- #
15
- # @private
16
- class Text < Cell
17
-
18
- TextOptions = [:inline_format, :kerning, :size, :align, :valign,
19
- :rotate, :rotate_around, :leading, :single_line, :skip_encoding,
20
- :overflow, :min_font_size]
21
-
22
- TextOptions.each do |option|
23
- define_method("#{option}=") { |v| @text_options[option] = v }
24
- define_method(option) { @text_options[option] }
25
- end
26
-
27
- attr_writer :font, :text_color
28
-
29
- def initialize(pdf, point, options={})
30
- @text_options = {}
31
- super
32
- end
33
-
34
- # Returns the font that will be used to draw this cell.
35
- #
36
- def font
37
- with_font { @pdf.font }
38
- end
39
-
40
- # Sets the style of the font in use. Equivalent to the Text::Box
41
- # +style+ option, but we already have a style method.
42
- #
43
- def font_style=(style)
44
- @text_options[:style] = style
45
- end
46
-
47
- # Returns the width of this text with no wrapping. This will be far off
48
- # from the final width if the text is long.
49
- #
50
- def natural_content_width
51
- @natural_content_width ||= [styled_width_of(@content), @pdf.bounds.width].min
52
- end
53
-
54
- # Returns the natural height of this block of text, wrapped to the
55
- # preset width.
56
- #
57
- def natural_content_height
58
- with_font do
59
- b = text_box(:width => spanned_content_width + FPTolerance)
60
- b.render(:dry_run => true)
61
- b.height + b.line_gap
62
- end
63
- end
64
-
65
- # Draws the text content into its bounding box.
66
- #
67
- def draw_content
68
- with_font do
69
- @pdf.move_down((@pdf.font.line_gap + @pdf.font.descender)/2)
70
- with_text_color do
71
- text_box(:width => spanned_content_width + FPTolerance,
72
- :height => spanned_content_height + FPTolerance,
73
- :at => [0, @pdf.cursor]).render
74
- end
75
- end
76
- end
77
-
78
- def set_width_constraints
79
- # Sets a reasonable minimum width. If the cell has any content, make
80
- # sure we have enough width to be at least one character wide. This is
81
- # a bit of a hack, but it should work well enough.
82
- unless defined?(@min_width) && @min_width
83
- min_content_width = [natural_content_width, styled_width_of_single_character].min
84
- @min_width = padding_left + padding_right + min_content_width
85
- super
86
- end
87
- end
88
-
89
- protected
90
-
91
- def with_font
92
- @pdf.save_font do
93
- options = {}
94
- options[:style] = @text_options[:style] if @text_options[:style]
95
- options[:style] ||= @pdf.font.options[:style] if @pdf.font.options[:style]
96
-
97
- @pdf.font(defined?(@font) && @font || @pdf.font.family, options)
98
-
99
- yield
100
- end
101
- end
102
-
103
- def with_text_color
104
- if defined?(@text_color) && @text_color
105
- begin
106
- old_color = @pdf.fill_color || '000000'
107
- @pdf.fill_color(@text_color)
108
- yield
109
- ensure
110
- @pdf.fill_color(old_color)
111
- end
112
- else
113
- yield
114
- end
115
- end
116
-
117
- def text_box(extra_options={})
118
- if p = @text_options[:inline_format]
119
- p = [] unless p.is_a?(Array)
120
- options = @text_options.dup
121
- options.delete(:inline_format)
122
- options.merge!(extra_options)
123
- options[:document] = @pdf
124
-
125
- array = @pdf.text_formatter.format(@content, *p)
126
- ::Prawn::Text::Formatted::Box.new(array,
127
- options.merge(extra_options).merge(:document => @pdf))
128
- else
129
- ::Prawn::Text::Box.new(@content, @text_options.merge(extra_options).
130
- merge(:document => @pdf))
131
- end
132
- end
133
-
134
- # Returns the width of +text+ under the given text options.
135
- #
136
- def styled_width_of(text)
137
- @pdf.width_of(text, @text_options)
138
- end
139
-
140
- private
141
-
142
- # Returns the greatest possible width of any single character
143
- # under the given text options.
144
- # (We use this to determine the minimum width of a table cell)
145
- # (Although we currently determine this by measuring "M", it should really
146
- # use whichever character is widest under the current font)
147
- #
148
- def styled_width_of_single_character
149
- styled_width_of("M")
150
- end
151
- end
152
- end
153
- end
154
- end
@@ -1,255 +0,0 @@
1
- # encoding: utf-8
2
-
3
- # cells.rb: Methods for accessing rows, columns, and cells of a Prawn::Table.
4
- #
5
- # Copyright December 2009, Brad Ediger. All Rights Reserved.
6
- #
7
- # This is free software. Please see the LICENSE and COPYING files for details.
8
-
9
- module Prawn
10
- class Table
11
- # Selects the given rows (0-based) for styling. Returns a Cells object --
12
- # see the documentation on Cells for things you can do with cells.
13
- #
14
- def rows(row_spec)
15
- cells.rows(row_spec)
16
- end
17
- alias_method :row, :rows
18
-
19
- # Selects the given columns (0-based) for styling. Returns a Cells object
20
- # -- see the documentation on Cells for things you can do with cells.
21
- #
22
- def columns(col_spec)
23
- cells.columns(col_spec)
24
- end
25
- alias_method :column, :columns
26
-
27
- # Represents a selection of cells to be styled. Operations on a CellProxy
28
- # can be chained, and cell properties can be set one-for-all on the proxy.
29
- #
30
- # To set vertical borders only:
31
- #
32
- # table.cells.borders = [:left, :right]
33
- #
34
- # To highlight a rectangular area of the table:
35
- #
36
- # table.rows(1..3).columns(2..4).background_color = 'ff0000'
37
- #
38
- class Cells < Array
39
-
40
- # @group Experimental API
41
-
42
- # Limits selection to the given row or rows. +row_spec+ can be anything
43
- # that responds to the === operator selecting a set of 0-based row
44
- # numbers; most commonly a number or a range.
45
- #
46
- # table.row(0) # selects first row
47
- # table.rows(3..4) # selects rows four and five
48
- #
49
- def rows(row_spec)
50
- index_cells unless defined?(@indexed) && @indexed
51
- row_spec = transform_spec(row_spec, @first_row, @row_count)
52
- Cells.new(@rows[row_spec] ||= select { |c|
53
- row_spec.respond_to?(:include?) ?
54
- row_spec.include?(c.row) : row_spec === c.row })
55
- end
56
- alias_method :row, :rows
57
-
58
- # Returns the number of rows in the list.
59
- #
60
- def row_count
61
- index_cells unless defined?(@indexed) && @indexed
62
- @row_count
63
- end
64
-
65
- # Limits selection to the given column or columns. +col_spec+ can be
66
- # anything that responds to the === operator selecting a set of 0-based
67
- # column numbers; most commonly a number or a range.
68
- #
69
- # table.column(0) # selects first column
70
- # table.columns(3..4) # selects columns four and five
71
- #
72
- def columns(col_spec)
73
- index_cells unless defined?(@indexed) && @indexed
74
- col_spec = transform_spec(col_spec, @first_column, @column_count)
75
- Cells.new(@columns[col_spec] ||= select { |c|
76
- col_spec.respond_to?(:include?) ?
77
- col_spec.include?(c.column) : col_spec === c.column })
78
- end
79
- alias_method :column, :columns
80
-
81
- # Returns the number of columns in the list.
82
- #
83
- def column_count
84
- index_cells unless defined?(@indexed) && @indexed
85
- @column_count
86
- end
87
-
88
- # Allows you to filter the given cells by arbitrary properties.
89
- #
90
- # table.column(4).filter { |cell| cell.content =~ /Yes/ }.
91
- # background_color = '00ff00'
92
- #
93
- def filter(&block)
94
- Cells.new(select(&block))
95
- end
96
-
97
- # Retrieves a cell based on its 0-based row and column. Returns an
98
- # individual Cell, not a Cells collection.
99
- #
100
- # table.cells[0, 0].content # => "First cell content"
101
- #
102
- def [](row, col)
103
- return nil if empty?
104
- index_cells unless defined?(@indexed) && @indexed
105
- row_array, col_array = @rows[@first_row + row] || [], @columns[@first_column + col] || []
106
- if row_array.length < col_array.length
107
- row_array.find { |c| c.column == @first_column + col }
108
- else
109
- col_array.find { |c| c.row == @first_row + row }
110
- end
111
- end
112
-
113
- # Puts a cell in the collection at the given position. Internal use only.
114
- #
115
- def []=(row, col, cell) # :nodoc:
116
- cell.extend(Cell::InTable)
117
- cell.row = row
118
- cell.column = col
119
-
120
- if defined?(@indexed) && @indexed
121
- (@rows[row] ||= []) << cell
122
- (@columns[col] ||= []) << cell
123
- @first_row = row if !@first_row || row < @first_row
124
- @first_column = col if !@first_column || col < @first_column
125
- @row_count = @rows.size
126
- @column_count = @columns.size
127
- end
128
-
129
- self << cell
130
- end
131
-
132
- # Supports setting multiple properties at once.
133
- #
134
- # table.cells.style(:padding => 0, :border_width => 2)
135
- #
136
- # is the same as:
137
- #
138
- # table.cells.padding = 0
139
- # table.cells.border_width = 2
140
- #
141
- # You can also pass a block, which will be called for each cell in turn.
142
- # This allows you to set more complicated properties:
143
- #
144
- # table.cells.style { |cell| cell.border_width += 12 }
145
- #
146
- def style(options={}, &block)
147
- each do |cell|
148
- next if cell.is_a?(Cell::SpanDummy)
149
- cell.style(options, &block)
150
- end
151
- end
152
-
153
- # Returns the total width of all columns in the selected set.
154
- #
155
- def width
156
- widths = {}
157
- each do |cell|
158
- per_cell_width = cell.width_ignoring_span.to_f / cell.colspan
159
- cell.colspan.times do |n|
160
- widths[cell.column+n] = [widths[cell.column+n], per_cell_width].
161
- compact.max
162
- end
163
- end
164
- widths.values.inject(0, &:+)
165
- end
166
-
167
- # Returns minimum width required to contain cells in the set.
168
- #
169
- def min_width
170
- aggregate_cell_values(:column, :avg_spanned_min_width, :max)
171
- end
172
-
173
- # Returns maximum width that can contain cells in the set.
174
- #
175
- def max_width
176
- aggregate_cell_values(:column, :max_width_ignoring_span, :max)
177
- end
178
-
179
- # Returns the total height of all rows in the selected set.
180
- #
181
- def height
182
- aggregate_cell_values(:row, :height_ignoring_span, :max)
183
- end
184
-
185
- # Supports setting arbitrary properties on a group of cells.
186
- #
187
- # table.cells.row(3..6).background_color = 'cc0000'
188
- #
189
- def method_missing(id, *args, &block)
190
- if id.to_s =~ /=\z/
191
- each { |c| c.send(id, *args, &block) if c.respond_to?(id) }
192
- else
193
- super
194
- end
195
- end
196
-
197
- protected
198
-
199
- # Defers indexing until rows() or columns() is actually called on the
200
- # Cells object. Without this, we would needlessly index the leaf nodes of
201
- # the object graph, the ones that are only there to be iterated over.
202
- #
203
- # Make sure to call this before using @rows or @columns.
204
- #
205
- def index_cells
206
- @rows = {}
207
- @columns = {}
208
-
209
- each do |cell|
210
- @rows[cell.row] ||= []
211
- @rows[cell.row] << cell
212
-
213
- @columns[cell.column] ||= []
214
- @columns[cell.column] << cell
215
- end
216
-
217
- @first_row = @rows.keys.min
218
- @first_column = @columns.keys.min
219
-
220
- @row_count = @rows.size
221
- @column_count = @columns.size
222
-
223
- @indexed = true
224
- end
225
-
226
- # Sum up a min/max value over rows or columns in the cells selected.
227
- # Takes the min/max (per +aggregate+) of the result of sending +meth+ to
228
- # each cell, grouped by +row_or_column+.
229
- #
230
- def aggregate_cell_values(row_or_column, meth, aggregate)
231
- ColumnWidthCalculator.new(self).aggregate_cell_values(row_or_column, meth, aggregate)
232
- end
233
-
234
- # Transforms +spec+, a column / row specification, into an object that
235
- # can be compared against a row or column number using ===. Normalizes
236
- # negative indices to be positive, given a total size of +total+. The
237
- # first row/column is indicated by +first+; this value is considered row
238
- # or column 0.
239
- #
240
- def transform_spec(spec, first, total)
241
- case spec
242
- when Range
243
- transform_spec(spec.begin, first, total) ..
244
- transform_spec(spec.end, first, total)
245
- when Integer
246
- spec < 0 ? (first + total + spec) : first + spec
247
- when Enumerable
248
- spec.map { |x| first + x }
249
- else # pass through
250
- raise "Don't understand spec #{spec.inspect}"
251
- end
252
- end
253
- end
254
- end
255
- end