lib/prawn/document.rb in prawn-0.14.0 vs lib/prawn/document.rb in prawn-0.15.0
- old
+ new
@@ -5,10 +5,11 @@
# Copyright April 2008, Gregory Brown. All Rights Reserved.
#
# This is free software. Please see the LICENSE and COPYING files for details.
require "stringio"
+
require_relative "document/bounding_box"
require_relative "document/column_box"
require_relative "document/internals"
require_relative "document/span"
require_relative "document/snapshot"
@@ -60,10 +61,12 @@
include Prawn::Graphics
include Prawn::Images
include Prawn::Stamp
include Prawn::SoftMask
+ # @group Extension API
+
# NOTE: We probably need to rethink the options validation system, but this
# constant temporarily allows for extensions to modify the list.
VALID_OPTIONS = [:page_size, :page_layout, :margin, :left_margin,
:right_margin, :top_margin, :bottom_margin, :skip_page_creation,
@@ -88,18 +91,32 @@
#
# Prawn::Document.generate("foo.pdf") do
# party!
# end
#
+ #
def self.extensions
@extensions ||= []
end
- def self.inherited(base) #:nodoc:
+ # @private
+ def self.inherited(base)
extensions.each { |e| base.extensions << e }
end
+ # @group Stable Attributes
+
+ attr_accessor :margin_box
+ attr_reader :margins, :y
+ attr_accessor :page_number
+
+ # @group Extension Attributes
+
+ attr_accessor :text_formatter
+
+ # @group Stable API
+
# Creates and renders a PDF document.
#
# When using the implicit block form, Prawn will evaluate the block
# within an instance of Prawn::Document, simplifying your syntax.
# However, please note that you will not be able to reference variables
@@ -213,32 +230,12 @@
if block
block.arity < 1 ? instance_eval(&block) : block[self]
end
end
- attr_accessor :margin_box
- attr_reader :margins, :y
- attr_writer :font_size
- attr_accessor :page_number
- attr_accessor :text_formatter
+ # @group Stable API
- def state
- @internal_state
- end
-
- def page
- state.page
- end
-
- def initialize_first_page(options)
- if options[:skip_page_creation]
- start_new_page(options.merge(:orphan => true))
- else
- start_new_page(options)
- end
- end
-
# Creates and advances to a new page in the document.
#
# Page size, margins, and layout can also be set when generating a
# new page. These values will become the new defaults for page creation
#
@@ -354,10 +351,13 @@
# Renders the PDF document to string.
# Pass an open file descriptor to render to file.
#
def render(output = StringIO.new)
+ if output.instance_of?(StringIO)
+ output.set_encoding(::Encoding::ASCII_8BIT)
+ end
finalize_all_page_contents
render_header(output)
render_body(output)
render_xref(output)
@@ -410,10 +410,11 @@
@bounding_box
end
# Returns the innermost non-stretchy bounding box.
#
+ # @private
def reference_bounds
@bounding_box.reference_bounds
end
# Sets Document#bounds to the BoundingBox provided. See above for a brief
@@ -495,51 +496,10 @@
#
def indent(left, right = 0, &block)
bounds.indent(left, right, &block)
end
-
- def mask(*fields) # :nodoc:
- # Stores the current state of the named attributes, executes the block, and
- # then restores the original values after the block has executed.
- # -- I will remove the nodoc if/when this feature is a little less hacky
- stored = {}
- fields.each { |f| stored[f] = send(f) }
- yield
- fields.each { |f| send("#{f}=", stored[f]) }
- end
-
- # Attempts to group the given block vertically within the current context.
- # First attempts to render it in the current position on the current page.
- # If that attempt overflows, it is tried anew after starting a new context
- # (page or column). Returns a logically true value if the content fits in
- # one page/column, false if a new page or column was needed.
- #
- # Raises CannotGroup if the provided content is too large to fit alone in
- # the current page or column.
- #
- def group(second_attempt=false)
- old_bounding_box = @bounding_box
- @bounding_box = SimpleDelegator.new(@bounding_box)
-
- def @bounding_box.move_past_bottom
- raise RollbackTransaction
- end
-
- success = transaction { yield }
-
- @bounding_box = old_bounding_box
-
- unless success
- raise Prawn::Errors::CannotGroup if second_attempt
- old_bounding_box.move_past_bottom
- group(second_attempt=true) { yield }
- end
-
- success
- end
-
# Places a text box on specified pages for page numbering. This should be called
# towards the end of document creation, after all your content is already in
# place. In your template string, <page> refers to the current page, and
# <total> refers to the total amount of pages in the document. Page numbering should
# occur at the end of your Prawn::Document.generate block because the method iterates
@@ -608,10 +568,50 @@
end
pseudopage += 1 if start_count
end
end
+ # Returns true if content streams will be compressed before rendering,
+ # false otherwise
+ #
+ def compression_enabled?
+ !!state.compress
+ end
+
+ # @group Experimental API
+
+ # Attempts to group the given block vertically within the current context.
+ # First attempts to render it in the current position on the current page.
+ # If that attempt overflows, it is tried anew after starting a new context
+ # (page or column). Returns a logically true value if the content fits in
+ # one page/column, false if a new page or column was needed.
+ #
+ # Raises CannotGroup if the provided content is too large to fit alone in
+ # the current page or column.
+ #
+ def group(second_attempt=false)
+ old_bounding_box = @bounding_box
+ @bounding_box = SimpleDelegator.new(@bounding_box)
+
+ # @private
+ def @bounding_box.move_past_bottom
+ raise RollbackTransaction
+ end
+
+ success = transaction { yield }
+
+ @bounding_box = old_bounding_box
+
+ unless success
+ raise Prawn::Errors::CannotGroup if second_attempt
+ old_bounding_box.move_past_bottom
+ group(second_attempt=true) { yield }
+ end
+
+ success
+ end
+
# Provides a way to execute a block of code repeatedly based on a
# page_filter.
#
# Available page filters are:
# :all repeats on every page
@@ -633,18 +633,45 @@
when Proc
page_filter.call(page_number)
end
end
+ # @private
+
+ def mask(*fields)
+ # Stores the current state of the named attributes, executes the block, and
+ # then restores the original values after the block has executed.
+ # -- I will remove the nodoc if/when this feature is a little less hacky
+ stored = {}
+ fields.each { |f| stored[f] = send(f) }
+ yield
+ fields.each { |f| send("#{f}=", stored[f]) }
+ end
- # Returns true if content streams will be compressed before rendering,
- # false otherwise
- #
- def compression_enabled?
- !!state.compress
+ # @group Extension API
+
+ def initialize_first_page(options)
+ if options[:skip_page_creation]
+ start_new_page(options.merge(:orphan => true))
+ else
+ start_new_page(options)
+ end
end
+ ## Internals. Don't depend on them!
+
+ # @private
+ def state
+ @internal_state
+ end
+
+ # @private
+ def page
+ state.page
+ end
+
private
+
# setting override_settings to true ensures that a new graphic state does not end up using
# previous settings.
def use_graphic_settings(override_settings = false)
set_fill_color if current_fill_color != "000000" || override_settings