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/doc/faq/faq.rb
    ADDED
    
    | @@ -0,0 +1,143 @@ | |
| 1 | 
            +
            require 'yaml'
         | 
| 2 | 
            +
            require 'redcloth'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            def process_faq_list( faqs )
         | 
| 5 | 
            +
              puts "<ul>"
         | 
| 6 | 
            +
              faqs.each do |faq|
         | 
| 7 | 
            +
                process_faq_list_item faq
         | 
| 8 | 
            +
              end
         | 
| 9 | 
            +
              puts "</ul>"
         | 
| 10 | 
            +
            end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            def process_faq_list_item( faq )
         | 
| 13 | 
            +
              question = faq.keys.first
         | 
| 14 | 
            +
              answer = faq.values.first
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              print "<li>"
         | 
| 17 | 
            +
             | 
| 18 | 
            +
              question_text = RedCloth.new(question).to_html.gsub( %r{</?p>},"" )
         | 
| 19 | 
            +
              if answer.is_a?( Array )
         | 
| 20 | 
            +
                puts question_text
         | 
| 21 | 
            +
                process_faq_list answer
         | 
| 22 | 
            +
              else
         | 
| 23 | 
            +
                print "<a href='##{question.id}'>#{question_text}</a>"
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              puts "</li>"
         | 
| 27 | 
            +
            end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
            def process_faq_descriptions( faqs, path=nil )
         | 
| 30 | 
            +
              faqs.each do |faq|
         | 
| 31 | 
            +
                process_faq_description faq, path
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            def process_faq_description( faq, path )
         | 
| 36 | 
            +
              question = faq.keys.first
         | 
| 37 | 
            +
              path = ( path ? path + " " : "" ) + question
         | 
| 38 | 
            +
              answer = faq.values.first
         | 
| 39 | 
            +
             | 
| 40 | 
            +
              if answer.is_a?( Array )
         | 
| 41 | 
            +
                process_faq_descriptions( answer, path )
         | 
| 42 | 
            +
              else
         | 
| 43 | 
            +
                title = RedCloth.new( path ).to_html.gsub( %r{</?p>}, "" )
         | 
| 44 | 
            +
                answer = RedCloth.new( answer || "" )
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                puts "<a name='#{question.id}'></a>"
         | 
| 47 | 
            +
                puts "<div class='faq-title'>#{title}</div>"
         | 
| 48 | 
            +
                puts "<div class='faq-answer'>#{add_api_links(answer.to_html)}</div>"
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
            end
         | 
| 51 | 
            +
             | 
| 52 | 
            +
            API_OBJECTS = [
         | 
| 53 | 
            +
              "Container", "Interceptor", "LogFactory", "Logger", "LoggingInterceptor",
         | 
| 54 | 
            +
              "Registry", "ServicePoint", "QueryableMutex", "Pipeline::Collection",
         | 
| 55 | 
            +
              "Pipeline::Element" ].inject( "(" ) { |acc,name|
         | 
| 56 | 
            +
                acc << "|" if acc.length > 1
         | 
| 57 | 
            +
                acc << name
         | 
| 58 | 
            +
                acc
         | 
| 59 | 
            +
              } + ")"
         | 
| 60 | 
            +
             | 
| 61 | 
            +
            def add_api_links( text )
         | 
| 62 | 
            +
              text.gsub( /#{API_OBJECTS}(#(\w+))?/ ) do
         | 
| 63 | 
            +
                disp_obj = obj = $1
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                method = $3
         | 
| 66 | 
            +
                s = "<a href='http://needle.rubyforge.org/api/classes/Needle/#{obj}.html'>#{disp_obj}"
         | 
| 67 | 
            +
                s << "##{method}" if method
         | 
| 68 | 
            +
                s << "</a>"
         | 
| 69 | 
            +
                s
         | 
| 70 | 
            +
              end
         | 
| 71 | 
            +
            end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
            faqs = YAML.load( File.read( "faq.yml" ) )
         | 
| 74 | 
            +
             | 
| 75 | 
            +
            puts <<-EOF
         | 
| 76 | 
            +
            <html>
         | 
| 77 | 
            +
              <head>
         | 
| 78 | 
            +
                <title>Needle FAQ</title>
         | 
| 79 | 
            +
                <style type="text/css">
         | 
| 80 | 
            +
                  a, a:visited, a:active {
         | 
| 81 | 
            +
                    color: #00F;
         | 
| 82 | 
            +
                    text-decoration: none;
         | 
| 83 | 
            +
                  }
         | 
| 84 | 
            +
             | 
| 85 | 
            +
                  a:hover {
         | 
| 86 | 
            +
                    text-decoration: underline;
         | 
| 87 | 
            +
                  }
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  .faq-list {
         | 
| 90 | 
            +
                    color: #000;
         | 
| 91 | 
            +
                    font-family: vera-sans, verdana, arial, sans-serif;
         | 
| 92 | 
            +
                  }
         | 
| 93 | 
            +
             | 
| 94 | 
            +
                  .faq-title {
         | 
| 95 | 
            +
                    background: #007;
         | 
| 96 | 
            +
                    color: #FFF;
         | 
| 97 | 
            +
                    font-family: vera-sans, verdana, arial, sans-serif;
         | 
| 98 | 
            +
                    padding-left: 1em;
         | 
| 99 | 
            +
                    padding-top: 0.5em;
         | 
| 100 | 
            +
                    padding-bottom: 0.5em;
         | 
| 101 | 
            +
                    font-weight: bold;
         | 
| 102 | 
            +
                    font-size: large;
         | 
| 103 | 
            +
                    border: 1px solid #000;
         | 
| 104 | 
            +
                  }
         | 
| 105 | 
            +
             | 
| 106 | 
            +
                  .faq-answer {
         | 
| 107 | 
            +
                    margin-left: 1em;
         | 
| 108 | 
            +
                    color: #000;
         | 
| 109 | 
            +
                    font-family: vera-sans, verdana, arial, sans-serif;
         | 
| 110 | 
            +
                  }
         | 
| 111 | 
            +
             | 
| 112 | 
            +
                  .faq-answer pre {
         | 
| 113 | 
            +
                    margin-left: 1em;
         | 
| 114 | 
            +
                    color: #000;
         | 
| 115 | 
            +
                    background: #FFE;
         | 
| 116 | 
            +
                    font-size: normal;
         | 
| 117 | 
            +
                    border: 1px dotted #CCC;
         | 
| 118 | 
            +
                    padding: 1em;
         | 
| 119 | 
            +
                  }
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                  h1 {
         | 
| 122 | 
            +
                    background: #005;
         | 
| 123 | 
            +
                    color: #FFF;
         | 
| 124 | 
            +
                    font-family: vera-sans, verdana, arial, sans-serif;
         | 
| 125 | 
            +
                    padding-left: 1em;
         | 
| 126 | 
            +
                    padding-top: 1em;
         | 
| 127 | 
            +
                    padding-bottom: 1em;
         | 
| 128 | 
            +
                    font-weight: bold;
         | 
| 129 | 
            +
                    font-size: x-large;
         | 
| 130 | 
            +
                    border: 1px solid #00F;
         | 
| 131 | 
            +
                  }
         | 
| 132 | 
            +
                </style>
         | 
| 133 | 
            +
              </head>
         | 
| 134 | 
            +
              <body>
         | 
| 135 | 
            +
              <h1>Needle FAQ</h1>
         | 
| 136 | 
            +
              <div class="faq-list">
         | 
| 137 | 
            +
            EOF
         | 
| 138 | 
            +
             | 
| 139 | 
            +
            process_faq_list( faqs )
         | 
| 140 | 
            +
            puts "</div>"
         | 
| 141 | 
            +
            process_faq_descriptions( faqs )
         | 
| 142 | 
            +
             | 
| 143 | 
            +
            puts "</body></html>"
         | 
    
        data/doc/faq/faq.yml
    ADDED
    
    | @@ -0,0 +1,75 @@ | |
| 1 | 
            +
            ---
         | 
| 2 | 
            +
            - "What is a...":
         | 
| 3 | 
            +
              - "container?": >-
         | 
| 4 | 
            +
                  A _container_ is collection of service points and other containers. It
         | 
| 5 | 
            +
                  is used to organize services. Each container has access to all of the
         | 
| 6 | 
            +
                  service points in its ancestor containers.
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              - "registry?": >-
         | 
| 9 | 
            +
                  A _registry_ is a special kind of container that has no parent container.
         | 
| 10 | 
            +
                  It also defines a few services (such as the LoggingInterceptor, and
         | 
| 11 | 
            +
                  the various service models and pipeline elements), so that they are
         | 
| 12 | 
            +
                  available by default to all of the services it contains.
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              - "service point?": >-
         | 
| 15 | 
            +
                  A _service point_ is the definition of a service. Just as a class is the
         | 
| 16 | 
            +
                  definition of an object, and you instantiate an object from a class, so
         | 
| 17 | 
            +
                  do you instantiate services from service points.
         | 
| 18 | 
            +
             | 
| 19 | 
            +
              - "service?": >-
         | 
| 20 | 
            +
                  A _service_ is the instantiation of a service point.
         | 
| 21 | 
            +
             | 
| 22 | 
            +
              - "service model?": >-
         | 
| 23 | 
            +
                  A _service model_ is a description of the lifecycle of a service. By
         | 
| 24 | 
            +
                  default, all services are _singletons_, meaning that every time you ask
         | 
| 25 | 
            +
                  a container for a particular service, you'll get the same object
         | 
| 26 | 
            +
                  instance back.
         | 
| 27 | 
            +
             | 
| 28 | 
            +
             | 
| 29 | 
            +
                  There are other service models available, though, including "prototype"
         | 
| 30 | 
            +
                  (which returns a new instance for each request of a service) and
         | 
| 31 | 
            +
                  "deferred" (which returns a proxy, deferring the instatiation of the
         | 
| 32 | 
            +
                  service itself until a method is invoked on the service). 
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              - "interceptor?": >-
         | 
| 35 | 
            +
                  An _interceptor_ is an object that may be placed between the client and
         | 
| 36 | 
            +
                  a service. Every request to the service is thus _intercepted_ by that
         | 
| 37 | 
            +
                  object, which can do operations on the request (such as logging) and may
         | 
| 38 | 
            +
                  even reroute or ignore the request altogether. This provides a kind of
         | 
| 39 | 
            +
                  "poor man's AOP", since you can do "before", "after", and "around" advice
         | 
| 40 | 
            +
                  on the methods of a service.
         | 
| 41 | 
            +
             | 
| 42 | 
            +
             | 
| 43 | 
            +
                  Needle comes with one standard interceptor, the LoggingInterceptor. It
         | 
| 44 | 
            +
                  will log a message on method entry and exit, and also when an exception
         | 
| 45 | 
            +
                  is raised.
         | 
| 46 | 
            +
             | 
| 47 | 
            +
              - "pipeline?": >-
         | 
| 48 | 
            +
                  In Needle, the _instantiation pipeline_ is used to control how and when
         | 
| 49 | 
            +
                  services are instantiated. The _service models_ are implemented as
         | 
| 50 | 
            +
                  pipelines.
         | 
| 51 | 
            +
             | 
| 52 | 
            +
             | 
| 53 | 
            +
                  Just as the _interceptors_ are for hooking into method invocations, the
         | 
| 54 | 
            +
                  pipelines are for hooking into service instantiations. Every time a
         | 
| 55 | 
            +
                  service is requested, it's instantiation pipeline is executed. By
         | 
| 56 | 
            +
                  choosing the appropriate kinds of pipeline elements, all of the available
         | 
| 57 | 
            +
                  service models can be implemented (prototype, prototype_deferred,
         | 
| 58 | 
            +
                  singleton, singleton_deferred, etc.).
         | 
| 59 | 
            +
             | 
| 60 | 
            +
            - "How do I...":
         | 
| 61 | 
            +
              - "create a new registry?":
         | 
| 62 | 
            +
              - "register a service?":
         | 
| 63 | 
            +
              - "create a namespace?":
         | 
| 64 | 
            +
              - "write log messages?":
         | 
| 65 | 
            +
              - "exclude methods from being intercepted?":
         | 
| 66 | 
            +
            - "When should I...":
         | 
| 67 | 
            +
              - "specify a service model?":
         | 
| 68 | 
            +
                - "Like, :prototype?":
         | 
| 69 | 
            +
                - "Like, :prototype_deferred?":
         | 
| 70 | 
            +
                - "Like, :singleton?":
         | 
| 71 | 
            +
                - "Like, :singleton_deferred?":
         | 
| 72 | 
            +
                - "Like, :threaded?":
         | 
| 73 | 
            +
                - "Like, :threaded_deferred?":
         | 
| 74 | 
            +
              - "use interceptors?":
         | 
| 75 | 
            +
              - "create my own pipeline element?":
         | 
| @@ -14,8 +14,8 @@ | |
| 14 14 | 
             
                      </div>
         | 
| 15 15 | 
             
                    </td><td valign='middle' align='right'>
         | 
| 16 16 | 
             
                      <div class="info">
         | 
| 17 | 
            -
                        Needle Version: <strong>0. | 
| 18 | 
            -
                        Manual Last Updated: <strong>2004-10- | 
| 17 | 
            +
                        Needle Version: <strong>0.9.0</strong><br />
         | 
| 18 | 
            +
                        Manual Last Updated: <strong>2004-10-28 15:34 GMT</strong>
         | 
| 19 19 | 
             
                      </div>
         | 
| 20 20 | 
             
                    </td></tr>
         | 
| 21 21 | 
             
                  </table>
         | 
| @@ -70,27 +70,37 @@ | |
| 70 70 |  | 
| 71 71 | 
             
                        <li>
         | 
| 72 72 | 
             
                            <a href="chapter-3.html">
         | 
| 73 | 
            -
                             | 
| 73 | 
            +
                            Service Locator
         | 
| 74 74 | 
             
                            </a>
         | 
| 75 75 |  | 
| 76 76 | 
             
                          <ol type="1">
         | 
| 77 77 |  | 
| 78 | 
            +
                              <li><a href="chapter-3.html#s1">Overview</a></li>
         | 
| 79 | 
            +
                            
         | 
| 80 | 
            +
                              <li><a href="chapter-3.html#s2">Conventional Architecture</a></li>
         | 
| 81 | 
            +
                            
         | 
| 82 | 
            +
                              <li><a href="chapter-3.html#s3">Locator Pattern</a></li>
         | 
| 83 | 
            +
                            
         | 
| 78 84 | 
             
                          </ol>
         | 
| 79 85 | 
             
                        </li>
         | 
| 80 86 |  | 
| 81 87 | 
             
                        <li>
         | 
| 82 88 | 
             
                            <a href="chapter-4.html">
         | 
| 83 | 
            -
                             | 
| 89 | 
            +
                            Dependency Injection
         | 
| 84 90 | 
             
                            </a>
         | 
| 85 91 |  | 
| 86 92 | 
             
                          <ol type="1">
         | 
| 87 93 |  | 
| 94 | 
            +
                              <li><a href="chapter-4.html#s1">Overview</a></li>
         | 
| 95 | 
            +
                            
         | 
| 96 | 
            +
                              <li><a href="chapter-4.html#s2">Setup</a></li>
         | 
| 97 | 
            +
                            
         | 
| 88 98 | 
             
                          </ol>
         | 
| 89 99 | 
             
                        </li>
         | 
| 90 100 |  | 
| 91 101 | 
             
                        <li>
         | 
| 92 102 | 
             
                            <a href="chapter-5.html">
         | 
| 93 | 
            -
                             | 
| 103 | 
            +
                            Interceptors
         | 
| 94 104 | 
             
                            </a>
         | 
| 95 105 |  | 
| 96 106 | 
             
                          <ol type="1">
         | 
| @@ -100,7 +110,7 @@ | |
| 100 110 |  | 
| 101 111 | 
             
                        <li>
         | 
| 102 112 | 
             
                            <a href="chapter-6.html">
         | 
| 103 | 
            -
                             | 
| 113 | 
            +
                            Service Models
         | 
| 104 114 | 
             
                            </a>
         | 
| 105 115 |  | 
| 106 116 | 
             
                          <ol type="1">
         | 
| @@ -110,6 +120,16 @@ | |
| 110 120 |  | 
| 111 121 | 
             
                        <li>
         | 
| 112 122 | 
             
                            <a href="chapter-7.html">
         | 
| 123 | 
            +
                            Logging
         | 
| 124 | 
            +
                            </a>
         | 
| 125 | 
            +
                            
         | 
| 126 | 
            +
                          <ol type="1">
         | 
| 127 | 
            +
                            
         | 
| 128 | 
            +
                          </ol>
         | 
| 129 | 
            +
                        </li>
         | 
| 130 | 
            +
                      
         | 
| 131 | 
            +
                        <li>
         | 
| 132 | 
            +
                            <a href="chapter-8.html">
         | 
| 113 133 | 
             
                            Creating Libraries
         | 
| 114 134 | 
             
                            </a>
         | 
| 115 135 |  | 
| @@ -14,8 +14,8 @@ | |
| 14 14 | 
             
                      </div>
         | 
| 15 15 | 
             
                    </td><td valign='middle' align='right'>
         | 
| 16 16 | 
             
                      <div class="info">
         | 
| 17 | 
            -
                        Needle Version: <strong>0. | 
| 18 | 
            -
                        Manual Last Updated: <strong>2004-10- | 
| 17 | 
            +
                        Needle Version: <strong>0.9.0</strong><br />
         | 
| 18 | 
            +
                        Manual Last Updated: <strong>2004-10-28 15:34 GMT</strong>
         | 
| 19 19 | 
             
                      </div>
         | 
| 20 20 | 
             
                    </td></tr>
         | 
| 21 21 | 
             
                  </table>
         | 
| @@ -70,27 +70,37 @@ | |
| 70 70 |  | 
| 71 71 | 
             
                        <li>
         | 
| 72 72 | 
             
                            <a href="chapter-3.html">
         | 
| 73 | 
            -
                             | 
| 73 | 
            +
                            Service Locator
         | 
| 74 74 | 
             
                            </a>
         | 
| 75 75 |  | 
| 76 76 | 
             
                          <ol type="1">
         | 
| 77 77 |  | 
| 78 | 
            +
                              <li><a href="chapter-3.html#s1">Overview</a></li>
         | 
| 79 | 
            +
                            
         | 
| 80 | 
            +
                              <li><a href="chapter-3.html#s2">Conventional Architecture</a></li>
         | 
| 81 | 
            +
                            
         | 
| 82 | 
            +
                              <li><a href="chapter-3.html#s3">Locator Pattern</a></li>
         | 
| 83 | 
            +
                            
         | 
| 78 84 | 
             
                          </ol>
         | 
| 79 85 | 
             
                        </li>
         | 
| 80 86 |  | 
| 81 87 | 
             
                        <li>
         | 
| 82 88 | 
             
                            <a href="chapter-4.html">
         | 
| 83 | 
            -
                             | 
| 89 | 
            +
                            Dependency Injection
         | 
| 84 90 | 
             
                            </a>
         | 
| 85 91 |  | 
| 86 92 | 
             
                          <ol type="1">
         | 
| 87 93 |  | 
| 94 | 
            +
                              <li><a href="chapter-4.html#s1">Overview</a></li>
         | 
| 95 | 
            +
                            
         | 
| 96 | 
            +
                              <li><a href="chapter-4.html#s2">Setup</a></li>
         | 
| 97 | 
            +
                            
         | 
| 88 98 | 
             
                          </ol>
         | 
| 89 99 | 
             
                        </li>
         | 
| 90 100 |  | 
| 91 101 | 
             
                        <li>
         | 
| 92 102 | 
             
                            <a href="chapter-5.html">
         | 
| 93 | 
            -
                             | 
| 103 | 
            +
                            Interceptors
         | 
| 94 104 | 
             
                            </a>
         | 
| 95 105 |  | 
| 96 106 | 
             
                          <ol type="1">
         | 
| @@ -100,7 +110,7 @@ | |
| 100 110 |  | 
| 101 111 | 
             
                        <li>
         | 
| 102 112 | 
             
                            <a href="chapter-6.html">
         | 
| 103 | 
            -
                             | 
| 113 | 
            +
                            Service Models
         | 
| 104 114 | 
             
                            </a>
         | 
| 105 115 |  | 
| 106 116 | 
             
                          <ol type="1">
         | 
| @@ -110,6 +120,16 @@ | |
| 110 120 |  | 
| 111 121 | 
             
                        <li>
         | 
| 112 122 | 
             
                            <a href="chapter-7.html">
         | 
| 123 | 
            +
                            Logging
         | 
| 124 | 
            +
                            </a>
         | 
| 125 | 
            +
                            
         | 
| 126 | 
            +
                          <ol type="1">
         | 
| 127 | 
            +
                            
         | 
| 128 | 
            +
                          </ol>
         | 
| 129 | 
            +
                        </li>
         | 
| 130 | 
            +
                      
         | 
| 131 | 
            +
                        <li>
         | 
| 132 | 
            +
                            <a href="chapter-8.html">
         | 
| 113 133 | 
             
                            Creating Libraries
         | 
| 114 134 | 
             
                            </a>
         | 
| 115 135 |  | 
| @@ -191,15 +211,25 @@ | |
| 191 211 |  | 
| 192 212 | 
             
            	<p>The parameter to the block will be a reference to the registry. This allows you to register services with the registry as soon as it is created.</p>
         | 
| 193 213 |  | 
| 194 | 
            -
            	<p> | 
| 214 | 
            +
            	<p>Another convenience method is <code>#define!</code>:</p>
         | 
| 215 | 
            +
             | 
| 216 | 
            +
            <pre>
         | 
| 217 | 
            +
              registry = Needle::Registry.define! do
         | 
| 218 | 
            +
                ...
         | 
| 219 | 
            +
              end
         | 
| 220 | 
            +
            </pre>
         | 
| 221 | 
            +
             | 
| 222 | 
            +
            	<p>This block accepts no parameters, and evaluates the block as if it were passed to <code>Registry#define!</code> (see below).</p>
         | 
| 223 | 
            +
             | 
| 224 | 
            +
            	<p>There can be problems with using <code>define!</code>, however, since it uses <code>instance_eval</code> to evaluate the block within the context of another object. If you find yourself running into scoping issues, you might want to consider using <code>#define</code>:</p>
         | 
| 195 225 |  | 
| 196 226 | 
             
            <pre>
         | 
| 197 | 
            -
              registry = Needle::Registry. | 
| 227 | 
            +
              registry = Needle::Registry.define do |b|
         | 
| 198 228 | 
             
                ...
         | 
| 199 229 | 
             
              end
         | 
| 200 230 | 
             
            </pre>
         | 
| 201 231 |  | 
| 202 | 
            -
            	<p>This block accepts  | 
| 232 | 
            +
            	<p>This block accepts a single parameter—a “builder” object to aid in registering services—and evaluates the block as if it were passed to <code>Registry#define</code> (see below).<br />
         | 
| 203 233 | 
             
            </p>
         | 
| 204 234 | 
             
               </div>
         | 
| 205 235 |  | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            <html>
         | 
| 2 2 | 
             
              <head>
         | 
| 3 | 
            -
                <title>Needle Manual :: Chapter 3:  | 
| 3 | 
            +
                <title>Needle Manual :: Chapter 3: Service Locator</title>
         | 
| 4 4 | 
             
                <link type="text/css" rel="stylesheet" href="manual.css" />
         | 
| 5 5 | 
             
              </head>
         | 
| 6 6 |  | 
| @@ -14,8 +14,8 @@ | |
| 14 14 | 
             
                      </div>
         | 
| 15 15 | 
             
                    </td><td valign='middle' align='right'>
         | 
| 16 16 | 
             
                      <div class="info">
         | 
| 17 | 
            -
                        Needle Version: <strong>0. | 
| 18 | 
            -
                        Manual Last Updated: <strong>2004-10- | 
| 17 | 
            +
                        Needle Version: <strong>0.9.0</strong><br />
         | 
| 18 | 
            +
                        Manual Last Updated: <strong>2004-10-28 15:34 GMT</strong>
         | 
| 19 19 | 
             
                      </div>
         | 
| 20 20 | 
             
                    </td></tr>
         | 
| 21 21 | 
             
                  </table>
         | 
| @@ -70,27 +70,37 @@ | |
| 70 70 |  | 
| 71 71 | 
             
                        <li><strong>
         | 
| 72 72 | 
             
                            <a href="chapter-3.html">
         | 
| 73 | 
            -
                             | 
| 73 | 
            +
                            Service Locator
         | 
| 74 74 | 
             
                            </a>
         | 
| 75 75 | 
             
                            </strong> <big>←</big>
         | 
| 76 76 | 
             
                          <ol type="1">
         | 
| 77 77 |  | 
| 78 | 
            +
                              <li><a href="chapter-3.html#s1">Overview</a></li>
         | 
| 79 | 
            +
                            
         | 
| 80 | 
            +
                              <li><a href="chapter-3.html#s2">Conventional Architecture</a></li>
         | 
| 81 | 
            +
                            
         | 
| 82 | 
            +
                              <li><a href="chapter-3.html#s3">Locator Pattern</a></li>
         | 
| 83 | 
            +
                            
         | 
| 78 84 | 
             
                          </ol>
         | 
| 79 85 | 
             
                        </li>
         | 
| 80 86 |  | 
| 81 87 | 
             
                        <li>
         | 
| 82 88 | 
             
                            <a href="chapter-4.html">
         | 
| 83 | 
            -
                             | 
| 89 | 
            +
                            Dependency Injection
         | 
| 84 90 | 
             
                            </a>
         | 
| 85 91 |  | 
| 86 92 | 
             
                          <ol type="1">
         | 
| 87 93 |  | 
| 94 | 
            +
                              <li><a href="chapter-4.html#s1">Overview</a></li>
         | 
| 95 | 
            +
                            
         | 
| 96 | 
            +
                              <li><a href="chapter-4.html#s2">Setup</a></li>
         | 
| 97 | 
            +
                            
         | 
| 88 98 | 
             
                          </ol>
         | 
| 89 99 | 
             
                        </li>
         | 
| 90 100 |  | 
| 91 101 | 
             
                        <li>
         | 
| 92 102 | 
             
                            <a href="chapter-5.html">
         | 
| 93 | 
            -
                             | 
| 103 | 
            +
                            Interceptors
         | 
| 94 104 | 
             
                            </a>
         | 
| 95 105 |  | 
| 96 106 | 
             
                          <ol type="1">
         | 
| @@ -100,7 +110,7 @@ | |
| 100 110 |  | 
| 101 111 | 
             
                        <li>
         | 
| 102 112 | 
             
                            <a href="chapter-6.html">
         | 
| 103 | 
            -
                             | 
| 113 | 
            +
                            Service Models
         | 
| 104 114 | 
             
                            </a>
         | 
| 105 115 |  | 
| 106 116 | 
             
                          <ol type="1">
         | 
| @@ -110,6 +120,16 @@ | |
| 110 120 |  | 
| 111 121 | 
             
                        <li>
         | 
| 112 122 | 
             
                            <a href="chapter-7.html">
         | 
| 123 | 
            +
                            Logging
         | 
| 124 | 
            +
                            </a>
         | 
| 125 | 
            +
                            
         | 
| 126 | 
            +
                          <ol type="1">
         | 
| 127 | 
            +
                            
         | 
| 128 | 
            +
                          </ol>
         | 
| 129 | 
            +
                        </li>
         | 
| 130 | 
            +
                      
         | 
| 131 | 
            +
                        <li>
         | 
| 132 | 
            +
                            <a href="chapter-8.html">
         | 
| 113 133 | 
             
                            Creating Libraries
         | 
| 114 134 | 
             
                            </a>
         | 
| 115 135 |  | 
| @@ -143,7 +163,156 @@ | |
| 143 163 |  | 
| 144 164 | 
             
                    <div id="content">
         | 
| 145 165 |  | 
| 146 | 
            -
                      <h1>3.  | 
| 166 | 
            +
                      <h1>3. Service Locator</h1>
         | 
| 167 | 
            +
             | 
| 168 | 
            +
             | 
| 169 | 
            +
             | 
| 170 | 
            +
                 <h2>
         | 
| 171 | 
            +
                   <a name="s1"></a>
         | 
| 172 | 
            +
                   3.1. Overview
         | 
| 173 | 
            +
                 </h2>
         | 
| 174 | 
            +
             | 
| 175 | 
            +
               
         | 
| 176 | 
            +
             | 
| 177 | 
            +
               <div class="section">
         | 
| 178 | 
            +
                 <p>The <em>service locator</em> design pattern can be considered a subset of dependency injection. Because it is simpler, it is as good of a place to start teaching DI as any.</p>
         | 
| 179 | 
            +
             | 
| 180 | 
            +
            	<p>To demonstrate both techniques, we’ll pretend we’re going to write an online forum application. To start, let’s come up with a rough design by cataloging the components we’ll need.</p>
         | 
| 181 | 
            +
             | 
| 182 | 
            +
            	<ul>
         | 
| 183 | 
            +
            	<li><code>Logger</code>. This will be used to write messages to a file.</li>
         | 
| 184 | 
            +
            		<li><code>Authenticator</code>. This will be used to validate whether a user is who they say they are.</li>
         | 
| 185 | 
            +
            		<li><code>Database</code>. This encapsulates access to the database that will store our forum data.</li>
         | 
| 186 | 
            +
            		<li><code>Session</code>. This represents a single user’s session.</li>
         | 
| 187 | 
            +
            		<li><code>View</code>. The presentation manager, used to render pages to the user.</li>
         | 
| 188 | 
            +
            		<li><code>Application</code>. The controller that ties it all together.</li>
         | 
| 189 | 
            +
            	</ul>
         | 
| 190 | 
            +
             | 
| 191 | 
            +
            	<p>(Of course, a <em>real</em> online forum application would be significantly more complex, but the above components will do for our puroses.)</p>
         | 
| 192 | 
            +
             | 
| 193 | 
            +
            	<p>The dependencies between these components are:</p>
         | 
| 194 | 
            +
             | 
| 195 | 
            +
            	<ul>
         | 
| 196 | 
            +
            	<li><code>Authenticator</code> <em>has</em> <code>Database</code> (for querying user authentication information) and <code>Logger</code></li>
         | 
| 197 | 
            +
            		<li><code>Database</code> <em>has</em> <code>Logger</code> (for indicating database accesses and query times)</li>
         | 
| 198 | 
            +
            		<li><code>Session</code> <em>has</em> <code>Database</code> (for storing session information) and <code>Logger</code></li>
         | 
| 199 | 
            +
            		<li><code>Application</code> <em>has</em> <code>Database</code>, <code>View</code>, <code>Session</code>, and <code>Authenticator</code>, and <code>Logger</code></li>
         | 
| 200 | 
            +
            	</ul>
         | 
| 201 | 
            +
               </div>
         | 
| 202 | 
            +
             | 
| 203 | 
            +
             | 
| 204 | 
            +
             | 
| 205 | 
            +
                 <h2>
         | 
| 206 | 
            +
                   <a name="s2"></a>
         | 
| 207 | 
            +
                   3.2. Conventional Architecture
         | 
| 208 | 
            +
                 </h2>
         | 
| 209 | 
            +
             | 
| 210 | 
            +
               
         | 
| 211 | 
            +
             | 
| 212 | 
            +
               <div class="section">
         | 
| 213 | 
            +
                 <p>A conventional architecture will have each component instantiate its own dependencies. For example, the <code>Application</code> would do something like this:</p>
         | 
| 214 | 
            +
             | 
| 215 | 
            +
            <pre>
         | 
| 216 | 
            +
              class Application
         | 
| 217 | 
            +
                def initialize
         | 
| 218 | 
            +
                  @logger = Logger.new
         | 
| 219 | 
            +
                  @authenticator = Authenticator.new
         | 
| 220 | 
            +
                  @database = Database.new
         | 
| 221 | 
            +
                  @view = View.new
         | 
| 222 | 
            +
                  @session = Session.new
         | 
| 223 | 
            +
                end
         | 
| 224 | 
            +
              end
         | 
| 225 | 
            +
            </pre>
         | 
| 226 | 
            +
             | 
| 227 | 
            +
            	<p>However, the above is already flawed, because the <code>Authenticator</code> and the <code>Session</code> both need access to the <code>Database</code>, so you really need to make sure you instantiate things in the right order and pass them as parameters to the constructor of each object that needs them, like so:</p>
         | 
| 228 | 
            +
             | 
| 229 | 
            +
            <pre>
         | 
| 230 | 
            +
              class Application
         | 
| 231 | 
            +
                def initialize
         | 
| 232 | 
            +
                  @view = View.new
         | 
| 233 | 
            +
                  @logger = Logger.new
         | 
| 234 | 
            +
                  @database = Database.new( @logger )
         | 
| 235 | 
            +
                  @authenticator = Authenticator.new( @logger, @database )
         | 
| 236 | 
            +
                  @session = Session.new( @logger, @database )
         | 
| 237 | 
            +
                end
         | 
| 238 | 
            +
              end
         | 
| 239 | 
            +
            </pre>
         | 
| 240 | 
            +
             | 
| 241 | 
            +
            	<p>The problem with this is that if you later decide that <code>View</code> needs to access the database, you need to rearrange the order of how things are instantiated in the <code>Application</code> constructor.<br />
         | 
| 242 | 
            +
            </p>
         | 
| 243 | 
            +
               </div>
         | 
| 244 | 
            +
             | 
| 245 | 
            +
             | 
| 246 | 
            +
             | 
| 247 | 
            +
                 <h2>
         | 
| 248 | 
            +
                   <a name="s3"></a>
         | 
| 249 | 
            +
                   3.3. Locator Pattern
         | 
| 250 | 
            +
                 </h2>
         | 
| 251 | 
            +
             | 
| 252 | 
            +
               
         | 
| 253 | 
            +
             | 
| 254 | 
            +
               <div class="section">
         | 
| 255 | 
            +
                 <p>The <em>service locator</em> pattern makes things a <em>little</em> easier. Instead of instantiating everything in the constructor of the <code>Application</code>, you can create a factory method somewhere that returns the new <code>Application</code> instance. Then, inside of this factory method, you assign each new object to collection, and pass that collection to each constructor.</p>
         | 
| 256 | 
            +
             | 
| 257 | 
            +
            <pre>
         | 
| 258 | 
            +
              require 'needle'
         | 
| 259 | 
            +
             | 
| 260 | 
            +
              def create_application
         | 
| 261 | 
            +
                locator = Needle::Registry.new
         | 
| 262 | 
            +
             | 
| 263 | 
            +
                locator.register( :view ) { View.new(locator) }
         | 
| 264 | 
            +
                locator.register( :logger ) { Logger.new(locator) }
         | 
| 265 | 
            +
                locator.register( :database ) { Database.new(locator) }
         | 
| 266 | 
            +
                locator.register( :authenticator ) {Authenticator.new(locator) }
         | 
| 267 | 
            +
                locator.register( :session ) { Session.new(locator) }
         | 
| 268 | 
            +
                locator.register( :app ) { Application.new(locator) }
         | 
| 269 | 
            +
             | 
| 270 | 
            +
                locator[:app]
         | 
| 271 | 
            +
              end
         | 
| 272 | 
            +
             | 
| 273 | 
            +
              class Application
         | 
| 274 | 
            +
                def initialize( locator )
         | 
| 275 | 
            +
                  @view = locator[:view]
         | 
| 276 | 
            +
                  @logger = locator[:logger]
         | 
| 277 | 
            +
                  @database = locator[:database]
         | 
| 278 | 
            +
                  @authenticator = locator[:authenticator]
         | 
| 279 | 
            +
                  @session = locator[:session]
         | 
| 280 | 
            +
                end
         | 
| 281 | 
            +
              end
         | 
| 282 | 
            +
             | 
| 283 | 
            +
              class Session
         | 
| 284 | 
            +
                def initialize( locator )
         | 
| 285 | 
            +
                  @database = locator[:database]
         | 
| 286 | 
            +
                  @logger = locator[:logger]
         | 
| 287 | 
            +
                end
         | 
| 288 | 
            +
              end
         | 
| 289 | 
            +
             | 
| 290 | 
            +
              ...
         | 
| 291 | 
            +
            </pre>
         | 
| 292 | 
            +
             | 
| 293 | 
            +
            	<p>This has the benefit of allowing each object to construct itself <em>� la carte</em> from the objects in the locator. Also, each object no longer cares what class implements each service—it only cares that each object implements the methods it will attempt to invoke on that object.</p>
         | 
| 294 | 
            +
             | 
| 295 | 
            +
            	<p>Also, because Needle defers the instantiation of each service until the service is actually requested, we can actually register each item with the locator in any arbitrary order. All that is happening is the block is associated with the symbol, so that when the service is requested, the corresponding block is invoked. What is more, by default each service is then cached, so that it is only instantiated once.</p>
         | 
| 296 | 
            +
             | 
| 297 | 
            +
            	<p>Thus, when we get the <code>:app</code> service (on the last line), the <code>Application</code> constructor is invoked, passing the locator to the constructor. Inside the constructor, <code>Application</code> retrieves each of its dependencies from the locator, causing each of them to be instantiated in turn. By this means, everything is initialized and constructed when the <code>create_application</code> method returns.</p>
         | 
| 298 | 
            +
             | 
| 299 | 
            +
            	<p>In the interest of brevity, the <code>create_application</code> could have been written like this, using a “builder” object (called <code>b</code> in the example below) to help register the services:</p>
         | 
| 300 | 
            +
             | 
| 301 | 
            +
            <pre>
         | 
| 302 | 
            +
              def create_application
         | 
| 303 | 
            +
                locator = Needle::Registry.define do |b|
         | 
| 304 | 
            +
                  b.view { View.new(locator) }
         | 
| 305 | 
            +
                  b.logger { Logger.new(locator) }
         | 
| 306 | 
            +
                  b.database { Database.new(locator) }
         | 
| 307 | 
            +
                  b.authenticator {Authenticator.new(locator) }
         | 
| 308 | 
            +
                  b.session { Session.new(locator) }
         | 
| 309 | 
            +
                  b.app { Application.new(locator) }
         | 
| 310 | 
            +
                end
         | 
| 311 | 
            +
             | 
| 312 | 
            +
                locator[:app]
         | 
| 313 | 
            +
              end
         | 
| 314 | 
            +
            </pre>
         | 
| 315 | 
            +
               </div>
         | 
| 147 316 |  | 
| 148 317 |  | 
| 149 318 |  |