一個巢穴,二十種Ruby DSL(7)

發表于:2013-02-28來源:圖靈社區作者:Martin Fowler點擊數: 標簽:
[:item, :small_power_plant, [:provides, [:electricity, 11]], [:depends_on, :secure_air_vent]]] 可變參數方法 有些語言支持可變參數方法,此時在函數調用中使用字面量列表是一

  [:item, :small_power_plant,

  [:provides, [:electricity, 11]],

  [:depends_on, :secure_air_vent]]]

  可變參數方法

  有些語言支持可變參數方法,此時在函數調用中使用字面量列表是一種很有用的技術。在下面的代碼中,我把這種方式應用于uses方法。

  下載 lairs/rules24.rb

  item :secure_air_vent

  item(:acid_bath) do

  uses(acid(:type => :hcl, :grade => 5),

  electricity(12))

  end

  item(:camera) do

  uses(electricity(1))

  end

  item(:small_power_plant) do

  provides(electricity(11))

  depends_on(:secure_air_vent)

  end

  在這種需要把方法調用中的列表組合在一起的情況下,使用可變參數是非常趁手的——尤其是當語言對在何處放置字面量列表限制得非常嚴格時。

  3.7 動態接收

  動態編程語言的一個特性是:它能對沒有在接收對象里定義的方法調用進行響應。

  讓我們在這個例子中探索一下這句話的含義。到目前為止,我們假設巢穴里的資源數量是相對固定的,我們可以編寫相應的代碼來處理這些固定數量的資源。但如果不是假設的這種情況呢?如果有很多資源呢?如果需要把非常多的資源置于配置中呢?

  下載 lairs/rules23.rb

  resource :electricity, :power

  resource :acid, :type, :grade

  item :secure_air_vent

  item(:acid_bath).

  uses(acid(:type => :hcl, :grade => 5)).

  uses(electricity(:power => 12))

  item(:camera).

  uses(electricity(:power => 1))

  item(:small_power_plant).

  provides(electricity(:power => 11)).

  depends_on(:secure_air_vent)

  electricity和acid仍舊是生成器中的方法。我希望這些方法可以創建新定義的資源,但我不希望去定義這些方法,而是希望它們能夠根據資源的數據來自動創建。

  在Ruby中可以通過重寫method_missing方法來實現。在Ruby中,如果一個對象接收了一個沒有定義的方法調用,那么它就會執行method_missing方法。這個方法默認是從Object類中繼承而來,而且會拋出一個異常。我們可以通過重寫這個方法來做一些有趣的事情。

  首先做好對資源方法調用的準備工作。

  下載 lairs/builder23.rb

  def resource name, *attributes

  attributes << :name

  new_resource = Struct.new(*attributes)

  @configuration.add_resource_type name, new_resource

  end

  Ruby有一個用來創建匿名類的工具,叫做struct。當需要一個資源時,調用struct進行定義。以resource方法的第一個參數作為新定義資源的名字,并根據隨后的參數設置新定義資源的屬性(property)。然后把這些新定義的資源保存于配置中。

  接著我重寫了method_missing方法。該方法在一個字面量字典中遍歷了所有新定義的資源,以確定方法名是否與新的struct之一對應。如果有,則加載這個struct。

  下載 lairs/builder23.rb

  def method_missing sym, *args

  super sym, *args unless @configuration.resource_names.include? sym

  obj = @configuration.resource_type(sym).new

  obj[:name] = sym

  args[0].each_pair do |key, value|

  obj[key] = value

  end

  return obj

  end

  在method_missing被調用時,首先確認是否有資源可以響應這個調用。如果沒有,則調用超類中的method_missing以引發一個異常。

  大多數動態語言都可以重寫“處理未知調用的方法”。這是一個很強大的技術,但在使用時需要格外小心,因為它會改變程序方法分派系統的機制。如果沒有合理使用,代碼會變得難以理解。

  Ruby的生成器庫(由Jim Weirich編寫)就是一個如何正確使用method_missing的好例子。生成器庫是用來生成XML標記的,它非常合理地使用了閉包和method_missing。

  可以通過一個簡單的例子來說明這一點。如下代碼,

  下載 lairs/frags

  Builder::XmlMarkup.new("" , 2)

  puts builder.person do |b|

  b.name("jim")

  b.phone("555-1234" , "local" =>"yes")

  b.address("Cincinnati")

  end

  會生成下面這段標記。

  下載 lairs/frags

  

  jim

  555-1234

  

Cincinnati

  

  3.8 總結

  兩年之前,Dave Thomas在他的博客中提及“代碼拆招”(code katas)的概念:在嘗試使用各種方法來解決一個簡單問題的過程中,研究和比較各種解決方案的優劣。本章就是這樣的一個練習。最后我也沒有給出任何確定的結論,但它確實帶著我們探討和領略了用Ruby編寫內部DSL的各種方法(當然,大部分方法也可以通過其他語言來實現)。

原文轉自:http://www.ituring.com.cn/article/17818

国产97人人超碰caoprom_尤物国产在线一区手机播放_精品国产一区二区三_色天使久久综合给合久久97