jeeves 0.2.1 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,56 @@
1
+ module Jeeves
2
+ class DefineImportedMethod
3
+ def call(target, internal_name, options)
4
+ @target = target
5
+ @internal_name = internal_name
6
+ @scope = options.fetch(:from)
7
+ @external_name = options.fetch(:name)
8
+ if options[:lazy] == true
9
+ define_lazy
10
+ elsif options[:lazy] == false
11
+ define_non_lazy
12
+ else
13
+ define_smart
14
+ end
15
+ define_on_instance
16
+ end
17
+
18
+ private
19
+
20
+ def define_lazy
21
+ scope = @scope
22
+ external_name = @external_name
23
+ @target.class.send(:define_method, @internal_name) do |*args, &block|
24
+ delegator = ResolveDependency.call(scope, external_name)
25
+ delegator.call(*args, &block)
26
+ end
27
+ end
28
+
29
+ def define_non_lazy
30
+ delegator = ResolveDependency.call(@scope, @external_name)
31
+ @target.class.send(:define_method, @internal_name) do |*args, &block|
32
+ delegator.call(*args, &block)
33
+ end
34
+ end
35
+
36
+ def define_smart
37
+ scope = @scope
38
+ internal_name = @internal_name
39
+ external_name = @external_name
40
+ @target.class.send(:define_method, @internal_name) do |*args, &block|
41
+ delegator = ResolveDependency.call(scope, external_name)
42
+ self.class.send(:define_method, internal_name) do |*args, &block|
43
+ delegator.call(*args, &block)
44
+ end
45
+ delegator.call(*args, &block)
46
+ end
47
+ end
48
+
49
+ def define_on_instance
50
+ internal_name = @internal_name
51
+ @target.send(:define_method, internal_name) do |*args, &block|
52
+ self.class.send(internal_name, *args, &block)
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,27 @@
1
+ module Jeeves
2
+ class Import
3
+ def call(target, *args)
4
+ @target = target
5
+ parse_options(args)
6
+ @names.each do |external_name, internal_name|
7
+ DefineImportedMethod.new.call(target, internal_name, from: @scope,
8
+ name: external_name, lazy: @lazy)
9
+ end
10
+ end
11
+
12
+ private
13
+
14
+ def parse_options(args)
15
+ options = args.last.is_a?(Hash) ? args.pop : {}
16
+ @names = args.map { |name| name.is_a?(Array) ? name : [name, name] }
17
+ @scope = options.fetch(:from) { default_scope }
18
+ @lazy = options.fetch(:lazy, :smart)
19
+ end
20
+
21
+ def default_scope
22
+ module_names = @target.ancestors.first.to_s.split('::')[0..-2]
23
+ module_names.inject(Object) { |m, c| m.const_get(c) }
24
+ end
25
+ end
26
+ end
27
+
@@ -10,16 +10,12 @@ module Jeeves
10
10
  RESOLVERS.each do |resolver|
11
11
  break if delegator = resolver.call(scope, name)
12
12
  end
13
- delegator = mock(delegator, scope, name) if in_test_framework?
13
+ delegator = mock(delegator, scope, name) if Jeeves.in_test_framework?
14
14
  delegator or unresolved(scope, name)
15
15
  end
16
16
 
17
17
  private
18
18
 
19
- def self.in_test_framework?
20
- defined?(RSpec) || defined?(Test::Unit)
21
- end
22
-
23
19
  def self.mock(delegator, scope, name)
24
20
  lambda do |*args, &block|
25
21
  if Jeeves.respond_to?(name)
@@ -0,0 +1,19 @@
1
+ module Jeeves
2
+ class StubScope
3
+ def self.call(name)
4
+ Module.new do
5
+ @name = [name]
6
+ class << self
7
+ def const_missing(name)
8
+ @name << name
9
+ self
10
+ end
11
+ def to_s
12
+ @name.join("::")
13
+ end
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+
@@ -1,4 +1,7 @@
1
1
  module Jeeves
2
- VERSION = "0.2.1"
2
+ MAJOR_VERSION = 0
3
+ MINOR_VERSION = 2
4
+ PATCH_VERSION = 2
5
+ VERSION = [MAJOR_VERSION, MINOR_VERSION, PATCH_VERSION].join('.')
3
6
  end
4
7
 
data/lib/jeeves.rb CHANGED
@@ -1,36 +1,26 @@
1
1
  module Jeeves
2
- autoload :ResolveDependency, "jeeves/resolve_dependency"
3
- autoload :ResolveMethod, "jeeves/resolve_method"
4
- autoload :ResolveCallable, "jeeves/resolve_callable"
5
- autoload :ResolveConstant, "jeeves/resolve_constant"
2
+ autoload :Import, "jeeves/import"
3
+ autoload :ResolveDependency, "jeeves/resolve_dependency"
4
+ autoload :ResolveMethod, "jeeves/resolve_method"
5
+ autoload :ResolveCallable, "jeeves/resolve_callable"
6
+ autoload :ResolveConstant, "jeeves/resolve_constant"
7
+ autoload :DefineImportedMethod, "jeeves/define_imported_method"
8
+ autoload :StubScope, "jeeves/stub_scope"
6
9
 
7
10
  def import(*args)
8
- options = args.last.is_a?(Hash) ? args.pop : {}
9
- scope = options.fetch(:from) do
10
- module_names = ancestors.first.to_s.split('::')[0..-2]
11
- module_names.inject(Object) { |m, c| m.const_get(c) }
12
- end
13
- args.each do |name|
14
- if name.is_a?(Array)
15
- external_name, internal_name = *name
16
- else
17
- external_name = internal_name = name
18
- end
19
- if options[:lazy]
20
- self.class.send(:define_method, internal_name) do |*args, &block|
21
- delegator = ResolveDependency.call(scope, external_name)
22
- delegator.call(*args, &block)
23
- end
24
- else
25
- delegator = ResolveDependency.call(scope, external_name)
26
- self.class.send(:define_method, internal_name) do |*args, &block|
27
- delegator.call(*args, &block)
28
- end
29
- end
30
- define_method(internal_name) do |*args, &block|
31
- self.class.send(internal_name, *args, &block)
32
- end
11
+ Import.new.call(self, *args)
12
+ end
13
+
14
+ def const_missing(name)
15
+ if Jeeves.in_test_framework?
16
+ StubScope.call(name)
17
+ else
18
+ super
33
19
  end
34
20
  end
21
+
22
+ def self.in_test_framework?
23
+ defined?(RSpec) || defined?(Test::Unit)
24
+ end
35
25
  end
36
26
 
@@ -29,10 +29,15 @@ module JeevesTestApp
29
29
  class TestSubject
30
30
  extend Jeeves
31
31
  import :my_method, :my_callable, :my_constant, from: OtherScope
32
- import :marco, :static_callable
32
+ import :marco, :static_callable, lazy: false
33
33
  import :lazy_method, lazy: true
34
+ import :smart_resolver
34
35
  import [:marco, :say_polo]
35
36
  end
37
+
38
+ def self.smart_resolver
39
+ :acts_smart
40
+ end
36
41
  end
37
42
  end
38
43
 
@@ -63,8 +68,10 @@ describe "import" do
63
68
  end
64
69
 
65
70
  it "resolves lazy dependencies at call time" do
66
- JeevesTestApp::InnerScope.stub(:lazy_method) { :snooze }
67
- subject.lazy_method.should == :snooze
71
+ JeevesTestApp::InnerScope.stub(:lazy_method) { :snooze1 }
72
+ subject.lazy_method.should == :snooze1
73
+ JeevesTestApp::InnerScope.stub(:lazy_method) { :snooze2 }
74
+ subject.lazy_method.should == :snooze2
68
75
  end
69
76
 
70
77
  it "resolves non-lazy dependencies at import time" do
@@ -72,6 +79,12 @@ describe "import" do
72
79
  subject.marco.should == :polo
73
80
  end
74
81
 
82
+ it "defaults to resolving dependencies once at first call" do
83
+ subject.smart_resolver
84
+ JeevesTestApp::InnerScope.stub(:smart_resolver) { :snooze }
85
+ subject.smart_resolver.should == :acts_smart
86
+ end
87
+
75
88
  it "imports under an alias" do
76
89
  subject.say_polo.should == :polo
77
90
  end
@@ -82,10 +95,22 @@ describe "import" do
82
95
  end
83
96
 
84
97
  it "raises an error if no importers can find the dependency" do
85
- Jeeves::ResolveDependency.stub(:in_test_framework?) { false } # to avoid RSpec integration
86
- expect { subject.class.import :unknown, from: JeevesTestApp::OtherScope }.
87
- to raise_error(Jeeves::UnresolvedDependency,
88
- "Dependency 'unknown' was not found in JeevesTestApp::OtherScope")
98
+ Jeeves.stub(:in_test_framework?) { false } # to avoid RSpec integration
99
+ expect do
100
+ class JeevesTestApp::InnerScope::TestSubject
101
+ import :unknown, from: JeevesTestApp::OtherScope, lazy: false
102
+ end
103
+ end.to raise_error(Jeeves::UnresolvedDependency,
104
+ "Dependency 'unknown' was not found in JeevesTestApp::OtherScope")
105
+ end
106
+
107
+ it "raises an error if the scope is undefined" do
108
+ Jeeves.stub(:in_test_framework?) { false } # to avoid RSpec integration
109
+ expect do
110
+ class JeevesTestApp::InnerScope::TestSubject
111
+ import :unknown, from: MyUndefined::Scope, lazy: false
112
+ end
113
+ end.to raise_error(NameError)
89
114
  end
90
115
  end
91
116
 
@@ -9,6 +9,7 @@ module JeevesTestApp
9
9
  class TestSubject
10
10
  extend Jeeves
11
11
  import :my_mock, :loaded_dependency
12
+ import :external_mock, from: MyUndefined::Scope
12
13
 
13
14
  def call
14
15
  my_mock(42)
@@ -17,6 +18,10 @@ module JeevesTestApp
17
18
  def call_integrated
18
19
  loaded_dependency
19
20
  end
21
+
22
+ def call_external
23
+ external_mock
24
+ end
20
25
  end
21
26
  end
22
27
  end
@@ -34,7 +39,7 @@ describe "rspec integration" do
34
39
  "Dependency 'my_mock' was not found in JeevesTestApp::InnerScope")
35
40
  end
36
41
 
37
- it "overrides loaded dependencies with mocked methdos on Jeeves" do
42
+ it "overrides loaded dependencies with mocked methods on Jeeves" do
38
43
  Jeeves.stub(:loaded_dependency) { :stubbed_value }
39
44
  subject.call_integrated.should == :stubbed_value
40
45
  end
@@ -42,5 +47,15 @@ describe "rspec integration" do
42
47
  it "uses loaded dependencies if they are not mocked on Jeeves" do
43
48
  subject.call_integrated.should == :real_value
44
49
  end
50
+
51
+ it "treats missing scope as Jeeves" do
52
+ Jeeves.stub(:external_mock) { :stubbed_value }
53
+ subject.call_external.should == :stubbed_value
54
+ end
55
+
56
+ it "raises an error if the dependency in missing scope is not mocked" do
57
+ expect { subject.call_external }.to raise_error(Jeeves::UnresolvedDependency,
58
+ "Dependency 'external_mock' was not found in MyUndefined::Scope")
59
+ end
45
60
  end
46
61
 
@@ -18,7 +18,6 @@ end
18
18
 
19
19
  module Jeeves
20
20
  describe ResolveCallable do
21
-
22
21
  it "returns an anonymous function which delegates to the static call method of the callable" do
23
22
  delegator = ResolveCallable.call(JeevesTestApp::CallableTest, :static_callable)
24
23
  result = delegator.call(:foo, :bar, :baz) { |s| s.capitalize }
@@ -35,7 +34,6 @@ module Jeeves
35
34
  delegator = ResolveCallable.call(JeevesTestApp::CallableTest, :undefined_callable)
36
35
  delegator.should be(nil)
37
36
  end
38
-
39
37
  end
40
38
  end
41
39
 
@@ -8,7 +8,6 @@ end
8
8
 
9
9
  module Jeeves
10
10
  describe ResolveConstant do
11
-
12
11
  it "returns an anonymous function which returns the constant" do
13
12
  delegator = ResolveConstant.call(JeevesTestApp::ConstantTest, :my_constant)
14
13
  delegator.call.should == "MY VALUE"
@@ -18,7 +17,6 @@ module Jeeves
18
17
  delegator = ResolveConstant.call(JeevesTestApp::ConstantTest, :undefined_constant)
19
18
  delegator.should be(nil)
20
19
  end
21
-
22
20
  end
23
21
  end
24
22
 
@@ -11,7 +11,7 @@ module Jeeves
11
11
  let(:delegator) { stub("delegator") }
12
12
 
13
13
  before do
14
- Jeeves::ResolveDependency.stub(:in_test_framework?) { false } # to avoid RSpec integration
14
+ Jeeves.stub(:in_test_framework?) { false } # to avoid RSpec integration
15
15
  ResolveMethod.stub(:call)
16
16
  ResolveCallable.stub(:call)
17
17
  ResolveConstant.stub(:call)
@@ -10,7 +10,6 @@ end
10
10
 
11
11
  module Jeeves
12
12
  describe ResolveMethod do
13
-
14
13
  it "returns an anonymous function which delegates to the method" do
15
14
  delegator = ResolveMethod.call(JeevesTestApp::MethodTest, :my_method)
16
15
  result = delegator.call(:foo, :bar, :baz) { |s| s.upcase }
@@ -21,7 +20,6 @@ module Jeeves
21
20
  delegator = ResolveMethod.call(JeevesTestApp::MethodTest, :undefined_method)
22
21
  delegator.should be(nil)
23
22
  end
24
-
25
23
  end
26
24
  end
27
25
 
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: jeeves
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.1
4
+ version: 0.2.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-06-18 00:00:00.000000000 Z
12
+ date: 2012-06-20 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: rspec
@@ -36,10 +36,13 @@ extensions: []
36
36
  extra_rdoc_files: []
37
37
  files:
38
38
  - lib/jeeves.rb
39
+ - lib/jeeves/import.rb
40
+ - lib/jeeves/define_imported_method.rb
39
41
  - lib/jeeves/resolve_dependency.rb
40
42
  - lib/jeeves/version.rb
41
43
  - lib/jeeves/resolve_constant.rb
42
44
  - lib/jeeves/resolve_method.rb
45
+ - lib/jeeves/stub_scope.rb
43
46
  - lib/jeeves/resolve_callable.rb
44
47
  - spec/integration/rspec_spec.rb
45
48
  - spec/integration/import_spec.rb