arrow 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (198) hide show
  1. data/ChangeLog +1590 -0
  2. data/LICENSE +28 -0
  3. data/README +75 -0
  4. data/Rakefile +366 -0
  5. data/Rakefile.local +63 -0
  6. data/data/arrow/applets/TEMPLATE.rb.tpl +53 -0
  7. data/data/arrow/applets/args.rb +50 -0
  8. data/data/arrow/applets/config.rb +55 -0
  9. data/data/arrow/applets/error.rb +63 -0
  10. data/data/arrow/applets/files.rb +46 -0
  11. data/data/arrow/applets/inspect.rb +46 -0
  12. data/data/arrow/applets/nosuchapplet.rb +31 -0
  13. data/data/arrow/applets/status.rb +92 -0
  14. data/data/arrow/applets/test.rb +133 -0
  15. data/data/arrow/applets/tutorial/counter.rb +96 -0
  16. data/data/arrow/applets/tutorial/dingus.rb +67 -0
  17. data/data/arrow/applets/tutorial/hello.rb +34 -0
  18. data/data/arrow/applets/tutorial/hello2.rb +73 -0
  19. data/data/arrow/applets/tutorial/imgtext.rb +90 -0
  20. data/data/arrow/applets/tutorial/imgtext2.rb +286 -0
  21. data/data/arrow/applets/tutorial/index.rb +36 -0
  22. data/data/arrow/applets/tutorial/logo.rb +98 -0
  23. data/data/arrow/applets/tutorial/memcache.rb +61 -0
  24. data/data/arrow/applets/tutorial/missing.rb +37 -0
  25. data/data/arrow/applets/tutorial/protected.rb +100 -0
  26. data/data/arrow/applets/tutorial/redirector.rb +52 -0
  27. data/data/arrow/applets/tutorial/rndimages.rb +159 -0
  28. data/data/arrow/applets/tutorial/sharenotes.rb +83 -0
  29. data/data/arrow/applets/tutorial/subclassed-hello.rb +32 -0
  30. data/data/arrow/applets/tutorial/superhello.rb +72 -0
  31. data/data/arrow/applets/tutorial/timeclock.rb +78 -0
  32. data/data/arrow/applets/view-applet.rb +123 -0
  33. data/data/arrow/applets/view-template.rb +85 -0
  34. data/data/arrow/applets/wiki.rb +274 -0
  35. data/data/arrow/templates/TEMPLATE.tmpl.tpl +36 -0
  36. data/data/arrow/templates/applet-status.tmpl +153 -0
  37. data/data/arrow/templates/args-display.tmpl +120 -0
  38. data/data/arrow/templates/config/display-table.tmpl +36 -0
  39. data/data/arrow/templates/config/display.tmpl +36 -0
  40. data/data/arrow/templates/counter-deleted.tmpl +33 -0
  41. data/data/arrow/templates/counter.tmpl +59 -0
  42. data/data/arrow/templates/dingus.tmpl +55 -0
  43. data/data/arrow/templates/enumtable.tmpl +8 -0
  44. data/data/arrow/templates/error-display.tmpl +92 -0
  45. data/data/arrow/templates/filemap.tmpl +89 -0
  46. data/data/arrow/templates/hello-world-src.tmpl +34 -0
  47. data/data/arrow/templates/hello-world.tmpl +60 -0
  48. data/data/arrow/templates/imgtext/fontlist.tmpl +46 -0
  49. data/data/arrow/templates/imgtext/form.tmpl +70 -0
  50. data/data/arrow/templates/imgtext/reload-error.tmpl +40 -0
  51. data/data/arrow/templates/imgtext/reload.tmpl +55 -0
  52. data/data/arrow/templates/inspect/display.tmpl +80 -0
  53. data/data/arrow/templates/loginform.tmpl +64 -0
  54. data/data/arrow/templates/logout.tmpl +32 -0
  55. data/data/arrow/templates/memcache/display.tmpl +41 -0
  56. data/data/arrow/templates/navbar.incl +27 -0
  57. data/data/arrow/templates/nosuchapplet.tmpl +32 -0
  58. data/data/arrow/templates/printsource.tmpl +35 -0
  59. data/data/arrow/templates/protected.tmpl +36 -0
  60. data/data/arrow/templates/rndimages.tmpl +38 -0
  61. data/data/arrow/templates/service-response.tmpl +13 -0
  62. data/data/arrow/templates/sharenotes/display.tmpl +38 -0
  63. data/data/arrow/templates/status.tmpl +120 -0
  64. data/data/arrow/templates/templateviewer.tmpl +43 -0
  65. data/data/arrow/templates/test/harness.tmpl +57 -0
  66. data/data/arrow/templates/test/list.tmpl +48 -0
  67. data/data/arrow/templates/test/problem.tmpl +42 -0
  68. data/data/arrow/templates/tutorial/index.tmpl +37 -0
  69. data/data/arrow/templates/tutorial/missingapplet.tmpl +29 -0
  70. data/data/arrow/templates/view-applet-nosuch.tmpl +32 -0
  71. data/data/arrow/templates/view-applet.tmpl +40 -0
  72. data/data/arrow/templates/view-template.tmpl +83 -0
  73. data/data/arrow/templates/wiki/formerror.tmpl +47 -0
  74. data/data/arrow/templates/wiki/markup_help.incl +6 -0
  75. data/data/arrow/templates/wiki/new.tmpl +56 -0
  76. data/data/arrow/templates/wiki/new_system.tmpl +122 -0
  77. data/data/arrow/templates/wiki/sectionlist.tmpl +43 -0
  78. data/data/arrow/templates/wiki/show.tmpl +34 -0
  79. data/docs/manual/layouts/default.page +43 -0
  80. data/docs/manual/lib/api-filter.rb +81 -0
  81. data/docs/manual/lib/editorial-filter.rb +64 -0
  82. data/docs/manual/lib/examples-filter.rb +244 -0
  83. data/docs/manual/lib/links-filter.rb +117 -0
  84. data/lib/apache/fakerequest.rb +448 -0
  85. data/lib/apache/logger.rb +33 -0
  86. data/lib/arrow.rb +51 -0
  87. data/lib/arrow/acceptparam.rb +207 -0
  88. data/lib/arrow/applet.rb +725 -0
  89. data/lib/arrow/appletmixins.rb +218 -0
  90. data/lib/arrow/appletregistry.rb +590 -0
  91. data/lib/arrow/applettestcase.rb +503 -0
  92. data/lib/arrow/broker.rb +255 -0
  93. data/lib/arrow/cache.rb +176 -0
  94. data/lib/arrow/config-loaders/yaml.rb +75 -0
  95. data/lib/arrow/config.rb +615 -0
  96. data/lib/arrow/constants.rb +24 -0
  97. data/lib/arrow/cookie.rb +359 -0
  98. data/lib/arrow/cookieset.rb +108 -0
  99. data/lib/arrow/dispatcher.rb +368 -0
  100. data/lib/arrow/dispatcherloader.rb +50 -0
  101. data/lib/arrow/exceptions.rb +61 -0
  102. data/lib/arrow/fallbackhandler.rb +48 -0
  103. data/lib/arrow/formvalidator.rb +631 -0
  104. data/lib/arrow/htmltokenizer.rb +343 -0
  105. data/lib/arrow/logger.rb +488 -0
  106. data/lib/arrow/logger/apacheoutputter.rb +69 -0
  107. data/lib/arrow/logger/arrayoutputter.rb +63 -0
  108. data/lib/arrow/logger/coloroutputter.rb +111 -0
  109. data/lib/arrow/logger/fileoutputter.rb +96 -0
  110. data/lib/arrow/logger/htmloutputter.rb +54 -0
  111. data/lib/arrow/logger/outputter.rb +123 -0
  112. data/lib/arrow/mixins.rb +425 -0
  113. data/lib/arrow/monkeypatches.rb +94 -0
  114. data/lib/arrow/object.rb +117 -0
  115. data/lib/arrow/path.rb +196 -0
  116. data/lib/arrow/service.rb +447 -0
  117. data/lib/arrow/session.rb +289 -0
  118. data/lib/arrow/session/dbstore.rb +100 -0
  119. data/lib/arrow/session/filelock.rb +160 -0
  120. data/lib/arrow/session/filestore.rb +132 -0
  121. data/lib/arrow/session/id.rb +98 -0
  122. data/lib/arrow/session/lock.rb +253 -0
  123. data/lib/arrow/session/md5id.rb +42 -0
  124. data/lib/arrow/session/nulllock.rb +42 -0
  125. data/lib/arrow/session/posixlock.rb +166 -0
  126. data/lib/arrow/session/sha1id.rb +54 -0
  127. data/lib/arrow/session/store.rb +366 -0
  128. data/lib/arrow/session/usertrackid.rb +52 -0
  129. data/lib/arrow/spechelpers.rb +73 -0
  130. data/lib/arrow/template.rb +713 -0
  131. data/lib/arrow/template/attr.rb +31 -0
  132. data/lib/arrow/template/call.rb +31 -0
  133. data/lib/arrow/template/comment.rb +33 -0
  134. data/lib/arrow/template/container.rb +118 -0
  135. data/lib/arrow/template/else.rb +41 -0
  136. data/lib/arrow/template/elsif.rb +44 -0
  137. data/lib/arrow/template/escape.rb +53 -0
  138. data/lib/arrow/template/export.rb +87 -0
  139. data/lib/arrow/template/for.rb +145 -0
  140. data/lib/arrow/template/if.rb +78 -0
  141. data/lib/arrow/template/import.rb +119 -0
  142. data/lib/arrow/template/include.rb +206 -0
  143. data/lib/arrow/template/iterator.rb +208 -0
  144. data/lib/arrow/template/nodes.rb +734 -0
  145. data/lib/arrow/template/parser.rb +571 -0
  146. data/lib/arrow/template/prettyprint.rb +53 -0
  147. data/lib/arrow/template/render.rb +191 -0
  148. data/lib/arrow/template/selectlist.rb +94 -0
  149. data/lib/arrow/template/set.rb +87 -0
  150. data/lib/arrow/template/timedelta.rb +81 -0
  151. data/lib/arrow/template/unless.rb +78 -0
  152. data/lib/arrow/template/urlencode.rb +51 -0
  153. data/lib/arrow/template/yield.rb +139 -0
  154. data/lib/arrow/templatefactory.rb +125 -0
  155. data/lib/arrow/testcase.rb +567 -0
  156. data/lib/arrow/transaction.rb +608 -0
  157. data/rake/191_compat.rb +26 -0
  158. data/rake/dependencies.rb +76 -0
  159. data/rake/documentation.rb +114 -0
  160. data/rake/helpers.rb +502 -0
  161. data/rake/hg.rb +282 -0
  162. data/rake/manual.rb +787 -0
  163. data/rake/packaging.rb +129 -0
  164. data/rake/publishing.rb +278 -0
  165. data/rake/style.rb +62 -0
  166. data/rake/svn.rb +668 -0
  167. data/rake/testing.rb +187 -0
  168. data/rake/verifytask.rb +64 -0
  169. data/spec/arrow/acceptparam_spec.rb +157 -0
  170. data/spec/arrow/applet_spec.rb +575 -0
  171. data/spec/arrow/appletmixins_spec.rb +409 -0
  172. data/spec/arrow/appletregistry_spec.rb +294 -0
  173. data/spec/arrow/broker_spec.rb +153 -0
  174. data/spec/arrow/config_spec.rb +224 -0
  175. data/spec/arrow/cookieset_spec.rb +164 -0
  176. data/spec/arrow/dispatcher_spec.rb +137 -0
  177. data/spec/arrow/dispatcherloader_spec.rb +65 -0
  178. data/spec/arrow/formvalidator_spec.rb +781 -0
  179. data/spec/arrow/logger_spec.rb +346 -0
  180. data/spec/arrow/mixins_spec.rb +120 -0
  181. data/spec/arrow/service_spec.rb +645 -0
  182. data/spec/arrow/session_spec.rb +121 -0
  183. data/spec/arrow/template/iterator_spec.rb +222 -0
  184. data/spec/arrow/templatefactory_spec.rb +185 -0
  185. data/spec/arrow/transaction_spec.rb +319 -0
  186. data/spec/arrow_spec.rb +37 -0
  187. data/spec/lib/appletmatchers.rb +281 -0
  188. data/spec/lib/constants.rb +77 -0
  189. data/spec/lib/helpers.rb +41 -0
  190. data/spec/lib/matchers.rb +44 -0
  191. data/tests/cookie.tests.rb +310 -0
  192. data/tests/path.tests.rb +157 -0
  193. data/tests/session.tests.rb +111 -0
  194. data/tests/session_id.tests.rb +82 -0
  195. data/tests/session_lock.tests.rb +191 -0
  196. data/tests/session_store.tests.rb +53 -0
  197. data/tests/template.tests.rb +1360 -0
  198. metadata +339 -0
@@ -0,0 +1,425 @@
1
+ #!/usr/bin/env ruby
2
+ module Arrow
3
+
4
+ require 'arrow/exceptions'
5
+
6
+ ### A collection of utilities for working with Hashes.
7
+ module HashUtilities
8
+
9
+ # Recursive hash-merge function
10
+ HashMergeFunction = Proc.new {|key, oldval, newval|
11
+ #debugMsg "Merging '%s': %s -> %s" %
12
+ # [ key.inspect, oldval.inspect, newval.inspect ]
13
+ case oldval
14
+ when Hash
15
+ case newval
16
+ when Hash
17
+ #debugMsg "Hash/Hash merge"
18
+ oldval.merge( newval, &HashMergeFunction )
19
+ else
20
+ newval
21
+ end
22
+
23
+ when Array
24
+ case newval
25
+ when Array
26
+ #debugMsg "Array/Array union"
27
+ oldval | newval
28
+ else
29
+ newval
30
+ end
31
+
32
+ when Arrow::Path
33
+ if newval.is_a?( Arrow::Path )
34
+ newval
35
+ else
36
+ Arrow::Path.new( newval )
37
+ end
38
+
39
+ else
40
+ newval
41
+ end
42
+ }
43
+
44
+ ###############
45
+ module_function
46
+ ###############
47
+
48
+ ### Return a version of the given +hash+ with its keys transformed
49
+ ### into Strings from whatever they were before.
50
+ def stringify_keys( hash )
51
+ newhash = {}
52
+
53
+ hash.each do |key,val|
54
+ if val.is_a?( Hash )
55
+ newhash[ key.to_s ] = stringify_keys( val )
56
+ else
57
+ newhash[ key.to_s ] = val
58
+ end
59
+ end
60
+
61
+ return newhash
62
+ end
63
+
64
+
65
+ ### Return a duplicate of the given +hash+ with its identifier-like keys
66
+ ### transformed into symbols from whatever they were before.
67
+ def symbolify_keys( hash )
68
+ newhash = {}
69
+
70
+ hash.each do |key,val|
71
+ keysym = key.to_s.dup.untaint.to_sym
72
+
73
+ if val.is_a?( Hash )
74
+ newhash[ keysym ] = symbolify_keys( val )
75
+ else
76
+ newhash[ keysym ] = val
77
+ end
78
+ end
79
+
80
+ return newhash
81
+ end
82
+ alias_method :internify_keys, :symbolify_keys
83
+
84
+ end
85
+
86
+
87
+ ### A collection of utilities for working with Arrays.
88
+ module ArrayUtilities
89
+
90
+ ###############
91
+ module_function
92
+ ###############
93
+
94
+ ### Return a version of the given +array+ with any Symbols contained in it turned into
95
+ ### Strings.
96
+ def stringify_array( array )
97
+ return array.collect do |item|
98
+ case item
99
+ when Symbol
100
+ item.to_s
101
+ when Array
102
+ stringify_array( item )
103
+ else
104
+ item
105
+ end
106
+ end
107
+ end
108
+
109
+
110
+ ### Return a version of the given +array+ with any Strings contained in it turned into
111
+ ### Symbols.
112
+ def symbolify_array( array )
113
+ return array.collect do |item|
114
+ case item
115
+ when String
116
+ item.to_sym
117
+ when Array
118
+ symbolify_array( item )
119
+ else
120
+ item
121
+ end
122
+ end
123
+ end
124
+
125
+ end
126
+
127
+
128
+ ### A collection of HTML utility functions
129
+ module HTMLUtilities
130
+
131
+ ###############
132
+ module_function
133
+ ###############
134
+
135
+ # The name of the Thread-local variable to keep the serialized-object
136
+ # cache in (i.e., Thread[ THREAD_DUMP_KEY ] = {}). The cache is keyed by
137
+ # object_id
138
+ THREAD_DUMP_KEY = :__to_html_cache__
139
+
140
+ # The HTML fragment to wrap around Hash objects
141
+ HASH_HTML_CONTAINER = %{<div class="hash-members">%s</div>}
142
+
143
+ # The HTML fragment to use for pairs of a Hash
144
+ HASH_PAIR_HTML = %{<div class="hash-pair %s">\n} +
145
+ %{<div class="key">%s</div>\n} +
146
+ %{<div class="value">%s</div>\n} +
147
+ %{</div>\n}
148
+
149
+ # The HTML fragment to wrap around Array objects
150
+ ARRAY_HTML_CONTAINER = %{<ol class="array-members"><li>%s</li></ol>}
151
+
152
+ # The HTML fragment to wrap around immediate objects
153
+ IMMEDIATE_OBJECT_HTML_CONTAINER = %{<div class="immediate-object">%s</div>}
154
+
155
+ # The HTML fragment to wrap around objects other than Arrays and Hashes.
156
+ OBJECT_HTML_CONTAINER = %{<div id="object-%d" class="object %s">%s</div>}
157
+
158
+ # The HTML fragment to use for instance variables inside of object DIVs.
159
+ IVAR_HTML_FRAGMENT = %Q{
160
+ <div class="%s">
161
+ <div class="name">%s</div>
162
+ <div class="value">%s</div>
163
+ </div>
164
+ }
165
+
166
+ ### Escape special characters in the given +string+ for display in an
167
+ ### HTML inspection interface. This escapes common invisible characters
168
+ ### like tabs and carriage-returns in additional to the regular HTML
169
+ ### escapes.
170
+ def escape_html( string )
171
+ return "nil" if string.nil?
172
+ string = string.inspect unless string.is_a?( String )
173
+ string.
174
+ gsub(/&/, '&amp;').
175
+ gsub(/</, '&lt;').
176
+ gsub(/>/, '&gt;').
177
+ gsub(/\n/, '&#8629;').
178
+ gsub(/\t/, '&#8594;')
179
+ end
180
+
181
+
182
+ ### Return an HTML fragment describing the specified +object+.
183
+ def make_html_for_object( object )
184
+ return object.html_inspect if
185
+ object.respond_to?( :html_inspect ) && ! object.is_a?( HtmlInspectableObject )
186
+ object_html = []
187
+
188
+ case object
189
+ when Hash
190
+ object_html << "\n<!-- Hash -->\n"
191
+ if object.empty?
192
+ object_html << '{}'
193
+ else
194
+ object_html << HASH_HTML_CONTAINER % [
195
+ object.collect {|k,v|
196
+ pairclass = v.instance_variables.empty? ?
197
+ "simple-hash-pair" :
198
+ "complex-hash-pair"
199
+ HASH_PAIR_HTML % [
200
+ pairclass,
201
+ make_html_for_object(k),
202
+ make_html_for_object(v),
203
+ ]
204
+ }
205
+ ]
206
+ end
207
+
208
+ when Array
209
+ object_html << "\n<!-- Array -->\n"
210
+ if object.empty?
211
+ object_html << '[]'
212
+ else
213
+ object_html << ARRAY_HTML_CONTAINER % [
214
+ object.collect {|o| make_html_for_object(o) }.join('</li><li>')
215
+ ]
216
+ end
217
+
218
+ else
219
+ if object.instance_variables.empty?
220
+ return IMMEDIATE_OBJECT_HTML_CONTAINER %
221
+ [ HTMLUtilities.escape_html(object.inspect) ]
222
+ else
223
+ object_html << make_object_html_wrapper( object )
224
+ end
225
+ end
226
+
227
+ return object_html.join("\n")
228
+ end
229
+
230
+
231
+ ### Wrap up the various parts of a complex object in an HTML fragment. If the
232
+ ### object has already been wrapped, returns a link to the previous rendering
233
+ ### instead.
234
+ def make_object_html_wrapper( object )
235
+
236
+ # If the object has been rendered already, just return a link to the previous
237
+ # HTML fragment
238
+ Thread.current[ THREAD_DUMP_KEY ] ||= {}
239
+ if Thread.current[ THREAD_DUMP_KEY ].key?( object.object_id )
240
+ return %Q{<a href="#object-%d" class="cache-link" title="jump to previous details">%s</a>} % [
241
+ object.object_id,
242
+ %{&rarr; %s #%d} % [ object.class.name, object.object_id ]
243
+ ]
244
+ else
245
+ Thread.current[ THREAD_DUMP_KEY ][ object.object_id ] = true
246
+ end
247
+
248
+ # Assemble the innards as an array of parts
249
+ parts = [
250
+ %{<div class="object-header">},
251
+ %{<span class="object-class">#{object.class.name}</span>},
252
+ %{<span class="object-id">##{object.object_id}</span>},
253
+ %{</div>},
254
+ %{<div class="object-body">},
255
+ ]
256
+
257
+ object.instance_variables.sort.each do |ivar|
258
+ value = object.instance_variable_get( ivar )
259
+ html = make_html_for_object( value )
260
+ classes = %w[instance-variable]
261
+ if value.instance_variables.empty? && !value.respond_to?( :values_at )
262
+ classes << 'simple'
263
+ else
264
+ classes << 'complex'
265
+ end
266
+ parts << IVAR_HTML_FRAGMENT % [ classes.join(' '), ivar, html ]
267
+ end
268
+
269
+ parts << %{</div>}
270
+
271
+ # Make HTML class names out of the object's namespaces
272
+ namespaces = object.class.name.downcase.split(/::/)
273
+ classes = []
274
+ namespaces.each_index do |i|
275
+ classes << namespaces[0..i].join('-') + '-object'
276
+ end
277
+
278
+ # Glue the whole thing together and return it
279
+ return OBJECT_HTML_CONTAINER % [
280
+ object.object_id,
281
+ classes.join(" "),
282
+ parts.join("\n")
283
+ ]
284
+ end
285
+
286
+ end # module HTMLUtilities
287
+
288
+
289
+ ### Add a #html_inspect method to the including object that is capable of dumping its
290
+ ### state as an HTML fragment.
291
+ ###
292
+ ### class MyObject
293
+ ### include HtmlInspectableObject
294
+ ### end
295
+ ###
296
+ ### irb> MyObject.new.html_inspect
297
+ ### ==> "<span class=\"immediate-object\">#&lt;MyObject:0x56e780&gt;</span>"
298
+ module HtmlInspectableObject
299
+ include Arrow::HTMLUtilities
300
+
301
+ ### Return the receiver as an HTML fragment.
302
+ def html_inspect
303
+ if self.instance_variables.empty?
304
+ return make_html_for_object( self )
305
+ else
306
+ return make_object_html_wrapper( self )
307
+ end
308
+ end
309
+
310
+ end # HtmlInspectableObject
311
+
312
+
313
+ # Adds dependency-injection bejavior to a class. Classes which are Injectable
314
+ # are loadable by name, making it easier to refer to them from a configuration
315
+ # file or other symbolic source. Instead of classes explicitly referring to
316
+ # one another to satisfy their associations, these dependencies can be
317
+ # "injected" at runtime.
318
+ #
319
+ # Some references for the Dependency Injection pattern:
320
+ #
321
+ # * http://www.martinfowler.com/articles/injection.html
322
+ # * http://en.wikipedia.org/wiki/Dependency_injection
323
+ #
324
+ # == Usage
325
+ #
326
+ # # in myclass.rb
327
+ # require 'arrow/mixins'
328
+ #
329
+ # class MyClass
330
+ # include Arrow::Injectable
331
+ # end
332
+ #
333
+ # # somewhere else
334
+ # myclass = Arrow::Injectable.load_class( "myclass" )
335
+ #
336
+ #
337
+ module Injectable
338
+
339
+ @derivatives = {}
340
+ def self::derivatives; @derivatives; end
341
+
342
+ ### Make the given object (which must be a Class) injectable.
343
+ def self::extend_object( obj )
344
+ raise ArgumentError, "can't make a #{obj.class} Injectable" unless
345
+ obj.is_a?( Class )
346
+ super
347
+ @derivatives[ obj.name ] = obj
348
+ end
349
+
350
+
351
+ ### Mixin hook: extend including classes
352
+ def self::included( mod )
353
+ Arrow::Logger[self].debug "%s included Injectable" % [ mod.name ]
354
+ mod.extend( self )
355
+ super
356
+ end
357
+
358
+
359
+ ### Return the Class object for the given derivative +classname+,
360
+ ### attempting to load it if it hasn't been already.
361
+ def self::load_class( classname )
362
+ Arrow::Logger[self].debug "Loading injectable class '#{classname}'"
363
+
364
+ unless Arrow::Injectable.derivatives.include?( classname )
365
+ modname = classname.downcase.gsub( /::/, '/' )
366
+ Arrow::Logger[self].debug "Class not loaded yet. Trying to " +
367
+ "load it from #{modname}"
368
+ require modname or
369
+ raise "%s didn't register with Injectable for some reason" % [ classname ]
370
+ Arrow::Logger[self].debug "Loaded injectable class %s (%d classes loaded)" %
371
+ [ classname, Arrow::Injectable.derivatives.length ]
372
+ end
373
+
374
+ Arrow::Injectable.derivatives[ classname ]
375
+ end
376
+
377
+
378
+ #############################################################
379
+ ### A P P E N D E D M E T H O D S
380
+ #############################################################
381
+
382
+ ### Classes which inherit from Injectable classes should be
383
+ ### Injectable, too.
384
+ def inherited( klass )
385
+ Arrow::Logger[self].debug "making %s Injectable" % [ klass.name ]
386
+ klass.extend( Arrow::Injectable )
387
+ super
388
+ end
389
+
390
+ end # module Injectable
391
+
392
+
393
+ # A mixin that adds a #log method to including classes that calls
394
+ # Arrow::Logger with the class of the receiving object.
395
+ #
396
+ # == Usage
397
+ #
398
+ # require "arrow/mixins"
399
+ #
400
+ # class MyClass
401
+ # include Arrow::Loggable
402
+ #
403
+ # def some_method
404
+ # self.log.debug "A debugging message"
405
+ # end
406
+ # end
407
+ #
408
+ module Loggable
409
+ require 'arrow/logger'
410
+
411
+ #########
412
+ protected
413
+ #########
414
+
415
+ ### Return the Arrow::Logger object for the receiving class.
416
+ def log
417
+ Arrow::Logger[ self.class ]
418
+ end
419
+
420
+ end # module Loggable
421
+
422
+
423
+ end # module Arrow
424
+
425
+
@@ -0,0 +1,94 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'arrow/constants'
4
+
5
+ #
6
+ # A (hopefully) minimal collection of extensions to core classes.
7
+ #
8
+ # == Authors
9
+ #
10
+ # * Martin Chase <mchase@rubycrafters.com>
11
+ # * Michael Granger <mgranger@rubycrafters.com>
12
+ # * David McCorkhill <dmccorkhill@rubycrafters.com>
13
+ #
14
+ # Please see the file LICENSE in the top-level directory for licensing details.
15
+ #
16
+
17
+ ### Add some operator methods to regular expression objects for catenation,
18
+ ### union, etc.
19
+ module Arrow::RegexpOperators
20
+
21
+ ### Append the given +other+ Regexp (or String) onto a copy of the receiving
22
+ ### one and return it.
23
+ def +( other )
24
+ return self.class.new( self.to_s + other.to_s )
25
+ end
26
+
27
+ ### Create and return a new Regexp that is an alternation between the
28
+ ### receiver and the +other+ Regexp.
29
+ def |( other )
30
+ return Regexp.new( "(?:%s|%s)" % [self.to_s, other.to_s] )
31
+ end
32
+ end
33
+
34
+ # Extended with Arrow::RegexpOperators
35
+ class Regexp # :nodoc:
36
+ include Arrow::RegexpOperators
37
+ end
38
+
39
+
40
+ ### Add some stuff to the String class to allow easy transformation to Regexp
41
+ ### and in-place interpolation.
42
+ module Arrow::StringExtensions
43
+
44
+ ### Return the receiving String as a Regexp.
45
+ def to_re( casefold=false, extended=false )
46
+ return Regexp.new( self.dup )
47
+ end
48
+
49
+
50
+ ### Ideas for String-interpolation stuff courtesy of Hal E. Fulton
51
+ ### <hal9000@hypermetrics.com> via ruby-talk
52
+
53
+ ### Interpolate any '#{...}' placeholders in the string within the given
54
+ ### +scope+ (a Binding object).
55
+ def interpolate( scope )
56
+ unless scope.is_a?( Binding )
57
+ raise TypeError, "Argument to interpolate must be a Binding, not "\
58
+ "a #{scope.class.name}"
59
+ end
60
+
61
+ # $stderr.puts ">>> Interpolating '#{self}'..."
62
+
63
+ copy = self.gsub( /"/, %q:\": )
64
+ eval( '"' + copy + '"', scope )
65
+ rescue Exception => err
66
+ nicetrace = err.backtrace.find_all {|frame|
67
+ /in `(interpolate|eval)'/i !~ frame
68
+ }
69
+ Kernel.raise( err, err.message, nicetrace )
70
+ end
71
+
72
+ end
73
+
74
+ # Extended with Arrow::StringExtensions
75
+ class String # :nodoc:
76
+ include Arrow::StringExtensions
77
+ end
78
+
79
+
80
+ ### Override RubyGem's use of values out of ENV since they're always tainted.
81
+ # module Gem
82
+ # def self::find_home
83
+ # if defined?( Apache )
84
+ # return Apache.server_root
85
+ # else
86
+ # homedir = ENV['HOME'].dup
87
+ # homedir.untaint
88
+ #
89
+ # return homedir
90
+ # end
91
+ # end
92
+ # end
93
+
94
+