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.
- data/ChangeLog +1590 -0
- data/LICENSE +28 -0
- data/README +75 -0
- data/Rakefile +366 -0
- data/Rakefile.local +63 -0
- data/data/arrow/applets/TEMPLATE.rb.tpl +53 -0
- data/data/arrow/applets/args.rb +50 -0
- data/data/arrow/applets/config.rb +55 -0
- data/data/arrow/applets/error.rb +63 -0
- data/data/arrow/applets/files.rb +46 -0
- data/data/arrow/applets/inspect.rb +46 -0
- data/data/arrow/applets/nosuchapplet.rb +31 -0
- data/data/arrow/applets/status.rb +92 -0
- data/data/arrow/applets/test.rb +133 -0
- data/data/arrow/applets/tutorial/counter.rb +96 -0
- data/data/arrow/applets/tutorial/dingus.rb +67 -0
- data/data/arrow/applets/tutorial/hello.rb +34 -0
- data/data/arrow/applets/tutorial/hello2.rb +73 -0
- data/data/arrow/applets/tutorial/imgtext.rb +90 -0
- data/data/arrow/applets/tutorial/imgtext2.rb +286 -0
- data/data/arrow/applets/tutorial/index.rb +36 -0
- data/data/arrow/applets/tutorial/logo.rb +98 -0
- data/data/arrow/applets/tutorial/memcache.rb +61 -0
- data/data/arrow/applets/tutorial/missing.rb +37 -0
- data/data/arrow/applets/tutorial/protected.rb +100 -0
- data/data/arrow/applets/tutorial/redirector.rb +52 -0
- data/data/arrow/applets/tutorial/rndimages.rb +159 -0
- data/data/arrow/applets/tutorial/sharenotes.rb +83 -0
- data/data/arrow/applets/tutorial/subclassed-hello.rb +32 -0
- data/data/arrow/applets/tutorial/superhello.rb +72 -0
- data/data/arrow/applets/tutorial/timeclock.rb +78 -0
- data/data/arrow/applets/view-applet.rb +123 -0
- data/data/arrow/applets/view-template.rb +85 -0
- data/data/arrow/applets/wiki.rb +274 -0
- data/data/arrow/templates/TEMPLATE.tmpl.tpl +36 -0
- data/data/arrow/templates/applet-status.tmpl +153 -0
- data/data/arrow/templates/args-display.tmpl +120 -0
- data/data/arrow/templates/config/display-table.tmpl +36 -0
- data/data/arrow/templates/config/display.tmpl +36 -0
- data/data/arrow/templates/counter-deleted.tmpl +33 -0
- data/data/arrow/templates/counter.tmpl +59 -0
- data/data/arrow/templates/dingus.tmpl +55 -0
- data/data/arrow/templates/enumtable.tmpl +8 -0
- data/data/arrow/templates/error-display.tmpl +92 -0
- data/data/arrow/templates/filemap.tmpl +89 -0
- data/data/arrow/templates/hello-world-src.tmpl +34 -0
- data/data/arrow/templates/hello-world.tmpl +60 -0
- data/data/arrow/templates/imgtext/fontlist.tmpl +46 -0
- data/data/arrow/templates/imgtext/form.tmpl +70 -0
- data/data/arrow/templates/imgtext/reload-error.tmpl +40 -0
- data/data/arrow/templates/imgtext/reload.tmpl +55 -0
- data/data/arrow/templates/inspect/display.tmpl +80 -0
- data/data/arrow/templates/loginform.tmpl +64 -0
- data/data/arrow/templates/logout.tmpl +32 -0
- data/data/arrow/templates/memcache/display.tmpl +41 -0
- data/data/arrow/templates/navbar.incl +27 -0
- data/data/arrow/templates/nosuchapplet.tmpl +32 -0
- data/data/arrow/templates/printsource.tmpl +35 -0
- data/data/arrow/templates/protected.tmpl +36 -0
- data/data/arrow/templates/rndimages.tmpl +38 -0
- data/data/arrow/templates/service-response.tmpl +13 -0
- data/data/arrow/templates/sharenotes/display.tmpl +38 -0
- data/data/arrow/templates/status.tmpl +120 -0
- data/data/arrow/templates/templateviewer.tmpl +43 -0
- data/data/arrow/templates/test/harness.tmpl +57 -0
- data/data/arrow/templates/test/list.tmpl +48 -0
- data/data/arrow/templates/test/problem.tmpl +42 -0
- data/data/arrow/templates/tutorial/index.tmpl +37 -0
- data/data/arrow/templates/tutorial/missingapplet.tmpl +29 -0
- data/data/arrow/templates/view-applet-nosuch.tmpl +32 -0
- data/data/arrow/templates/view-applet.tmpl +40 -0
- data/data/arrow/templates/view-template.tmpl +83 -0
- data/data/arrow/templates/wiki/formerror.tmpl +47 -0
- data/data/arrow/templates/wiki/markup_help.incl +6 -0
- data/data/arrow/templates/wiki/new.tmpl +56 -0
- data/data/arrow/templates/wiki/new_system.tmpl +122 -0
- data/data/arrow/templates/wiki/sectionlist.tmpl +43 -0
- data/data/arrow/templates/wiki/show.tmpl +34 -0
- data/docs/manual/layouts/default.page +43 -0
- data/docs/manual/lib/api-filter.rb +81 -0
- data/docs/manual/lib/editorial-filter.rb +64 -0
- data/docs/manual/lib/examples-filter.rb +244 -0
- data/docs/manual/lib/links-filter.rb +117 -0
- data/lib/apache/fakerequest.rb +448 -0
- data/lib/apache/logger.rb +33 -0
- data/lib/arrow.rb +51 -0
- data/lib/arrow/acceptparam.rb +207 -0
- data/lib/arrow/applet.rb +725 -0
- data/lib/arrow/appletmixins.rb +218 -0
- data/lib/arrow/appletregistry.rb +590 -0
- data/lib/arrow/applettestcase.rb +503 -0
- data/lib/arrow/broker.rb +255 -0
- data/lib/arrow/cache.rb +176 -0
- data/lib/arrow/config-loaders/yaml.rb +75 -0
- data/lib/arrow/config.rb +615 -0
- data/lib/arrow/constants.rb +24 -0
- data/lib/arrow/cookie.rb +359 -0
- data/lib/arrow/cookieset.rb +108 -0
- data/lib/arrow/dispatcher.rb +368 -0
- data/lib/arrow/dispatcherloader.rb +50 -0
- data/lib/arrow/exceptions.rb +61 -0
- data/lib/arrow/fallbackhandler.rb +48 -0
- data/lib/arrow/formvalidator.rb +631 -0
- data/lib/arrow/htmltokenizer.rb +343 -0
- data/lib/arrow/logger.rb +488 -0
- data/lib/arrow/logger/apacheoutputter.rb +69 -0
- data/lib/arrow/logger/arrayoutputter.rb +63 -0
- data/lib/arrow/logger/coloroutputter.rb +111 -0
- data/lib/arrow/logger/fileoutputter.rb +96 -0
- data/lib/arrow/logger/htmloutputter.rb +54 -0
- data/lib/arrow/logger/outputter.rb +123 -0
- data/lib/arrow/mixins.rb +425 -0
- data/lib/arrow/monkeypatches.rb +94 -0
- data/lib/arrow/object.rb +117 -0
- data/lib/arrow/path.rb +196 -0
- data/lib/arrow/service.rb +447 -0
- data/lib/arrow/session.rb +289 -0
- data/lib/arrow/session/dbstore.rb +100 -0
- data/lib/arrow/session/filelock.rb +160 -0
- data/lib/arrow/session/filestore.rb +132 -0
- data/lib/arrow/session/id.rb +98 -0
- data/lib/arrow/session/lock.rb +253 -0
- data/lib/arrow/session/md5id.rb +42 -0
- data/lib/arrow/session/nulllock.rb +42 -0
- data/lib/arrow/session/posixlock.rb +166 -0
- data/lib/arrow/session/sha1id.rb +54 -0
- data/lib/arrow/session/store.rb +366 -0
- data/lib/arrow/session/usertrackid.rb +52 -0
- data/lib/arrow/spechelpers.rb +73 -0
- data/lib/arrow/template.rb +713 -0
- data/lib/arrow/template/attr.rb +31 -0
- data/lib/arrow/template/call.rb +31 -0
- data/lib/arrow/template/comment.rb +33 -0
- data/lib/arrow/template/container.rb +118 -0
- data/lib/arrow/template/else.rb +41 -0
- data/lib/arrow/template/elsif.rb +44 -0
- data/lib/arrow/template/escape.rb +53 -0
- data/lib/arrow/template/export.rb +87 -0
- data/lib/arrow/template/for.rb +145 -0
- data/lib/arrow/template/if.rb +78 -0
- data/lib/arrow/template/import.rb +119 -0
- data/lib/arrow/template/include.rb +206 -0
- data/lib/arrow/template/iterator.rb +208 -0
- data/lib/arrow/template/nodes.rb +734 -0
- data/lib/arrow/template/parser.rb +571 -0
- data/lib/arrow/template/prettyprint.rb +53 -0
- data/lib/arrow/template/render.rb +191 -0
- data/lib/arrow/template/selectlist.rb +94 -0
- data/lib/arrow/template/set.rb +87 -0
- data/lib/arrow/template/timedelta.rb +81 -0
- data/lib/arrow/template/unless.rb +78 -0
- data/lib/arrow/template/urlencode.rb +51 -0
- data/lib/arrow/template/yield.rb +139 -0
- data/lib/arrow/templatefactory.rb +125 -0
- data/lib/arrow/testcase.rb +567 -0
- data/lib/arrow/transaction.rb +608 -0
- data/rake/191_compat.rb +26 -0
- data/rake/dependencies.rb +76 -0
- data/rake/documentation.rb +114 -0
- data/rake/helpers.rb +502 -0
- data/rake/hg.rb +282 -0
- data/rake/manual.rb +787 -0
- data/rake/packaging.rb +129 -0
- data/rake/publishing.rb +278 -0
- data/rake/style.rb +62 -0
- data/rake/svn.rb +668 -0
- data/rake/testing.rb +187 -0
- data/rake/verifytask.rb +64 -0
- data/spec/arrow/acceptparam_spec.rb +157 -0
- data/spec/arrow/applet_spec.rb +575 -0
- data/spec/arrow/appletmixins_spec.rb +409 -0
- data/spec/arrow/appletregistry_spec.rb +294 -0
- data/spec/arrow/broker_spec.rb +153 -0
- data/spec/arrow/config_spec.rb +224 -0
- data/spec/arrow/cookieset_spec.rb +164 -0
- data/spec/arrow/dispatcher_spec.rb +137 -0
- data/spec/arrow/dispatcherloader_spec.rb +65 -0
- data/spec/arrow/formvalidator_spec.rb +781 -0
- data/spec/arrow/logger_spec.rb +346 -0
- data/spec/arrow/mixins_spec.rb +120 -0
- data/spec/arrow/service_spec.rb +645 -0
- data/spec/arrow/session_spec.rb +121 -0
- data/spec/arrow/template/iterator_spec.rb +222 -0
- data/spec/arrow/templatefactory_spec.rb +185 -0
- data/spec/arrow/transaction_spec.rb +319 -0
- data/spec/arrow_spec.rb +37 -0
- data/spec/lib/appletmatchers.rb +281 -0
- data/spec/lib/constants.rb +77 -0
- data/spec/lib/helpers.rb +41 -0
- data/spec/lib/matchers.rb +44 -0
- data/tests/cookie.tests.rb +310 -0
- data/tests/path.tests.rb +157 -0
- data/tests/session.tests.rb +111 -0
- data/tests/session_id.tests.rb +82 -0
- data/tests/session_lock.tests.rb +191 -0
- data/tests/session_store.tests.rb +53 -0
- data/tests/template.tests.rb +1360 -0
- metadata +339 -0
data/lib/arrow/mixins.rb
ADDED
|
@@ -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(/&/, '&').
|
|
175
|
+
gsub(/</, '<').
|
|
176
|
+
gsub(/>/, '>').
|
|
177
|
+
gsub(/\n/, '↵').
|
|
178
|
+
gsub(/\t/, '→')
|
|
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
|
+
%{→ %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\">#<MyObject:0x56e780></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
|
+
|