2017-05-30 37 views
1

我将Prawn-RailsPrawnRailsForms一起扩展。我希望这些方法只能在给它们一些上下文的块中使用。例如,我的分机的使用可能看起来像:如何使用助手对象扩展Ruby库

field_row height: 25, units: 8 do 
    text_field field: 'Favorite fruit', # ... 
end 

这在底层工作在我的图书馆的方式是field_row方法实例化一个辅助对象,否则其他的方法,如text_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_row = nil,这让我觉得自己做错了一些事情。

回答

2

有没有更好的方法来确保我的方法只能在正确的上下文中运行,例如,当FieldRow对象可用时?

API,如这通常使用instance_eval从而使块内的方法被称为实例化对象:

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 

...它将使用height:units:实例化FieldRow对象,然后在该对象上调用text_field


如果您需要FieldRow对文档本身进行操作,您可以采取几种方法。一个是刚刚通过self(文档对象)FieldRow的构造函数,并将其存储在一个实例变量,其中供text_field等:

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

你也可以定义上FieldRow的方法到您传递文档目的。在这种情况下,FieldRow的方法(例如text_field)“配置”输出和render(或您选择调用它的任何内容)实际上会创建输出。

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

我会提醒不要向Document添加一堆方法。由于text_field只适用于field_row,因此在text_field上使用Document实例方法并没有什么意义(并且,正如您发现的那样,它有一些疑难解答)。

+0

嗯,除了'text_field'需要是'PrawnRails :: Document'的实例方法,以便它可以在文档上操作(创建框,添加文本,样式等)。 – dfaulken

+0

@dfaulken您可能希望了解一下Prawn本身是如何实现类似的方法的,因为它可能有一个既定的约定(或者甚至可以搭载一些方便的功能),但我已经编辑了我的答案以包含几个可能的解决方案。 –

+0

这是一个很好的建议。感谢您分享这么多想法! – dfaulken