contracts-lite 0.14.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.markdown +80 -0
  3. data/Gemfile +16 -0
  4. data/LICENSE +23 -0
  5. data/README.md +102 -0
  6. data/TODO.markdown +6 -0
  7. data/TUTORIAL.md +747 -0
  8. data/benchmarks/bench.rb +67 -0
  9. data/benchmarks/hash.rb +69 -0
  10. data/benchmarks/invariants.rb +91 -0
  11. data/benchmarks/io.rb +62 -0
  12. data/benchmarks/wrap_test.rb +57 -0
  13. data/contracts.gemspec +13 -0
  14. data/lib/contracts.rb +231 -0
  15. data/lib/contracts/builtin_contracts.rb +541 -0
  16. data/lib/contracts/call_with.rb +97 -0
  17. data/lib/contracts/core.rb +52 -0
  18. data/lib/contracts/decorators.rb +47 -0
  19. data/lib/contracts/engine.rb +26 -0
  20. data/lib/contracts/engine/base.rb +136 -0
  21. data/lib/contracts/engine/eigenclass.rb +50 -0
  22. data/lib/contracts/engine/target.rb +70 -0
  23. data/lib/contracts/error_formatter.rb +121 -0
  24. data/lib/contracts/errors.rb +71 -0
  25. data/lib/contracts/formatters.rb +134 -0
  26. data/lib/contracts/invariants.rb +68 -0
  27. data/lib/contracts/method_handler.rb +195 -0
  28. data/lib/contracts/method_reference.rb +100 -0
  29. data/lib/contracts/support.rb +59 -0
  30. data/lib/contracts/validators.rb +139 -0
  31. data/lib/contracts/version.rb +3 -0
  32. data/script/rubocop +7 -0
  33. data/spec/builtin_contracts_spec.rb +461 -0
  34. data/spec/contracts_spec.rb +748 -0
  35. data/spec/error_formatter_spec.rb +68 -0
  36. data/spec/fixtures/fixtures.rb +710 -0
  37. data/spec/invariants_spec.rb +17 -0
  38. data/spec/module_spec.rb +18 -0
  39. data/spec/override_validators_spec.rb +162 -0
  40. data/spec/ruby_version_specific/contracts_spec_1.9.rb +24 -0
  41. data/spec/ruby_version_specific/contracts_spec_2.0.rb +55 -0
  42. data/spec/ruby_version_specific/contracts_spec_2.1.rb +63 -0
  43. data/spec/spec_helper.rb +102 -0
  44. data/spec/support.rb +10 -0
  45. data/spec/support_spec.rb +21 -0
  46. data/spec/validators_spec.rb +47 -0
  47. metadata +94 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 5a0087eb9cbfbfbac59abc12f636caccf3699b81
4
+ data.tar.gz: eb6161c0401a24b4a37ac8fff330de398198fd74
5
+ SHA512:
6
+ metadata.gz: 681aa159502c17ae1dccc23060193b73cd70f81034a724398003edf886156ecd7c5e23199c53a1a5c1f90a0cd03257ace3de9733058c76c616d2e0af2356fb27
7
+ data.tar.gz: 170938443f38a9cbc575e1ae4261dc6365d44c7615108fc5cd25195af0554e8f4afc82395f04bdd17e9f0f4eff859d0a262a57a00c527f5ee01843ecb350cbc7
@@ -0,0 +1,80 @@
1
+ ## v0.15.0
2
+
3
+ ## v0.14.0
4
+ - Enhancement: Add StrictHash contract - [Fyodor](https://github.com/cbrwizard) [#236](https://github.com/egonSchiele/contracts.ruby/pull/236)
5
+ - Bugfix: dont fail if something other than a hash is passed to a KeywordArgs - [Dan Padilha](https://github.com/dpad) [#234](https://github.com/egonSchiele/contracts.ruby/pull/234)
6
+ - LICENSE ADDED: Simplified BSD (same as what is specified in the readme) - [Charles Dale](https://github.com/chuckd) [#233](https://github.com/egonSchiele/contracts.ruby/pull/233)
7
+ - Bugfix: fix constant looking when including a module that includes contracts (requires removing the check to see if contracts is already included) - [Aditya Bhargava](https://github.com/egonSchiele) [#232](https://github.com/egonSchiele/contracts.ruby/pull/232)
8
+ - Bugfix for err case when KeywordArgs and Proc are used together - [Aditya Bhargava](https://github.com/egonSchiele) [#230](https://github.com/egonSchiele/contracts.ruby/pull/230)
9
+ - Enhancement: Add DescendantOf contract - [Miguel Palhas](https://github.com/naps62) [#227](https://github.com/egonSchiele/contracts.ruby/pull/227)
10
+
11
+ ## v0.13.0
12
+
13
+ - Enhancement: Add support for Ruby 2.3 - [Oleksii Fedorov](https://github.com/waterlink) [#216](https://github.com/egonSchiele/contracts.ruby/pull/216)
14
+ - Enhancement: Added Int, Nat and NatPos builtin contracts - [Simon George](https://github.com/sfcgeorge) [#212](https://github.com/egonSchiele/contracts.ruby/pull/212)
15
+ - Bugfix: Allow contracts on singleton of subclass - [Oleksii Federov](https://github.com/waterlink) [#211](https://github.com/egonSchiele/contracts.ruby/pull/211)
16
+
17
+ ## v0.12.0
18
+
19
+ - Feature: add `Regexp` validator - [Gert Goet](https://github.com/eval) [#196](https://github.com/egonSchiele/contracts.ruby/pull/196)
20
+ - Docs: bootstrap cucumber/aruba/relish setup - [Oleksii Fedorov](https://github.com/waterlink) [#195](https://github.com/egonSchiele/contracts.ruby/pull/195)
21
+ - Bugfix: allow to `extend` module, that has `Contracts` or `Contracts::Core` included without harming current module/class `Contracts` functionality, see: [#176](https://github.com/egonSchiele/contracts.ruby/issues/176) - [Oleksii Fedorov](https://github.com/waterlink) [#198](https://github.com/egonSchiele/contracts.ruby/pull/198)
22
+ - Enhancement: add `include Contracts::Builtin` to allow users to use builtin contracts without `Contracts::` prefix together with `include Contracts::Core` - [PikachuEXE](https://github.com/PikachuEXE) [#199](https://github.com/egonSchiele/contracts.ruby/pull/199)
23
+
24
+ ## v0.11.0
25
+
26
+ - Enhancement: add `include Contracts::Core` that doesn't pollute the namespace as much as `include Contracts` - [Oleksii Federov](https://github.com/waterlink) [#185](https://github.com/egonSchiele/contracts.ruby/pull/185)
27
+ - Bugfix: fail if a non-hash is provided to a `HashOf` contract - [Abe Voelker](https://github.com/abevoelker) [#190](https://github.com/egonSchiele/contracts.ruby/pull/190)
28
+ - Bugfix: bugfix for using varargs and `Maybe[Proc]` together - [Adit Bhargava](https://github.com/egonSchiele) [#188](https://github.com/egonSchiele/contracts.ruby/pull/188)
29
+ - Bugfix: make KeywordArgs fail if unexpected keys are passed in - [Abe Voelker](https://github.com/abevoelker) [#187](https://github.com/egonSchiele/contracts.ruby/pull/187)
30
+ - Feature: range contract added - [Oleksii Fedorov](https://github.com/waterlink) [#184](https://github.com/egonSchiele/contracts.ruby/pull/184)
31
+ - Feature: enum contract added - [Dennis Günnewig](https://github.com/dg-ratiodata) [#181](https://github.com/egonSchiele/contracts.ruby/pull/181)
32
+
33
+ ## v0.10.1
34
+
35
+ - Enhancement: make `@pattern_match` instance variable not render ruby warning. Required to use new aruba versions in rspec tests - [Dennis Günnewig](https://github.com/dg-ratiodata) [#179](https://github.com/egonSchiele/contracts.ruby/pull/179)
36
+
37
+ ## v0.10
38
+
39
+ - Bugfix: make `Maybe[Proc]` work correctly - [Simon George](https://github.com/sfcgeorge) [#142](https://github.com/egonSchiele/contracts.ruby/pull/142)
40
+ - Bugfix: make `Func` contract verified when used as return contract - [Rob Rosenbaum](https://github.com/robnormal) [#145](https://github.com/egonSchiele/contracts.ruby/pull/145)
41
+ - Bugfix: make `Pos`, `Neg` and `Nat` contracts handle non-numeric values correctly - [Matt Griffin](https://github.com/betamatt) and [Gavin Sinclair](https://github.com/gsinclair) [#147](https://github.com/egonSchiele/contracts.ruby/pull/147) [#173](https://github.com/egonSchiele/contracts.ruby/pull/173)
42
+ - Enhancement: reduce user class pollution through introduction of contracts engine - [Oleksii Fedorov](https://github.com/waterlink) [#141](https://github.com/egonSchiele/contracts.ruby/pull/141)
43
+ - Feature: add builtin `KeywordArgs` and `Optional` contracts for keyword arguments handling - [Oleksii Fedorov](https://github.com/waterlink) [#151](https://github.com/egonSchiele/contracts.ruby/pull/151)
44
+ - Feature: recognize module as a class contract - [Oleksii Fedorov](https://github.com/waterlink) [#153](https://github.com/egonSchiele/contracts.ruby/pull/153)
45
+ - Feature: custom validators with `Contract.override_validator` - [Oleksii Fedorov](https://github.com/waterlink) [#159](https://github.com/egonSchiele/contracts.ruby/pull/159)
46
+ - Feature: add builtin `RangeOf[...]` contract - [Gavin Sinclair](https://github.com/gsinclair) [#171](https://github.com/egonSchiele/contracts.ruby/pull/171)
47
+
48
+ ## v0.9
49
+
50
+ - MAJOR fix in pattern-matching: If the return contract for a pattern-matched function fails, it should NOT try the next pattern-match function. Pattern-matching is only for params, not return values.
51
+ - raise an error if multiple defns have the same contract for pattern matching.
52
+
53
+ - New syntax for functions with no input params (the old style still works)
54
+ Old way:
55
+ ```ruby
56
+ Contract nil => 1
57
+ def one
58
+ ```
59
+ New way:
60
+ ```
61
+ Contract 1
62
+ def one
63
+ ```
64
+
65
+ - Prettier HashOf contract can now be written like this: `HashOf[Num => String]`
66
+ - Add `SetOf` contract
67
+ - various small fixes
68
+
69
+ ## v0.8
70
+
71
+ - code refactored (very slight loss of performance, big increase in readability)
72
+ - fail when defining a contract on a module without `include Contracts::Modules`
73
+ - fixed several bugs in argument parsing, functions with complex params get contracts applied correctly now.
74
+ - added rubocop to ci.
75
+ - if a contract is set on a protected method, it should not become public.
76
+ - fixed pattern matching when the multiple definitions of functions have different arities.
77
+ - couple of new built-in contracts: Nat, Eq.
78
+ - changed `Invariant` to `invariant`: `invariant(:day) { 1 <= day && day <= 31 }`
79
+ - prettier error messages (`Contracts::Num` is now just `Num`, for example)
80
+ - support for yard-contracts
data/Gemfile ADDED
@@ -0,0 +1,16 @@
1
+ source "http://rubygems.org"
2
+
3
+ gemspec
4
+
5
+ group :test do
6
+ gem "rspec"
7
+ gem "rubocop", "~> 0.29.1", :platform => [:ruby_20, :ruby_21, :ruby_22, :ruby_23]
8
+ end
9
+
10
+ group :development do
11
+ gem "relish"
12
+ gem "method_profiler"
13
+ gem "ruby-prof"
14
+ gem "rake"
15
+ gem "byebug"
16
+ end
data/LICENSE ADDED
@@ -0,0 +1,23 @@
1
+ Copyright (c) 2012-2016 Aditya Bhargava
2
+ All rights reserved.
3
+
4
+ Redistribution and use in source and binary forms, with or without
5
+ modification, are permitted provided that the following conditions are met:
6
+
7
+ * Redistributions of source code must retain the above copyright notice, this
8
+ list of conditions and the following disclaimer.
9
+
10
+ * Redistributions in binary form must reproduce the above copyright notice,
11
+ this list of conditions and the following disclaimer in the documentation
12
+ and/or other materials provided with the distribution.
13
+
14
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
15
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
17
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
18
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
20
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
21
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
22
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
23
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
data/README.md ADDED
@@ -0,0 +1,102 @@
1
+ # contracts.ruby [![Build Status](https://travis-ci.org/ddd-ruby/contracts.ruby.png?branch=master)](https://travis-ci.org/ddd-ruby/contracts.ruby) [![Join the chat at https://gitter.im/egonSchiele/contracts.ruby](https://img.shields.io/badge/gitter-join%20chat-brightgreen.svg)](https://gitter.im/egonSchiele/contracts.ruby)
2
+
3
+ Contracts let you clearly – even beautifully – express how your code behaves, and free you from writing tons of boilerplate, defensive code.
4
+
5
+ You can think of contracts as `assert` on steroids.
6
+
7
+ ## Installation
8
+
9
+ gem install contracts
10
+
11
+ ## Hello World
12
+
13
+ A contract is one line of code that you write above a method definition. It validates the arguments to the method, and validates the return value of the method.
14
+
15
+ Here is a simple contract:
16
+
17
+ ```ruby
18
+ Contract Num => Num
19
+ def double(x)
20
+ ```
21
+
22
+ This says that double expects a number and returns a number. Here's the full code:
23
+
24
+ ```ruby
25
+ require 'contracts'
26
+
27
+ class Example
28
+ include Contracts::Core
29
+ include Contracts::Builtin
30
+
31
+ Contract Num => Num
32
+ def double(x)
33
+ x * 2
34
+ end
35
+ end
36
+
37
+ puts Example.new.double("oops")
38
+ ```
39
+
40
+ Save this in a file and run it. Notice we are calling `double` with `"oops"`, which is not a number. The contract fails with a detailed error message:
41
+
42
+ ```
43
+ ParamContractError: Contract violation for argument 1 of 1:
44
+ Expected: Num,
45
+ Actual: "oops"
46
+ Value guarded in: Example::double
47
+ With Contract: Num => Num
48
+ At: main.rb:8
49
+ ...stack trace...
50
+ ```
51
+
52
+ Instead of throwing an exception, you could log it, print a clean error message for your user...whatever you want. contracts.ruby is here to help you handle bugs better, not to get in your way.
53
+
54
+ ## Tutorial
55
+
56
+ Check out [this awesome tutorial](http://egonschiele.github.com/contracts.ruby).
57
+
58
+ ## Use Cases
59
+
60
+ Check out [this screencast](https://vimeo.com/85883356).
61
+
62
+ ## Development
63
+
64
+ To get started do the following:
65
+
66
+ 1. Install required gems for development
67
+
68
+ `bundle install`
69
+
70
+ 2. Run our test suite
71
+
72
+ `bundle exec rake`
73
+
74
+ ## Performance
75
+
76
+ Using contracts.ruby results in very little slowdown. Check out [this blog post](http://adit.io/posts/2013-03-04-How-I-Made-My-Ruby-Project-10x-Faster.html#seconds-6) for more info.
77
+
78
+ **Q.** What Rubies can I use this with?
79
+
80
+ **A.** It's been tested with `1.9.2`, `1.9.3`, `2.0.0`, `2.1`, `2.2`, and `jruby` (1.9 mode).
81
+
82
+ If you're using the library, please [let me know](https://github.com/egonSchiele) what project you're using it on :)
83
+
84
+ ## Testimonials
85
+
86
+ > Contracts literally saves us hours of pain at Snowplow every day
87
+
88
+ Alexander Dean, creator of [Snowplow](https://github.com/snowplow/snowplow)
89
+
90
+ > Contracts caught a bug that saved us several hundred dollars. It took less than 30 seconds to add the contract.
91
+
92
+ Michael Tomer
93
+
94
+ ## Credits
95
+
96
+ Inspired by [contracts.coffee](http://disnetdev.com/contracts.coffee/).
97
+
98
+ Copyright 2012-2015 [Aditya Bhargava](http://adit.io).
99
+ Major improvements by [Alexey Fedorov](https://github.com/waterlink).
100
+
101
+ BSD Licensed.
102
+
data/TODO.markdown ADDED
@@ -0,0 +1,6 @@
1
+ - maybe make some screencasts
2
+
3
+ - you can now do something like Haskell's quickcheck. Every contract has a method 'test_data' or something. You can use that data to automatically check methods with contracts to make sure they are correct.
4
+ - http://www.cse.chalmers.se/~rjmh/QuickCheck/manual.html
5
+ - for stuff like the Not contract, should I make a standard set of classes to check those functions with? Would that be useful at all?
6
+ - also write specs for this stuff
data/TUTORIAL.md ADDED
@@ -0,0 +1,747 @@
1
+ # The contracts.ruby tutorial
2
+
3
+ ## Introduction
4
+
5
+ contracts.ruby brings code contracts to the Ruby language. Code contracts allow you make some assertions about your code, and then checks them to make sure they hold. This lets you
6
+
7
+ - catch bugs faster
8
+ - make it very easy to catch certain types of bugs
9
+ - make sure that the user gets proper messaging when a bug occurs.
10
+
11
+ ## Installation
12
+
13
+ gem install contracts
14
+
15
+ ## Basics
16
+
17
+ A simple example:
18
+
19
+ ```ruby
20
+ Contract Contracts::Num, Contracts::Num => Contracts::Num
21
+ def add(a, b)
22
+ a + b
23
+ end
24
+ ```
25
+
26
+ Here, the contract is `Contract Num, Num => Num`. This says that the `add` function takes two numbers and returns a number.
27
+
28
+ Copy this code into a file and run it:
29
+
30
+ ```ruby
31
+ require 'contracts'
32
+
33
+ class Math
34
+ include Contracts::Core
35
+
36
+ Contract Contracts::Num, Contracts::Num => Contracts::Num
37
+ def self.add(a, b)
38
+ a + b
39
+ end
40
+ end
41
+
42
+ puts Math.add(1, "foo")
43
+ ```
44
+
45
+ You'll see a detailed error message like so:
46
+
47
+ ./contracts.rb:60:in `failure_callback': Contract violation: (RuntimeError)
48
+ Expected: Contracts::Num,
49
+ Actual: "foo"
50
+ Value guarded in: Object::add
51
+ With Contract: Contracts::Num, Contracts::Num
52
+ At: foo.rb:6
53
+
54
+ That tells you that your contract was violated! `add` expected a `Num`, and got a string (`"foo"`) instead.
55
+ By default, an exception is thrown when a contract fails. This can be changed to do whatever you want. More on this later.
56
+
57
+ You can also see the contract for a function with the `functype` method:
58
+
59
+ functype(:add)
60
+ => "add :: Num, Num => Num"
61
+
62
+ This can be useful if you're in a REPL and want to figure out how a function should be used.
63
+
64
+ ## Built-in Contracts
65
+
66
+ `Num` is one of the built-in contracts that contracts.ruby comes with. The built-in contracts are in the `Contracts` namespace. The easiest way to use them is to include the `Contracts::Builtin` module in your class/module.
67
+
68
+ contracts.ruby comes with a lot of built-in contracts, including the following:
69
+
70
+ * Basic types
71
+ * [`Num`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Num) – checks that the argument is `Numeric`
72
+ * [`Pos`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Pos) – checks that the argument is a positive number
73
+ * [`Neg`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Neg) – checks that the argument is a negative number
74
+ * [`Int`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Int) – checks that the argument is an integer
75
+ * [`Nat`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Nat) – checks that the argument is a natural number (>= 0)
76
+ * [`NatPos`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/NatPos) – checks that the argument is a positive natural number (> 0)
77
+ * [`Bool`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Bool) – checks that the argument is `true` or `false`
78
+ * [`Any`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Any) – Passes for any argument. Use when the argument has no constraints.
79
+ * [`None`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/None) – Fails for any argument. Use when the method takes no arguments.
80
+
81
+ * Logical combinations
82
+ * [`Maybe`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Maybe) – specifies that a value _may be_ nil, e.g. `Maybe[String]` (equivalent to `Or[String,nil]`)
83
+ * [`Or`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Or) – passes if any of the given contracts pass, e.g. `Or[Fixnum, Float]`
84
+ * [`Xor`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Xor) – passes if exactly one of the given contracts pass, e.g. `Xor[Fixnum, Float]`
85
+ * [`And`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/And) – passes if all contracts pass, e.g. `And[Nat, -> (n) { n.even? }]`
86
+ * [`Not`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Not) – passes if all contracts fail for the given argument, e.g. `Not[nil]`
87
+
88
+ * Collections
89
+ * [`ArrayOf`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/ArrayOf) – checks that the argument is an array, and all elements pass the given contract, e.g. `ArrayOf[Num]`
90
+ * [`SetOf`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/SetOf) – checks that the argument is a set, and all elements pass the given contract, e.g. `SetOf[Num]`
91
+ * [`HashOf`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/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]`
92
+ * [`StrictHash`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/StrictHash) – checks that the argument is a hash, and every key passed is present in the given contract, e.g. `StrictHash[{ :description => String, :number => Fixnum }]`
93
+ * [`RangeOf`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/RangeOf) – checks that the argument is a range whose elements (#first and #last) pass the given contract, e.g. `RangeOf[Date]`
94
+ * [`Enum`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Enum) – checks that the argument is part of a given collection of objects, e.g. `Enum[:a, :b, :c]`
95
+
96
+ * Keyword arguments
97
+ * [`KeywordArgs`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/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]]`
98
+ * [`Optional`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Optional) – checks that the keyword argument is either not present or pass the given contract, can not be used outside of `KeywordArgs` contract, e.g. `Optional[Num]`
99
+
100
+ * Duck typing
101
+ * [`RespondTo`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/RespondTo) – checks that the argument responds to all of the given methods, e.g. `RespondTo[:password, :credit_card]`
102
+ * [`Send`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Send) – checks that all named methods return a truthy value, e.g. `Send[:valid?]`
103
+
104
+ * Miscellaneous
105
+ * [`Exactly`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Exactly) – checks that the argument has the given type, not accepting sub-classes, e.g. `Exactly[Numeric]`.
106
+ * [`Eq`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Eq) – checks that the argument is precisely equal to the given value, e.g. `Eq[String]` matches the class `String` and not a string instance.
107
+ * [`Func`](http://www.rubydoc.info/gems/contracts/Contracts/Builtin/Func) – specifies the contract for a proc/lambda e.g. `Contract ArrayOf[Num], Func[Num => Num] => ArrayOf[Num]`. See section "Contracts On Functions".
108
+
109
+ To see all the built-in contracts and their full descriptions, check out the [RDoc](http://rubydoc.info/gems/contracts/Contracts/Builtin).
110
+
111
+ It is recommended to use shortcut for referring builtin contracts:
112
+
113
+ ```ruby
114
+ # define shortcut somewhere at the top level of your codebase:
115
+ C = Contracts
116
+
117
+ # and use it:
118
+ Contract C::Maybe[C::Num], String => C::Num
119
+ ```
120
+
121
+ Shortcut name should not be necessary `C`, can be anything that you are comfort
122
+ with while typing and anything that does not conflict with libraries you use.
123
+
124
+ All examples after this point assume you have chosen a shortcut as `C::`.
125
+
126
+ If you are sure, that builtin contracts will not nameclash with your own code
127
+ and libraries you may use, then you can include all builtin contracts in your
128
+ class/module:
129
+
130
+ ```ruby
131
+ class Example
132
+ include Contracts::Core
133
+ include Contracts::Builtin
134
+
135
+ Contract Maybe[Num], Or[Float, String] => Bool
136
+ def complicated_algorithm(a, b)
137
+ # ...
138
+ end
139
+ end
140
+ ```
141
+
142
+ ## More Examples
143
+
144
+ ### Hello, World
145
+
146
+ ```ruby
147
+ Contract String => nil
148
+ def hello(name)
149
+ puts "hello, #{name}!"
150
+ end
151
+ ```
152
+
153
+ You always need to specify a contract for the return value. In this example, `hello` doesn't return anything, so the contract is `nil`. Now you know that you can use a constant like `nil` as the end of a contract. Valid values for a contract are:
154
+
155
+ - the name of a class (like `String` or `Fixnum`)
156
+ - a constant (like `nil` or `1`)
157
+ - a `Proc` that takes a value and returns true or false to indicate whether the contract passed or not
158
+ - a class that responds to the `valid?` class method (more on this later)
159
+ - an instance of a class that responds to the `valid?` method (more on this later)
160
+
161
+ ### A Double Function
162
+
163
+ ```ruby
164
+ Contract C::Or[Fixnum, Float] => C::Or[Fixnum, Float]
165
+ def double(x)
166
+ 2 * x
167
+ end
168
+ ```
169
+
170
+ Sometimes you want to be able to choose between a few contracts. `Or` takes a variable number of contracts and checks the argument against all of them. If it passes for any of the contracts, then the `Or` contract passes.
171
+ This introduces some new syntax. One of the valid values for a contract is an instance of a class that responds to the `valid?` method. This is what `Or[Fixnum, Float]` is. The longer way to write it would have been:
172
+
173
+ ```ruby
174
+ Contract C::Or.new(Fixnum, Float) => C::Or.new(Fixnum, Float)
175
+ ```
176
+
177
+ All the built-in contracts have overridden the square brackets (`[]`) to give the same functionality. So you could write
178
+
179
+ ```ruby
180
+ Contract C::Or[Fixnum, Float] => C::Or[Fixnum, Float]
181
+ ```
182
+
183
+ or
184
+
185
+ ```ruby
186
+ Contract C::Or.new(Fixnum, Float) => C::Or.new(Fixnum, Float)
187
+ ```
188
+
189
+ whichever you prefer. They both mean the same thing here: make a new instance of `Or` with `Fixnum` and `Float`. Use that instance to validate the argument.
190
+
191
+ ### A Product Function
192
+
193
+ ```ruby
194
+ Contract C::ArrayOf[C::Num] => C::Num
195
+ def product(vals)
196
+ total = 1
197
+ vals.each do |val|
198
+ total *= val
199
+ end
200
+ total
201
+ end
202
+ ```
203
+
204
+ This contract uses the `ArrayOf` contract. Here's how `ArrayOf` works: it takes a contract. It expects the argument to be a list. Then it checks every value in that list to see if it satisfies that contract.
205
+
206
+ ```ruby
207
+ # passes
208
+ product([1, 2, 3, 4])
209
+
210
+ # fails
211
+ product([1, 2, 3, "foo"])
212
+ ```
213
+
214
+ ### Another Product Function
215
+
216
+ ```ruby
217
+ Contract C::Args[C::Num] => C::Num
218
+ def product(*vals)
219
+ total = 1
220
+ vals.each do |val|
221
+ total *= val
222
+ end
223
+ total
224
+ end
225
+ ```
226
+
227
+ This function uses varargs (`*args`) instead of an array. To make a contract on varargs, use the `Args` contract. It takes one contract as an argument and uses it to validate every element passed in through `*args`. So for example,
228
+
229
+ `Args[Num]` means they should all be numbers.
230
+
231
+ `Args[Or[Num, String]]` means they should all be numbers or strings.
232
+
233
+ `Args[Any]` means all arguments are allowed (`Any` is a contract that passes for any argument).
234
+
235
+ ### Contracts On Arrays
236
+
237
+ If an array is one of the arguments and you know how many elements it's going to have, you can put a contract on it:
238
+
239
+ ```ruby
240
+ # a function that takes an array of two elements...a person's age and a person's name.
241
+ Contract [C::Num, String] => nil
242
+ def person(data)
243
+ p data
244
+ end
245
+ ```
246
+
247
+ If you don't know how many elements it's going to have, use `ArrayOf`.
248
+
249
+ ### Contracts On Hashes
250
+
251
+ Here's a contract that requires a Hash. We can put contracts on each of the keys:
252
+
253
+ ```ruby
254
+ # note the parentheses around the hash; without those you would get a syntax error
255
+ Contract ({ :age => C::Num, :name => String }) => nil
256
+ def person(data)
257
+ p data
258
+ end
259
+ ```
260
+
261
+ Then if someone tries to call the function with bad data, it will fail:
262
+
263
+ ```ruby
264
+ # error: age can't be nil!
265
+ person({:name => "Adit", :age => nil})
266
+ ```
267
+
268
+ You don't need to put a contract on every key. So this call would succeed:
269
+
270
+ ```ruby
271
+ person({:name => "Adit", :age => 42, :foo => "bar"})
272
+ ```
273
+
274
+ even though we don't specify a type for `:foo`. If you need this check though, use `StrictHash` instead.
275
+
276
+ Peruse this contract on the keys and values of a Hash.
277
+
278
+ ```ruby
279
+ Contract C::HashOf[Symbol, C::Num] => C::Num
280
+ def give_largest_value(hsh)
281
+ hsh.values.max
282
+ end
283
+ ```
284
+ Which you use like so:
285
+ ```ruby
286
+ # succeeds
287
+ give_largest_value(a: 1, b: 2, c: 3) # returns 3
288
+
289
+ # fails
290
+ give_largest_value("a" => 1, 2 => 2, c: 3)
291
+ ```
292
+
293
+ ### Contracts On Strings
294
+
295
+ When you want a contract to match not just any string (i.e. `Contract String => nil`), you can use regular expressions:
296
+ ```ruby
297
+ Contract /World|Mars/i => nil
298
+ def greet(name)
299
+ puts "Hello #{name}!"
300
+ end
301
+ ```
302
+
303
+ Using logical combinations you can combine existing definitions, instead of writing 1 big regular expression:
304
+ ```ruby
305
+ Contract C::And[default_mail_regexp, /#{AppConfig.domain}\z/] => nil
306
+ def send_admin_invite(email)
307
+ ```
308
+
309
+ ### Contracts On Keyword Arguments
310
+
311
+ ruby 2.0+, but can be used for normal hashes too, when keyword arguments are
312
+ not available
313
+
314
+ Lets say you are writing a simple function and require a bunch of keyword arguments:
315
+
316
+ ```ruby
317
+ def connect(host, port:, user:, password:)
318
+ ```
319
+
320
+ You can of course put `Hash` contract on it:
321
+
322
+ ```ruby
323
+ Contract String, { :port => C::Num, :user => String, :password => String } => Connection
324
+ def connect(host, port:, user:, password:)
325
+ ```
326
+
327
+ But this will not quite work if you want to have a default values:
328
+
329
+ ```ruby
330
+ Contract String, { :port => C::Num, :user => String, :password => String } => Connection
331
+ def connect(host, port: 5000, user:, password:)
332
+ # ...
333
+ end
334
+
335
+ # No value is passed for port
336
+ connect("example.org", user: "me", password: "none")
337
+ ```
338
+
339
+ Results in:
340
+
341
+ ```
342
+ ContractError: Contract violation for argument 2 of 2:
343
+ Expected: {:port=>Num, :user=>String, :password=>String},
344
+ Actual: {:user=>"me", :password=>"none"}
345
+ Value guarded in: Object::connect
346
+ With Contract: String, Hash => Connection
347
+ At: (irb):12
348
+ ```
349
+
350
+ This can be fixed with contract `{ :port => C::Maybe[C::Num], ... }`, but that will
351
+ allow `nil` to be passed in, which is not the original intent.
352
+
353
+ So that is where `KeywordArgs` and `Optional` contracts jump in:
354
+
355
+ ```ruby
356
+ Contract String, C::KeywordArgs[ :port => C::Optional[C::Num], :user => String, :password => String ] => Connection
357
+ def connect(host, port: 5000, user:, password:)
358
+ ```
359
+
360
+ It looks just like the hash contract, but wrapped in `KeywordArgs` contract. Notice the usage of `Optional` contract - this way you specify that `:port` argument is optional. And it will not fail, when you omit this argument, but it will fail when you pass in `nil`.
361
+
362
+ ### Contracts On Functions
363
+
364
+ Lets say you are writing a simple map function:
365
+
366
+ ```ruby
367
+ def map(arr, func)
368
+ ```
369
+
370
+ `map` takes an array, and a function. Suppose you want to add a contract to this function. You could try this:
371
+
372
+ ```ruby
373
+ Contract C::ArrayOf[C::Any], Proc => C::ArrayOf[C::Any]
374
+ def map(arr, func)
375
+ ```
376
+
377
+ This says that the second argument should be a `Proc`. You can call the function like so:
378
+
379
+ ```ruby
380
+ p map([1, 2, 3], lambda { |x| x + 1 }) # works
381
+ ```
382
+
383
+ But suppose you want to have a contract on the Proc too! Suppose you want to make sure that the Proc returns a number. Use the `Func` contract. `Func` takes a contract as its argument, and uses that contract on the function that you pass in.
384
+
385
+ Here's a `map` function that requires an array of numbers, and a function that takes a number and returns a number:
386
+
387
+ ```ruby
388
+ Contract C::ArrayOf[C::Num], C::Func[C::Num => C::Num] => C::ArrayOf[C::Num]
389
+ def map(arr, func)
390
+ ret = []
391
+ arr.each do |x|
392
+ ret << func[x]
393
+ end
394
+ ret
395
+ end
396
+ ```
397
+
398
+ Earlier, we used `Proc`, which just says "make sure the second variable is a Proc". Now we are using `Func[Num => Num]`, which says "make sure the second variable is a Proc that takes a number and returns a number". Better!
399
+
400
+ Try this map function with these two examples:
401
+
402
+ ```ruby
403
+ p map([1, 2, 3], lambda { |x| x + 1 }) # works
404
+ p map([1, 2, 3], lambda { |x| "oops" }) # fails, the lambda returns a string.
405
+ ```
406
+
407
+ The above examples showed a method accepting a `Proc` as the last argument, but the same contract works on methods that accept a block:
408
+
409
+ ```ruby
410
+ def map(arr, &block)
411
+ ```
412
+
413
+ NOTE: This is not valid:
414
+
415
+ ```ruby
416
+ Contract C::ArrayOf[C::Num], C::Func => C::ArrayOf[C::Num]
417
+ def map(arr, &func)
418
+ ```
419
+
420
+ Here I am using `Func` without specifying a contract, like `Func[Num => Num]`. That's not a legal contract. If you just want to validate that the second argument is a proc, use `Proc`.
421
+
422
+ ### Returning Multiple Values
423
+ Treat the return value as an array. For example, here's a function that returns two numbers:
424
+
425
+ ```ruby
426
+ Contract C::Num => [C::Num, C::Num]
427
+ def mult(x)
428
+ return x, x+1
429
+ end
430
+ ```
431
+
432
+ ## Synonyms For Contracts
433
+
434
+ If you use a contract a lot, it's a good idea to give it a meaningful synonym that tells the reader more about what your code returns. For example, suppose you have many functions that return a `Hash` or `nil`. If a `Hash` is returned, it contains information about a person. Your contact might look like this:
435
+
436
+ ```ruby
437
+ Contract String => C::Or[Hash, nil]
438
+ def some_func(str)
439
+ ```
440
+
441
+ You can make your contract more meaningful with a synonym:
442
+
443
+ ```ruby
444
+ # the synonym
445
+ Person = Or[Hash, nil]
446
+
447
+ # use the synonym here
448
+ Contract String => Person
449
+ def some_func(str)
450
+ ```
451
+
452
+ Now you can use `Person` wherever you would have used `Or[Hash, nil]`. Your code is now cleaner and more clearly says what the function is doing.
453
+
454
+ ## Defining Your Own Contracts
455
+
456
+ Contracts are very easy to define. To re-iterate, there are 5 kinds of contracts:
457
+
458
+ - the name of a class (like `String` or `Fixnum`)
459
+ - a constant (like `nil` or `1`)
460
+ - a `Proc` that takes a value and returns true or false to indicate whether the contract passed or not
461
+ - a class that responds to the `valid?` class method (more on this later)
462
+ - an instance of a class that responds to the `valid?` method (more on this later)
463
+
464
+ The first two don't need any extra work to define: you can just use any constant or class name in your contract and it should just work. Here are examples for the rest:
465
+
466
+ ### A Proc
467
+
468
+ ```ruby
469
+ Contract lambda { |x| x.is_a? Numeric } => C::Num
470
+ def double(x)
471
+ ```
472
+
473
+ The lambda takes one parameter: the argument that is getting passed to the function. It checks to see if it's a `Numeric`. If it is, it returns true. Otherwise it returns false.
474
+ It's not good practice to write a lambda right in your contract...if you find yourself doing it often, write it as a class instead:
475
+
476
+ ### A Class With `valid?` As a Class Method
477
+
478
+ Here's how the `Num` class is defined. It does exactly what the `lambda` did in the previous example:
479
+
480
+ ```ruby
481
+ class Num
482
+ def self.valid? val
483
+ val.is_a? Numeric
484
+ end
485
+ end
486
+ ```
487
+
488
+ The `valid?` class method takes one parameter: the argument that is getting passed to the function. It returns true or false.
489
+
490
+ ### A Class With `valid?` As an Instance Method
491
+
492
+ Here's how the `Or` class is defined:
493
+
494
+ ```ruby
495
+ class Or < CallableClass
496
+ def initialize(*vals)
497
+ @vals = vals
498
+ end
499
+
500
+ def valid?(val)
501
+ @vals.any? do |contract|
502
+ res, _ = Contract.valid?(val, contract)
503
+ res
504
+ end
505
+ end
506
+ end
507
+ ```
508
+
509
+ The `Or` contract takes a sequence of contracts, and passes if any of them pass. It uses `Contract.valid?` to validate the value against the contracts.
510
+
511
+ This class inherits from `CallableClass`, which allows us to use `[]` when using the class:
512
+
513
+ ```ruby
514
+ Contract C::Or[Fixnum, Float] => C::Num
515
+ def double(x)
516
+ 2 * x
517
+ end
518
+ ```
519
+
520
+ Without `CallableClass`, we would have to use `.new` instead:
521
+
522
+ ```ruby
523
+ Contract C::Or.new(Fixnum, Float) => C::Num
524
+ def double(x)
525
+ # etc
526
+ ```
527
+
528
+ You can use `CallableClass` in your own contracts to make them callable using `[]`.
529
+
530
+ ## Customizing Error Messages
531
+
532
+ When a contract fails, part of the error message prints the contract:
533
+
534
+ ...
535
+ Expected: Contracts::Num,
536
+ ...
537
+
538
+ You can customize this message by overriding the `to_s` method on your class or proc. For example, suppose we overrode `Num`'s `to_s` method:
539
+
540
+ ```ruby
541
+ def Num.to_s
542
+ "a number please"
543
+ end
544
+ ```
545
+
546
+ Now the error says:
547
+
548
+ ...
549
+ Expected: a number please,
550
+ ...
551
+
552
+ ## Failure Callbacks
553
+
554
+ Supposing you don't want contract failures to become exceptions. You run a popular website, and when there's a contract exception you would rather log it and continue than throw an exception and break your site.
555
+
556
+ contracts.ruby provides a failure callback that gets called when a contract fails. For example, here we log every failure instead of raising an error:
557
+
558
+ ```ruby
559
+ Contract.override_failure_callback do |data|
560
+ puts "You had an error"
561
+ puts failure_msg(data)
562
+ end
563
+ ```
564
+
565
+ `failure_msg` is a function that prints out information about the failure. Your failure callback gets a hash with the following values:
566
+
567
+ {
568
+ :arg => the argument to the method,
569
+ :contract => the contract that got violated,
570
+ :class => the method's class,
571
+ :method => the method,
572
+ :contracts => the contract object
573
+ }
574
+
575
+ If your failure callback returns `false`, the method that the contract is guarding will not be called (the default behaviour).
576
+
577
+ ## Providing your own custom validators
578
+
579
+ This can be done with `Contract.override_validator`:
580
+
581
+ ```ruby
582
+ # Make contracts accept all RSpec doubles
583
+ Contract.override_validator(:class) do |contract|
584
+ lambda do |arg|
585
+ arg.is_a?(RSpec::Mocks::Double) ||
586
+ arg.is_a?(contract)
587
+ end
588
+ end
589
+ ```
590
+
591
+ The block you provide should always return lambda accepting one argument - validated argument. Block itself accepts contract as an argument.
592
+
593
+ Possible validator overrides:
594
+
595
+ - `override_validator(MyCustomContract)` - allows to add some special behaviour for custom contracts,
596
+ - `override_validator(Proc)` - e.g. `lambda { true }`,
597
+ - `override_validator(Array)` - e.g. `[C::Num, String]`,
598
+ - `override_validator(Hash)` - e.g. `{ :a => C::Num, :b => String }`,
599
+ - `override_validator(Range)` - e.g. `(1..10)`,
600
+ - `override_validator(Regexp)` - e.g. `/foo/`,
601
+ - `override_validator(Contracts::Args)` - e.g. `C::Args[C::Num]`,
602
+ - `override_validator(Contracts::Func)` - e.g. `C::Func[C::Num => C::Num]`,
603
+ - `override_validator(:valid)` - allows to override how contracts that respond to `:valid?` are handled,
604
+ - `override_validator(:class)` - allows to override how class/module contract constants are handled,
605
+ - `override_validator(:default)` - otherwise, raw value contracts.
606
+
607
+ Default validators can be found here: [lib/contracts/validators.rb](https://github.com/egonSchiele/contracts.ruby/blob/master/lib/contracts/validators.rb).
608
+
609
+ ## Disabling contracts
610
+
611
+ If you want to disable contracts, set the `NO_CONTRACTS` environment variable. This will disable contracts and you won't have a performance hit. Pattern matching will still work if you disable contracts in this way! With NO_CONTRACTS only pattern-matching contracts are defined.
612
+
613
+ ## Method overloading
614
+
615
+ You can use contracts for method overloading! This is commonly called "pattern matching" in functional programming languages.
616
+
617
+ For example, here's a factorial function without method overloading:
618
+
619
+ ```ruby
620
+ Contract C::Num => C::Num
621
+ def fact x
622
+ if x == 1
623
+ x
624
+ else
625
+ x * fact(x - 1)
626
+ end
627
+ end
628
+ ```
629
+
630
+ Here it is again, re-written with method overloading:
631
+
632
+ ```ruby
633
+ Contract 1 => 1
634
+ def fact x
635
+ x
636
+ end
637
+
638
+ Contract C::Num => C::Num
639
+ def fact x
640
+ x * fact(x - 1)
641
+ end
642
+ ```
643
+
644
+ For an argument, each function will be tried in order. The first function that doesn't raise a `ContractError` will be used. So in this case, if x == 1, the first function will be used. For all other values, the second function will be used.
645
+
646
+ This allows you write methods more declaratively, rather than using conditional branching. This feature is not only useful for recursion; you can use it to keep parallel use cases separate:
647
+
648
+ ```ruby
649
+ Contract lambda{|n| n < 12 } => Ticket
650
+ def get_ticket(age)
651
+ ChildTicket.new(age: age)
652
+ end
653
+
654
+ Contract lambda{|n| n >= 12 } => Ticket
655
+ def get_ticket(age)
656
+ AdultTicket.new(age: age)
657
+ end
658
+
659
+ ```
660
+
661
+ Note that the second `get_ticket` contract above could have been simplified to:
662
+
663
+ ```ruby
664
+ Contract C::Num => Ticket
665
+ ```
666
+
667
+ This is because the first contract eliminated the possibility of `age` being less than 12. However, the simpler contract is less explicit; you may want to "spell out" the age condition for clarity, especially if the method is overloaded with many contracts.
668
+
669
+ ## Contracts in modules
670
+
671
+ Usage is the same as contracts in classes:
672
+
673
+ ```ruby
674
+ module M
675
+ include Contracts::Core
676
+
677
+ Contract String => String
678
+ def self.parse
679
+ # do some hard parsing
680
+ end
681
+ end
682
+ ```
683
+
684
+ ## Invariants
685
+
686
+ Invariants are conditions on objects that should always hold. If after any method call on given object, any of the Invariants fails, then Invariant violation error will be generated.
687
+
688
+ **NOTE**: Only methods with contracts will be affected.
689
+
690
+ A simple example:
691
+
692
+ ```ruby
693
+ class MyBirthday < Struct.new(:day, :month)
694
+ include Contracts::Core
695
+ include Contracts::Invariants
696
+
697
+ invariant(:day) { 1 <= day && day <= 31 }
698
+ invariant(:month) { 1 <= month && month <= 12 }
699
+
700
+ Contract C::None => Fixnum
701
+ def silly_next_day!
702
+ self.day += 1
703
+ end
704
+ end
705
+
706
+ birthday = MyBirthday.new(31, 12)
707
+ birthday.silly_next_day!
708
+ ```
709
+
710
+ If you run it, last line will generate invariant violation:
711
+
712
+ ```ruby
713
+ ./invariant.rb:38:in `failure_callback': Invariant violation: (RuntimeError)
714
+ Expected: day condition to be true
715
+ Actual: false
716
+ Value guarded in: MyBirthday::silly_next_day!
717
+ At: main.rb:9
718
+ ```
719
+
720
+ Which means, that after `#silly_next_day!` all checks specified in `invariant` statement will be verified, and if at least one fail, then invariant violation error will be raised.
721
+
722
+ ## Using contracts within your own code
723
+
724
+ contracts.ruby is obviously designed to check method parameters and return values. But if you want to check whether some other data obeys a contract, you can use `Contract.valid?(value, contract)`. For instance:
725
+
726
+ ```ruby
727
+ data = parse(user_input)
728
+ unless Contract.valid?(data, HashOf[String,Nat])
729
+ raise UserInputError.new(user_input)
730
+ end
731
+ ```
732
+
733
+ ## Auto-generate documentation using contracts
734
+
735
+ If you are generating documentation for your code with [YARD](http://yardoc.org/), check out [yard-contracts](https://github.com/sfcgeorge/yard-contracts). It will automatically annotate your functions with contracts information. Instead of documenting each parameter for a function yourself, you can just add a contract and yard-contracts will generate the documentation for you!
736
+
737
+ ## Misc
738
+
739
+ Please submit any bugs [here](https://github.com/egonSchiele/contracts.ruby/issues) and I'll try to get them resolved ASAP!
740
+
741
+ See any mistakes in this tutorial? I try to make it bug-free, but they can creep in. [File an issue](https://github.com/egonSchiele/contracts.ruby/issues).
742
+
743
+ If you're using the library, please [let me know](https://github.com/egonSchiele) what project you're using it on :)
744
+
745
+ See the [wiki](https://github.com/egonSchiele/contracts.ruby/wiki) for more info.
746
+
747
+ Happy Coding!