interjectable 1.0.0 → 1.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGES.md +6 -0
- data/README.md +9 -6
- data/lib/interjectable/rspec.rb +43 -28
- data/lib/interjectable/version.rb +1 -1
- data/spec/interjectable/rspec_spec.rb +5 -4
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: bf87a04b27e693b7dec66842c4c51ea738a7942e
|
4
|
+
data.tar.gz: 6c8fdb8852fa3fc8dea1bb3f17ae47dbab4d29b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cbe3d00e061ff7b5a39ba5f49564ee58f7cd07b69b9f927b4f2bf766d7cef3656ea452ef5305bbb2c75c4f0280fb1785c190bd2836d8547098af91d378b454ad
|
7
|
+
data.tar.gz: 980a68ad0da41b00ad1d0663f049137d9984bcc0be716dd592bd985247396ef8f6fd0657d802fe683415785643433c7fe7993a805cac93fec08844a07ef9ac7b
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,11 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
# v1.1.0
|
4
|
+
|
5
|
+
- Add another RSpec helper `test_inject` to avoid needing a local variable for
|
6
|
+
the setter block to reference. Again, see the [README.md](README.md) for
|
7
|
+
usage.
|
8
|
+
|
3
9
|
# v1.0.0
|
4
10
|
|
5
11
|
- Calling `#inject` or `#inject_static` multiple times is now an error. Use
|
data/README.md
CHANGED
@@ -79,12 +79,12 @@ require "interjectable/rspec"
|
|
79
79
|
describe A do
|
80
80
|
describe "#read" do
|
81
81
|
before do
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
82
|
+
# You can use the block form of #test_inject to inject a fake object that references methods on a.
|
83
|
+
a.test_inject(:b) { FakeB.new(foo) }
|
84
|
+
|
85
|
+
# You can use the test_inject RSpec helper if you just want to inject an object that doesn't
|
86
|
+
# need to reference anything on a.
|
87
|
+
test_inject(described_class, :c, instance_double(C, boom: "goat"))
|
88
88
|
end
|
89
89
|
|
90
90
|
it "parses from its b, and foos from its c" do
|
@@ -93,6 +93,9 @@ describe A do
|
|
93
93
|
end
|
94
94
|
end
|
95
95
|
|
96
|
+
# Both Interjectable.test_inject and the RSpec test_inject helper will setup
|
97
|
+
# RSpec after hooks to cleanup any test_inject-ed dependencies after the
|
98
|
+
# context they are defined in.
|
96
99
|
it "doesn't pollute other tests" do
|
97
100
|
expect(subject.read).to eq(B.new.parse)
|
98
101
|
expect(subject.foo).to eq(C.new.boom)
|
data/lib/interjectable/rspec.rb
CHANGED
@@ -2,15 +2,17 @@
|
|
2
2
|
|
3
3
|
module Interjectable
|
4
4
|
module ClassMethods
|
5
|
+
BLANK = Object.new
|
6
|
+
|
5
7
|
class SuperclassInjectStatic < Struct.new(:klass, :dependency)
|
6
|
-
def override(setter)
|
8
|
+
def override(value, &setter)
|
7
9
|
cvar = "@@#{dependency}"
|
8
10
|
klass.remove_class_variable(cvar) if klass.class_variable_defined?(cvar)
|
9
11
|
klass.define_singleton_method(dependency) do
|
10
12
|
if class_variable_defined?(cvar)
|
11
13
|
class_variable_get(cvar)
|
12
14
|
else
|
13
|
-
class_variable_set(cvar, instance_eval(&setter))
|
15
|
+
class_variable_set(cvar, value != ::Interjectable::ClassMethods::BLANK ? value : instance_eval(&setter))
|
14
16
|
end
|
15
17
|
end
|
16
18
|
end
|
@@ -36,13 +38,13 @@ module Interjectable
|
|
36
38
|
end
|
37
39
|
|
38
40
|
class SuperclassInject < Struct.new(:klass, :dependency)
|
39
|
-
def override(setter)
|
41
|
+
def override(value, &setter)
|
40
42
|
ivar = "@#{dependency}"
|
41
43
|
klass.define_method(dependency) do
|
42
44
|
if instance_variable_defined?(ivar)
|
43
45
|
instance_variable_get(ivar)
|
44
46
|
else
|
45
|
-
instance_variable_set(ivar, instance_eval(&setter))
|
47
|
+
instance_variable_set(ivar, value != ::Interjectable::ClassMethods::BLANK ? value : instance_eval(&setter))
|
46
48
|
end
|
47
49
|
end
|
48
50
|
end
|
@@ -72,31 +74,36 @@ module Interjectable
|
|
72
74
|
end
|
73
75
|
rspec_example_group = setter.binding.receiver.class
|
74
76
|
|
77
|
+
ClassMethods.test_inject(rspec_example_group, self, dependency, BLANK, &setter)
|
78
|
+
end
|
79
|
+
|
80
|
+
def self.test_inject(rspec_example_group, target, dependency, value, &setter)
|
81
|
+
unless value || setter
|
82
|
+
raise ArgumentError, "missing value or setter for #{target}'s #{dependency.inspect}"
|
83
|
+
end
|
84
|
+
|
75
85
|
unless rspec_example_group < RSpec::Core::ExampleGroup
|
76
86
|
raise "#test_inject can only be called from an RSpec ExampleGroup (e.g.: it, before, after)"
|
77
87
|
end
|
78
88
|
|
79
|
-
injector = if singleton_methods(false).include?(dependency) # inject_static(dependency) on this class
|
80
|
-
InjectStatic.new(
|
81
|
-
elsif singleton_methods.include?(dependency) # inject_static(dependency) on a superclass of this class
|
82
|
-
SuperclassInjectStatic.new(
|
83
|
-
elsif instance_methods(false).include?(dependency) # inject(dependency) on this class
|
84
|
-
Inject.new(
|
85
|
-
elsif instance_methods.include?(dependency) # inject(dependency) on a superclass of this class
|
86
|
-
SuperclassInject.new(
|
89
|
+
injector = if target.singleton_methods(false).include?(dependency) # inject_static(dependency) on this class
|
90
|
+
InjectStatic.new(target, dependency)
|
91
|
+
elsif target.singleton_methods.include?(dependency) # inject_static(dependency) on a superclass of this class
|
92
|
+
SuperclassInjectStatic.new(target, dependency)
|
93
|
+
elsif target.instance_methods(false).include?(dependency) # inject(dependency) on this class
|
94
|
+
Inject.new(target, dependency)
|
95
|
+
elsif target.instance_methods.include?(dependency) # inject(dependency) on a superclass of this class
|
96
|
+
SuperclassInject.new(target, dependency)
|
87
97
|
else
|
88
98
|
raise ArgumentError, "tried to override a non-existent dependency: #{dependency.inspect}"
|
89
99
|
end
|
90
100
|
|
91
|
-
injector.override(setter)
|
92
101
|
|
93
|
-
|
102
|
+
injector.override(value, &setter)
|
94
103
|
|
95
|
-
|
96
|
-
# if dependency == :dependency && scope == :each
|
97
|
-
# puts "override: #{key.inspect} #{rspec_example_group}"
|
98
|
-
# end
|
104
|
+
scope = rspec_example_group.currently_executing_a_context_hook? ? :context : :each
|
99
105
|
|
106
|
+
key = [target, dependency, scope]
|
100
107
|
# If we already have a restore after(:each) hook for this class +
|
101
108
|
# dependency + scope, don't add another. To check if we already have an
|
102
109
|
# after(:each) hook, we look at all previous after(:each) hooks we've
|
@@ -107,21 +114,29 @@ module Interjectable
|
|
107
114
|
# for the same #test_inject call since those before hooks only run once,
|
108
115
|
# and therefore only setup a single after hook.
|
109
116
|
return if scope == :each && RESTORE_HOOKS[key].any? { |group| rspec_example_group <= group }
|
110
|
-
# if dependency == :dependency && scope == :each
|
111
|
-
# puts "adding new after=#{key.inspect} hooks=#{RESTORE_HOOKS[key]} group=#{rspec_example_group}"
|
112
|
-
# end
|
113
117
|
RESTORE_HOOKS[key] << rspec_example_group
|
114
118
|
|
115
|
-
# if dependency == :dependency && scope == :each
|
116
|
-
# puts RESTORE_HOOKS.select { |(_, d, s)| d == :dependency && s == :each }
|
117
|
-
# end
|
118
|
-
|
119
119
|
rspec_example_group.after(scope) do
|
120
|
-
# if dependency == :dependency && scope == :each
|
121
|
-
# puts "restore: #{key.inspect} #{rspec_example_group}"
|
122
|
-
# end
|
123
120
|
injector.restore
|
124
121
|
end
|
125
122
|
end
|
126
123
|
end
|
124
|
+
|
125
|
+
module RSpecHelper
|
126
|
+
def test_inject(target, dependency, value)
|
127
|
+
unless value
|
128
|
+
raise ArgumentError, "missing value for #{dependency.inspect}, correct usage: test_inject(my_thing, #{dependency.inspect}, FakeDependency.new)"
|
129
|
+
end
|
130
|
+
|
131
|
+
ClassMethods.test_inject(self.class, target, dependency, value)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
if defined?(RSpec)
|
137
|
+
RSpec.configure do |c|
|
138
|
+
c.include(Interjectable::RSpecHelper)
|
139
|
+
end
|
140
|
+
else
|
141
|
+
raise "RSpec helper was required but RSpec has not beed defined"
|
127
142
|
end
|
@@ -50,7 +50,7 @@ describe "RSpec test helper #test_inject" do
|
|
50
50
|
end
|
51
51
|
|
52
52
|
before do
|
53
|
-
|
53
|
+
test_inject(Klass, :dependency, :another_unused_dependency)
|
54
54
|
Klass.test_inject(:dependency) { foo }
|
55
55
|
Klass.test_inject(:static_dependency) { :overriden_static_dependency }
|
56
56
|
end
|
@@ -75,7 +75,7 @@ describe "RSpec test helper #test_inject" do
|
|
75
75
|
context "override dependency" do
|
76
76
|
before(:all) do
|
77
77
|
Klass.test_inject(:dependency) { :yet_another_unused_dependency }
|
78
|
-
|
78
|
+
test_inject(Klass, :static_dependency, :unused_static_dependency)
|
79
79
|
end
|
80
80
|
|
81
81
|
before do
|
@@ -143,7 +143,8 @@ describe "RSpec test helper #test_inject" do
|
|
143
143
|
context "isoloated context: subclass before :all" do
|
144
144
|
before(:all) do
|
145
145
|
SubKlass.test_inject(:static_dependency) { :bar }
|
146
|
-
SubKlass.test_inject(:static_dependency) { :
|
146
|
+
SubKlass.test_inject(:static_dependency) { :zoo }
|
147
|
+
test_inject(SubKlass, :static_dependency, :baz)
|
147
148
|
end
|
148
149
|
|
149
150
|
it "sets the static_dependency" do
|
@@ -152,7 +153,7 @@ describe "RSpec test helper #test_inject" do
|
|
152
153
|
|
153
154
|
context "subcontext" do
|
154
155
|
before(:all) do
|
155
|
-
|
156
|
+
test_inject(SubKlass, :static_dependency, :goat)
|
156
157
|
end
|
157
158
|
|
158
159
|
it "sets the static_dependency" do
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: interjectable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Zach Margolis
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2018-10-
|
11
|
+
date: 2018-10-17 00:00:00.000000000 Z
|
12
12
|
dependencies: []
|
13
13
|
description: A simple dependency injection library for unit testing
|
14
14
|
email:
|