hypo 0.7.0 → 0.8.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: 1a5df4c1be9652a444db79865461197009cf9b49
4
- data.tar.gz: 71d0370d8cf8f3e9f672651c1ecab2e61e477047
3
+ metadata.gz: f95c8eb6eb6a8fdcef40c219b52f93ef7f019e57
4
+ data.tar.gz: 3026722dd03cdb35709b13c0325b72fd248c3841
5
5
  SHA512:
6
- metadata.gz: 19459aa0a3c3a230855b25d3750c2540d958732698791f02dce185ff6b2a7c3de885b10ba84e8b303495a5aa11cb811a6eaf862efce9f98265613c855892e58b
7
- data.tar.gz: d852deaa4743bcf8783c5a4da1a3f752c6e9897926005acae1873107b22607edd68c1065fc1619eca12e40fea0e5ec621cdc72a71deb3c97ae82d5894a595528
6
+ metadata.gz: ea62c01f490442eb5456e23294dda1559b2c96837e85c3f04fe9a2aa4b2b263f24fb16c5c086d3171bd67176f0c94041db39883039d14325a236b064f9bf5c23
7
+ data.tar.gz: 1f26a3b5bedefd8a8ab10a5527e20228769e910402686519dd291c55b461bcd88d5a389eba52595dd170fcb3d4abd34279310e6c26d96e4765fa1d450ce22dce
data/README.md CHANGED
@@ -62,7 +62,7 @@ and if you registered both of them, you can do:
62
62
  # user.company is resolved as well
63
63
  ```
64
64
 
65
- Sometimes you're not able to manage a type lifecycle, i.e. when you use 3rd-party static stuff, like:
65
+ Sometimes you're not able to manage a type lifetime, i.e. when you use 3rd-party static stuff, like:
66
66
  ```ruby
67
67
  class DB
68
68
  def self.connect
@@ -74,37 +74,21 @@ In that case you can register an instance instead of a type:
74
74
  ```ruby
75
75
  connection = DB.connect
76
76
  container.register_instance(connection, :connection)
77
- ```
78
- ## Component Life Cycle
79
- By default all registered components have life cycle Hypo::Transient (:transient).
77
+ ```
78
+
79
+ ## Advanced Usage
80
+ ### Component Lifetime
81
+ By default all registered components have lifetime Hypo::Lifetime::Transient (:transient).
80
82
  It means, every time when you resolve a component Hypo returns new instance of its type.
81
83
  If you wanna change this behavior then you can replace lifetime strategy.
82
- Out of the box Hypo provides Hypo::Singleton (:singleton) strategy, you can use it when register a component:
84
+ Out of the box Hypo provides Hypo::Lifetime::Singleton (:singleton) strategy, you can use it when register a component:
83
85
 
84
86
  ```ruby
85
- container.register(User).using_life_cycle(:singleton)
87
+ container.register(User).using_lifetime(:singleton)
86
88
  ```
87
- Actually you can implement your own life cycle,
88
- i.e. makes sense to think about HttpRequest strategy for your web applications.
89
-
90
- **Instances support only :singleton life cycle.**
91
-
92
- Sometimes you need to manage a component life cycle manually. Especially it can be useful for "instances".
93
- For example, you're going to inject new instance of request parameters every http request in your web application:
94
-
95
- ```ruby
96
- # somewhere in Rack application
97
- # ...
98
- query_string = env['QUERY_STRING']
99
- container.register_instance(query_string, :query_string)
100
-
101
- # handle the request
102
89
 
103
- container.remove(:query_string)
104
- # ...
105
- ```
106
-
107
- Hypo resolves components with different life cycle strategies independently.
90
+ #### Lifetime compatibility
91
+ Hypo resolves components with different lifetime strategies independently.
108
92
  In other words you can inject a dependency with less lifespan than acceptor type. I.e.:
109
93
 
110
94
  ```ruby
@@ -117,14 +101,89 @@ class B
117
101
  end
118
102
 
119
103
 
120
- container.register(A, :type_a).using_life_cycle(:transient)
121
- container.register(B, :type_b).using_life_cycle(:singleton)
104
+ container.register(A, :type_a).using_lifetime(:transient)
105
+ container.register(B, :type_b).using_lifetime(:singleton)
122
106
 
107
+ container.resolve(:type_b)
123
108
  ```
124
109
 
125
110
  According to :transient strategy every time when you try to resolve a singleton
126
111
  you retrieve exactly the same instance of the singleton **but with new instance** of transient dependency.
127
112
 
113
+ #### Custom Lifetime
114
+ Actually you can implement your own lifetime,
115
+ i.e. makes sense to think about HttpRequest strategy for your web applications. You can do that using "add_lifetime" method:
116
+
117
+ ```ruby
118
+ # somewhere in Rack application: application initialization
119
+ lifetime = Lifetime::Request.new
120
+ container.add_lifetime(lifetime, :request)
121
+ ```
122
+
123
+ A class of new lifetime must respond to "instance" method. This method just a factory method which creates new instance according to your strategy. For example, Lifetime::Request could cache instanes of a components during http request lifespan. Take a look to [:singleton implementation](https://github.com/cylon-v/hypo/blob/master/lib/hypo/lifetime/singleton.rb). You can manually purge internal state of components registry according your strategy. In case of http-request lifetime you could clean up it right after request has done:
124
+
125
+ ```ruby
126
+ # somewhere in Rack application: application initialization
127
+ # ...
128
+ container
129
+ .register(SQLTransation, :transaction)
130
+ .using_lifetime(:request)
131
+ ```
132
+
133
+ ```ruby
134
+ # somewhere in Rack application: request handling
135
+ container.register_instance(query_string, :query_string)
136
+
137
+ # handle the request
138
+ # ...
139
+
140
+ lifetime.purge
141
+ ```
142
+
143
+ #### Lifetime :scope
144
+ For most of cases when you need to bind dependency lifetime to lifetime of another item of your application
145
+ you can use Hypo::Lifetime::Scope (:scope) strategy.
146
+
147
+
148
+ ```ruby
149
+ # somewhere in Rack application: application initialization
150
+ # ...
151
+ container
152
+ .register(SQLTransation, :transaction)
153
+ .using_lifetime(:scope)
154
+ .bound_to(:request) # you can use symbol
155
+ ```
156
+
157
+ ```ruby
158
+ # somewhere in Rack application: request handling
159
+ container
160
+ .register_instance(request, :request)
161
+ .using_lifetime(:scope)
162
+ .bound_to(request) # an object
163
+
164
+ # handle the request
165
+ # ...
166
+
167
+ lifetime.purge(request)
168
+ ```
169
+
170
+ ### Remove components
171
+ Sometimes you need to manage a component lifetime manually. Especially it can be useful for "instances".
172
+ For example, you're going to inject new instance of request parameters every http request in your web application:
173
+
174
+ ```ruby
175
+ # somewhere in Rack application: request handling
176
+ # ...
177
+ query_string = env['QUERY_STRING']
178
+ container.register_instance(query_string, :query_string)
179
+
180
+ # handle the request
181
+ # ...
182
+
183
+ container.remove(:query_string)
184
+ # ...
185
+ ```
186
+
128
187
  ## Development
129
188
 
130
189
  After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
@@ -137,4 +196,4 @@ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERN
137
196
 
138
197
  ## License
139
198
 
140
- The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
199
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
@@ -1,22 +1,24 @@
1
- require 'hypo/life_cycle/transient'
2
- require 'hypo/chainable'
1
+ require 'hypo/lifetime/transient'
2
+ require 'hypo/scope_friendly'
3
+ require 'hypo/lifetime_friendly'
3
4
 
4
5
  module Hypo
5
6
  class Component
6
- include Chainable
7
+ include ScopeFriendly
8
+ include LifetimeFriendly
7
9
 
8
- attr_reader :name, :type, :container, :life_cycle
10
+ attr_reader :name, :type, :container, :lifetime, :scope
9
11
 
10
12
  def initialize(type, container, name = nil)
11
13
  @container = container
12
14
  @type = type
13
15
  @name = name || type.name.gsub(/(.)([A-Z](?=[a-z]))/, '\1_\2').delete('::').downcase.to_sym
14
- @life_cycle = container.life_cycles[:transient]
16
+ @lifetime = container.lifetimes[:transient]
15
17
  @dependency_names = @type.instance_method(:initialize).parameters.map {|p| p[1]}
16
18
  end
17
19
 
18
20
  def instance
19
- instance = @life_cycle.instance(self)
21
+ instance = @lifetime.instance(self)
20
22
 
21
23
  @dependency_names.each do |dependency|
22
24
  instance.instance_variable_set "@#{dependency}".to_sym, @container.resolve(dependency)
@@ -28,13 +30,5 @@ module Hypo
28
30
  def dependencies
29
31
  @dependency_names.map { |dependency| @container.resolve(dependency) }
30
32
  end
31
-
32
- def use_life_cycle(life_cycle)
33
- @life_cycle = container.life_cycles[life_cycle]
34
-
35
- self
36
- end
37
-
38
- alias using_life_cycle use_life_cycle
39
33
  end
40
34
  end
@@ -1,18 +1,19 @@
1
1
  require 'hypo/container_error'
2
2
  require 'hypo/component'
3
3
  require 'hypo/instance'
4
- require 'hypo/life_cycle/transient'
5
- require 'hypo/life_cycle/singleton'
4
+ require 'hypo/lifetime/transient'
5
+ require 'hypo/lifetime/singleton'
6
6
 
7
7
  module Hypo
8
8
  class Container
9
- attr_reader :life_cycles
9
+ attr_reader :lifetimes
10
10
 
11
11
  def initialize
12
12
  @components = {}
13
- @life_cycles = {}
14
- add_life_cycle(LifeCycle::Transient.new, :transient)
15
- add_life_cycle(LifeCycle::Singleton.new, :singleton)
13
+ @lifetimes = {}
14
+ add_lifetime(Lifetime::Transient.new, :transient)
15
+ add_lifetime(Lifetime::Singleton.new, :singleton)
16
+ add_lifetime(Lifetime::Scope.new, :scope)
16
17
  register_instance self, :container
17
18
  end
18
19
 
@@ -24,11 +25,11 @@ module Hypo
24
25
 
25
26
  component = Component.new(item, self, name)
26
27
 
27
- if @components.key?(component.name)
28
- raise ContainerError, "Component \"#{component.name}\" has already been registered"
28
+ unless @components.key?(component.name)
29
+ @components[component.name] = component
29
30
  end
30
31
 
31
- @components[component.name] = component
32
+ @components[component.name]
32
33
  end
33
34
 
34
35
  def register_instance(item, name)
@@ -37,12 +38,12 @@ module Hypo
37
38
  'If you wanna register a type please use method "register".'
38
39
  end
39
40
 
40
- if @components.key?(name)
41
- raise ContainerError, "Component \"#{name}\" has already been registered"
41
+ unless @components.key?(name)
42
+ instance = Instance.new(item, self, name)
43
+ @components[name] = instance
42
44
  end
43
45
 
44
- instance = Instance.new(item, self, name)
45
- @components[name] = instance
46
+ @components[name]
46
47
  end
47
48
 
48
49
  def resolve(name)
@@ -53,12 +54,8 @@ module Hypo
53
54
  @components[name].instance
54
55
  end
55
56
 
56
- def remove(name)
57
- @components.delete(name)
58
- end
59
-
60
- def add_life_cycle(life_cycle, name)
61
- @life_cycles[name] = life_cycle
57
+ def add_lifetime(lifetime, name)
58
+ @lifetimes[name] = lifetime
62
59
 
63
60
  self
64
61
  end
@@ -1,7 +1,4 @@
1
1
  module Hypo
2
2
  class ContainerError < StandardError
3
- def initialize(message)
4
- super(message)
5
- end
6
3
  end
7
4
  end
data/lib/hypo/instance.rb CHANGED
@@ -1,21 +1,24 @@
1
- require 'hypo/chainable'
1
+ require 'hypo/scope_friendly'
2
+ require 'hypo/lifetime_friendly'
2
3
 
3
4
  module Hypo
4
5
  class Instance
5
- include Chainable
6
+ include ScopeFriendly
7
+ include LifetimeFriendly
6
8
 
7
- attr_reader :name, :container
9
+ attr_reader :name, :container, :scope, :object
8
10
 
9
11
  def initialize(object, container, name)
10
12
  raise ContainerError, 'Registered object should have a name' if name.nil?
11
13
 
12
14
  @object = object
13
15
  @container = container
16
+ @lifetime = container.lifetimes[:transient]
14
17
  @name = name
15
18
  end
16
19
 
17
20
  def instance
18
- @object
21
+ @lifetime.instance(self)
19
22
  end
20
23
  end
21
24
  end
@@ -0,0 +1,33 @@
1
+ module Hypo
2
+ module Lifetime
3
+ class Scope
4
+ def initialize
5
+ @instances = {}
6
+ end
7
+
8
+ def instance(component)
9
+ if component.scope.nil?
10
+ raise ContainerError, "Component \"#{component.name}\" must be bound to a scope" \
11
+ " according to Hupo::Lifetime::Scope lifetime strategy"
12
+ end
13
+
14
+ scope = component.scope.object_id
15
+ @instances[scope] = {} unless @instances.key? scope
16
+
17
+ unless @instances[scope].key? component.name
18
+ if component.respond_to? :type
19
+ @instances[scope][component.name] = component.type.new(*component.dependencies)
20
+ else
21
+ @instances[scope][component.name] = component.object
22
+ end
23
+ end
24
+
25
+ @instances[scope][component.name]
26
+ end
27
+
28
+ def purge(scope)
29
+ @instances.delete scope.object_id
30
+ end
31
+ end
32
+ end
33
+ end
@@ -1,5 +1,5 @@
1
1
  module Hypo
2
- module LifeCycle
2
+ module Lifetime
3
3
  class Singleton
4
4
  def initialize
5
5
  @instances = {}
@@ -7,7 +7,11 @@ module Hypo
7
7
 
8
8
  def instance(component)
9
9
  unless @instances.key? component.name
10
- @instances[component.name] = component.type.new(*component.dependencies)
10
+ if component.respond_to? :type
11
+ @instances[component.name] = component.type.new(*component.dependencies)
12
+ else
13
+ @instances[component.name] = component.object
14
+ end
11
15
  end
12
16
 
13
17
  @instances[component.name]
@@ -0,0 +1,13 @@
1
+ module Hypo
2
+ module Lifetime
3
+ class Transient
4
+ def instance(component)
5
+ if component.respond_to? :type
6
+ component.type.new(*component.dependencies)
7
+ else
8
+ component.object
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,11 @@
1
+ module Hypo
2
+ module LifetimeFriendly
3
+ def use_lifetime(lifetime)
4
+ @lifetime = @container.lifetimes[lifetime]
5
+
6
+ self
7
+ end
8
+
9
+ alias using_lifetime use_lifetime
10
+ end
11
+ end
@@ -0,0 +1,15 @@
1
+ module Hypo
2
+ module ScopeFriendly
3
+ def bind_to(scope)
4
+ if scope.is_a? Symbol
5
+ @scope = @container.resolve(scope)
6
+ else
7
+ @scope = scope
8
+ end
9
+
10
+ self
11
+ end
12
+
13
+ alias bound_to bind_to
14
+ end
15
+ end
data/lib/hypo/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Hypo
2
- VERSION = '0.7.0'
2
+ VERSION = '0.8.0'
3
3
  end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hypo
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.7.0
4
+ version: 0.8.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Vladimir Kalinkin
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2017-09-18 00:00:00.000000000 Z
11
+ date: 2017-09-24 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -70,13 +70,15 @@ files:
70
70
  - bin/setup
71
71
  - hypo.gemspec
72
72
  - lib/hypo.rb
73
- - lib/hypo/chainable.rb
74
73
  - lib/hypo/component.rb
75
74
  - lib/hypo/container.rb
76
75
  - lib/hypo/container_error.rb
77
76
  - lib/hypo/instance.rb
78
- - lib/hypo/life_cycle/singleton.rb
79
- - lib/hypo/life_cycle/transient.rb
77
+ - lib/hypo/lifetime/scope.rb
78
+ - lib/hypo/lifetime/singleton.rb
79
+ - lib/hypo/lifetime/transient.rb
80
+ - lib/hypo/lifetime_friendly.rb
81
+ - lib/hypo/scope_friendly.rb
80
82
  - lib/hypo/version.rb
81
83
  homepage: https://github.com/cylon-v/hypo
82
84
  licenses:
@@ -1,7 +0,0 @@
1
- module Hypo
2
- module Chainable
3
- def register(item, name = nil)
4
- @container.register(item, name)
5
- end
6
- end
7
- end
@@ -1,9 +0,0 @@
1
- module Hypo
2
- module LifeCycle
3
- class Transient
4
- def instance(component)
5
- component.type.new(*component.dependencies)
6
- end
7
- end
8
- end
9
- end