diftw 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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.
@@ -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') }
@@ -0,0 +1,2 @@
1
+ require 'diftw/injector'
2
+ require 'diftw/version'
@@ -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, &registrator)
46
+ @registry, @mutexes = {}, {}
47
+ @singleton = singleton
48
+ instance_eval &registrator 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
@@ -0,0 +1,4 @@
1
+ module DiFtw
2
+ # Library version
3
+ VERSION = '0.0.1'.freeze
4
+ 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: []