1

我正在研究一个使用 Prawn gem 生成 PDF 的类。我有一些类似的方法。所有这些都以同一行开头。这是代码:

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

我应该如何定义代码块?

4

2 回答 2

2

首先,您需要使所有辅助方法返回lambda实例:

def defaults
  lambda do
    font_size 16
    text 'hola'
  end
end

现在您可以将助手返回的 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
于 2015-09-24T05:42:58.130 回答
2

您可以定义一个document返回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)

team_info.pdf

于 2015-09-24T07:42:49.427 回答