1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101
|
# frozen_string_literal: true
# prawn/view.rb : Implements a mixin for Prawn's DSL
#
# This is free software. Please see the LICENSE and COPYING files for details.
module Prawn
# This mixin allows you to create modular Prawn code without the
# need to create subclasses of Prawn::Document.
#
# class Greeter
# include Prawn::View
#
# # Optional override: allows you to set document options or even use
# # a custom document class
# def document
# @document ||= Prawn::Document.new(page_size: 'A4')
# end
#
# def initialize(name)
# @name = name
# end
#
# def say_hello
# text "Hello, #{@name}!"
# end
#
# def say_goodbye
# font("Courier") do
# text "Goodbye, #{@name}!"
# end
# end
# end
#
# greeter = Greeter.new("Gregory")
#
# greeter.say_hello
# greeter.say_goodbye
#
# greeter.save_as("greetings.pdf")
#
# The short story about why you should use this mixin rather than
# creating subclasses of +Prawn::Document+ is that it helps
# prevent accidental conflicts between your code and Prawn's
# code.
#
# Here's the slightly longer story...
#
# By using composition rather than inheritance under the hood, this
# mixin allows you to keep your state separate from +Prawn::Document+'s
# state, and also will prevent unexpected method name collisions due
# to late binding effects.
#
# This mixin is mostly meant for extending Prawn's functionality
# with your own additions, but you can also use it to replace or
# wrap existing Prawn methods. Calling +super+ will still work
# as expected, and alternatively you can explictly call
# +document.some_method+ to delegate to Prawn where needed.
module View
# @group Experimental API
# Lazily instantiates a +Prawn::Document+ object.
#
# You can also redefine this method in your own classes to use
# a custom document class.
def document
@document ||= Prawn::Document.new
end
# Delegates all unhandled calls to object returned by +document+ method.
# (which is an instance of Prawn::Document by default)
def method_missing(method_name, *arguments, &block)
return super unless document.respond_to?(method_name)
document.send(method_name, *arguments, &block)
end
def respond_to_missing?(method_name, _include_all = false)
document.respond_to?(method_name)
end
# Syntactic sugar that uses +instance_eval+ under the hood to provide
# a block-based DSL.
#
# greeter.update do
# say_hello
# say_goodbye
# end
#
def update(&block)
instance_eval(&block)
end
# Syntatic sugar that calls +document.render_file+ under the hood.
#
# greeter.save_as("greetings.pdf")
def save_as(filename)
document.render_file(filename)
end
end
end
|