Reputation: 99
I'm working on a class that generates a PDF using Prawn gem. I have some similar methods. All of them start with the same line. Here is the code:
module PDFGenerator
class MatchTeamInfo
include Prawn::View
def initialize(match)
@match = match
@output = Prawn::Document.new page_layout: :landscape
defaults
header
footer
end
def render
@output.render
end
def defaults
@output.instance_exec do
font_size 16
text 'hola'
end
end
def header
@output.instance_exec do
bounding_box [bounds.left, bounds.top], :width => bounds.width do
text "Fulbo", align: :center, size: 32
stroke_horizontal_rule
move_down(5)
end
end
end
def footer
@output.instance_exec do
bounding_box [bounds.left, bounds.bottom + 25], :width => bounds.width do
stroke_horizontal_rule
move_down(5)
text "Tu sitio favorito!", align: :center
end
end
end
end
end
Is there a way to avoid @output.instance_exec
in every method and use something like blocks? I tried it, but I can't get it work. Can I do something like this?
def apply
@output.instance_exec do
yield
end
end
How am I supposed to define the code blocks?
Upvotes: 1
Views: 74
Reputation: 114138
You can define a method document
that returns a Prawn::Document
instance.
Prawn::View
will then delegated the method calls to that document. Here's an example:
module PDFGenerator
class MatchTeamInfo
include Prawn::View
def initialize(match)
@match = match
defaults
header
footer
end
def document
@document ||= Prawn::Document.new page_layout: :landscape
end
def defaults
font_size 16
text 'hola'
end
def header
bounding_box [bounds.left, bounds.top], :width => bounds.width do
text "Fulbo", align: :center, size: 32
stroke_horizontal_rule
move_down(5)
end
end
def footer
bounding_box [bounds.left, bounds.bottom + 25], :width => bounds.width do
stroke_horizontal_rule
move_down(5)
text "Tu sitio favorito!", align: :center
end
end
end
end
Example usage:
pdf = PDFGenerator::MatchTeamInfo.new(nil)
pdf.save_as('team_info.pdf')
Output: (converted to PNG)
Upvotes: 2
Reputation: 120990
First of all, you need to make all helper methods to return lambda
instance:
def defaults
lambda do
font_size 16
text 'hola'
end
end
Now you might pass lambdas returned by your helpers to instance_exec
. To acknowledge it about “this is code block rather than regular param,” lambda is to be prefixed with ampersand:
def apply
# ⇓ NB! codeblock is passed!
@output.instance_exec &defaults
end
If you want to pass a codeblock to apply
, you should re-pass it to instance_exec
. Unfortunately I know no way to re-pass it using yield
keyword, but here is a trick: Proc.new
called without parameters inside a method that was called with a codeblock given, is instantiated with this codeblock, so here you go:
def apply
raise 'Codeblock expected' unless block_given?
@output.instance_exec &Proc.new
end
Upvotes: 2