diff --git a/Gemfile b/Gemfile index e0c8a59..2ca6c2f 100644 --- a/Gemfile +++ b/Gemfile @@ -6,7 +6,7 @@ group :test do gem "rspec" gem "aruba" gem "cucumber", "~> 1.3.20" - gem "rubocop", "~> 0.29.1", :platform => [:ruby_20, :ruby_21, :ruby_22, :ruby_23] + gem "rubocop", "~> 0.29.1" if RUBY_VERSION >= "2" end group :development do diff --git a/lib/contracts/call_with.rb b/lib/contracts/call_with.rb index 29a609f..c8a8b62 100644 --- a/lib/contracts/call_with.rb +++ b/lib/contracts/call_with.rb @@ -26,7 +26,9 @@ def call_with(this, *args, &blk) :return_value => false) end - if contract.is_a?(Contracts::Func) + if contract.is_a?(Contracts::Func) && blk && !nil_block_appended + blk = Contract.new(klass, arg, *contract.contracts) + elsif contract.is_a?(Contracts::Func) args[i] = Contract.new(klass, arg, *contract.contracts) end end @@ -73,7 +75,8 @@ def call_with(this, *args, &blk) method.call(*args, &blk) else # original method name referrence - method.send_to(this, *args, &blk) + added_block = blk ? lambda { |*params| blk.call(*params) } : nil + method.send_to(this, *args, &added_block) end unless @ret_validator[result] diff --git a/spec/methods_spec.rb b/spec/methods_spec.rb new file mode 100644 index 0000000..334fb4e --- /dev/null +++ b/spec/methods_spec.rb @@ -0,0 +1,54 @@ +RSpec.describe "Contracts:" do + describe "method called with blocks" do + module FuncTest + include Contracts::Core + include Contracts::Builtin + + Contract Func[Num=>Num] => nil + def foo(&blk) + _ = blk.call(2) + nil + end + + Contract Num, Func[Num=>Num] => nil + def foo2(a, &blk) + _ = blk.call(2) + nil + end + + Contract Func[Num=>Num] => nil + def bar(blk) + _ = blk.call(2) + nil + end + + Contract Num, Func[Num=>Num] => nil + def bar2(a, blk) + _ = blk.call(2) + nil + end + end + + def obj + Object.new.tap do |o| + o.extend(FuncTest) + end + end + + it "should enforce return value inside block with no other parameter" do + expect { obj.foo(&:to_s) }.to raise_error + end + + it "should enforce return value inside block with other parameter" do + expect { obj.foo2(2) { |x| x.to_s } }.to raise_error + end + + it "should enforce return value inside lambda with no other parameter" do + expect { obj.bar lambda { |x| x.to_s } }.to raise_error + end + + it "should enforce return value inside lambda with other parameter" do + expect { obj.bar2(2, lambda { |x| x.to_s }) }.to raise_error + end + end +end