arrow 1.0.7

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.
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
+