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.
@@ -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. Instead of passing the container to
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 ) { |ns| block.call( ns.builder ) }
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
- return @name.to_s unless @parent
129
- "#{@parent.fullname}.#{@name}"
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
- # immediately, singleton instantiation is sufficient for 99% of the things
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
- # immediately, singleton instantiation is sufficient for 99% of the things
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.namespace!( :operations ) do
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
- def namespace!( name, opts={}, &block )
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
@@ -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
- # #new! method for easily registering new services.
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.new! do
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.new!( *parms, &block )
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. If the first parameter is a string, it will
66
- # be used as the name of this registry. If the next parameter is a Hash,
67
- # it will be used as the options to use when bootstrapping the registry.
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
- # The options hash may include options used to initialize the logger
70
- # factory. The logger factory options should be in another hash, keyed
71
- # by the value <tt>:logs</tt>.
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( *parms )
91
- raise ArgumentError, "expected <= 2 arguments" if parms.length > 2
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
- # Return the name of this registry, enclosed in square braces.
103
+ # Returns +nil+. Registries are unnamed containers.
107
104
  def fullname
108
- "[#{super}]"
105
+ nil
109
106
  end
110
107
 
111
108
  # Bootstraps the pipeline elements, service models, logger factory, and
@@ -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
- "#{@container.fullname}.#{@name}"
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
@@ -18,7 +18,7 @@ module Needle
18
18
  module Version
19
19
 
20
20
  MAJOR = 0
21
- MINOR = 6
21
+ MINOR = 9
22
22
  TINY = 0
23
23
 
24
24
  # The version of the Needle library in use.
@@ -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 "[].test" if cache
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
 
@@ -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.namespace :subitem, :pipeline=>[] do |b2|
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
 
@@ -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 test_new_no_options!
35
- reg = Needle::Registry.new! do
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 test_new_with_options!
43
- reg = Needle::Registry.new!( :logs => { :device => STDOUT } ) do
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
- assert_equal "[]", @registry.fullname
86
+ assert_nil @registry.fullname
70
87
  end
71
88
 
72
89
  end
@@ -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.6.0
7
- date: 2004-10-21
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