needle 0.6.0 → 0.9.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.
- data/doc/faq/faq.rb +143 -0
- data/doc/faq/faq.yml +75 -0
- data/doc/manual-html/chapter-1.html +26 -6
- data/doc/manual-html/chapter-2.html +39 -9
- data/doc/manual-html/chapter-3.html +177 -8
- data/doc/manual-html/chapter-4.html +108 -8
- data/doc/manual-html/chapter-5.html +28 -8
- data/doc/manual-html/chapter-6.html +28 -8
- data/doc/manual-html/chapter-7.html +29 -9
- data/doc/manual-html/chapter-8.html +176 -0
- data/doc/manual-html/index.html +26 -6
- data/doc/manual/manual.rb +1 -1
- data/doc/manual/manual.yml +7 -0
- data/doc/manual/parts/02_creating.txt +12 -2
- data/doc/manual/parts/03_conventional.txt +29 -0
- data/doc/manual/parts/03_locator.txt +60 -0
- data/doc/manual/parts/03_overview.txt +19 -0
- data/doc/manual/parts/04_overview.txt +9 -0
- data/doc/manual/parts/04_setup.txt +44 -0
- data/lib/needle/container.rb +68 -11
- data/lib/needle/registry.rb +25 -28
- data/lib/needle/service-point.rb +6 -1
- data/lib/needle/version.rb +1 -1
- data/test/models/model_test.rb +21 -1
- data/test/tc_container.rb +28 -1
- data/test/tc_registry.rb +22 -5
- data/test/tc_service_point.rb +9 -0
- metadata +11 -2
data/lib/needle/container.rb
CHANGED
@@ -41,7 +41,7 @@ module Needle
|
|
41
41
|
protected_instance_methods +
|
42
42
|
public_instance_methods -
|
43
43
|
[ "instance_eval", "__id__", "__send__", "initialize", "remove_const",
|
44
|
-
"method_missing", "inspect" ]
|
44
|
+
"method_missing", "method", "class", "inspect", "to_s", "instance_variables" ]
|
45
45
|
).
|
46
46
|
each { |m| undef_method m }
|
47
47
|
|
@@ -63,11 +63,9 @@ module Needle
|
|
63
63
|
@container.intercept( name )
|
64
64
|
end
|
65
65
|
|
66
|
-
# Delegate to Container#namespace.
|
67
|
-
# the new namespace, however, pass the definition context for the new
|
68
|
-
# container.
|
66
|
+
# Delegate to Container#namespace.
|
69
67
|
def namespace( *parms, &block )
|
70
|
-
@container.namespace( *parms
|
68
|
+
@container.namespace( *parms, &block )
|
71
69
|
end
|
72
70
|
|
73
71
|
# Delegate to Container#namespace!.
|
@@ -75,6 +73,11 @@ module Needle
|
|
75
73
|
@container.namespace!( *parms, &block )
|
76
74
|
end
|
77
75
|
|
76
|
+
# Delegate to Container#define on the new namespace.
|
77
|
+
def namespace_define( *parms, &block )
|
78
|
+
@container.namespace( *parms ) { |ns| ns.define( &block ) }
|
79
|
+
end
|
80
|
+
|
78
81
|
# Any method invocation with no block and no parameters is interpreted to
|
79
82
|
# be a service reference on the wrapped container, and delegates to
|
80
83
|
# Container#[]. If the block is not given but the args are not empty, a
|
@@ -125,8 +128,9 @@ module Needle
|
|
125
128
|
# container's name and all parent's names up to the root container,
|
126
129
|
# catenated together with dot characters, i.e., "one.two.three".
|
127
130
|
def fullname
|
128
|
-
|
129
|
-
|
131
|
+
parent_name = ( @parent ? @parent.fullname : nil )
|
132
|
+
return @name.to_s unless parent_name
|
133
|
+
"#{parent_name}.#{@name}"
|
130
134
|
end
|
131
135
|
|
132
136
|
# Returns the DefinitionContext instance that can be used to "build"
|
@@ -173,6 +177,8 @@ module Needle
|
|
173
177
|
# requested (with Container#[]), the associated callback will be used
|
174
178
|
# to construct it.
|
175
179
|
#
|
180
|
+
# This returns the registry that was used to register the service.
|
181
|
+
#
|
176
182
|
# Usage:
|
177
183
|
#
|
178
184
|
# container.register( :calc, :model=>:prototype ) do |c|
|
@@ -184,6 +190,8 @@ module Needle
|
|
184
190
|
name = name.to_s.intern unless name.is_a?( Symbol )
|
185
191
|
@service_points[ name ] =
|
186
192
|
ServicePoint.new( self, name, opts, &callback )
|
193
|
+
|
194
|
+
self
|
187
195
|
end
|
188
196
|
|
189
197
|
# Create a new namespace within the container, with the given name. If a
|
@@ -198,7 +206,7 @@ module Needle
|
|
198
206
|
#
|
199
207
|
# Note that this means that namespaces may be singletons or prototypes, or
|
200
208
|
# have immediate or deferred instantiation, and so forth. (The default of
|
201
|
-
#
|
209
|
+
# immediate, singleton instantiation is sufficient for 99% of the things
|
202
210
|
# you'll use namespaces for.)
|
203
211
|
#
|
204
212
|
# Usage:
|
@@ -209,6 +217,11 @@ module Needle
|
|
209
217
|
# end
|
210
218
|
#
|
211
219
|
# adder = container.calc.operations.add
|
220
|
+
#
|
221
|
+
# *Note*: the block is not invoked until the namespace is created, which
|
222
|
+
# is not until it is first referenced. If you need the namespace to be
|
223
|
+
# created immediately, either use #namespace_define or reference the
|
224
|
+
# namespace as soon as you've created it.
|
212
225
|
def namespace( name, opts={}, &block )
|
213
226
|
register( name, opts ) do |c,p|
|
214
227
|
ns = Container.new( c, name )
|
@@ -229,20 +242,64 @@ module Needle
|
|
229
242
|
#
|
230
243
|
# Note that this means that namespaces may be singletons or prototypes, or
|
231
244
|
# have immediate or deferred instantiation, and so forth. (The default of
|
232
|
-
#
|
245
|
+
# immediate, singleton instantiation is sufficient for 99% of the things
|
233
246
|
# you'll use namespaces for.)
|
234
247
|
#
|
235
248
|
# Usage:
|
236
249
|
#
|
237
|
-
# container.
|
250
|
+
# container.namespace_define!( :operations ) do
|
238
251
|
# add { Adder.new }
|
239
252
|
# ...
|
240
253
|
# end
|
241
254
|
#
|
242
255
|
# adder = container.calc.operations.add
|
243
|
-
|
256
|
+
#
|
257
|
+
# *Note*: this method will immediately instantiate the new namespace,
|
258
|
+
# unlike #namespace. If you want instantiation of the namespace to be
|
259
|
+
# deferred, either use a deferring service model
|
260
|
+
# (like <tt>:singleton_deferred</tt>) or create the namespace via
|
261
|
+
# #namespace.
|
262
|
+
def namespace_define!( name, opts={}, &block )
|
244
263
|
raise ArgumentError, "block expected" unless block
|
245
264
|
namespace( name, opts ) { |ns| ns.define!( &block ) }
|
265
|
+
self[name]
|
266
|
+
end
|
267
|
+
|
268
|
+
alias :namespace! :namespace_define!
|
269
|
+
|
270
|
+
# Create a new namespace within the container, with the given name.
|
271
|
+
# The block (which is required) will be passed to Container#define on
|
272
|
+
# the new namespace.
|
273
|
+
#
|
274
|
+
# For the curious, namespaces are simply services that are implemented
|
275
|
+
# by Container. The two statements are really identical:
|
276
|
+
#
|
277
|
+
# container.namespace( :calc )
|
278
|
+
# container.register( :calc ) { |c| Needle::Container.new( c, :calc ) }
|
279
|
+
#
|
280
|
+
# Note that this means that namespaces may be singletons or prototypes, or
|
281
|
+
# have immediate or deferred instantiation, and so forth. (The default of
|
282
|
+
# immediate, singleton instantiation is sufficient for 99% of the things
|
283
|
+
# you'll use namespaces for.)
|
284
|
+
#
|
285
|
+
# Usage:
|
286
|
+
#
|
287
|
+
# container.define_namespace( :operations ) do |b|
|
288
|
+
# b.add { Adder.new }
|
289
|
+
# ...
|
290
|
+
# end
|
291
|
+
#
|
292
|
+
# adder = container.calc.operations.add
|
293
|
+
#
|
294
|
+
# *Note*: this method will immediately instantiate the new namespace,
|
295
|
+
# unlike #namespace. If you want instantiation of the namespace to be
|
296
|
+
# deferred, either use a deferring service model
|
297
|
+
# (like <tt>:singleton_deferred</tt>) or create the namespace via
|
298
|
+
# #namespace.
|
299
|
+
def namespace_define( name, opts={}, &block )
|
300
|
+
raise ArgumentError, "block expected" unless block
|
301
|
+
namespace( name, opts ) { |ns| ns.define( &block ) }
|
302
|
+
self[name]
|
246
303
|
end
|
247
304
|
|
248
305
|
# Describe a new interceptor to use that will intercept method calls
|
data/lib/needle/registry.rb
CHANGED
@@ -28,7 +28,7 @@ module Needle
|
|
28
28
|
|
29
29
|
# Registry is a specialization of Container, with additional functionality
|
30
30
|
# for bootstrapping basic services into a new registry. It also supports a
|
31
|
-
# #
|
31
|
+
# #define! method for easily registering new services.
|
32
32
|
#
|
33
33
|
# Usage:
|
34
34
|
#
|
@@ -41,34 +41,41 @@ module Needle
|
|
41
41
|
# bar = registry.bar
|
42
42
|
class Registry < Container
|
43
43
|
|
44
|
-
# This is the default name given to a registry. If you have multiple
|
45
|
-
# independent registries in the same application, it can help to given them
|
46
|
-
# each names. By default, the name is empty.
|
47
|
-
DEFAULT_REGISTRY_NAME = ""
|
48
|
-
|
49
44
|
# Instantiate a new Registry (via #new) and immediately invoke #define!
|
50
45
|
# using the given block.
|
51
46
|
#
|
52
47
|
# Usage:
|
53
48
|
#
|
54
|
-
# registry = Needle::Registry.
|
49
|
+
# registry = Needle::Registry.define! do
|
55
50
|
# add { Adder.new }
|
56
51
|
# ...
|
57
52
|
# end
|
58
53
|
#
|
59
54
|
# adder = registry.add
|
60
|
-
def self.
|
55
|
+
def self.define!( *parms, &block )
|
61
56
|
raise NeedleError, "needs a block" if block.nil?
|
62
57
|
new( *parms ) { |reg| reg.define!( &block ) }
|
63
58
|
end
|
64
59
|
|
65
|
-
# Instantiate a new Registry
|
66
|
-
#
|
67
|
-
#
|
60
|
+
# Instantiate a new Registry (via #new) and immediately invoke #define
|
61
|
+
# using the given block.
|
62
|
+
#
|
63
|
+
# Usage:
|
64
|
+
#
|
65
|
+
# registry = Needle::Registry.define do |b|
|
66
|
+
# b.add { Adder.new }
|
67
|
+
# ...
|
68
|
+
# end
|
68
69
|
#
|
69
|
-
#
|
70
|
-
|
71
|
-
|
70
|
+
# adder = registry.add
|
71
|
+
def self.define( *parms, &block )
|
72
|
+
raise NeedleError, "needs a block" if block.nil?
|
73
|
+
new( *parms ) { |reg| reg.define( &block ) }
|
74
|
+
end
|
75
|
+
|
76
|
+
# Instantiate a new Registry. The options hash may include options
|
77
|
+
# used to initialize the logger factory. The logger factory options
|
78
|
+
# should be in another hash, keyed by the value <tt>:logs</tt>.
|
72
79
|
#
|
73
80
|
# If a block is given, the constructed registry instance is yielded to it.
|
74
81
|
#
|
@@ -87,25 +94,15 @@ module Needle
|
|
87
94
|
# registry = Needle::Registry.new(
|
88
95
|
# :logs => { :filename => "/dev/null" }
|
89
96
|
# )
|
90
|
-
def initialize(
|
91
|
-
|
92
|
-
name = ( parms.first.is_a?( String ) ? parms.shift :
|
93
|
-
DEFAULT_REGISTRY_NAME )
|
94
|
-
opts = ( parms.first.is_a?( Hash ) ? parms.shift : {} )
|
95
|
-
|
96
|
-
if parms.length > 0
|
97
|
-
raise ArgumentError, "invalid parameter(s): #{parms.inspect}"
|
98
|
-
end
|
99
|
-
|
100
|
-
super( nil, name )
|
97
|
+
def initialize( opts={} )
|
98
|
+
super( nil, nil )
|
101
99
|
bootstrap( opts )
|
102
|
-
|
103
100
|
yield( self ) if block_given?
|
104
101
|
end
|
105
102
|
|
106
|
-
#
|
103
|
+
# Returns +nil+. Registries are unnamed containers.
|
107
104
|
def fullname
|
108
|
-
|
105
|
+
nil
|
109
106
|
end
|
110
107
|
|
111
108
|
# Bootstraps the pipeline elements, service models, logger factory, and
|
data/lib/needle/service-point.rb
CHANGED
@@ -73,7 +73,12 @@ module Needle
|
|
73
73
|
# name, its container's name, and all of its container's ancestors' names
|
74
74
|
# concatenated together with dot characters, i.e. "one.two.three".
|
75
75
|
def fullname
|
76
|
-
|
76
|
+
container_name = @container.fullname
|
77
|
+
if container_name
|
78
|
+
"#{container_name}.#{@name}"
|
79
|
+
else
|
80
|
+
@name.to_s
|
81
|
+
end
|
77
82
|
end
|
78
83
|
|
79
84
|
# Adds the given interceptor definition to this service point. The
|
data/lib/needle/version.rb
CHANGED
data/test/models/model_test.rb
CHANGED
@@ -30,6 +30,10 @@ class ModelTest_MockService
|
|
30
30
|
@init_result = :initialized
|
31
31
|
end
|
32
32
|
|
33
|
+
def custom_init
|
34
|
+
@init_result = :custom
|
35
|
+
end
|
36
|
+
|
33
37
|
end
|
34
38
|
|
35
39
|
module ModelTest
|
@@ -65,7 +69,7 @@ module ModelTest
|
|
65
69
|
def assert_threaded
|
66
70
|
define_method( :extra_setup ) do
|
67
71
|
cache = Thread.current[:threaded_services]
|
68
|
-
cache.delete "
|
72
|
+
cache.delete "test" if cache
|
69
73
|
end
|
70
74
|
|
71
75
|
define_method( :test_multiplicity_singlethread ) do
|
@@ -109,10 +113,26 @@ module ModelTest
|
|
109
113
|
end
|
110
114
|
|
111
115
|
def assert_init
|
116
|
+
if instance_methods.include?( "extra_setup" )
|
117
|
+
save_setup = instance_method( :extra_setup )
|
118
|
+
end
|
119
|
+
|
120
|
+
define_method( :extra_setup ) do
|
121
|
+
save_setup.bind( self ).call if save_setup
|
122
|
+
@registry.register( :test_init, :model=>self.class.model,
|
123
|
+
:init_method=>:custom_init
|
124
|
+
) { ModelTest_MockService.new }
|
125
|
+
end
|
126
|
+
|
112
127
|
define_method( :test_initialize ) do
|
113
128
|
o = @registry[ :test ]
|
114
129
|
assert_equal :initialized, o.init_result
|
115
130
|
end
|
131
|
+
|
132
|
+
define_method( :test_custom_initialize ) do
|
133
|
+
o = @registry[ :test_init ]
|
134
|
+
assert_equal :custom, o.init_result
|
135
|
+
end
|
116
136
|
end
|
117
137
|
end
|
118
138
|
|
data/test/tc_container.rb
CHANGED
@@ -146,7 +146,7 @@ class TC_Container < Test::Unit::TestCase
|
|
146
146
|
|
147
147
|
container.define do |b|
|
148
148
|
b.test( :pipeline=>[] ) { Hash.new }
|
149
|
-
b.
|
149
|
+
b.namespace_define :subitem, :pipeline=>[] do |b2|
|
150
150
|
b2.test2( :pipeline=>[] ) { Hash.new }
|
151
151
|
end
|
152
152
|
end
|
@@ -192,6 +192,33 @@ class TC_Container < Test::Unit::TestCase
|
|
192
192
|
assert_instance_of Needle::Container, container.test2
|
193
193
|
end
|
194
194
|
|
195
|
+
def test_namespace_define
|
196
|
+
container = Needle::Container.new
|
197
|
+
container.namespace_define( :test, :pipeline=>[] ) do |b|
|
198
|
+
b.item( :pipeline=>[] ) { Hash.new }
|
199
|
+
end
|
200
|
+
assert container.has_key?( :test )
|
201
|
+
assert container.test.has_key?( :item )
|
202
|
+
end
|
203
|
+
|
204
|
+
def test_namespace_define!
|
205
|
+
container = Needle::Container.new
|
206
|
+
container.namespace_define!( :test, :pipeline=>[] ) do
|
207
|
+
item( :pipeline=>[] ) { Hash.new }
|
208
|
+
end
|
209
|
+
assert container.has_key?( :test )
|
210
|
+
assert container.test.has_key?( :item )
|
211
|
+
end
|
212
|
+
|
213
|
+
def test_namespace!
|
214
|
+
container = Needle::Container.new
|
215
|
+
container.namespace!( :test, :pipeline=>[] ) do
|
216
|
+
item( :pipeline=>[] ) { Hash.new }
|
217
|
+
end
|
218
|
+
assert container.has_key?( :test )
|
219
|
+
assert container.test.has_key?( :item )
|
220
|
+
end
|
221
|
+
|
195
222
|
def test_has_key
|
196
223
|
container = Needle::Container.new
|
197
224
|
|
data/test/tc_registry.rb
CHANGED
@@ -31,16 +31,33 @@ class TC_Registry < Test::Unit::TestCase
|
|
31
31
|
assert_equal 12, @registry.service_models.length
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
35
|
-
reg = Needle::Registry.
|
34
|
+
def test_define_no_options
|
35
|
+
reg = Needle::Registry.define do |b|
|
36
|
+
b.svc1 { Object.new }
|
37
|
+
end
|
38
|
+
|
39
|
+
assert_respond_to reg, :svc1
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_define_with_options
|
43
|
+
reg = Needle::Registry.define( :logs => { :device => STDOUT } ) do |b|
|
44
|
+
b.svc1 { Object.new }
|
45
|
+
end
|
46
|
+
|
47
|
+
assert_respond_to reg, :svc1
|
48
|
+
assert_equal STDOUT, reg.logs.device
|
49
|
+
end
|
50
|
+
|
51
|
+
def test_define_no_options!
|
52
|
+
reg = Needle::Registry.define! do
|
36
53
|
svc1 { Object.new }
|
37
54
|
end
|
38
55
|
|
39
56
|
assert_respond_to reg, :svc1
|
40
57
|
end
|
41
58
|
|
42
|
-
def
|
43
|
-
reg = Needle::Registry.
|
59
|
+
def test_define_with_options!
|
60
|
+
reg = Needle::Registry.define!( :logs => { :device => STDOUT } ) do
|
44
61
|
svc1 { Object.new }
|
45
62
|
end
|
46
63
|
|
@@ -66,7 +83,7 @@ class TC_Registry < Test::Unit::TestCase
|
|
66
83
|
end
|
67
84
|
|
68
85
|
def test_fullname
|
69
|
-
|
86
|
+
assert_nil @registry.fullname
|
70
87
|
end
|
71
88
|
|
72
89
|
end
|
data/test/tc_service_point.rb
CHANGED
@@ -91,6 +91,15 @@ class TC_ServicePoint < Test::Unit::TestCase
|
|
91
91
|
end
|
92
92
|
end
|
93
93
|
|
94
|
+
def test_instance_with_explicit_pipeline_class
|
95
|
+
point =
|
96
|
+
Needle::ServicePoint.new( @container, "test", :pipeline => [ Model ] ) {
|
97
|
+
Hash.new }
|
98
|
+
|
99
|
+
inst = point.instance
|
100
|
+
assert_instance_of Hash, inst
|
101
|
+
end
|
102
|
+
|
94
103
|
def test_instance
|
95
104
|
point =
|
96
105
|
Needle::ServicePoint.new( @container, "test", :model => :mock ) {
|
metadata
CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.8.1
|
|
3
3
|
specification_version: 1
|
4
4
|
name: needle
|
5
5
|
version: !ruby/object:Gem::Version
|
6
|
-
version: 0.
|
7
|
-
date: 2004-10-
|
6
|
+
version: 0.9.0
|
7
|
+
date: 2004-10-28
|
8
8
|
summary: Needle is a Dependency Injection/Inversion of Control container for Ruby. It supports both type-2 (setter) and type-3 (constructor) injection. It takes advantage of the dynamic nature of Ruby to provide a rich and flexible approach to injecting dependencies.
|
9
9
|
require_paths:
|
10
10
|
- lib
|
@@ -30,6 +30,7 @@ files:
|
|
30
30
|
- benchmarks/interceptors.rb
|
31
31
|
- benchmarks/instantiability.rb
|
32
32
|
- benchmarks/interceptors2.rb
|
33
|
+
- doc/faq
|
33
34
|
- doc/README
|
34
35
|
- doc/LICENSE-RUBY
|
35
36
|
- doc/di-in-ruby.rdoc
|
@@ -38,6 +39,8 @@ files:
|
|
38
39
|
- doc/LICENSE-BSD
|
39
40
|
- doc/LICENSE-GPL
|
40
41
|
- doc/manual
|
42
|
+
- doc/faq/faq.yml
|
43
|
+
- doc/faq/faq.rb
|
41
44
|
- doc/manual-html/manual.css
|
42
45
|
- doc/manual-html/chapter-1.html
|
43
46
|
- doc/manual-html/chapter-2.html
|
@@ -46,6 +49,7 @@ files:
|
|
46
49
|
- doc/manual-html/chapter-5.html
|
47
50
|
- doc/manual-html/chapter-6.html
|
48
51
|
- doc/manual-html/chapter-7.html
|
52
|
+
- doc/manual-html/chapter-8.html
|
49
53
|
- doc/manual-html/index.html
|
50
54
|
- doc/images/di_classdiagram.jpg
|
51
55
|
- doc/manual/manual.css
|
@@ -58,13 +62,18 @@ files:
|
|
58
62
|
- doc/manual/manual.rb
|
59
63
|
- doc/manual/parts/02_namespaces.txt
|
60
64
|
- doc/manual/parts/01_support.txt
|
65
|
+
- doc/manual/parts/03_locator.txt
|
61
66
|
- doc/manual/parts/02_services.txt
|
67
|
+
- doc/manual/parts/04_setup.txt
|
62
68
|
- doc/manual/parts/01_alternatives.txt
|
69
|
+
- doc/manual/parts/04_overview.txt
|
63
70
|
- doc/manual/parts/01_what_is_needle.txt
|
71
|
+
- doc/manual/parts/03_overview.txt
|
64
72
|
- doc/manual/parts/02_creating.txt
|
65
73
|
- doc/manual/parts/01_license.txt
|
66
74
|
- doc/manual/parts/01_use_cases.txt
|
67
75
|
- doc/manual/parts/02_overview.txt
|
76
|
+
- doc/manual/parts/03_conventional.txt
|
68
77
|
- lib/needle.rb
|
69
78
|
- lib/needle
|
70
79
|
- lib/needle/interceptor.rb
|