jeeves 0.2.1 → 0.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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