From 3864490a02a9e9c4350af420eb30847df90f28b7 Mon Sep 17 00:00:00 2001 From: Oleksii Fedorov Date: Wed, 9 Sep 2015 16:53:48 +0200 Subject: [PATCH 1/2] [fixes #176] Do not redefine 'Contract' in class_eval for 'extend' to work --- lib/contracts/core.rb | 6 +++++- spec/contracts_spec.rb | 29 +++++++++++++++++++++++++++++ 2 files changed, 34 insertions(+), 1 deletion(-) diff --git a/lib/contracts/core.rb b/lib/contracts/core.rb index 89f6e3e..14b207c 100644 --- a/lib/contracts/core.rb +++ b/lib/contracts/core.rb @@ -28,7 +28,11 @@ def functype(funcname) # TODO: deprecate # Required when contracts are included in global scope def Contract(*args) - self.class.Contract(*args) + if defined?(super) + super + else + self.class.Contract(*args) + end end def functype(funcname) diff --git a/spec/contracts_spec.rb b/spec/contracts_spec.rb index 31e2df8..b7f1bc4 100644 --- a/spec/contracts_spec.rb +++ b/spec/contracts_spec.rb @@ -717,4 +717,33 @@ def delim(match) expect { c.double("asd") }.to raise_error end end + + describe "classes with extended modules" do + let(:klass) do + m = Module.new do + include Contracts::Core + end + + Class.new do + include Contracts::Core + extend m + + Contract String => nil + def foo(x) + end + end + end + + it "is possible to define it" do + expect { klass }.not_to raise_error + end + + it "works correctly with methods with passing contracts" do + expect { klass.new.foo("bar") }.not_to raise_error + end + + it "works correctly with methods with passing contracts" do + expect { klass.new.foo(42) }.to raise_error(ContractError, /Expected: String/) + end + end end From e637c44035078e25825a514e9fb4a8b4bf21663b Mon Sep 17 00:00:00 2001 From: Oleksii Fedorov Date: Wed, 9 Sep 2015 23:59:43 +0200 Subject: [PATCH 2/2] Fix defined?(super) for ruby 1.9.2 --- lib/contracts/core.rb | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/contracts/core.rb b/lib/contracts/core.rb index 14b207c..fdbb517 100644 --- a/lib/contracts/core.rb +++ b/lib/contracts/core.rb @@ -24,7 +24,10 @@ def functype(funcname) end end - base.class_eval do + # NOTE: Workaround for `defined?(super)` bug in ruby 1.9.2 + # source: http://stackoverflow.com/a/11181685 + # bug: https://bugs.ruby-lang.org/issues/6644 + base.class_eval <<-RUBY # TODO: deprecate # Required when contracts are included in global scope def Contract(*args) @@ -34,7 +37,9 @@ def Contract(*args) self.class.Contract(*args) end end + RUBY + base.class_eval do def functype(funcname) contracts = Engine.fetch_from(self.class).decorated_methods_for(:instance_methods, funcname) if contracts.nil?