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