diff --git a/TUTORIAL.md b/TUTORIAL.md index 87ee57a..615d5d8 100644 --- a/TUTORIAL.md +++ b/TUTORIAL.md @@ -88,6 +88,7 @@ contracts.ruby comes with a lot of built-in contracts, including the following: * [`SetOf`](http://www.rubydoc.info/gems/contracts/Contracts/SetOf) – checks that the argument is a set, and all elements pass the given contract, e.g. `SetOf[Num]` * [`HashOf`](http://www.rubydoc.info/gems/contracts/Contracts/HashOf) – checks that the argument is a hash, and all keys and values pass the given contract, e.g. `HashOf[Symbol => String]` or `HashOf[Symbol,String]` * [`RangeOf`](http://www.rubydoc.info/gems/contracts/Contracts/RangeOf) – checks that the argument is a range whose elements (#first and #last) pass the given contract, e.g. `RangeOf[Date]` + * [`Enum`](http://www.rubydoc.info/gems/contracts/Contracts/Enum) – checks that the argument is part of a given collection of objects, e.g. `Enum[:a, :b, :c]` * Keyword arguments * [`KeywordArgs`](http://www.rubydoc.info/gems/contracts/Contracts/KeywordArgs) – checks that the argument is an options hash, and all required keyword arguments are present, and all values pass their respective contracts, e.g. `KeywordArgs[:number => Num, :description => Optional[String]]` diff --git a/lib/contracts/builtin_contracts.rb b/lib/contracts/builtin_contracts.rb index ee74015..1187b2f 100644 --- a/lib/contracts/builtin_contracts.rb +++ b/lib/contracts/builtin_contracts.rb @@ -201,6 +201,20 @@ def to_s end end + # Takes a list of values, e.g. +[:a, :b, :c]+. If argument is included in + # the list, the contract passes. + # + # Example: Enum[:a, :b, :c]? + class Enum < CallableClass + def initialize(*vals) + @vals = vals + end + + def valid?(val) + @vals.include? val + end + end + # Takes a value +v+. If the argument is +.equal+ to +v+, the contract passes, # otherwise the contract fails. # Example: Eq[Class] diff --git a/spec/builtin_contracts_spec.rb b/spec/builtin_contracts_spec.rb index 63a5420..66cf670 100644 --- a/spec/builtin_contracts_spec.rb +++ b/spec/builtin_contracts_spec.rb @@ -164,6 +164,16 @@ end end + describe "Enum:" do + it "should pass for an object that is included" do + expect { @o.enum_test(:a) }.to_not raise_error + end + + it "should fail for an object that is not included" do + expect { @o.enum_test(:z) }.to raise_error(ContractError) + end + end + describe "RespondTo:" do it "should pass for an object that responds to :good" do expect { @o.responds_test(A.new) }.to_not raise_error diff --git a/spec/fixtures/fixtures.rb b/spec/fixtures/fixtures.rb index 430bb60..ecff42c 100644 --- a/spec/fixtures/fixtures.rb +++ b/spec/fixtures/fixtures.rb @@ -200,6 +200,10 @@ def xor_test(x) def and_test(x) end + Contract Enum[:a, :b, :c] => nil + def enum_test(x) + end + Contract RespondTo[:good] => nil def responds_test(x) end