interjectable 0.2.5 → 0.3.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 +4 -4
- data/CHANGES.md +6 -1
- data/README.md +2 -2
- data/interjectable.gemspec +1 -1
- data/lib/interjectable.rb +48 -37
- data/lib/interjectable/version.rb +1 -1
- data/spec/interjectable_spec.rb +31 -16
- metadata +14 -14
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: cc5668f979eb51feb5f750c012299e11afbb3f92
|
4
|
+
data.tar.gz: 6d302846198716cc7723fb930b465b92ead1b350
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: d06494d8a15447db4b5df5ede8c8cfb17b3676c50f0a8a54222a13e72b1bb6a7bb203ce64719d0338463296b5da0ce412026efc8effc9916cbf168bd93bd6830
|
7
|
+
data.tar.gz: b112f4d0623cccf90df647776a2712738a5cb6d105786b0f2f8ed767a79d24d496b713d0d26dd5d8dea3f028f2a112347b3d7e26a01880e7d2029eea123d0164
|
data/CHANGES.md
CHANGED
@@ -1,5 +1,10 @@
|
|
1
1
|
# Change Log
|
2
2
|
|
3
|
+
# v0.3.0
|
4
|
+
|
5
|
+
- Clear previously set class variables an subsequent calls to `#inject_static`
|
6
|
+
- Don't include `#inject` and `#inject_static` as instance variables on `include Interjectable`
|
7
|
+
|
3
8
|
# v0.2.0
|
4
9
|
|
5
10
|
Small feature.
|
@@ -18,4 +23,4 @@ Small patch.
|
|
18
23
|
|
19
24
|
Initial release.
|
20
25
|
|
21
|
-
- Added `Interjectable#inject`
|
26
|
+
- Added `Interjectable#inject`
|
data/README.md
CHANGED
@@ -58,7 +58,7 @@ Let's check it out: we can build a class A that normally references B, but in ou
|
|
58
58
|
```ruby
|
59
59
|
# a.rb
|
60
60
|
class A
|
61
|
-
|
61
|
+
include Interjectable
|
62
62
|
|
63
63
|
inject(:b) { B.new }
|
64
64
|
|
@@ -77,7 +77,7 @@ describe A do
|
|
77
77
|
end
|
78
78
|
|
79
79
|
it "parses from its b" do
|
80
|
-
subject.read.
|
80
|
+
expect(subject.read).to eq('result')
|
81
81
|
end
|
82
82
|
end
|
83
83
|
end
|
data/interjectable.gemspec
CHANGED
data/lib/interjectable.rb
CHANGED
@@ -2,51 +2,62 @@ require "interjectable/version"
|
|
2
2
|
|
3
3
|
module Interjectable
|
4
4
|
def self.included(mod)
|
5
|
-
mod.send(:extend,
|
5
|
+
mod.send(:extend, ClassMethods)
|
6
6
|
end
|
7
7
|
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
8
|
+
def self.extended(mod)
|
9
|
+
mod.send(:extend, ClassMethods)
|
10
|
+
end
|
11
|
+
|
12
|
+
module ClassMethods
|
13
|
+
# Defines a helper methods on instances that memoize values per-instance.
|
14
|
+
# Similar to writing
|
15
|
+
#
|
16
|
+
# attr_writer :dependency
|
17
|
+
#
|
18
|
+
# def dependency
|
19
|
+
# @dependency ||= instance_eval(&default_block)
|
20
|
+
# end
|
21
|
+
def inject(dependency, &default_block)
|
22
|
+
attr_writer dependency
|
18
23
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
24
|
+
define_method(dependency) do
|
25
|
+
ivar_name = "@#{dependency}"
|
26
|
+
if instance_variable_defined?(ivar_name)
|
27
|
+
instance_variable_get(ivar_name)
|
28
|
+
else
|
29
|
+
instance_variable_set(ivar_name, instance_eval(&default_block))
|
30
|
+
end
|
25
31
|
end
|
26
32
|
end
|
27
|
-
end
|
28
33
|
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
34
|
+
# Defines helper methods on instances that memoize values per-class.
|
35
|
+
# (shared across all instances of a class, including instances of subclasses).
|
36
|
+
#
|
37
|
+
# Calling a second time clears the value (if set) from previous times. This should
|
38
|
+
# probably only be called a second time in tests.
|
39
|
+
#
|
40
|
+
# Similar to writing
|
41
|
+
#
|
42
|
+
# cattr_writer :dependency
|
43
|
+
#
|
44
|
+
# def dependency
|
45
|
+
# @@dependency ||= instance_eval(&default_block)
|
46
|
+
# end
|
47
|
+
def inject_static(dependency, &default_block)
|
48
|
+
cvar_name = "@@#{dependency}"
|
49
|
+
remove_class_variable(cvar_name) if class_variable_defined?(cvar_name)
|
40
50
|
|
41
|
-
|
42
|
-
|
43
|
-
|
51
|
+
define_method("#{dependency}=") do |value|
|
52
|
+
self.class.class_variable_set(cvar_name, value)
|
53
|
+
end
|
44
54
|
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
55
|
+
define_method(dependency) do
|
56
|
+
if self.class.class_variable_defined?(cvar_name)
|
57
|
+
self.class.class_variable_get(cvar_name)
|
58
|
+
else
|
59
|
+
self.class.class_variable_set(cvar_name, instance_eval(&default_block))
|
60
|
+
end
|
50
61
|
end
|
51
62
|
end
|
52
63
|
end
|
data/spec/interjectable_spec.rb
CHANGED
@@ -9,35 +9,39 @@ describe Interjectable do
|
|
9
9
|
klass.inject(:some_dependency) { :service }
|
10
10
|
end
|
11
11
|
|
12
|
+
it "doesn't have #inject as an instance method" do
|
13
|
+
expect { instance.inject(:some_dependency) { :service } }.to raise_error(NameError)
|
14
|
+
end
|
15
|
+
|
12
16
|
it "adds an instance method getter and setter" do
|
13
17
|
instance.some_dependency = 'aaa'
|
14
|
-
instance.some_dependency.
|
18
|
+
expect(instance.some_dependency).to eq('aaa')
|
15
19
|
end
|
16
20
|
|
17
21
|
it "lazy-loads the default block" do
|
18
|
-
instance.instance_variable_get("@some_dependency").
|
19
|
-
instance.some_dependency.
|
20
|
-
instance.instance_variable_get("@some_dependency").
|
22
|
+
expect(instance.instance_variable_get("@some_dependency")).to be_nil
|
23
|
+
expect(instance.some_dependency).to eq(:service)
|
24
|
+
expect(instance.instance_variable_get("@some_dependency")).not_to be_nil
|
21
25
|
end
|
22
26
|
|
23
27
|
it "allows transitive dependencies (via instance_eval)" do
|
24
28
|
klass.inject(:first_dependency) { second_dependency }
|
25
29
|
klass.inject(:second_dependency) { :value }
|
26
30
|
|
27
|
-
instance.first_dependency.
|
31
|
+
expect(instance.first_dependency).to eq(:value)
|
28
32
|
end
|
29
33
|
|
30
34
|
it "calls dependency block once, even with a falsy value" do
|
31
35
|
count = 0;
|
32
36
|
klass.inject(:some_falsy_dependency) { count += 1; nil }
|
33
37
|
|
34
|
-
2.times { instance.some_falsy_dependency.
|
35
|
-
count.
|
38
|
+
2.times { expect(instance.some_falsy_dependency).to be_nil }
|
39
|
+
expect(count).to eq(1)
|
36
40
|
end
|
37
41
|
|
38
42
|
context "with a dependency on another class" do
|
39
43
|
before do
|
40
|
-
defined?(SomeOtherClass).
|
44
|
+
expect(defined?(SomeOtherClass)).to be_falsey
|
41
45
|
|
42
46
|
klass.inject(:some_other_class) { SomeOtherClass.new }
|
43
47
|
end
|
@@ -45,7 +49,7 @@ describe Interjectable do
|
|
45
49
|
it "does not need to load that class (can be stubbed away)" do
|
46
50
|
instance.some_other_class = :fake_other_class
|
47
51
|
|
48
|
-
instance.some_other_class.
|
52
|
+
expect(instance.some_other_class).to eq(:fake_other_class)
|
49
53
|
end
|
50
54
|
end
|
51
55
|
end
|
@@ -57,24 +61,35 @@ describe Interjectable do
|
|
57
61
|
klass.inject_static(:static_dependency) { :some_value }
|
58
62
|
end
|
59
63
|
|
64
|
+
it "doesn't have #inject_static as an instance method" do
|
65
|
+
expect { instance.inject_static(:static_dependency) { :some_value } }.to raise_error(NameError)
|
66
|
+
end
|
67
|
+
|
60
68
|
it "adds an instance method and setter" do
|
61
69
|
instance.static_dependency = 'aaa'
|
62
|
-
instance.static_dependency.
|
70
|
+
expect(instance.static_dependency).to eq('aaa')
|
63
71
|
end
|
64
72
|
|
65
73
|
it "shares a value across all instances of a class" do
|
66
74
|
instance.static_dependency = 'bbb'
|
67
|
-
other_instance.static_dependency.
|
75
|
+
expect(other_instance.static_dependency).to eq('bbb')
|
68
76
|
end
|
69
77
|
|
70
78
|
it "calls its dependency block once across all instances" do
|
71
79
|
count = 0;
|
72
80
|
klass.inject_static(:falsy_static_dependency) { count += 1; nil }
|
73
81
|
|
74
|
-
instance.falsy_static_dependency.
|
75
|
-
other_instance.falsy_static_dependency.
|
82
|
+
expect(instance.falsy_static_dependency).to be_nil
|
83
|
+
expect(other_instance.falsy_static_dependency).to be_nil
|
76
84
|
|
77
|
-
count.
|
85
|
+
expect(count).to eq(1)
|
86
|
+
end
|
87
|
+
|
88
|
+
it "clears class variable on subsequent calls to inject_static" do
|
89
|
+
expect(instance.static_dependency).to eq(:some_value)
|
90
|
+
klass.inject_static(:static_dependency) { :another_value }
|
91
|
+
expect(instance.static_dependency).to eq(:another_value)
|
92
|
+
expect(other_instance.static_dependency).to eq(:another_value)
|
78
93
|
end
|
79
94
|
|
80
95
|
context "with a subclas" do
|
@@ -83,7 +98,7 @@ describe Interjectable do
|
|
83
98
|
|
84
99
|
it "shares its values with its superclass" do
|
85
100
|
instance.static_dependency = 'ccc'
|
86
|
-
subclass_instance.static_dependency.
|
101
|
+
expect(subclass_instance.static_dependency).to eq('ccc')
|
87
102
|
end
|
88
103
|
end
|
89
104
|
end
|
@@ -96,7 +111,7 @@ describe Interjectable do
|
|
96
111
|
end
|
97
112
|
|
98
113
|
context "when included" do
|
99
|
-
let(:klass) { Class.new {
|
114
|
+
let(:klass) { Class.new { include Interjectable } }
|
100
115
|
|
101
116
|
it_should_behave_like "an interjectable class"
|
102
117
|
end
|
metadata
CHANGED
@@ -1,57 +1,57 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: interjectable
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.3.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:
|
11
|
+
date: 2018-08-13 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- - ~>
|
17
|
+
- - "~>"
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '1.3'
|
20
20
|
type: :development
|
21
21
|
prerelease: false
|
22
22
|
version_requirements: !ruby/object:Gem::Requirement
|
23
23
|
requirements:
|
24
|
-
- - ~>
|
24
|
+
- - "~>"
|
25
25
|
- !ruby/object:Gem::Version
|
26
26
|
version: '1.3'
|
27
27
|
- !ruby/object:Gem::Dependency
|
28
28
|
name: rake
|
29
29
|
requirement: !ruby/object:Gem::Requirement
|
30
30
|
requirements:
|
31
|
-
- -
|
31
|
+
- - ">="
|
32
32
|
- !ruby/object:Gem::Version
|
33
33
|
version: '0'
|
34
34
|
type: :development
|
35
35
|
prerelease: false
|
36
36
|
version_requirements: !ruby/object:Gem::Requirement
|
37
37
|
requirements:
|
38
|
-
- -
|
38
|
+
- - ">="
|
39
39
|
- !ruby/object:Gem::Version
|
40
40
|
version: '0'
|
41
41
|
- !ruby/object:Gem::Dependency
|
42
42
|
name: rspec
|
43
43
|
requirement: !ruby/object:Gem::Requirement
|
44
44
|
requirements:
|
45
|
-
- -
|
45
|
+
- - ">="
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version:
|
47
|
+
version: 3.0.0
|
48
48
|
type: :development
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
|
-
- -
|
52
|
+
- - ">="
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version:
|
54
|
+
version: 3.0.0
|
55
55
|
description: A simple dependency injection library for unit testing
|
56
56
|
email:
|
57
57
|
- zbmargolis@gmail.com
|
@@ -59,7 +59,7 @@ executables: []
|
|
59
59
|
extensions: []
|
60
60
|
extra_rdoc_files: []
|
61
61
|
files:
|
62
|
-
- .gitignore
|
62
|
+
- ".gitignore"
|
63
63
|
- CHANGES.md
|
64
64
|
- Gemfile
|
65
65
|
- LICENSE.txt
|
@@ -80,17 +80,17 @@ require_paths:
|
|
80
80
|
- lib
|
81
81
|
required_ruby_version: !ruby/object:Gem::Requirement
|
82
82
|
requirements:
|
83
|
-
- -
|
83
|
+
- - ">="
|
84
84
|
- !ruby/object:Gem::Version
|
85
85
|
version: '0'
|
86
86
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
87
87
|
requirements:
|
88
|
-
- -
|
88
|
+
- - ">="
|
89
89
|
- !ruby/object:Gem::Version
|
90
90
|
version: '0'
|
91
91
|
requirements: []
|
92
92
|
rubyforge_project:
|
93
|
-
rubygems_version: 2.
|
93
|
+
rubygems_version: 2.6.14
|
94
94
|
signing_key:
|
95
95
|
specification_version: 4
|
96
96
|
summary: A simple dependency injection library for unit testing
|