如何重构多次使用“instance_exec”的代码?
How do I refactor code that uses `instance_exec` several times?
我正在研究使用 Prawn gem 生成 PDF 的 class。我有一些类似的方法。它们都以同一行开头。这是代码:
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
有没有办法在每个方法中避免 @output.instance_exec
并使用类似块的东西?我试过了,但我无法让它工作。我可以做这样的事情吗?
def apply
@output.instance_exec do
yield
end
end
我应该如何定义代码块?
首先,您需要将所有辅助方法制作成 return lambda
实例:
def defaults
lambda do
font_size 16
text 'hola'
end
end
现在您可以将助手 return 编辑的 lambda 传递给 instance_exec
。要承认“这是代码块而不是常规参数”,lambda 应以 & 符号为前缀:
def apply
# ⇓ NB! codeblock is passed!
@output.instance_exec &defaults
end
如果您想将代码块传递给 apply
,您应该将其重新传递给 instance_exec
。不幸的是,我不知道如何使用 yield
关键字重新传递它,但这里有一个技巧: Proc.new
在使用给定代码块调用的方法中调用时没有参数,使用此代码块实例化,所以给你:
def apply
raise 'Codeblock expected' unless block_given?
@output.instance_exec &Proc.new
end
您可以定义一个 document
方法 returns 一个 Prawn::Document
实例。
Prawn::View
然后会将方法调用委托给该文档。这是一个例子:
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
用法示例:
pdf = PDFGenerator::MatchTeamInfo.new(nil)
pdf.save_as('team_info.pdf')
输出:(转换为 PNG)
我正在研究使用 Prawn gem 生成 PDF 的 class。我有一些类似的方法。它们都以同一行开头。这是代码:
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
有没有办法在每个方法中避免 @output.instance_exec
并使用类似块的东西?我试过了,但我无法让它工作。我可以做这样的事情吗?
def apply
@output.instance_exec do
yield
end
end
我应该如何定义代码块?
首先,您需要将所有辅助方法制作成 return lambda
实例:
def defaults
lambda do
font_size 16
text 'hola'
end
end
现在您可以将助手 return 编辑的 lambda 传递给 instance_exec
。要承认“这是代码块而不是常规参数”,lambda 应以 & 符号为前缀:
def apply
# ⇓ NB! codeblock is passed!
@output.instance_exec &defaults
end
如果您想将代码块传递给 apply
,您应该将其重新传递给 instance_exec
。不幸的是,我不知道如何使用 yield
关键字重新传递它,但这里有一个技巧: Proc.new
在使用给定代码块调用的方法中调用时没有参数,使用此代码块实例化,所以给你:
def apply
raise 'Codeblock expected' unless block_given?
@output.instance_exec &Proc.new
end
您可以定义一个 document
方法 returns 一个 Prawn::Document
实例。
Prawn::View
然后会将方法调用委托给该文档。这是一个例子:
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
用法示例:
pdf = PDFGenerator::MatchTeamInfo.new(nil)
pdf.save_as('team_info.pdf')
输出:(转换为 PNG)