needle 0.6.0 → 0.9.0

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