你可以不喜歡以下,但我希望有寶石的是做到這一點,更多,更好地做到這一點:
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
帶來了很多的東西,你不」不需要,從命令行運行時不會得到。
謝謝安德魯 - 超快速的反應,非常有幫助! – Brian
嘿@AndrewMarshall,我想知道你是否可以解釋爲什麼我們在'驗證'方法中包含爆炸的原因? – Brian
@Brian只是因爲它在「false」的情況下引發了一個異常。這個約定來自Rails,但通常只在那裏使用(我認爲)當有非禁止版本時。 Ruby核心做同樣的事情,但具有破壞性(變異)的方法。最終偏好,因爲沒有功能效果。 –