You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
rubygem-contracts/rubygem-contracts-0.16.0-00...

103 lines
3.7 KiB

From 726e28c473b8d4453b4485922a2c52e9511bfc42 Mon Sep 17 00:00:00 2001
From: Chris Seaton <chris@chrisseaton.com>
Date: Fri, 10 Nov 2017 17:20:38 +0000
Subject: [PATCH 1/5] Don't use exceptions for control flow
---
lib/contracts/call_with.rb | 22 +++++++++++++--------
lib/contracts/method_handler.rb | 34 +++++++++++++--------------------
2 files changed, 27 insertions(+), 29 deletions(-)
diff --git a/lib/contracts/call_with.rb b/lib/contracts/call_with.rb
index c8a8b62..2735d1e 100644
--- a/lib/contracts/call_with.rb
+++ b/lib/contracts/call_with.rb
@@ -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
@@ -16,14 +20,16 @@ module Contracts
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
diff --git a/lib/contracts/method_handler.rb b/lib/contracts/method_handler.rb
index ee16b6b..fe301cd 100644
--- a/lib/contracts/method_handler.rb
+++ b/lib/contracts/method_handler.rb
@@ -125,31 +125,23 @@ module Contracts
# 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
--
2.29.2