needle 1.2.0 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (46) hide show
  1. data/doc/manual-html/chapter-1.html +138 -78
  2. data/doc/manual-html/chapter-2.html +180 -99
  3. data/doc/manual-html/chapter-3.html +111 -75
  4. data/doc/manual-html/chapter-4.html +80 -48
  5. data/doc/manual-html/chapter-5.html +106 -56
  6. data/doc/manual-html/chapter-6.html +82 -34
  7. data/doc/manual-html/chapter-7.html +74 -38
  8. data/doc/manual-html/chapter-8.html +70 -41
  9. data/doc/manual-html/chapter-9.html +88 -63
  10. data/doc/manual-html/index.html +6 -6
  11. data/doc/manual-html/needle.png +0 -0
  12. data/doc/manual-html/{manual.css → stylesheets/manual.css} +83 -10
  13. data/doc/manual-html/stylesheets/ruby.css +17 -0
  14. data/doc/manual/chapter.erb +20 -0
  15. data/doc/manual/img/Needle.ai +0 -0
  16. data/doc/manual/img/needle.png +0 -0
  17. data/doc/manual/manual.rb +80 -5
  18. data/doc/manual/manual.yml +3 -3
  19. data/doc/manual/page.erb +1 -1
  20. data/doc/manual/parts/01_use_cases.txt +70 -70
  21. data/doc/manual/parts/02_creating.txt +19 -19
  22. data/doc/manual/parts/02_namespaces.txt +29 -29
  23. data/doc/manual/parts/02_services.txt +40 -41
  24. data/doc/manual/parts/03_conventional.txt +20 -20
  25. data/doc/manual/parts/03_locator.txt +44 -44
  26. data/doc/manual/parts/04_overview.txt +1 -1
  27. data/doc/manual/parts/04_setup.txt +32 -32
  28. data/doc/manual/parts/customizing_contexts.txt +14 -14
  29. data/doc/manual/parts/customizing_interceptors.txt +25 -25
  30. data/doc/manual/parts/customizing_namespaces.txt +12 -12
  31. data/doc/manual/parts/interceptors_attaching.txt +29 -30
  32. data/doc/manual/parts/interceptors_custom.txt +16 -16
  33. data/doc/manual/parts/interceptors_ordering.txt +5 -5
  34. data/doc/manual/parts/libraries_creating.txt +18 -18
  35. data/doc/manual/parts/libraries_using.txt +19 -19
  36. data/doc/manual/parts/logging_configuration.txt +13 -13
  37. data/doc/manual/parts/logging_logfactory.txt +21 -22
  38. data/doc/manual/parts/models_models.txt +8 -8
  39. data/doc/manual/parts/models_overview.txt +1 -1
  40. data/doc/manual/parts/models_pipelines.txt +22 -22
  41. data/doc/manual/{manual.css → stylesheets/manual.css} +83 -10
  42. data/doc/manual/stylesheets/ruby.css +17 -0
  43. data/lib/needle/definition-context.rb +3 -2
  44. data/lib/needle/lifecycle/proxy.rb +1 -1
  45. data/lib/needle/version.rb +1 -1
  46. metadata +94 -85
@@ -2,24 +2,24 @@ Creating your own interceptors is very easy. As was demonstrated earlier, you ca
2
2
 
3
3
  An interceptor factory can be any object, as long as it implements the method @#new@ with two parameters, the _service point_ (service "definition") of the service that the interceptor will be bound to, and a hash of the options that were passed to the interceptor when it was attached to the service. This method should then return a new interceptor instance, which must implement the @#process@ method. The @#process@ method should accept two parameters: an object representing the _chain_ of interceptors, and the invocation _context_.
4
4
 
5
- <pre>
6
- class MyInterceptorFactory
7
- def initialize( point, options )
8
- ...
9
- end
5
+ {{{lang=ruby,number=true,caption=Custom interceptor example
6
+ class MyInterceptorFactory
7
+ def initialize( point, options )
8
+ ...
9
+ end
10
10
 
11
- def process( chain, context )
12
- # context.sym : the name of the method that was invoked
13
- # context.args : the array of arguments passed to the method
14
- # context.block : the block passed to the method, if any
15
- # context.data : a hash that may be used to share data between interceptors
16
- return context.process_next( context )
17
- end
11
+ def process( chain, context )
12
+ # context.sym : the name of the method that was invoked
13
+ # context.args : the array of arguments passed to the method
14
+ # context.block : the block passed to the method, if any
15
+ # context.data : a hash that may be used to share data between interceptors
16
+ return context.process_next( context )
18
17
  end
19
- </pre>
18
+ end
19
+ }}}
20
20
 
21
21
  Once you've created your factory, you can attach it to a service:
22
22
 
23
- <pre>
24
- reg.intercept( :foo ).with { MyInterceptorFactory }
25
- </pre>
23
+ {{{lang=ruby,caption=Attaching a custom interceptor
24
+ reg.intercept( :foo ).with { MyInterceptorFactory }
25
+ }}}
@@ -4,10 +4,10 @@ You can specify a different ordering of the interceptors by giving each one a _p
4
4
 
5
5
  You can specify the priority as an option when attaching an interceptor:
6
6
 
7
- <pre>
8
- reg.register( :foo ) { ... }
9
- reg.intercept( :foo ).with { Something }.with_options( :priority => 100 )
10
- reg.intercept( :foo ).with { SomethingElse }.with_options( :priority => 50 )
11
- </pre>
7
+ {{{lang=ruby,number=true,caption=Setting interceptor priorities
8
+ reg.register( :foo ) { ... }
9
+ reg.intercept( :foo ).with { Something }.with_options( :priority => 100 )
10
+ reg.intercept( :foo ).with { SomethingElse }.with_options( :priority => 50 )
11
+ }}}
12
12
 
13
13
  Without the priorities, when a method of @:foo@ was invoked, Something would be called first, and then SomethingElse. _With_ the priorities (as specified), SomethingElse would be called before Something (since SomethingElse has a lower priority).
@@ -2,28 +2,28 @@ This centralization is implemented by creating a module for each library you wan
2
2
 
3
3
  For example, if I had a library of cryptographic routines and I wanted to make them accessible as Needle services, I would create a module to contain the service definitions. Typically, this module will be defined in a file called "services.rb", although you can certainly name it whatever you like.
4
4
 
5
- <pre>
6
- module Crypto
7
-
8
- def register_services( container )
9
- container.namespace_define( :crypto ) do |b|
10
- b.prng do
11
- require 'crypto/prng'
12
- PRNG.new
13
- end
14
-
15
- b.des do
16
- require 'crypto/des'
17
- DES.new
18
- end
5
+ {{{lang=ruby,number=true,caption=Needle-enabled library example
6
+ module Crypto
7
+
8
+ def register_services( container )
9
+ container.namespace_define( :crypto ) do |b|
10
+ b.prng do
11
+ require 'crypto/prng'
12
+ PRNG.new
13
+ end
19
14
 
20
- ...
15
+ b.des do
16
+ require 'crypto/des'
17
+ DES.new
21
18
  end
22
- end
23
- module_function :register_services
24
19
 
20
+ ...
21
+ end
25
22
  end
26
- </pre>
23
+ module_function :register_services
24
+
25
+ end
26
+ }}}
27
27
 
28
28
  Notice that there are no explicit dependencies on Needle, only on the interfaces Needle publishes. Thus, third-parties can add service configuration modules to their libraries without introducing dependencies on Needle.
29
29
 
@@ -1,31 +1,31 @@
1
1
  Using the libraries is as simple as requiring the file that has the service definitions, and then invoking the @#register_services@ module function:
2
2
 
3
- <pre>
4
- require 'needle'
3
+ {{{lang=ruby,number=true,caption=Example of using a Needle-enabled library
4
+ require 'needle'
5
5
 
6
- reg = Needle::Registry.new
7
- reg.define do |b|
8
- b.foo { Foo.new }
6
+ reg = Needle::Registry.new
7
+ reg.define do |b|
8
+ b.foo { Foo.new }
9
9
 
10
- require 'crypto/services'
11
- Crypto.register_services( reg )
12
- end
10
+ require 'crypto/services'
11
+ Crypto.register_services( reg )
12
+ end
13
13
 
14
- prng = reg.crypto.prng
15
- </pre>
14
+ prng = reg.crypto.prng
15
+ }}}
16
16
 
17
17
  To make this easier, the Container class has a convenience method named @#require@:
18
18
 
19
- <pre>
20
- require 'needle'
19
+ {{{lang=ruby,number=true,caption=Example of using Container#require
20
+ require 'needle'
21
21
 
22
- reg = Needle::Registry.new
23
- reg.define do |b|
24
- b.foo { Foo.new }
25
- b.require 'crypto/services', "Crypto"
26
- end
22
+ reg = Needle::Registry.new
23
+ reg.define do |b|
24
+ b.foo { Foo.new }
25
+ b.require 'crypto/services', "Crypto"
26
+ end
27
27
 
28
- prng = reg.crypto.prng
29
- </pre>
28
+ prng = reg.crypto.prng
29
+ }}}
30
30
 
31
31
  The @Container#require@ method will require the file, and then look for a @#register_services@ method of the named module. It will execute that method, passing the container as an argument.
@@ -12,19 +12,19 @@ You can configure the LogFactory when you create the registry by passing a hash
12
12
 
13
13
  By default, the filename is "./needle.log", and the roll_size is one megabyte. The default level is @:debug@. If you wanted to specify a different filename and default level of @:warn@, you could do:
14
14
 
15
- <pre>
16
- reg = Needle::Registry.new(
17
- :logs => {
18
- :filename => "./my-app.log",
19
- :default_level => :warn }
20
- )
21
- </pre>
15
+ {{{lang=ruby,number=true,caption=Configuring the loggers
16
+ reg = Needle::Registry.new(
17
+ :logs => {
18
+ :filename => "./my-app.log",
19
+ :default_level => :warn }
20
+ )
21
+ }}}
22
22
 
23
23
  Alternatively, you can easily put the logging configuration in a YAML file and read it in, like so:
24
24
 
25
- <pre>
26
- require 'yaml'
27
- reg = Needle::Registry.new(
28
- :logs => YAML.load( File.read( "log-conf.yml" ) )
29
- )
30
- </pre>
25
+ {{{lang=ruby,number=true,caption=Configuring the loggers from a YAML file
26
+ require 'yaml'
27
+ reg = Needle::Registry.new(
28
+ :logs => YAML.load( File.read( "log-conf.yml" ) )
29
+ )
30
+ }}}
@@ -1,14 +1,14 @@
1
1
  The LogFactory is available as a service, so that any component that needs a logger instance can gain easy access to one. The factory's service name is @:logs@.
2
2
 
3
- <pre>
4
- factory = reg.logs
5
- </pre>
3
+ {{{lang=ruby,caption=Accessing the LogFactory service
4
+ factory = reg.logs
5
+ }}}
6
6
 
7
7
  You obtain logger instances from the factory by passing a logger name to @#get@:
8
8
 
9
- <pre>
10
- logger = reg.logs.get "a logger name"
11
- </pre>
9
+ {{{lang=ruby,caption=Getting a named logger instance
10
+ logger = reg.logs.get "a logger name"
11
+ }}}
12
12
 
13
13
  Subsequent calls to @#get@ will return the same logger instance for the given logger name.
14
14
 
@@ -16,25 +16,24 @@ h3. Loggers for Services
16
16
 
17
17
  Typically, you'll use this to assign a logger instance to a service when it is constructed. In that case, the name of the logger is the fully-qualified name of the service:
18
18
 
19
- <pre>
20
- reg.register( :foo ) do |c,p|
21
- Foo.new( c.logs.get( p.fullname ) )
22
- end
23
- </pre>
19
+ {{{lang=ruby,number=true,caption=Getting a logger for a service
20
+ reg.register( :foo ) do |c,p|
21
+ Foo.new( c.logs.get( p.fullname ) )
22
+ end
23
+ }}}
24
24
 
25
25
  As a convenience, if the value passed to @#get@ responds to either @fullname@ or @name@, the return value of that message will be used as the name. Thus, you can do the following:
26
26
 
27
- <pre>
28
- reg.register( :foo ) do |c,p|
29
- Foo.new( c.logs.get( p ) )
30
- end
31
- </pre>
27
+ {{{lang=ruby,number=true,caption=Getting a logger for a service (simplified)
28
+ reg.register( :foo ) do |c,p|
29
+ Foo.new( c.logs.get( p ) )
30
+ end
31
+ }}}
32
32
 
33
33
  As a further convenience, there is a @:log_for@ service that is parameterized. Just pass the name of the log to retreive (or the service point instance) and it will return the log handle directly:
34
34
 
35
- <pre>
36
- reg.register( :foo ) do |c,p|
37
- Foo.new( c.log_for( p ) )
38
- end
39
- </pre>
40
-
35
+ {{{lang=ruby,number=true,caption=Getting a logger for a service (simplified further)
36
+ reg.register( :foo ) do |c,p|
37
+ Foo.new( c.log_for( p ) )
38
+ end
39
+ }}}
@@ -2,7 +2,7 @@ Specifying an entire pipeline for every service point can be tedious. For that r
2
2
 
3
3
  h3. Standard Service Models:
4
4
 
5
- table{border: 1px solid black}.
5
+ table(list).
6
6
  |_<. Name|_<. Pipeline|_<. Effect|
7
7
  |^. @:multiton@|^. @:multiton@|The returned value will be unique for each unique parameter set given to the service.|
8
8
  |^. @:multiton_deferred@|^. @:multiton@, @:deferred@|As @:multiton@, but a proxy is returned, deferring the instantiation of the service itself until a method is invoked on it.|
@@ -25,15 +25,15 @@ h3. Specifying a Service Model
25
25
 
26
26
  You specify the service model by passing the @:model@ option when you register a service. (You must only specify _either_ the model, _or_ the pipeline, but not both.)
27
27
 
28
- <pre>
29
- reg.register( :foo, :model => :singleton_deferred ) {...}
30
- </pre>
28
+ {{{lang=ruby,caption=Specifying a service model
29
+ reg.register( :foo, :model => :singleton_deferred ) {...}
30
+ }}}
31
31
 
32
32
  h3. Defining New Models
33
33
 
34
34
  You can create your own service models by adding the corresponding pipelines to the @:service_models@ service:
35
35
 
36
- <pre>
37
- reg.service_models[ :my_service_model ] = [ :singleton, :my_pipeline_element ]
38
- reg.register( :foo, :model => :my_service_model ) {...}
39
- </pre>
36
+ {{{lang=ruby,number=true,caption=Defining a custom model
37
+ reg.service_models[ :my_service_model ] = [ :singleton, :my_pipeline_element ]
38
+ reg.register( :foo, :model => :my_service_model ) {...}
39
+ }}}
@@ -1,3 +1,3 @@
1
- Service models are the mechanism by which a client can specify how the lifecycle of a particular service should be managed. By default, all services are managed as _singletons_, but it is a simple matter to choose a different behavior when a service is registered.
1
+ Service models are the mechanism by which a client can specify how the lifestyle of a particular service should be managed. By default, all services are managed as _singletons_, but it is a simple matter to choose a different behavior when a service is registered.
2
2
 
3
3
  Underneath, service models are implemented using an _instantiation pipeline_.
@@ -1,10 +1,10 @@
1
1
  An _instantiation pipeline_ is a sequence of elements, each of which knows how to perform some aspect of the instantiation of a service.
2
2
 
3
- Every service consists of at least one instantiation element--the block that was given when the service was registered. Other elements may be combined with this block to enforce various aspects of lifecycle management, such as _multiplicity_ (singleton vs. prototype) and _laziness_ (deferred vs. immediate instantiation).
3
+ Every service consists of at least one instantiation element--the block that was given when the service was registered. Other elements may be combined with this block to enforce various aspects of lifestyle management, such as _multiplicity_ (singleton vs. prototype) and _laziness_ (deferred vs. immediate instantiation).
4
4
 
5
5
  h3. Standard Pipeline Elements
6
6
 
7
- There are five standard pipeline elements available in Needle (although you may certainly create your own):
7
+ There are six standard pipeline elements available in Needle (although you may certainly create your own):
8
8
 
9
9
  * @deferred@: this will always return a proxy that wraps subsequent pipeline elements, causing the subsequent elements to be executed only when a method is invoked on the proxy (at which point the method is then delegated to the resulting service).
10
10
  * @initialize@: this will invoke a method on the resulting service (defaults to @initialize_service@, though it can be changed). It is used for doing final initialization of services (for services that need it).
@@ -23,20 +23,20 @@ h3. Custom Pipeline Elements
23
23
 
24
24
  Creating new pipeline elements simple. Just create a new class that extends @Needle::Pipeline::Element@. Set the default pipeline priority (using the @#set_default_priority@ class method), and then implement the @#call@ method (accepting at least two parameters: the container and the service point).
25
25
 
26
- <pre>
27
- require 'needle/pipeline/element'
28
-
29
- class MyPipelineElement < Needle::Pipeline::Element
30
- set_default_priority 50
31
-
32
- def call( container, point, *args )
33
- ...
34
- result = succ.call( container, point, *args )
35
- ...
36
- return result
37
- end
26
+ {{{lang=ruby,number=true,caption=Custom pipeline element example
27
+ require 'needle/pipeline/element'
28
+
29
+ class MyPipelineElement < Needle::Pipeline::Element
30
+ set_default_priority 50
31
+
32
+ def call( container, point, *args )
33
+ ...
34
+ result = succ.call( container, point, *args )
35
+ ...
36
+ return result
38
37
  end
39
- </pre>
38
+ end
39
+ }}}
40
40
 
41
41
  To invoke the next element of the pipeline, just invoke @#succ.call(...)@.
42
42
 
@@ -48,9 +48,9 @@ h3. Added Pipelines Elements to Services
48
48
 
49
49
  You can specify the pipeline elements to use for a service via the @:pipeline@ option. This must refer to an array, each element of which must be either a symbol (in which case it references an element of the @:pipeline_elements@ service), or a class (in which case it must implement the interface required by @Needle::Pipeline::Element).
50
50
 
51
- <pre>
52
- reg.register( :foo, :pipeline => [ :singleton, MyPipelineElement ] ) { ... }
53
- </pre>
51
+ {{{lang=ruby,caption=Adding pipelines to services
52
+ reg.register( :foo, :pipeline => [ :singleton, MyPipelineElement ] ) { ... }
53
+ }}}
54
54
 
55
55
  The elements will be sorted based on their priorities, with lower priorities sorting closer to the instantiation block, and higher priorities sorting closer to the client.
56
56
 
@@ -58,7 +58,7 @@ h3. Making Custom Pipeline Elements Available
58
58
 
59
59
  You can make your custom pipeline elements available (so they can be referenced by symbol, instead of class name) by adding them to the @:pipeline_elements@ service:
60
60
 
61
- <pre>
62
- reg.pipeline_elements[ :my_pipeline_element ] = MyPipelineElement
63
- reg.register( :foo, :pipeline => [ :singleton, :my_pipeline_element ] ) { ... }
64
- </pre>
61
+ {{{lang=ruby,number=true,caption=Publishing custom pipeline elements
62
+ reg.pipeline_elements[ :my_pipeline_element ] = MyPipelineElement
63
+ reg.register( :foo, :pipeline => [ :singleton, :my_pipeline_element ] ) { ... }
64
+ }}}
@@ -87,8 +87,8 @@ a:hover {
87
87
  }
88
88
 
89
89
  #navigation ul, #navigation ol {
90
- margin-left: 1.5em;
91
- padding-left: 1.5em;
90
+ margin-left: 1.2em;
91
+ padding-left: 1.2em;
92
92
  }
93
93
 
94
94
  #navigation .license {
@@ -107,12 +107,6 @@ a:hover {
107
107
  text-align: justify;
108
108
  }
109
109
 
110
- #content pre {
111
- background: #FFE;
112
- border: 1px dotted #AAA;
113
- padding: 1em;
114
- }
115
-
116
110
  #content h1 {
117
111
  background: #005;
118
112
  color: #FFF;
@@ -186,7 +180,86 @@ a:hover {
186
180
  text-align: center;
187
181
  }
188
182
 
189
- table.list td {
190
- border-bottom: 1px dotted #005;
183
+ table.list {
184
+ margin: 2em;
185
+ border: 1px solid black;
186
+ background: #FFD;
187
+ padding: 0px;
188
+ border-spacing: 0px;
189
+ }
190
+
191
+ table.list th {
192
+ border-bottom: 1px solid #005;
191
193
  padding-bottom: 5px;
194
+ background: #008;
195
+ color: white;
196
+ padding: 0.5em;
197
+ text-align: left;
198
+ }
199
+
200
+ table.list td {
201
+ padding: 0.2em;
202
+ text-align: left;
203
+ vertical-align: top;
204
+ border-bottom: 1px solid;
205
+ }
206
+
207
+ .prevnext {
208
+ padding: 0.5em 1em 0.5em 1em;
209
+ background: #557;
210
+ color: #FFF;
211
+ font-size: small;
212
+ font-weight: bold;
213
+ border: 1px solid #000;
214
+ }
215
+
216
+ .prevnext a {
217
+ color: #FF0;
218
+ }
219
+
220
+ .top .prevnext {
221
+ margin: 0 0 1em 0;
222
+ text-align: left;
223
+ }
224
+
225
+ .bottom .prevnext {
226
+ margin: 1em 0 0 0;
227
+ text-align: right;
228
+ }
229
+
230
+ .figure {
231
+ border: 1px solid black;
232
+ line-height: normal;
233
+ background: #FFD;
234
+ margin: 2em;
235
+ }
236
+
237
+ .figure .caption {
238
+ background: #008;
239
+ color: white;
240
+ font-weight: bold;
241
+ font-size: small;
242
+ padding: 4px 24px 4px 8px;
243
+ margin-left: -4px;
244
+ border: 1px dotted #77F;
245
+ }
246
+
247
+ .figure .body {
248
+ padding-left: 1em;
249
+ }
250
+
251
+ .figure pre {
252
+ padding: 0px;
253
+ background: transparent;
254
+ border: none;
255
+ font-size: small;
256
+ font-family: mono;
257
+ }
258
+
259
+ .figure .lineno {
260
+ text-align: right;
261
+ color: #B00;
262
+ font-family: mono;
263
+ font-size: small;
264
+ padding-right: 1em;
192
265
  }