lib/constrain.rb in constrain-0.1.3 vs lib/constrain.rb in constrain-0.2.0

- old
+ new

@@ -4,45 +4,47 @@ # Raised on any error class Error < StandardError; end # Raised if types doesn't match a class expression class TypeError < Error - def initialize(value, exprs, msg = nil) + def initialize(value, exprs, msg = nil, unwind: 0) super msg || "Expected #{value.inspect} to match #{Constrain.fmt_exprs(exprs)}" end end # Check that value matches one of the class expressions. Raises a # Constrain::Error if the expression is invalid and a Constrain::TypeError if - # the value doesn't match - def constrain(value, *exprs) + # the value doesn't match. The exception's backtrace skips :unwind number of entries + def constrain(value, *exprs, unwind: 0) msg = exprs.pop if exprs.last.is_a?(String) begin !exprs.empty? or raise Error, "Empty class expression" - exprs.any? { |expr| Constrain.check(value, expr) } or raise TypeError.new(value, exprs, msg) + exprs.any? { |expr| Constrain.constrain?(value, expr) } or + raise TypeError.new(value, exprs, msg, unwind: unwind) rescue Error => ex - ex.set_backtrace(caller[1..-1]) + ex.set_backtrace(caller[1 + unwind..-1]) raise end + value end # Return true if the value matches the class expression. Raises a # Constrain::Error if the expression is invalid - def self.check(value, expr) + def self.constrain?(value, expr) case expr when Class, Module value.is_a?(expr) when Array !expr.empty? or raise Error, "Empty array" - value.is_a?(Array) && value.all? { |elem| expr.any? { |e| check(elem, e) } } + value.is_a?(Array) && value.all? { |elem| expr.any? { |e| constrain?(elem, e) } } when Hash value.is_a?(Hash) && value.all? { |key, value| expr.any? { |key_expr, value_expr| [[key, key_expr], [value, value_expr]].all? { |value, expr| if expr.is_a?(Array) && (expr.size > 1 || expr.first.is_a?(Array)) - expr.any? { |e| check(value, e) } + expr.any? { |e| constrain?(value, e) } else - check(value, expr) + constrain?(value, expr) end } } } when Proc