From cd4e37731326a971647ec122339b4f2c8288f918 Mon Sep 17 00:00:00 2001 From: Aditya Bhargava Date: Thu, 23 Jul 2015 16:53:34 -0700 Subject: [PATCH] when varargs are given with a maybe[block], and the block is not provided, do not append an extra nil to the varargs (fixes issue #161) --- lib/contracts.rb | 9 +++++++-- lib/contracts/call_with.rb | 5 +++-- spec/contracts_spec.rb | 10 ++++++++++ spec/fixtures/fixtures.rb | 1 + 4 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/contracts.rb b/lib/contracts.rb index 7a1e711..928eba0 100644 --- a/lib/contracts.rb +++ b/lib/contracts.rb @@ -118,6 +118,7 @@ def initialize(klass, method, *contracts) maybe_a_proc = last_contract.is_a?(Contracts::Maybe) && last_contract.include_proc? @has_proc_contract = is_a_proc || maybe_a_proc || last_contract.is_a?(Contracts::Func) + # ==== # == @has_options_contract @@ -235,20 +236,24 @@ def call(*args, &blk) # a better way to handle this might be to take this into account # before throwing a "mismatched # of args" error. + # returns true if it appended nil def maybe_append_block! args, blk - return unless @has_proc_contract && !blk && + return false unless @has_proc_contract && !blk && (@args_contract_index || args.size < args_contracts.size) args << nil + true end # Same thing for when we have named params but didn't pass any in. + # returns true if it appended nil def maybe_append_options! args, blk - return unless @has_options_contract + return false unless @has_options_contract if @has_proc_contract && args_contracts[-2].is_a?(Hash) && !args[-2].is_a?(Hash) args.insert(-2, {}) elsif args_contracts[-1].is_a?(Hash) && !args[-1].is_a?(Hash) args << {} end + true end # Used to determine type of failure exception this contract should raise in case of failure diff --git a/lib/contracts/call_with.rb b/lib/contracts/call_with.rb index 123a20f..29a609f 100644 --- a/lib/contracts/call_with.rb +++ b/lib/contracts/call_with.rb @@ -4,7 +4,7 @@ def call_with(this, *args, &blk) args << blk if blk # Explicitly append blk=nil if nil != Proc contract violation anticipated - maybe_append_block!(args, blk) + nil_block_appended = maybe_append_block!(args, blk) # Explicitly append options={} if Hash contract is present maybe_append_options!(args, blk) @@ -66,7 +66,8 @@ def call_with(this, *args, &blk) end # If we put the block into args for validating, restore the args - args.slice!(-1) if blk + # OR if we added a fake nil at the end because a block wasn't passed in. + args.slice!(-1) if blk || nil_block_appended result = if method.respond_to?(:call) # proc, block, lambda, etc method.call(*args, &blk) diff --git a/spec/contracts_spec.rb b/spec/contracts_spec.rb index 4e5429d..9a1490e 100644 --- a/spec/contracts_spec.rb +++ b/spec/contracts_spec.rb @@ -423,6 +423,16 @@ def self.greeting(name) @o.maybe_call("bad") end.to raise_error(ContractError) end + + describe "varargs are given with a maybe block" do + it "when a block is passed in, varargs should be correct" do + expect(@o.maybe_call(1, 2, 3) { 1 + 1 }).to eq([1, 2, 3]) + end + + it "when a block is NOT passed in, varargs should still be correct" do + expect(@o.maybe_call(1, 2, 3)).to eq([1, 2, 3]) + end + end end describe "varargs" do diff --git a/spec/fixtures/fixtures.rb b/spec/fixtures/fixtures.rb index a138602..784d489 100644 --- a/spec/fixtures/fixtures.rb +++ b/spec/fixtures/fixtures.rb @@ -133,6 +133,7 @@ def do_call(&block) Contract Args[Num], Maybe[Proc] => Any def maybe_call(*vals, &block) block.call if block + vals end Contract Args[Num] => Num