2013-10-27 14 views
2

我正在用一個Product類的Ruby編寫一個程序。每當使用錯誤類型的參數初始化Product時,我都會引發一些異常。有沒有一種方法可以幹掉我提出的例外情況(我甚至可以正確引用那些例外情況?)我很感激這種幫助。代碼如下:如何在初始化方法中幹掉我的ruby異常?

class Product 
    attr_accessor :quantity, :type, :price, :imported 

    def initialize(quantity, type, price, imported) 
    raise ArgumentError.new("Type must be a string") if type.class != String 
    raise ArgumentError.new("Quantity must be greater than zero") if quantity <= 0 
    raise ArgumentError.new("Price must be a float") if price.class != Float 

    @quantity = quantity 
    @type  = type 
    @price = price.round(2) 
    @imported = imported 
    end 
end 

回答

4

慣用的方法是不行的類型檢查在所有的,而是強制的傳遞的對象(使用to_sto_f等):

class Product 
    attr_accessor :quantity, :type, :price, :imported 

    def initialize(quantity, type, price, imported) 
    raise ArgumentError.new("Quantity must be greater than zero") unless quantity > 0 

    @quantity = quantity 
    @type  = type.to_s 
    @price = price.to_f.round(2) 
    @imported = imported 
    end 
end 

然後你會得到適當的String/Float /等。傳遞對象的表示形式,以及如果他們不知道如何強制這些類型(因爲他們不響應該方法),那麼您將適當地得到一個NoMethodError。

至於在數量上的檢查,這看起來很像一個驗證,你可能要拔出到一個單獨的方法(特別是如果獲得是他們中的很多):

class Product 
    attr_accessor :quantity, :type, :price, :imported 

    def initialize(quantity, type, price, imported) 
    @quantity = quantity 
    @type  = type.to_s 
    @price = price.to_f.round(2) 
    @imported = imported 

    validate! 
    end 

    private 

    def validate! 
    raise ArgumentError.new("Quantity must be greater than zero") unless @quantity > 0 
    end 
end 
+0

謝謝安德魯 - 超快速的反應,非常有幫助! – Brian

+0

嘿@AndrewMarshall,我想知道你是否可以解釋爲什麼我們在'驗證'方法中包含爆炸的原因? – Brian

+0

@Brian只是因爲它在「false」的情況下引發了一個異常。這個約定來自Rails,但通常只在那裏使用(我認爲)當有非禁止版本時。 Ruby核心做同樣的事情,但具有破壞性(變異)的方法。最終偏好,因爲沒有功能效果。 –

1
class Product 
    attr_accessor :quantity, :type, :price, :imported 

    def initialize(quantity, type, price, imported) 
    raise ArgumentError.new "Type must be a string" unless type.is_a?(String) 
    raise ArgumentError.new "Quantity must be greater than zero" if quantity.zero? 
    raise ArgumentError.new "Price must be a float" unless price.is_a?(Float) 

    @quantity, @type, @price, @imported = quantity, type, price.round(2), imported 
    end 
end 
+0

這真的很酷,我不知道我可以設置這樣的變量!感謝您的幫助 – Brian

+0

是的,你可以:)這是平行分配。 – kiddorails

1

你可以不喜歡以下,但我希望有寶石的是做到這一點,更多,更好地做到這一點:

module ArgCheck 
    def type_check(label, arg, klass) 
    raise_arg_err label + \ 
     " (= #{arg}) is a #{arg.class} object, but should be be a #{klass} object" unless arg.is_a? klass 
    end 

    def range_check(label, val, min, max) 
    raise_arg_err label + " (= #{val}) must be between #{min} and #{max}" unless val >= min && val <= max 
    end 

    def min_check(label, val, min) 
    puts "val = #{val}, min = #{min}" 
    raise_arg_err label + " (= #{val}) must be >= #{min}" unless val >= min 
    end 

    def max_check(val, min) 
    raise_arg_err label + " (= #{val}) must be <= #{max}" unless val <= max 
    end  

    # Possibly other checks here 

    private 

    def raise_arg_err(msg) 
    raise ArgumentError, msg + "\n backtrace: #{caller_locations}" 
    end 
end 

class Product 
    include ArgCheck 
    attr_accessor :quantity, :type, :price, :imported 

    def initialize(quantity, type, price) 
    # Check arguments 
    min_check 'quantity', quantity, 0 
    type_check 'type',  type,  String 
    type_check 'price', price, Float 

    @quantity = quantity 
    @type  = type 
    @price = price.round(2) 
    end 
end 

product = Product.new(-1, :cat, 3) 
# => arg_check.rb:23:in `raise_arg_err': quantity (= -1) must be >= 0 (ArgumentError) 
# backtrace: ["arg_check.rb:11:in `min_check'", "arg_check.rb:33:in `initialize'", \ 
#  "arg_check.rb:43:in `new'", "arg_check.rb:43:in `<main>'"] 

product = Product.new(1, :cat, 3) 
# => arg_check.rb:26:in `raise_arg_err': type (= cat) is a Symbol object, \ 
#  but should be be a String object (ArgumentError) 
#  backtrace: ["arg_check.rb:3:in `type_check'", "arg_check.rb:34:in `initialize'", \ 
#   "arg_check.rb:48:in `new'", "arg_check.rb:48:in `<main>'"] 

product = Product.new(1, "cat", 3) 
# => arg_check.rb:23:in `raise_arg_err': price (= 3) must be a Float object (ArgumentError) 
#  backtrace: ["arg_check.rb:3:in `type_check'", "arg_check.rb:35:in `initialize'", \ 
#  "arg_check.rb:53:in `new'", "arg_check.rb:53:in `<main>'"] 

product = Product.new(1, "cat", 3.00) # No exception raised 

需要注意的是,在IRB運行時,Kernel#caller_locations帶來了很多的東西,你不」不需要,從命令行運行時不會得到。