-
Notifications
You must be signed in to change notification settings - Fork 2
Conditional Specs
Jamie English edited this page Jul 23, 2017
·
1 revision
Speculation allows you to combine specs with S.or and S.and.
S.and allows you to construct a spec using multiple specs. For a given value to conform to the
spec, it must conform to every constituent spec.
S.valid? S.and(Integer, ->(i) { i.positive? }), "foo" # => false
S.valid? S.and(Integer, ->(i) { i.positive? }), -1 # => false
S.valid? S.and(Integer, ->(i) { i.positive? }), 1 # => trueCombining specs with S.and allows you reuse specs in different contexts. It also makes it easy to
avoid calling predicate methods on objects that might not implement them. For example:
is_positive = ->(i) { i.positive? }
S.valid? is_positive, "foo" # NoMethodError: undefined method `positive?' for "foo":StringSometimes there are multiple ways a given data structure can be considered valid. S.or will
consider a value valid if it conforms to any of its constituent specs:
S.valid? S.or(s: String, i: Integer), "foo" # => true
S.valid? S.or(s: String, i: Integer), 1 # => true
S.valid? S.or(s: String, i: Integer), 1.0 # => false
S.explain S.or(s: String, i: Integer), 1.0
# => val: 1.0 fails at: [:s] predicate: [String, [1.0]]
# => val: 1.0 fails at: [:i] predicate: [Integer, [1.0]]It can be useful to know how a data structure conformed to an or spec. Because we've labelled
our specs, S.conform will tell us which spec the value conformed to:
S.conform S.or(s: String, i: Integer), "foo" # => [:s, "foo"]
S.conform S.or(s: String, i: Integer), 1 # => [:i, 1]