簡體   English   中英

Ruby on Rails中的阻止調用

[英]Block call in Ruby on Rails

我正在嘗試清理我的代碼並擺脫許多丑陋的哈希值。 在我看來,我定義了以下幾種操作:

@actions = {
  :interest => {'Show interest', link_to(..), :disabled => true},
  :follow   => {'Follow this case', link_to(..)}
  ...
}

隨着這些哈希值的增長,可維護性下降。 我想將上述格式轉換為類似的格式:

actions do
   item :interest, 'Show interest', link_to(..), :disabled => true
   item :follow,   'Follow',        link_to(..)
   ...
end

我如何構造我的助手方法以允許這樣做? 優選地,“項目”方法應該僅在“動作”塊中可用,而不能在全局范圍內使用。

謝謝!

我認為這種技術被稱為“無塵室”,您在其中有一個匿名對象,其中包含您要調用的方法,因此該方法僅在您的塊中可用:

def actions(&block)
  cleanroom = Class.new{
    def item(*args)
      puts "these args were passed in: #{args.inspect}"
    end
  }
  cr = cleanroom.new
  cr.instance_eval &block
end

當然,此“ item”方法只是放置一些文本,但是您可以執行所需的任何操作。

actions do
  item "foo", "bar", "baz"
end  #=> these args were passed in: ["foo", "bar", "baz"]

我想做類似的事情,最后得到了一個復雜但非常有用的類,我將其命名為DslProxy。 它是我的延伸鐵寶石的一部分,但是歡迎您將其拉出並使用它,或者看看它是如何工作的。

DslProxy的文檔在這里: http ://rubydoc.info/gems/iron-extensions/1.1.2/DslProxy

github倉庫在這里: https : //github.com/irongaze/iron-extensions

基本上,做到這一點很難。 正如其他人指出的那樣,通常對元編程非常有用的instance_eval會丟失調用上下文/綁定,因此會丟失實例變量。 如果您想嵌套這些構建器調用,事情將變得更加艱巨。

這是我的DslProxy可以執行的操作的一個示例:

class ItemBuilder
  def actions(&block)
    @actions = []
    DslProxy.exec(self, &block)
    @actions
  end

  def item(*args)
    @actions << Item.new(*args)
  end
end

# ... in your view ...
<%
  @times = 5
  builder = ItemBuilder.new
  builder.actions do
    item :foo, link_to(...)
    @times.times do
      item :bob, link_to(...)
    end
  end
%>

調用上下文得以保留(例如,link_to調用工作),實例變量被傳播(例如,@ times可用),並且ItemBuilder實例定義的方法在沒有顯式接收器的情況下也可以使用(例如,對項目工作的調用符合預期)。

像所有元編程一樣,這很復雜。 您可能會發現在這里查看此類的規范很有幫助: https : //github.com/irongaze/iron-extensions/blob/master/spec/extensions/dsl_proxy_spec.rb

如有問題,請隨時與我聯系,或將問題發布到我的github跟蹤器。 :-)

這是一個類似的解決方案,實際上是在創建數據結構並避免在每次操作調用時都創建一個新類:

def action
  class << @actions ||= {}
    def item(name, *args) self[name] = args end
  end
  @actions.instance_eval(&Proc.new) if block_given?
  @actions
end

現在,您可以使用dsl來構建該結構:

actions do
  item :interest, 'Show interest', link_to(..), :disabled => true
end

actions # => { :interest => [ 'Show interest', link_to(..), :disabled => true ] }

actions.item :follow, 'Follow', link_to(..)

我進行了一些試驗,最終得出了一個目前可以使用的解決方案:

def actions(&block)
   @actions ||= []
   def item(id, content = '', options = {})
     @actions << [id, {
       :content => content || ''
     }.merge(options)]
   end
   block.call
end

就我而言,這可以使我執行以下操作:

actions do
  item :primary, link_to('Write letter', ...), :disabled => true
end

並且@ actions-variable填充了這些值。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM