2012-07-02 104 views
4

設置我想知道什麼是Ruby中規範的方法來創建自定義的setter和getter方法。通常情況下,我會通過attr_accessor來做到這一點,但我正在創建一個DSL。在DSL,setter方法被稱爲像這樣(使用=符號將創建本地變量):因此紅寶石獲得在一個方法

work do 
duration 15 
priority 5 
end 

,他們必須這樣實現:

def duration(dur) 
@duration = dur 
end 

然而,這使得實現吸氣劑有點棘手:創建一個名稱相同但沒有參數的方法只會覆蓋setter。

所以我寫這兩者都做了設置和獲取自定義的方法:

def duration(dur=nil) 
return @duration = dur if dur 
return @duration if @duration 
raise AttributeNotDefinedException, "Attribute '#{__method__}' hasn't been set" 
end 

這是一個很好的路要走呢?下面是與測試用例要點:

Ruby Custom Getters & Setters

謝謝!

回答

9

更爲棘手的情況是,如果你想設置設置@durationnil持續時間爲零。我能想到的這樣

def duration(*args) 
    @duration = args.first unless args.empty? 
    @duration 
end 

讓人們通過任何數量的參數的個數,並決定,基於數做什麼的兩種方式。如果傳遞多個參數,您也可以引發異常。

另一種方式是

def duration(value = (getter=true;nil)) 
    @duration = value unless getter 
    @duration 
end 

這利用缺省參數一點:它們可以是幾乎任何表情。

當不帶參數調用getter設置爲true時,但當提供參數(即使它是nil)時,不評估默認值。由於局部變量範圍的工作原理getter最終爲零。

可能有點聰明,但方法身體本身​​更清潔。

+0

這可能是「聰明」,但它是一個相當知名的習慣用法,所以我肯定會讓它在代碼審查中滑動。 –

+0

謝謝,這些都是很棒的點子。我沒有用於將值設置爲零的用例,但無論如何,最好知道如何覆蓋它。 – abbottjam

0

這似乎沒什麼問題,但你如果該值尚未設置引發錯誤似乎很奇怪。這是我通常會做:

def duration(dur=nil) 
@duration = dur if dur 
@duration 
end 

然而,這是一個簡單的方法,因爲這意味着你不能只用這種方法

+0

不是錯誤(這將是過於劇烈),但一個例外,即輸入不是非法的,而是錯誤的。我更喜歡引發異常返回nil的原因是它不會傳播給調用者並立即被發現,而不是在nil上調用方法時。 [看這個截屏](https://www.destroyallsoftware.com/screencasts/catalog/how-and-why-to-avoid-nil) – abbottjam

2

這樣的事情,我寧願底層類從DSL分離。也就是說,製作一個Work類,它具有通常的訪問器,即durationduration=。不管你想要通過DSL使用你的工作類

class AccessorMultiplexer 

    def initialize(target) 
    @target = target 
    end 

    def method_missing(method, *args) 
    method = "#{method}=" unless args.empty? 
    @target.send method, *args 
    end 

end 

,你會用它包裝:並通過DSL使用這個類,用的東西,可以situationally調用存取器,這樣換工作實例AccessorMultiplexer.new(work)

如果您反對包裝器中的元編程,您可以始終創建一個特定的WorkDSL包裝器,但不使用method_missing。但它會保持分離並保持你的Work類不受DSL語法怪癖的污染。您可能希望在您的代碼中的其他位置使用Work類,而DSL會妨礙您的工作。在耙子或腳本或 - 誰知道。

(從我的回答改編上codereview。)

+0

我喜歡分離的想法,所以我會追求這些想法。但是,你會用什麼來代替WorkDSL包裝中的'method_missing'?我寧願不使用這種方法 - 對於這種情況看起來太「全面」了。謝謝! – abbottjam

0

我通常做這個

def duration dur='UNDEFINED' 
    @duration = dur if dur != 'UNDEFINED' 
    @duration 
end 

你可以用你喜歡的東西取代未定義