Skip to content

Commit 9aa8b0a

Browse files
authored
Merge pull request #308 from egonSchiele/fix/pattern-matching
Fix pattern matching
2 parents 0c578a4 + 43457aa commit 9aa8b0a

File tree

2 files changed

+136
-1
lines changed

2 files changed

+136
-1
lines changed
+133
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,133 @@
1+
Feature: Method Overloading
2+
3+
You can use contracts for method overloading! This is commonly called "pattern matching" in functional programming languages.
4+
5+
```ruby
6+
Contract 1 => 1
7+
def fact x
8+
x
9+
end
10+
11+
Contract C::Num => C::Num
12+
def fact x
13+
x * fact(x - 1)
14+
end
15+
```
16+
17+
Background:
18+
Given a file named "method_overloading_with_positional_args_usage.rb" with:
19+
"""ruby
20+
require "contracts"
21+
C = Contracts
22+
23+
class Example
24+
include Contracts::Core
25+
26+
Contract 1 => 1
27+
def fact(x)
28+
x
29+
end
30+
31+
Contract C::Num => C::Num
32+
def fact(x)
33+
x * fact(x - 1)
34+
end
35+
end
36+
"""
37+
38+
Given a file named "method_overloading_with_keyword_args_usage.rb" with:
39+
"""ruby
40+
require "contracts"
41+
C = Contracts
42+
43+
class Example
44+
include Contracts::Core
45+
46+
Contract C::KeywordArgs[age: Integer, size: Symbol] => String
47+
def speak(age:, size:)
48+
"age: #{age} size: #{size}"
49+
end
50+
51+
Contract C::KeywordArgs[sound: String] => String
52+
def speak(sound:)
53+
"sound: #{sound}"
54+
end
55+
end
56+
"""
57+
58+
Scenario: Positional Args Method 1
59+
Given a file named "positional_args_method_1.rb" with:
60+
"""ruby
61+
require "./method_overloading_with_positional_args_usage"
62+
puts Example.new.fact(1)
63+
"""
64+
When I run `ruby positional_args_method_1.rb`
65+
Then the output should contain:
66+
"""
67+
1
68+
"""
69+
70+
Scenario: Positional Args Method 2
71+
Given a file named "positional_args_method_2.rb" with:
72+
"""ruby
73+
require "./method_overloading_with_positional_args_usage"
74+
puts Example.new.fact(4)
75+
"""
76+
When I run `ruby positional_args_method_2.rb`
77+
Then the output should contain:
78+
"""
79+
24
80+
"""
81+
82+
Scenario: Keyword Args Method 1
83+
Given a file named "keyword_args_method_1.rb" with:
84+
"""ruby
85+
require "./method_overloading_with_keyword_args_usage"
86+
puts Example.new.speak(age: 5, size: :large)
87+
"""
88+
When I run `ruby keyword_args_method_1.rb`
89+
Then the output should contain:
90+
"""
91+
age: 5 size: large
92+
"""
93+
94+
Scenario: Keyword Args Method 2
95+
Given a file named "keyword_args_method_2.rb" with:
96+
"""ruby
97+
require "./method_overloading_with_keyword_args_usage"
98+
puts Example.new.speak(sound: "woof")
99+
"""
100+
When I run `ruby keyword_args_method_2.rb`
101+
Then the output should contain:
102+
"""
103+
sound: woof
104+
"""
105+
106+
Scenario: Incorrect Positional Args Method
107+
Given a file named "incorrect_positional_args_method.rb" with:
108+
"""ruby
109+
require "contracts"
110+
C = Contracts
111+
112+
class Example
113+
include Contracts::Core
114+
115+
# Notice that this method's contract is wider than the one below
116+
# This would cause this method to be called every time but never the one below
117+
Contract C::Num => C::Num
118+
def fact(x)
119+
x * fact(x - 1)
120+
end
121+
122+
Contract 1 => 1
123+
def fact(x)
124+
x
125+
end
126+
end
127+
puts Example.new.fact(4)
128+
"""
129+
When I run `ruby incorrect_positional_args_method.rb`
130+
Then the output should contain:
131+
"""
132+
stack level too deep (SystemStackError)
133+
"""

lib/contracts/method_handler.rb

+3-1
Original file line numberDiff line numberDiff line change
@@ -174,8 +174,10 @@ def foo x
174174

175175
def validate_pattern_matching!
176176
new_args_contract = decorator.args_contracts
177+
new_kargs_contract = decorator.kargs_contract
177178
matched = decorated_methods.select do |contract|
178-
contract.args_contracts == new_args_contract
179+
contract.args_contracts == new_args_contract &&
180+
contract.kargs_contract == new_kargs_contract
179181
end
180182

181183
return if matched.empty?

0 commit comments

Comments
 (0)