needle-extras 1.0.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/LICENSE-BSD +27 -0
- data/doc/LICENSE-GPL +280 -0
- data/doc/LICENSE-RUBY +56 -0
- data/doc/README +50 -0
- data/doc/manual-html/chapter-1.html +214 -0
- data/doc/manual-html/chapter-2.html +180 -0
- data/doc/manual-html/chapter-3.html +168 -0
- data/doc/manual-html/chapter-4.html +184 -0
- data/doc/manual-html/index.html +155 -0
- data/doc/manual-html/manual.css +192 -0
- data/doc/manual/chapter.erb +18 -0
- data/doc/manual/index.erb +29 -0
- data/doc/manual/manual.css +192 -0
- data/doc/manual/manual.rb +202 -0
- data/doc/manual/manual.yml +45 -0
- data/doc/manual/page.erb +71 -0
- data/doc/manual/parts/attrinject_overview.txt +1 -0
- data/doc/manual/parts/attrinject_usage.txt +34 -0
- data/doc/manual/parts/intro_license.txt +5 -0
- data/doc/manual/parts/intro_support.txt +1 -0
- data/doc/manual/parts/intro_usage.txt +30 -0
- data/doc/manual/parts/intro_what_is_extras.txt +7 -0
- data/doc/manual/parts/multicast_overview.txt +1 -0
- data/doc/manual/parts/multicast_usage.txt +22 -0
- data/doc/manual/parts/requirelibrary_overview.txt +5 -0
- data/doc/manual/parts/requirelibrary_usage.txt +34 -0
- data/lib/needle/extras.rb +17 -0
- data/lib/needle/extras/attr-inject.rb +73 -0
- data/lib/needle/extras/multicast.rb +42 -0
- data/lib/needle/extras/require-library.rb +34 -0
- data/lib/needle/extras/version.rb +13 -0
- data/test/ALL-TESTS.rb +9 -0
- data/test/tc_attr-inject.rb +115 -0
- data/test/tc_multicast.rb +46 -0
- data/test/tc_require-library.rb +70 -0
- metadata +91 -0
@@ -0,0 +1,202 @@
|
|
1
|
+
# --------------------------------------------------------------------------
|
2
|
+
# Portions of this code were taken from the "poignant.rb" script created
|
3
|
+
# by whytheluckystiff, which generates "Why's (Poignant) Guide to Ruby".
|
4
|
+
# The original script may be obtained from the poignant CVS repository,
|
5
|
+
# at http://poignant.rubyforge.org.
|
6
|
+
#
|
7
|
+
# This script is distributed under the by-sa/1.0 Creative Commons license.
|
8
|
+
# --------------------------------------------------------------------------
|
9
|
+
|
10
|
+
require 'erb'
|
11
|
+
require 'fileutils'
|
12
|
+
require 'yaml'
|
13
|
+
require 'redcloth'
|
14
|
+
|
15
|
+
module Needle
|
16
|
+
module Manual
|
17
|
+
|
18
|
+
class Manual
|
19
|
+
attr_accessor :product, :meta, :chapters, :examples, :recent_updates
|
20
|
+
|
21
|
+
def Manual.load( file_name )
|
22
|
+
File.open( file_name ) { |file| YAML.load( file ) }
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
class Meta
|
27
|
+
attr_accessor :copyright, :author, :email
|
28
|
+
end
|
29
|
+
|
30
|
+
class Product
|
31
|
+
attr_accessor :name, :tagline, :version, :logo, :urls, :project
|
32
|
+
end
|
33
|
+
|
34
|
+
class Sidebar
|
35
|
+
attr_accessor :title, :content
|
36
|
+
end
|
37
|
+
|
38
|
+
class Chapter
|
39
|
+
attr_accessor :index, :title, :sections
|
40
|
+
|
41
|
+
def initialize( index, title, sections )
|
42
|
+
@index = index
|
43
|
+
@title = title
|
44
|
+
|
45
|
+
section_index = 0
|
46
|
+
@sections = ( sections || [] ).collect do |section|
|
47
|
+
section_index += 1
|
48
|
+
if section.respond_to? :keys
|
49
|
+
Section.new( section_index, section.keys.first, section.values.first )
|
50
|
+
else
|
51
|
+
section_index -= 1
|
52
|
+
Section.new( section_index, nil, section )
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def page_title
|
58
|
+
"Chapter #{index}: #{title}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
class Tutorial
|
63
|
+
attr_accessor :index, :title, :brief, :intro, :steps, :summary
|
64
|
+
|
65
|
+
def initialize( index, title, brief, intro, steps, summary )
|
66
|
+
@index = index
|
67
|
+
@title = title
|
68
|
+
@brief = RedCloth.new( brief )
|
69
|
+
@intro = RedCloth.new( intro ) if intro
|
70
|
+
@summary = RedCloth.new( summary ) if summary
|
71
|
+
@steps = steps.map { |step| RedCloth.new( step ) }
|
72
|
+
end
|
73
|
+
|
74
|
+
def page_title
|
75
|
+
"Tutorial #{index}: #{title}"
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
class Example
|
80
|
+
attr_accessor :index, :title, :brief, :intro, :design, :implementation, :summary
|
81
|
+
|
82
|
+
def initialize( index, title, brief, intro, design, implementation, summary )
|
83
|
+
@index = index
|
84
|
+
@title = title
|
85
|
+
@brief = RedCloth.new( brief )
|
86
|
+
@intro = RedCloth.new( intro )
|
87
|
+
@design = RedCloth.new( design )
|
88
|
+
@implementation = RedCloth.new( implementation )
|
89
|
+
@summary = RedCloth.new( summary )
|
90
|
+
end
|
91
|
+
|
92
|
+
def page_title
|
93
|
+
"Example #{index}: #{title}"
|
94
|
+
end
|
95
|
+
end
|
96
|
+
|
97
|
+
class Section
|
98
|
+
attr_accessor :index, :title, :content
|
99
|
+
|
100
|
+
def initialize( index, title, content )
|
101
|
+
@index = index
|
102
|
+
@title = RedCloth.new( title ).to_html.gsub( %r{</?p>}, "" ) if title
|
103
|
+
@content = RedCloth.new( content || "" )
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
YAML.add_private_type( 'file' ) { |type_id, value| File.read( value ) rescue "" }
|
108
|
+
YAML.add_private_type( 'eval' ) { |type_id, value| eval( value ) }
|
109
|
+
|
110
|
+
YAML.add_domain_type( 'jamisbuck.org,2004', 'manual' ) do |taguri, val|
|
111
|
+
index = 0
|
112
|
+
|
113
|
+
val['chapters'].collect! do |chapter|
|
114
|
+
index += 1
|
115
|
+
Chapter.new( index, chapter.keys.first, chapter.values.first )
|
116
|
+
end
|
117
|
+
|
118
|
+
YAML.object_maker( Manual, val )
|
119
|
+
end
|
120
|
+
|
121
|
+
YAML.add_domain_type( 'jamisbuck.org,2004', 'meta' ) do |taguri, val|
|
122
|
+
YAML.object_maker( Meta, val )
|
123
|
+
end
|
124
|
+
|
125
|
+
YAML.add_domain_type( 'jamisbuck.org,2004', 'product' ) do |taguri, val|
|
126
|
+
version = val["version"]
|
127
|
+
if version.respond_to?( :type_id )
|
128
|
+
if version.type_id == "version"
|
129
|
+
if version.value =~ %r{(.*)/(.*)}
|
130
|
+
require_file, constant = $1, $2
|
131
|
+
else
|
132
|
+
constant = version.value
|
133
|
+
end
|
134
|
+
|
135
|
+
require require_file if require_file
|
136
|
+
val["version"] = eval(constant)
|
137
|
+
else
|
138
|
+
raise "Unexpected type: #{val.type_id}"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
YAML.object_maker( Product, val )
|
142
|
+
end
|
143
|
+
|
144
|
+
YAML.add_domain_type( 'jamisbuck.org,2004', 'sidebar' ) do |taguri, val|
|
145
|
+
YAML.object_maker( Sidebar,
|
146
|
+
'title' => val.keys.first,
|
147
|
+
'content'=> RedCloth.new( val.values.first ) )
|
148
|
+
end
|
149
|
+
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
if __FILE__ == $0
|
154
|
+
|
155
|
+
def log_action( action )
|
156
|
+
$stderr.puts action
|
157
|
+
end
|
158
|
+
|
159
|
+
unless ( output_path = ARGV[0] )
|
160
|
+
$stderr.puts "Usage: #{$0} [/path/to/save/html]"
|
161
|
+
exit
|
162
|
+
end
|
163
|
+
|
164
|
+
Dir.mkdir output_path rescue nil
|
165
|
+
|
166
|
+
log_action "Loading manual.yml..."
|
167
|
+
manual = Needle::Manual::Manual.load( 'manual.yml' )
|
168
|
+
|
169
|
+
# force these to be defined at the TOPLEVEL_BINDING
|
170
|
+
object = nil
|
171
|
+
guts = nil
|
172
|
+
|
173
|
+
page = File.open( "page.erb" ) { |file| ERB.new( file.read ) }
|
174
|
+
page.filename = "page.erb"
|
175
|
+
|
176
|
+
template = File.open( "index.erb" ) { |file| ERB.new( file.read ) }
|
177
|
+
template.filename = "index.erb"
|
178
|
+
|
179
|
+
File.open( File.join( output_path, "index.html" ), "w" ) do |file|
|
180
|
+
guts = template.result
|
181
|
+
file << page.result
|
182
|
+
end
|
183
|
+
|
184
|
+
template = File.open( "chapter.erb" ) { |file| ERB.new( file.read ) }
|
185
|
+
template.filename = "chapter.erb"
|
186
|
+
|
187
|
+
manual.chapters.each do |object|
|
188
|
+
log_action "Processing chapter ##{object.index}..."
|
189
|
+
File.open( File.join( output_path, "chapter-#{object.index}.html" ), "w" ) do |file|
|
190
|
+
guts = template.result
|
191
|
+
file << page.result
|
192
|
+
end
|
193
|
+
end
|
194
|
+
|
195
|
+
log_action "Copying style sheets..."
|
196
|
+
FileUtils.cp Dir["*.css"], output_path
|
197
|
+
|
198
|
+
log_action "Copying images..."
|
199
|
+
FileUtils.cp Dir["img/*.jpg"], output_path
|
200
|
+
|
201
|
+
log_action "Done!"
|
202
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
--- !jamisbuck.org,2004/^manual
|
2
|
+
|
3
|
+
# This content is made available under the Attribution-ShareAlike 2.0
|
4
|
+
# license from the Create Commons:
|
5
|
+
#
|
6
|
+
# http://creativecommons.org/licenses/by-sa/2.0/
|
7
|
+
|
8
|
+
meta: !^meta
|
9
|
+
copyright: 2004
|
10
|
+
author: Jamis Buck
|
11
|
+
email: jgb3@email.byu.edu
|
12
|
+
|
13
|
+
product: !^product
|
14
|
+
name: Needle-Extras
|
15
|
+
tagline: for all your needle needs
|
16
|
+
version: !!eval require "../../lib/needle/extras/version"; Needle::Extras::Version::STRING
|
17
|
+
urls:
|
18
|
+
- Project Page: http://rubyforge.org/projects/needle
|
19
|
+
- User Manual: http://needle.rubyforge.org/extras
|
20
|
+
- API Documentation: http://needle.rubyforge.org/extras/api
|
21
|
+
- FAQ Document: http://needle.rubyforge.org/extras/faq.html
|
22
|
+
- Needle Wiki: http://needle.rubyforge.org/wiki/wiki.pl
|
23
|
+
|
24
|
+
recent_updates:
|
25
|
+
- First Draft
|
26
|
+
|
27
|
+
chapters:
|
28
|
+
|
29
|
+
- Introduction:
|
30
|
+
- What is Needle-Extras?: !!file parts/intro_what_is_extras.txt
|
31
|
+
- How Do I Use It?: !!file parts/intro_usage.txt
|
32
|
+
- License Information: !!file parts/intro_license.txt
|
33
|
+
- Support: !!file parts/intro_support.txt
|
34
|
+
|
35
|
+
- AttrInject:
|
36
|
+
- Overview: !!file parts/attrinject_overview.txt
|
37
|
+
- Usage: !!file parts/attrinject_usage.txt
|
38
|
+
|
39
|
+
- Multicast:
|
40
|
+
- Overview: !!file parts/multicast_overview.txt
|
41
|
+
- Usage: !!file parts/multicast_usage.txt
|
42
|
+
|
43
|
+
- RequireLibrary:
|
44
|
+
- Overview: !!file parts/requirelibrary_overview.txt
|
45
|
+
- Usage: !!file parts/requirelibrary_usage.txt
|
data/doc/manual/page.erb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
<html>
|
2
|
+
<head>
|
3
|
+
<title><%= manual.product.name %> Manual<% if object %> :: <%= object.page_title %><% end %></title>
|
4
|
+
<link type="text/css" rel="stylesheet" href="manual.css" />
|
5
|
+
</head>
|
6
|
+
|
7
|
+
<body>
|
8
|
+
<div id="banner">
|
9
|
+
<table border='0' cellpadding='0' cellspacing='0' width='100%'>
|
10
|
+
<tr><td valign='top' align='left'>
|
11
|
+
<div class="title">
|
12
|
+
<span class="product"><%= manual.product.name %>—</span><br />
|
13
|
+
<span class="tagline"><%= manual.product.tagline %></span>
|
14
|
+
</div>
|
15
|
+
</td><td valign='middle' align='right'>
|
16
|
+
<div class="info">
|
17
|
+
<%= manual.product.name %> Version: <strong><%= manual.product.version %></strong><br />
|
18
|
+
Manual Last Updated: <strong><%= Time.now.gmtime.strftime('%Y-%m-%d %H:%M %Z') %></strong>
|
19
|
+
</div>
|
20
|
+
</td></tr>
|
21
|
+
</table>
|
22
|
+
</div>
|
23
|
+
|
24
|
+
<table border='0' width='100%' cellpadding='0' cellspacing='0'>
|
25
|
+
<tr><td valign='top'>
|
26
|
+
|
27
|
+
<div id="navigation">
|
28
|
+
<h1><%= manual.product.name %> Manual</h1>
|
29
|
+
|
30
|
+
<h2>Chapters</h2>
|
31
|
+
<ol type="I">
|
32
|
+
<% manual.chapters.each do |c| %>
|
33
|
+
<li><%= "<strong>" if c == object %>
|
34
|
+
<a href="chapter-<%= c.index %>.html">
|
35
|
+
<%= c.title %>
|
36
|
+
</a>
|
37
|
+
<%= "</strong> <big>←</big>" if c == object %>
|
38
|
+
<ol type="1">
|
39
|
+
<% c.sections.each do |s|
|
40
|
+
next unless s.title %>
|
41
|
+
<li><a href="chapter-<%= c.index %>.html#s<%= s.index %>"><%= s.title %></a></li>
|
42
|
+
<% end %>
|
43
|
+
</ol>
|
44
|
+
</li>
|
45
|
+
<% end %>
|
46
|
+
</ol>
|
47
|
+
|
48
|
+
<h2>Other Documentation</h2>
|
49
|
+
|
50
|
+
<ul>
|
51
|
+
<li><a href="http://needle.rubyforge.org/extras/api/index.html">Needle-Extras API</a></li>
|
52
|
+
</ul>
|
53
|
+
|
54
|
+
<div class="license">
|
55
|
+
<a href="http://creativecommons.org/licenses/by-sa/2.0/"><img alt="Creative Commons License" border="0" src="http://creativecommons.org/images/public/somerights" /></a><br />
|
56
|
+
This manual is licensed under a <a href="http://creativecommons.org/licenses/by-sa/2.0/">Creative Commons License</a>.
|
57
|
+
</div>
|
58
|
+
</div>
|
59
|
+
|
60
|
+
</td><td valign='top' width="100%">
|
61
|
+
|
62
|
+
<div id="content">
|
63
|
+
|
64
|
+
<%= guts %>
|
65
|
+
|
66
|
+
</div>
|
67
|
+
|
68
|
+
</td></tr>
|
69
|
+
</table>
|
70
|
+
</body>
|
71
|
+
</html>
|
@@ -0,0 +1 @@
|
|
1
|
+
AttrInject is an implementation of dependency injection that uses declared interfaces to determine dependencies. It is based on an implementation by Christian Neukirchen at "http://rafb.net/paste/results/sexpfu84.html":http://rafb.net/paste/results/sexpfu84.html.
|
@@ -0,0 +1,34 @@
|
|
1
|
+
AttrInject is very straightforward to use. Just require the AttrInject library in every service implementation and use the new @attr_inject@ macro to specify which other services the class depends on:
|
2
|
+
|
3
|
+
<pre>
|
4
|
+
require 'needle/extras/attr-inject'
|
5
|
+
|
6
|
+
class Foo
|
7
|
+
attr_inject :bar
|
8
|
+
attr_inject :baz, :blah
|
9
|
+
|
10
|
+
def frobnicate
|
11
|
+
@bar + @baz / @blah
|
12
|
+
end
|
13
|
+
end
|
14
|
+
</pre>
|
15
|
+
|
16
|
+
The @attr_inject@ macro does not create any accessors--it only declares the dependencies that the corresponding service has. Then, when you register the service, you specify one of the @inject@ service models:
|
17
|
+
|
18
|
+
<pre>
|
19
|
+
require 'needle'
|
20
|
+
require 'needle/extras'
|
21
|
+
...
|
22
|
+
reg.require_library 'needle/extras'
|
23
|
+
reg.define do |b|
|
24
|
+
b.bar { 5 }
|
25
|
+
b.baz { 10 }
|
26
|
+
b.blah { Math::PI }
|
27
|
+
|
28
|
+
b.foo( :model => :singleton_inject ) { Foo.new }
|
29
|
+
end
|
30
|
+
</pre>
|
31
|
+
|
32
|
+
The @singleton_inject@ service model is just like @singleton@, but it will also automatically inject all of the declared dependencies into the new service. Thus, invoking @#frobnicate@ on the @foo@ service would compute and return (in this case) @5 + 10 / PI@.
|
33
|
+
|
34
|
+
This approach has the benefit of reducing the amount of initialization code you have to write. On the other hand, it more tightly couples your implementation code to Needle itself.
|
@@ -0,0 +1,5 @@
|
|
1
|
+
Needle-Extras is made available under either the BSD license, or the same license Ruby (which, by extension, also allows the GPL as a permissable license as well). You can view the full text of any of these licenses in the @doc@ subdirectory of the Needle distrubtion. The texts of the BSD and GPL licenses are also available online: "BSD":http://www.opensource.org/licenses/bsd-license.php and "GPL":http://www.opensource.org/licenses/gpl-license.php.
|
2
|
+
|
3
|
+
This manual (in any form, be it source or otherwise) and the scripts and templates used to generate it, are all distributed under the "Creative Commons":http://creativecommons.org "Attribution-ShareAlike":http://creativecommons.org/licenses/by-sa/2.0 license.
|
4
|
+
|
5
|
+
If you desire permission to use either Needle-Extras or the manual in a manner incompatible with these licenses, please contact the copyright holder ("Jamis Buck":mailto:jgb3@email.byu.edu) in order to negotiate a more compatible license.
|
@@ -0,0 +1 @@
|
|
1
|
+
Mailing lists, bug trackers, feature requests, and public forums are available (courtesy of "RubyForge":http://rubyforge.org) at Needle's RubyForge project page. Just direct your browser to "http://rubyforge.org/projects/needle":http://rubyforge.org/projects/needle.
|
@@ -0,0 +1,30 @@
|
|
1
|
+
You can make all of the services in Needle-Extras available to your applications in either of two ways.
|
2
|
+
|
3
|
+
The first way uses the standard @Collection#require@ method to load a service library and include it in a container:
|
4
|
+
|
5
|
+
<pre>
|
6
|
+
require 'needle'
|
7
|
+
|
8
|
+
reg = Needle::Registry.new
|
9
|
+
reg.require 'needle/extras', 'Needle::Extras'
|
10
|
+
...
|
11
|
+
</pre>
|
12
|
+
|
13
|
+
The second way uses the RequireLibrary framework provided by Needle-Extras itself:
|
14
|
+
|
15
|
+
<pre>
|
16
|
+
require 'needle'
|
17
|
+
require 'needle/extras'
|
18
|
+
|
19
|
+
reg = Needle::Registry.new
|
20
|
+
reg.require_library 'needle/extras'
|
21
|
+
</pre>
|
22
|
+
|
23
|
+
If you don't want to use _all_ of the services available in Needle-Extras, you can include just the ones you want by requiring them directly:
|
24
|
+
|
25
|
+
<pre>
|
26
|
+
require 'needle'
|
27
|
+
|
28
|
+
reg = Needle::Registry.new
|
29
|
+
reg.require 'needle/extras/multicast', 'Needle::Extras::Multicast'
|
30
|
+
</pre>
|
@@ -0,0 +1,7 @@
|
|
1
|
+
Needle-Extras is a collection of additional services and utilities that can be used in conjuction with Needle. It is a kind of test-bed for services that may eventually find their way into Needle itself.
|
2
|
+
|
3
|
+
Currently, Needle-Extras includes the following services and utilities:
|
4
|
+
|
5
|
+
* AttrInject: this is an implementation of simple interface-based dependency injection, inspired by a proof-of-concept by Christian Neukirchen ("http://rafb.net/paste/results/sexpfu84.html":http://rafb.net/paste/results/sexpfu84.html).
|
6
|
+
* Multicast: this is a demonstration of how to do multicast services--services that delegate the messages they receive to a collection of other services.
|
7
|
+
* RequireLibrary: this is not actually a service, so much as a mini-framework for simplifying the process of including a third-party service in your application.
|
@@ -0,0 +1 @@
|
|
1
|
+
The multicast service allows you to easily broadcast messages to a specified set of objects. It is, in essence, a kind of observer pattern, with t he observers being given to the multicaster when it is created. Events are then sent to the observers by invoking methods on the multicaster.
|
@@ -0,0 +1,22 @@
|
|
1
|
+
The multicast service is parameterized. Just send it a list of objects (i.e., other services) that you want multicasted to, and it will return a new multicaster object.
|
2
|
+
|
3
|
+
<pre>
|
4
|
+
reg = Needle::Registry.define do |b|
|
5
|
+
b.require 'needle/extras/multicast', 'Needle::Extras::Multicast'
|
6
|
+
|
7
|
+
b.foo { "hello" }
|
8
|
+
b.bar { [ 1, 2, 3 ] }
|
9
|
+
b.baz { "test" }
|
10
|
+
|
11
|
+
b.multicaster { |c,| c.multicast c.foo, c.bar, c.baz }
|
12
|
+
end
|
13
|
+
</pre>
|
14
|
+
|
15
|
+
Once you've registered your service, you can send messages to the observing services by sending messages to the multicaster:
|
16
|
+
|
17
|
+
<pre>
|
18
|
+
m = reg.multicaster
|
19
|
+
p m.length #-> [ 5, 3, 4 ]
|
20
|
+
</pre>
|
21
|
+
|
22
|
+
The multicaster will return an array of the return values of all of the observing services. Thus, in the above example, an array of the lengths of each of the @foo@, @bar@, and @baz@ services is returned.
|
@@ -0,0 +1,5 @@
|
|
1
|
+
RequireLibrary is not a service--it is a mini-framework for registering service libraries with Needle so that they can be imported into other projects with a minimum of headache.
|
2
|
+
|
3
|
+
Currently, Needle supports @Container#require@ as the library import mechanism. This requires you to specify both the file containing the service registration method, as well as the Module that contains the method.
|
4
|
+
|
5
|
+
RequireLibrary takes some of the duplication out of the process by allowing application developers to register a callback hook with Needle, which will be invoked when the new @Container#require_library@ method is invoked.
|
@@ -0,0 +1,34 @@
|
|
1
|
+
For developers of service libraries, RequireLibrary provides a hook for registering their libraries with Needle:
|
2
|
+
|
3
|
+
<pre>
|
4
|
+
module Foo
|
5
|
+
module Bar
|
6
|
+
|
7
|
+
def register_services( container )
|
8
|
+
...
|
9
|
+
end
|
10
|
+
module_function :register_services
|
11
|
+
|
12
|
+
if defined?(Needle.register_library)
|
13
|
+
Needle.register_library( 'foo/bar', self )
|
14
|
+
end
|
15
|
+
|
16
|
+
end
|
17
|
+
end
|
18
|
+
</pre>
|
19
|
+
|
20
|
+
The @#register_services@ method is Needle's standard callback for registering a library's services with the given container.
|
21
|
+
|
22
|
+
The next lines, though, check to see if @Needle.register_library@ is defined. This allows the library to be used even when Needle-Extras is not loaded, or even installed. If the method exists, it is invoked with the @require@ path of the file, and the module reference that contains the @#register_services@ method.
|
23
|
+
|
24
|
+
Then, consumers of the library can load it using RequireLibrary as follows:
|
25
|
+
|
26
|
+
<pre>
|
27
|
+
require 'needle'
|
28
|
+
|
29
|
+
reg = Needle::Registry.new
|
30
|
+
reg.require_library 'foo/bar'
|
31
|
+
...
|
32
|
+
</pre>
|
33
|
+
|
34
|
+
The call to @Container#require_library@ invokes @Kernel#require@, and then looks to see if there is a hook registered for the @'foo/bar'@ path. If there is, the hook is invoked, which (by default) invokes the @#register_services@ method, passing the current container as the parameter.
|