diftw 0.0.1
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 +7 -0
- data/LICENSE +19 -0
- data/README.md +86 -0
- data/lib/diftw.rb +2 -0
- data/lib/diftw/injector.rb +145 -0
- data/lib/diftw/version.rb +4 -0
- metadata +48 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 621429df0a88505d46bff336d29bb4cf4196726d
|
4
|
+
data.tar.gz: 52fbcdcc3013037ac707f08053fd8465a90f8bc6
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: e0ca2d926827c97501bbad7a38fc0ba2c7f0626b25a5e82a52161febe84ce02f759e3a04e84f61812ade709fcb6677de98802ff378ee3b4776fcb262227508e4
|
7
|
+
data.tar.gz: 6cd4cf04d662607d0ecfce83396501dbe44c34096ad7329d70cc537d8e09cc0c4bbbb71d07c9c7c250bf3df6d57f1549d5cebadd7df76cb2ab0cd180d0eebe86
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2016 Jordan Hollinger
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
# DiFtw
|
2
|
+
|
3
|
+
Dependency Injection For The Win! A small gem for simple, yet flexible, dependency injection in Ruby.
|
4
|
+
|
5
|
+
Some say you don't need DI in Ruby. Perhaps. Others say you don't need a DI *library* in Ruby. Probably true, but only in the pedantic sense that you don't need a DI library for *any* language. But I'll take a nice, idiomatic DI library over "just manually pass in every dependency to all your constructors!" any day. I couldn't find one, so I wrote this.
|
6
|
+
|
7
|
+
## Basic Use
|
8
|
+
|
9
|
+
# Create your injector
|
10
|
+
Injector = DiFtw::Injector.new do
|
11
|
+
# Register some dependencies
|
12
|
+
register :foo do
|
13
|
+
OpenStruct.new(message: "Foo")
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
# Or register them like this
|
18
|
+
Injector.register :bar do
|
19
|
+
OpenStruct.new(message: "Bar")
|
20
|
+
end
|
21
|
+
|
22
|
+
# Or with a lambda
|
23
|
+
Injector[:baz] = -> { OpenStruct.new(message: "Baz") }
|
24
|
+
|
25
|
+
# Inject some dependencies into your class
|
26
|
+
class Widget
|
27
|
+
include Injector.inject(:foo, :bar)
|
28
|
+
|
29
|
+
def initialize(random_arg)
|
30
|
+
# Unlike most DI, it doesn't hijack your initializer! Because Ruby!!1!
|
31
|
+
@random_arg = random_arg
|
32
|
+
end
|
33
|
+
end
|
34
|
+
|
35
|
+
# Now they're instance methods!
|
36
|
+
widget = Widget.new
|
37
|
+
puts widget.bar.message
|
38
|
+
=> "Bar"
|
39
|
+
|
40
|
+
## Singletons By Default
|
41
|
+
|
42
|
+
By default the injector injects singletons. Observe:
|
43
|
+
|
44
|
+
widget1, widget2 = Widget.new, Widget.new
|
45
|
+
widget1.bar.object_id == widget1.bar.object_id
|
46
|
+
=> true
|
47
|
+
widget1.bar.object_id == widget2.bar.object_id
|
48
|
+
=> true
|
49
|
+
|
50
|
+
If you *don't* want your injector to return singletons (i.e. get a new copy each time you inject), initialize your injector like this:
|
51
|
+
|
52
|
+
Injector = DiFtw::Injector.new(singleton: false)
|
53
|
+
Injector[:bar] = -> { OpenStruct.new(message: 'Bar') }
|
54
|
+
...
|
55
|
+
widget1, widget2 = Widget.new, Widget.new
|
56
|
+
widget1.bar.object_id == widget1.bar.object_id
|
57
|
+
=> true
|
58
|
+
widget1.bar.object_id == widget2.bar.object_id
|
59
|
+
=> false
|
60
|
+
|
61
|
+
Accessing injected singletons **is thread safe**. However, registering them is not.
|
62
|
+
|
63
|
+
## Lazy, Nested Dependencies
|
64
|
+
|
65
|
+
# Define your class and tell it to inject :ab into instances
|
66
|
+
class Spline
|
67
|
+
include Injector.inject(:ab)
|
68
|
+
end
|
69
|
+
|
70
|
+
# Init a Spline instance. Doesn't matter that :ab isn't registered; just don't call spline.ab yet.
|
71
|
+
spline = Spline.new
|
72
|
+
|
73
|
+
# Register :ab, which uses :a and :b. The order you register them in doesn't matter.
|
74
|
+
Injector[:ab] = -> { Injector[:a] + Injector[:b] }
|
75
|
+
Injector[:a] = -> { 'A' }
|
76
|
+
Injector[:b] = -> { 'B' }
|
77
|
+
|
78
|
+
# The :ab dependency isn't actually injected until .ab is called!
|
79
|
+
puts spline.ab
|
80
|
+
=> 'AB'
|
81
|
+
|
82
|
+
## DI in tests
|
83
|
+
|
84
|
+
# Presumably your injector is already initialized.
|
85
|
+
# Simply re-register the dependencies you need for your tests.
|
86
|
+
Injector[:foo] = -> { OpenStruct.new(message: 'Test Foo') }
|
data/lib/diftw.rb
ADDED
@@ -0,0 +1,145 @@
|
|
1
|
+
#
|
2
|
+
# Dependency Injection For The Win!
|
3
|
+
#
|
4
|
+
module DiFtw
|
5
|
+
#
|
6
|
+
# The Injector class. Create an instance to start registering and injecting dependencies.
|
7
|
+
#
|
8
|
+
# DI = DiFtw::Injector.new
|
9
|
+
#
|
10
|
+
# # You can call register on the Injector object
|
11
|
+
# DI.register :bar do
|
12
|
+
# Bar.new
|
13
|
+
# end
|
14
|
+
#
|
15
|
+
# # Or you can assign a Proc to the Injector object like a Hash
|
16
|
+
# DI[:baz] = -> { Baz.new }
|
17
|
+
#
|
18
|
+
# Alternatively, you can pass a block to the initializer and register your depencies right inside it:
|
19
|
+
#
|
20
|
+
# DI = DiFtw::Injector.new do
|
21
|
+
# register :foo do
|
22
|
+
# Foo.new
|
23
|
+
# end
|
24
|
+
#
|
25
|
+
# register(:bar) { Bar }
|
26
|
+
# end
|
27
|
+
#
|
28
|
+
class Injector
|
29
|
+
# @return [Boolean] If true, the Injector injects singleton objects
|
30
|
+
attr_reader :singleton
|
31
|
+
# @return [Hash] A Hash containing all registered depencies (as procs) keyed by Symbols
|
32
|
+
attr_reader :registry
|
33
|
+
# @return [Hash] A Hash containing a Mutex for each dependency (only if singleton == true)
|
34
|
+
attr_reader :mutexes
|
35
|
+
|
36
|
+
private :registry, :mutexes
|
37
|
+
|
38
|
+
#
|
39
|
+
# Instantiate a new Injector.
|
40
|
+
#
|
41
|
+
# DI = DiFtw::Injector.new
|
42
|
+
#
|
43
|
+
# @param singleton [Boolean] If true, each dependency will only be initialized once. When false, it will be initialized each time it's injected.
|
44
|
+
#
|
45
|
+
def initialize(singleton: true, ®istrator)
|
46
|
+
@registry, @mutexes = {}, {}
|
47
|
+
@singleton = singleton
|
48
|
+
instance_eval ®istrator if registrator
|
49
|
+
end
|
50
|
+
|
51
|
+
#
|
52
|
+
# Register a new dependency by passing a Proc or a block.
|
53
|
+
#
|
54
|
+
# DI.register :foo do
|
55
|
+
# Foo
|
56
|
+
# end
|
57
|
+
#
|
58
|
+
# DI.register :bar, -> { Bar }
|
59
|
+
#
|
60
|
+
# @param name [Symbol] name of the dependency
|
61
|
+
# @param y [Proc] the dependency wrapped in a Proc or block
|
62
|
+
# @return [Injector] returns the Injector object
|
63
|
+
#
|
64
|
+
def register(name, y = nil, &block)
|
65
|
+
registry[name] = y || block
|
66
|
+
mutexes[name] = Mutex.new if singleton
|
67
|
+
self
|
68
|
+
end
|
69
|
+
|
70
|
+
#
|
71
|
+
# Register a new dependency by passing a Proc or a block.
|
72
|
+
#
|
73
|
+
# DI[:foo] = -> { Foo }
|
74
|
+
#
|
75
|
+
# @param name [Symbol] name of the dependency
|
76
|
+
# @param y [Proc] the dependency wrapped in a Proc
|
77
|
+
#
|
78
|
+
def []=(name, y)
|
79
|
+
register name, y
|
80
|
+
end
|
81
|
+
|
82
|
+
#
|
83
|
+
# Fetches a dependency by name (calls the Proc/block). If this is a Singleton injector,
|
84
|
+
# the same object will be returned each time. Otherwise a new one will be returned each time.
|
85
|
+
#
|
86
|
+
# An application will probably never want to call this directly.
|
87
|
+
#
|
88
|
+
# @return whatever the Proc/block returns
|
89
|
+
#
|
90
|
+
def [](name)
|
91
|
+
if singleton
|
92
|
+
var = "@_singleton_#{name}"
|
93
|
+
instance_variable_get(var) || mutexes[name].synchronize {
|
94
|
+
instance_variable_get(var) || instance_variable_set(var, registry.fetch(name).call)
|
95
|
+
}
|
96
|
+
else
|
97
|
+
registry.fetch(name).call
|
98
|
+
end
|
99
|
+
end
|
100
|
+
|
101
|
+
#
|
102
|
+
# Creates and returns a new Module which contains instance methods for all the dependencies you specified.
|
103
|
+
# Simply include this module in your class, and all it's instances will have their dependencies injected.
|
104
|
+
#
|
105
|
+
# class Widget
|
106
|
+
# include DI.inject(:foo, :bar)
|
107
|
+
# end
|
108
|
+
#
|
109
|
+
# @param dependencies [Symbol] All dependency names you want to inject.
|
110
|
+
#
|
111
|
+
def inject(*dependencies)
|
112
|
+
injector_module.tap do |mod|
|
113
|
+
mod._diftw_injector = self
|
114
|
+
mod._diftw_dependencies = dependencies
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
private
|
119
|
+
|
120
|
+
#
|
121
|
+
# Builds a new module that, when included in a class, defines instance methods for each dependecy.
|
122
|
+
#
|
123
|
+
# @return a new module
|
124
|
+
#
|
125
|
+
def injector_module
|
126
|
+
Module.new do
|
127
|
+
class << self
|
128
|
+
attr_accessor :_diftw_injector, :_diftw_dependencies
|
129
|
+
end
|
130
|
+
|
131
|
+
def self.included(base)
|
132
|
+
di_mod = self
|
133
|
+
base.class_eval do
|
134
|
+
di_mod._diftw_dependencies.each do |dep|
|
135
|
+
define_method dep do
|
136
|
+
var = "@_diftw_#{dep}"
|
137
|
+
instance_variable_get(var) || instance_variable_set(var, di_mod._diftw_injector[dep])
|
138
|
+
end
|
139
|
+
end
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
end
|
144
|
+
end
|
145
|
+
end
|
metadata
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: diftw
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Jordan Hollinger
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-07-01 00:00:00.000000000 Z
|
12
|
+
dependencies: []
|
13
|
+
description: A small dependency injection library for Ruby
|
14
|
+
email: jordan.hollinger@gmail.com
|
15
|
+
executables: []
|
16
|
+
extensions: []
|
17
|
+
extra_rdoc_files: []
|
18
|
+
files:
|
19
|
+
- LICENSE
|
20
|
+
- README.md
|
21
|
+
- lib/diftw.rb
|
22
|
+
- lib/diftw/injector.rb
|
23
|
+
- lib/diftw/version.rb
|
24
|
+
homepage: https://github.com/jhollinger/ruby-diftw
|
25
|
+
licenses:
|
26
|
+
- MIT
|
27
|
+
metadata: {}
|
28
|
+
post_install_message:
|
29
|
+
rdoc_options: []
|
30
|
+
require_paths:
|
31
|
+
- lib
|
32
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
33
|
+
requirements:
|
34
|
+
- - ">="
|
35
|
+
- !ruby/object:Gem::Version
|
36
|
+
version: 2.0.0
|
37
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
38
|
+
requirements:
|
39
|
+
- - ">="
|
40
|
+
- !ruby/object:Gem::Version
|
41
|
+
version: '0'
|
42
|
+
requirements: []
|
43
|
+
rubyforge_project:
|
44
|
+
rubygems_version: 2.4.5.1
|
45
|
+
signing_key:
|
46
|
+
specification_version: 4
|
47
|
+
summary: Dependency Injection For The Win!
|
48
|
+
test_files: []
|