-
Notifications
You must be signed in to change notification settings - Fork 689
/
view.rb
116 lines (109 loc) · 3.14 KB
/
view.rb
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
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
# frozen_string_literal: true
module Prawn
# This mixin allows you to create modular Prawn code without the
# need to create subclasses of {Prawn::Document}.
#
# ```ruby
# 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 explicitly 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.
#
# @return [Prawn::Dcoument]
def document
@document ||= Prawn::Document.new
end
# Delegates all unhandled calls to object returned by {document} method.
#
# @param method_name [Symbol]
# @param args [Array] Positional arguments.
# @param kwargs [Hash] Keyword arguments.
# @param block [Proc]
def method_missing(method_name, *args, **kwargs, &block)
return super unless document.respond_to?(method_name)
document.public_send(method_name, *args, **kwargs, &block)
end
# Does this object respond to the specified message?
#
# @param method_name [Symbol]
# @param _include_all [Boolean]
# @return [Boolean]
def respond_to_missing?(method_name, _include_all = false)
document.respond_to?(method_name) || super
end
# Syntactic sugar that uses `instance_eval` under the hood to provide
# a block-based DSL.
#
# @example
# greeter.update do
# say_hello
# say_goodbye
# end
#
# @yield
# @return [void]
def update(&block)
instance_eval(&block)
end
# Syntatic sugar that calls `document.render_file` under the hood.
#
# @example
# greeter.save_as("greetings.pdf")
#
# @param filename [String]
# @return [void]
def save_as(filename)
document.render_file(filename)
end
end
end