hypo 0.7.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
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