-
Notifications
You must be signed in to change notification settings - Fork 2
Predicates
Predicates are at the core of Speculation. They are used to validate simple values and are built upon to conform complex, nested and branching data structures. They enable runtime instrumentation of methods, verifying arguments and return values. In many cases they provide random data generation for free.
There are several ways to define a basic predicate:
This is the most versatile kind of predicate. If the Proc's return value is truthy then it's valid, otherwise it's invalid.
S.valid?(->(x) { x.is_a?(Integer) }, 1) # => trueS.valid?(->(x) { x.even? }, 1) # => falseS.valid?(:odd?.to_proc, 1) # => trueS.valid?(->(x) { x.match?(/foo/) }, "bar") # => falseS.valid?(->(x) { x.nil? || x.even? }, nil) # => true
Moreover, anything that responds to #call can be used in this fashion.
class MyPredicate
def call(x)
x.between?(1..100)
end
end
S.valid?(MyPredicate.new, 5) # => trueA regular expression is a good choice when validating a string is in the expected format,.
S.valid?(/\Afoo\z/i, "FoO") # => true
S.valid?(/\Afoo\z/i, "bar") # => false
S.valid?(/baz/, "foobarbaz") # => trueis_a? checks are performed when supplying a Class or Module as the predicate.
S.valid?(Integer, 1) # => true
S.valid?(Array, [1]) # => true
S.valid?(Enumerable, [1]) # => true
S.valid?(String, 1) # => falseSet membership is performed when a set is given as a predicate.
S.valid?(Set[1, 2, 3], 1) # => true
S.valid?(Set[:a, :b, :c], 1) # => false
S.valid?(Set.new("a".."z"), "g") # => true