如何使用helper对象扩展Ruby库

如何使用helper对象扩展Ruby库,ruby,Ruby,我正在和你一起扩展。我希望这些方法只能在给它们一些上下文的块中使用。例如,my extension的用法可能如下所示: field_row height: 25, units: 8 do text_field field: 'Favorite fruit', # ... end 在我的库中,它的工作方式是field\u row方法实例化一个helper对象,没有它,其他方法,如text\u field,就不会运行: class FieldRow # ... end class Pra

我正在和你一起扩展。我希望这些方法只能在给它们一些上下文的块中使用。例如,my extension的用法可能如下所示:

field_row height: 25, units: 8 do
  text_field field: 'Favorite fruit', # ...
end
在我的库中,它的工作方式是
field\u row
方法实例化一个helper对象,没有它,其他方法,如
text\u field
,就不会运行:

class FieldRow
  # ...
end

class PrawnRails::Document

  attr_accessor :field_row # my helper object

  def field_row(height:, units:, &block)
     @field_row = FieldRow.new #...
     block.call
     @field_row = nil
  end

  def text_field(**args)
    unless @field_row.present?
      raise ArgumentError, 'Must be inside a field row'
    end
    # implementation which relies on @field_row...
  end
end
是否有更好的方法确保我的方法仅在
FieldRow
对象可用时运行?特别是,在
block.call
之后必须写入
@field\u row=nil
,这让我觉得自己做得不对

是否有更好的方法确保我的方法仅在适当的上下文中运行,例如当
FieldRow
对象可用时

这样的API通常用于在实例化对象上调用块内的方法:

module PrawnRailsForms
  class FieldRow
    def initialize(height:, units:, **)
      # ...
    end

    def text_field(field:, **)
      # ...
    end
  end

  module Document
    def field_row(**args, &block)
      @field_row = FieldRow.new(**args)
      @field_row.instance_eval(&block) unless block.nil?
      @field_row
    end
  end

  ::PrawnRails::Document.include(Document)
end
现在,当您执行此操作时:

doc.field_row(height: 25, units: 8) do
  text_field field: 'Favorite fruit'
end
…它将实例化一个具有
高度:
单位:
的FieldRow对象,然后在该对象上调用
text\u field


如果需要FieldRow对文档本身进行操作,可以采取以下几种方法。一种方法是将
self
(文档对象)传递给FieldRow的构造函数,并将其存储在其中的实例变量中,供
text\u field
等使用:

def field_row(**args, &block)
  row = FieldRow.new(self, **args)
  row.instance_eval(&block) unless block.nil?
end
您还可以在FieldRow上定义一个方法,将文档对象传递给该方法。在这种情况下,FieldRow的方法(例如,
text\u field
)“配置”输出,并
render
(或您选择的任何方法)实际创建输出

def field_row(**args, &block)
  row = FieldRow.new(**args)
  row.instance_eval(&block) unless block.nil?
  row.render(self)
end

我要提醒大家不要在文档中添加一堆方法。由于
text\u字段
仅在
field\u行
的上下文中起作用,因此将
text\u字段
作为文档的实例方法是没有意义的(并且,正如您所发现的,它有一些缺陷)。

Hmm,除了
text\u字段
需要是
PrawnRails::Document
的实例方法之外,因此,它可以对文档进行操作(创建框、添加文本、样式等)。@dfaulken您可能希望探索Prawn本身是如何实现类似方法的,因为它可能有一个既定的约定(甚至是一些方便的功能,您可以借助它),但是我编辑了我的答案,加入了一些可能的解决方案。这是一个很好的建议。谢谢你分享这么多的想法!