Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Don't use exceptions for control flow
  • Loading branch information
chrisseaton committed Nov 10, 2017
commit 565b16d3f6130e34065567eb4a62cf6e9442ded5
22 changes: 14 additions & 8 deletions lib/contracts/call_with.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
module Contracts
module CallWith
def call_with(this, *args, &blk)
call_with_inner(false, this, *args, &blk)
end

def call_with_inner(returns, this, *args, &blk)
args << blk if blk

# Explicitly append blk=nil if nil != Proc contract violation anticipated
Expand All @@ -16,14 +20,16 @@ def call_with(this, *args, &blk)
validator = @args_validators[i]

unless validator && validator[arg]
return unless Contract.failure_callback(:arg => arg,
:contract => contract,
:class => klass,
:method => method,
:contracts => self,
:arg_pos => i+1,
:total_args => args.size,
:return_value => false)
data = {:arg => arg,
:contract => contract,
:class => klass,
:method => method,
:contracts => self,
:arg_pos => i+1,
:total_args => args.size,
:return_value => false}
return ParamContractError.new("as return value", data) if returns
return unless Contract.failure_callback(data)
end

if contract.is_a?(Contracts::Func) && blk && !nil_block_appended
Expand Down
34 changes: 13 additions & 21 deletions lib/contracts/method_handler.rb
Original file line number Diff line number Diff line change
Expand Up @@ -125,31 +125,23 @@ def redefine_method
# function. Otherwise we return the result.
# If we run out of functions, we raise the last error, but
# convert it to_contract_error.
success = false
i = 0
result = nil

expected_error = decorated_methods[0].failure_exception
last_error = nil

until success
decorated_method = decorated_methods[i]
i += 1
begin
success = true
result = decorated_method.call_with(self, *args, &blk)
rescue expected_error => error
success = false
unless decorated_methods[i]
begin
::Contract.failure_callback(error.data, false)
rescue expected_error => final_error
raise final_error.to_contract_error
end
end
end
decorated_methods.each do |decorated_method|
result = decorated_method.call_with_inner(true, self, *args, &blk)
return result unless result.is_a?(ParamContractError)
last_error = result
end

# Return the result of successfully called method
result
begin
if ::Contract.failure_callback(last_error.data, false)
decorated_methods.last.call_with_inner(false, self, *args, &blk)
end
rescue expected_error => final_error
raise final_error.to_contract_error
end
end
end

Expand Down