Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #195 from waterlink/docs
Docs
- Loading branch information
Showing
37 changed files
with
1,537 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ | |
*.swo | ||
.* | ||
Gemfile.lock | ||
tmp/aruba |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
default: --require features |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
contracts.ruby brings code contracts to the Ruby language. | ||
|
||
Example: | ||
|
||
```ruby | ||
class Example | ||
include Contracts::Core | ||
C = Contracts | ||
|
||
Contract C::Num, C::Num => C::Num | ||
def add(a, b) | ||
a + b | ||
end | ||
end | ||
``` | ||
|
||
This documentation is [open source](https://github.com/egonSchiele/contracts.ruby/tree/master/features). If you find it incomplete or confusing, please [submit an issue](https://github.com/egonSchiele/contracts.ruby/issues), or, better yet, [a pull request](https://github.com/egonSchiele/contracts.ruby). |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
Feature: Fetching contracted function type | ||
|
||
You can use `functype(name)` method for that: | ||
|
||
```ruby | ||
functype(:add) # => "add :: Num, Num => Num" | ||
``` | ||
|
||
Background: | ||
Given a file named "example.rb" with: | ||
"""ruby | ||
require "contracts" | ||
C = Contracts | ||
class Example | ||
include Contracts::Core | ||
Contract C::Num, C::Num => C::Num | ||
def add(a, b) | ||
a + b | ||
end | ||
Contract String => String | ||
def self.greeting(name) | ||
"Hello, #{name}" | ||
end | ||
class << self | ||
Contract C::Num => String | ||
def th(number) | ||
suffix = { | ||
1 => "st", | ||
2 => "nd", | ||
3 => "rd" | ||
}.fetch(x % 10, "th") | ||
"#{number}#{suffix}" | ||
end | ||
end | ||
end | ||
""" | ||
|
||
Scenario: functype on instance method | ||
Given a file named "instance_method_functype.rb" with: | ||
"""ruby | ||
require "./example" | ||
puts Example.new.functype(:add) | ||
""" | ||
When I run `ruby instance_method_functype.rb` | ||
Then the output should contain: | ||
""" | ||
add :: Num, Num => Num | ||
""" | ||
|
||
Scenario: functype on class method | ||
Given a file named "class_method_functype.rb" with: | ||
"""ruby | ||
require "./example" | ||
puts Example.functype(:greeting) | ||
""" | ||
When I run `ruby class_method_functype.rb` | ||
Then the output should contain: | ||
""" | ||
greeting :: String => String | ||
""" | ||
|
||
Scenario: functype on singleton method | ||
Given a file named "singleton_method_functype.rb" with: | ||
"""ruby | ||
require "./example" | ||
puts Example.functype(:th) | ||
""" | ||
When I run `ruby singleton_method_functype.rb` | ||
Then the output should contain: | ||
""" | ||
th :: Num => String | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,210 @@ | ||
Feature: Simple examples and Contract violations | ||
|
||
Contracts.ruby allows specification of contracts on per-method basis, where | ||
method arguments and return value will be validated upon method call. | ||
|
||
Example: | ||
|
||
```ruby | ||
Contract C::Num, C::Num => C::Num | ||
def add(a, b) | ||
a + b | ||
end | ||
``` | ||
|
||
Here `Contract arg_contracts... => return_contract` defines list of argument | ||
contracts `args_contracts...` as `C::Num, C::Num` (i.e.: both arguments | ||
should be numbers) and return value contract `return_contract` as `C::Num` | ||
(i.e.: return value should be a number too). | ||
|
||
`Contract arg_contracts... => return_contract` affects next defined instance, | ||
class or singleton method, meaning that all of these work: | ||
|
||
- [Instance method](#instance-method), | ||
|
||
- [Class method](#class-method), | ||
|
||
- [Singleton method](#singleton-method). | ||
|
||
Whenever invalid argument is passed to a contracted method, corresponding | ||
`ContractError` will be raised. That happens right after bad value got into | ||
system protected by contracts and prevents error propagation: first | ||
non-contracts library frame in exception's backtrace is a culprit for passing | ||
an invalid argument - you do not need to verify 20-30 frames to find a | ||
culprit! Example of such error: [instance method contract | ||
violation](#instance-method-contract-violation). | ||
|
||
Whenever invalid return value is returned from a contracted method, | ||
corresponding `ContractError` will be raised. That happens right after method | ||
returned this value and prevents error propagation: `At: your_filename.rb:17` | ||
part of error message points directly to a culprit method. Example of such | ||
error: [return value contract | ||
violation](#singleton-method-return-value-contract-violation). | ||
|
||
Contract violation error consists of such parts: | ||
- Violation type: | ||
- `Contract violation for argument X of Y: (ParamContractError)`, | ||
- `Contract violation for return value (ReturnContractError)`. | ||
- Expected contract, example: `Expected: Num`. | ||
- Actual value, example: `Actual: "foo"`. | ||
- Location of violated contract, example: `Value guarded in: Example::add`. | ||
- Full contract, example: `With Contract: Num, Num => Num`. | ||
- Source code location of contracted method, example: `At: lib/your_library/some_class.rb:17`. | ||
|
||
Scenario: Instance method | ||
Given a file named "instance_method.rb" with: | ||
"""ruby | ||
require "contracts" | ||
C = Contracts | ||
class Example | ||
include Contracts::Core | ||
Contract C::Num, C::Num => C::Num | ||
def add(a, b) | ||
a + b | ||
end | ||
end | ||
puts Example.new.add(2, 2) | ||
""" | ||
When I run `ruby instance_method.rb` | ||
Then the output should contain: | ||
""" | ||
4 | ||
""" | ||
|
||
Scenario: Instance method contract violation | ||
Given a file named "instance_method_violation.rb" with: | ||
"""ruby | ||
require "contracts" | ||
C = Contracts | ||
class Example | ||
include Contracts::Core | ||
Contract C::Num, C::Num => C::Num | ||
def add(a, b) | ||
a + b | ||
end | ||
end | ||
puts Example.new.add(2, "foo") | ||
""" | ||
When I run `ruby instance_method_violation.rb` | ||
Then the output should contain: | ||
""" | ||
: Contract violation for argument 2 of 2: (ParamContractError) | ||
Expected: Num, | ||
Actual: "foo" | ||
Value guarded in: Example::add | ||
With Contract: Num, Num => Num | ||
At: instance_method_violation.rb:8 | ||
""" | ||
|
||
Scenario: Class method | ||
Given a file named "class_method.rb" with: | ||
"""ruby | ||
require "contracts" | ||
C = Contracts | ||
class Example | ||
include Contracts::Core | ||
Contract C::Num, C::Num => C::Num | ||
def self.add(a, b) | ||
a + b | ||
end | ||
end | ||
puts Example.add(2, 2) | ||
""" | ||
When I run `ruby class_method.rb` | ||
Then the output should contain: | ||
""" | ||
4 | ||
""" | ||
|
||
Scenario: Class method contract violation | ||
Given a file named "class_method_violation.rb" with: | ||
"""ruby | ||
require "contracts" | ||
C = Contracts | ||
class Example | ||
include Contracts::Core | ||
Contract C::Num, C::Num => C::Num | ||
def self.add(a, b) | ||
a + b | ||
end | ||
end | ||
puts Example.add(:foo, 2) | ||
""" | ||
When I run `ruby class_method_violation.rb` | ||
Then the output should contain: | ||
""" | ||
: Contract violation for argument 1 of 2: (ParamContractError) | ||
Expected: Num, | ||
Actual: :foo | ||
Value guarded in: Example::add | ||
With Contract: Num, Num => Num | ||
At: class_method_violation.rb:8 | ||
""" | ||
|
||
Scenario: Singleton method | ||
Given a file named "singleton_method.rb" with: | ||
"""ruby | ||
require "contracts" | ||
C = Contracts | ||
class Example | ||
include Contracts::Core | ||
class << self | ||
Contract C::Num, C::Num => C::Num | ||
def add(a, b) | ||
a + b | ||
end | ||
end | ||
end | ||
puts Example.add(2, 2) | ||
""" | ||
When I run `ruby singleton_method.rb` | ||
Then the output should contain: | ||
""" | ||
4 | ||
""" | ||
|
||
Scenario: Singleton method return value contract violation | ||
Given a file named "singleton_method_violation.rb" with: | ||
"""ruby | ||
require "contracts" | ||
C = Contracts | ||
class Example | ||
include Contracts::Core | ||
class << self | ||
Contract C::Num, C::Num => C::Num | ||
def add(a, b) | ||
# notice here non-number is returned | ||
nil | ||
end | ||
end | ||
end | ||
puts Example.add(2, 2) | ||
""" | ||
When I run `ruby singleton_method_violation.rb` | ||
Then the output should contain: | ||
""" | ||
: Contract violation for return value: (ReturnContractError) | ||
Expected: Num, | ||
Actual: nil | ||
Value guarded in: Example::add | ||
With Contract: Num, Num => Num | ||
At: singleton_method_violation.rb:9 | ||
""" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
To use builtin contracts you can refer them with `Contracts::*`: | ||
|
||
```ruby | ||
Contract Contracts::Num => Contracts::Maybe(Contracts::Num) | ||
``` | ||
|
||
It is recommended to use a short alias for `Contracts`, for example `C`: | ||
|
||
```ruby | ||
C = Contracts | ||
|
||
Contract C::Num => C::Maybe(C::Num) | ||
``` | ||
|
||
It is possible to `include Contracts` and refer them without namespace, but | ||
this is deprecated and not recommended. | ||
|
||
*NOTE: in the future it will be possible to do `include Contracts::Builtin` | ||
instead.* | ||
|
||
*NOTE: all contracts marked as (TODO) have their documentaion `.feature` file | ||
as stub. Contributions to those are warmly welcome!* |
Oops, something went wrong.