interjectable 1.0.0 → 1.1.0

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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fe0594cf0a21a6f303ae028952f2922aa4ccc389
4
- data.tar.gz: 19c22afac4eb1264b760d94f3a24b774b2b9ab0c
3
+ metadata.gz: bf87a04b27e693b7dec66842c4c51ea738a7942e
4
+ data.tar.gz: 6c8fdb8852fa3fc8dea1bb3f17ae47dbab4d29b5
5
5
  SHA512:
6
- metadata.gz: 5c433d1585325e8ddd5e40af9cd0b9bc4166eeeccb863b370dbef3da32cba6f604108fbbd6112673324f205034d2e11391c304b0fc9626fe3f926bdd6b949693
7
- data.tar.gz: 611df0ea5914b1d94781024d828a2ae5f76b9c27f2127164e6448449028ca78fcbb701ab984acb89f3c52907ecf7473a62547e7223fca351618d96a5f51f2ace
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
- instance_double(B, parse: "result").tap do |fake_b|
83
- a.test_inject(:b) { fake_b }
84
- end
85
- instance_double(C, boom: "goat").tap do |fake_c|
86
- a.test_inject(:c) { fake_c }
87
- end
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)
@@ -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(self, dependency)
81
- elsif singleton_methods.include?(dependency) # inject_static(dependency) on a superclass of this class
82
- SuperclassInjectStatic.new(self, dependency)
83
- elsif instance_methods(false).include?(dependency) # inject(dependency) on this class
84
- Inject.new(self, dependency)
85
- elsif instance_methods.include?(dependency) # inject(dependency) on a superclass of this class
86
- SuperclassInject.new(self, dependency)
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
- scope = rspec_example_group.currently_executing_a_context_hook? ? :context : :each
102
+ injector.override(value, &setter)
94
103
 
95
- key = [self, dependency, scope]
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
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Interjectable
4
- VERSION = "1.0.0"
4
+ VERSION = "1.1.0"
5
5
  end
@@ -50,7 +50,7 @@ describe "RSpec test helper #test_inject" do
50
50
  end
51
51
 
52
52
  before do
53
- Klass.test_inject(:dependency) { :another_unused_dependency }
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
- Klass.test_inject(:static_dependency) { :unused_static_dependency }
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) { :baz }
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
- SubKlass.test_inject(:static_dependency) { :goat }
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.0.0
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-16 00:00:00.000000000 Z
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: