2015-05-04 80 views
2

我試圖執行custom attribute accessors with validationRuby:自定義實現屬性訪問器驗證

比方說attr_validated。現在這個attr_validated

1:應該有與attr_accessor相同的setter和getter方法。 ##這部分完成

2:它應該驗證給定的塊。

attr_validated :num_legs do |v| 
v <= 4 
end 

這個問題可能看起來像任何其他問題,但它不是。 雖然google搜索,我得到

1: IST部分

class Class 
    def attr_validated(*args) 
    args.each do |arg| 
     # getter 
     self.class_eval("def #{arg};@#{arg};end") 
     # setter 
     self.class_eval("def #{arg}=(val);@#{arg}=val;end") 
    end 
    end 
end 

class Dog 
    attr_validated :num_legs ## Instead of this i need to validate a block also attr_validated :num_legs do |v| 
v <= 4 
end 

dog = Dog.new 
p dog.num_legs 
p dog.num_legs = 'Stack' 

2:我們該如何實施第二部分

任何幫助將不勝感激!!!

回答

4

怎麼是這樣的:

class Class 
    def attr_validated(*args, &validator) 
    args.each do |name| 
     define_method("#{name}=") do |value| 
     if block_given? 
      raise ArgumentError, "Value '#{value}' is invalid" unless validator.call(value) 
     end 

     instance_variable_set("@#{name}", value) 
     end 

     define_method(name) do 
     instance_variable_get("@#{name}") 
     end 
    end 
    end 
end 

class Person 
    attr_validated(:name, :occupation) { |name| name.length > 3 } 
end 

p1 = Person.new 
p1.name = "John The Tester" 
p1.occupation = "Software developer" 
p "#{p1.name} - #{p1.occupation}" 

p2 = Person.new 
p2.name = "test" 
p2.occupation = "Tester" 
p "#{p2.name} - #{p2.occupation}" 

這會產生這樣的輸出:

"John The Tester - Software developer" 
app.rb:6:in `block (2 levels) in attr_validated': Value 'test' is invalid (ArgumentError) 
     from app.rb:28:in `<main>' 

希望這有幫助!

祝你好運!

UPDATE

您可以添加另一種方法,將應用驗證的第一個參數是這樣的:

class Class 
    def attr_validated_first(*args, &validator) 
    args.each_with_index do |name, index| 
     define_method("#{name}=") do |value| 
     if block_given? && index == 0 
      raise ArgumentError, "Value '#{value}' is invalid" unless validator.call(value) 
     end 

     instance_variable_set("@#{name}", value) 
     end 

     define_method(name) do 
     instance_variable_get("@#{name}") 
     end 
    end 
    end 
end 

但是我不推薦這種方法,這將是混亂!如果你想用不同的驗證規則註冊幾個屬性......您可以使用attr_validated從第一個例子多次,像這樣:

class Person 
    attr_validated(:name)  { |name| name.length > 3 } 
    attr_validated(:occupation) { |occupation| occupation == "Ruby Developer" } 
end 
+0

許多許多謝謝@PawełDawczak ..它解決了我的問題。仍然我有一件事,塊條件將適用於每一個屬性..我們可以只爲第一參數.. – VKatz

+0

@Vinay - 請檢查更新的答案 –

+0

@Vinay通常這樣的方法適用於塊條件的所有項目,不只是第一個,至少是由Rails的約定來規定的。如果您需要更有選擇性地應用它們,請進行多個「attr_validated」調用,其中一個調用塊,另一個不調用。您可能還想採用如下模式:'attr_validated:example,with: - > {| v | v.length> 6}'作爲lambda傳入。 – tadman

3

這很簡單。只是raise在二傳手的ArgumentError如果塊說的論據是無效:

class Person 
    attr_reader :name 

    def name=(name) 
    raise ArgumentError, "'#{name}' is not a valid name!" if rejector.(name) 
    @name = name 
    end 

    private 

    attr_accessor :rejector 

    def initialize(&rejector) 
    self.rejector = rejector 
    end 
end 

artist = Person.new do |person| 
    person.length > 6 
end 

artist.name = 'The Artist Formerly Known As Prince' 
# ArgumentError: 'The Artist Formerly Known As Prince' is not a valid name! 
artist.name = 'ruby' 
# => 'ruby' 
+0

能否請您解釋一下..what self.rejector =剔除在這裏做..As我知道剔除是一個進程內對象和自我是人的對象..那麼什麼是在引擎蓋下.. – Tyshawn

+0

當我改變了問題。並感謝您的上一個答案。你能幫忙解決這個問題嗎?在此先感謝 – Tyshawn