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
|
@@ -0,0 +1,343 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'strscan'
|
|
4
|
+
require 'arrow/object'
|
|
5
|
+
require 'arrow/mixins'
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
module Arrow
|
|
9
|
+
|
|
10
|
+
# The Arrow::HTMLTokenizer class -- a simple HTML parser that can be used to break HTML
|
|
11
|
+
# down into tokens.
|
|
12
|
+
#
|
|
13
|
+
# Some of the code and design were stolen from the excellent HTMLTokenizer
|
|
14
|
+
# library by Ben Giddings <bg@infofiend.com>.
|
|
15
|
+
#
|
|
16
|
+
# == VCS Id
|
|
17
|
+
#
|
|
18
|
+
# $Id$
|
|
19
|
+
#
|
|
20
|
+
# == Authors
|
|
21
|
+
#
|
|
22
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
|
23
|
+
#
|
|
24
|
+
# :include: LICENSE
|
|
25
|
+
#
|
|
26
|
+
#--
|
|
27
|
+
#
|
|
28
|
+
# Please see the file LICENSE in the top-level directory for licensing details.
|
|
29
|
+
#
|
|
30
|
+
class HTMLTokenizer < Arrow::Object
|
|
31
|
+
include Enumerable
|
|
32
|
+
|
|
33
|
+
# SVN Revision
|
|
34
|
+
SVNRev = %q$Rev$
|
|
35
|
+
|
|
36
|
+
# SVN Id
|
|
37
|
+
SVNId = %q$Id$
|
|
38
|
+
|
|
39
|
+
|
|
40
|
+
### Create a new Arrow::HtmlTokenizer object.
|
|
41
|
+
def initialize( source )
|
|
42
|
+
@source = source
|
|
43
|
+
@scanner = StringScanner.new( source )
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
######
|
|
48
|
+
public
|
|
49
|
+
######
|
|
50
|
+
|
|
51
|
+
# The HTML source being tokenized
|
|
52
|
+
attr_reader :source
|
|
53
|
+
|
|
54
|
+
# The StringScanner doing the tokenizing
|
|
55
|
+
attr_reader :scanner
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
### Enumerable interface: Iterates over parsed tokens, calling the
|
|
59
|
+
### supplied block with each one.
|
|
60
|
+
def each
|
|
61
|
+
@scanner.reset
|
|
62
|
+
|
|
63
|
+
until @scanner.empty?
|
|
64
|
+
if @scanner.peek(1) == '<'
|
|
65
|
+
tag = @scanner.scan_until( />/ )
|
|
66
|
+
|
|
67
|
+
case tag
|
|
68
|
+
when /^<!--/
|
|
69
|
+
token = HTMLComment.new( tag )
|
|
70
|
+
when /^<!/
|
|
71
|
+
token = DocType.new( tag )
|
|
72
|
+
when /^<\?/
|
|
73
|
+
token = ProcessingInstruction.new( tag )
|
|
74
|
+
else
|
|
75
|
+
token = HTMLTag.new( tag )
|
|
76
|
+
end
|
|
77
|
+
else
|
|
78
|
+
text = @scanner.scan( /[^<]+/ )
|
|
79
|
+
token = HTMLText.new( text )
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
yield( token )
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
|
|
87
|
+
|
|
88
|
+
#########
|
|
89
|
+
protected
|
|
90
|
+
#########
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
end # class HTMLTokenizer
|
|
94
|
+
|
|
95
|
+
|
|
96
|
+
### Base class for HTML tokens output by Arrow::HTMLTokenizer.
|
|
97
|
+
class HTMLToken < Arrow::Object # :nodoc:
|
|
98
|
+
|
|
99
|
+
### Initialize a token with the +raw+ source of it.
|
|
100
|
+
def initialize( raw ) # :notnew:
|
|
101
|
+
super()
|
|
102
|
+
@raw = raw
|
|
103
|
+
end
|
|
104
|
+
|
|
105
|
+
# The raw source of the token
|
|
106
|
+
attr_accessor :raw
|
|
107
|
+
alias_method :to_s, :raw
|
|
108
|
+
|
|
109
|
+
### Return an HTML fragment that can be used to represent the token
|
|
110
|
+
### symbolically in a web-based introspection interface.
|
|
111
|
+
def to_html
|
|
112
|
+
content = nil
|
|
113
|
+
|
|
114
|
+
if block_given?
|
|
115
|
+
content = yield
|
|
116
|
+
# self.log.debug "content = %p" % content
|
|
117
|
+
else
|
|
118
|
+
content = self.escape_html( @raw )
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
tokenclass = self.css_class
|
|
122
|
+
|
|
123
|
+
%q{<span class="token %s">%s</span>} % [
|
|
124
|
+
tokenclass,
|
|
125
|
+
content,
|
|
126
|
+
]
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
|
|
130
|
+
### Return the HTML element class attribute that corresponds to this node.
|
|
131
|
+
def css_class
|
|
132
|
+
tokenclass = self.class.name.
|
|
133
|
+
sub( /Arrow::(HTML)?/i, '').
|
|
134
|
+
gsub( /::/, '-' ).
|
|
135
|
+
gsub( /([a-z])([A-Z])/, "\\1-\\2" ).
|
|
136
|
+
gsub( /[^-\w]+/, '' ).
|
|
137
|
+
downcase
|
|
138
|
+
tokenclass << "-token" unless /-token$/.match( tokenclass )
|
|
139
|
+
|
|
140
|
+
return tokenclass
|
|
141
|
+
end
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
### Escape special characters in the given +string+ for display in an
|
|
145
|
+
### HTML inspection interface. This escapes common invisible characters
|
|
146
|
+
### like tabs and carriage-returns in additional to the regular HTML
|
|
147
|
+
### escapes.
|
|
148
|
+
def escape_html( string )
|
|
149
|
+
return "nil" if string.nil?
|
|
150
|
+
string = string.inspect unless string.is_a?( String )
|
|
151
|
+
string.
|
|
152
|
+
gsub(/&/, '&').
|
|
153
|
+
gsub(/</, '<').
|
|
154
|
+
gsub(/>/, '>').
|
|
155
|
+
gsub(/\r?\n/, %Q{<br />\n}).
|
|
156
|
+
gsub(/\t/, ' ')
|
|
157
|
+
end
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
|
|
161
|
+
### Class for tokens output by Arrow::HTMLTokenizer for the text bits of an
|
|
162
|
+
### HTML document.
|
|
163
|
+
class HTMLText < HTMLToken # :nodoc:
|
|
164
|
+
|
|
165
|
+
### Return an HTML fragment that can be used to represent the token
|
|
166
|
+
### symbolically in a web-based introspection interface.
|
|
167
|
+
def to_html
|
|
168
|
+
marked = self.escape_html( @raw )
|
|
169
|
+
marked.gsub( /(&[^;]+;)/ ) {|ent|
|
|
170
|
+
%Q{<span class="entity">#{ent}</span>}
|
|
171
|
+
}
|
|
172
|
+
super { marked }
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
### Class for tokens output by Arrow::HTMLTokenizer for HTML comments.
|
|
179
|
+
class HTMLComment < HTMLToken # :nodoc:
|
|
180
|
+
CommentPattern = /^<!--((?:[^-]|-(?!-))*)-->$/
|
|
181
|
+
|
|
182
|
+
def initialize( raw )
|
|
183
|
+
super
|
|
184
|
+
|
|
185
|
+
unless (( match = CommentPattern.match(raw) ))
|
|
186
|
+
raise ArgumentError,
|
|
187
|
+
"Malformed comment %p" % raw
|
|
188
|
+
end
|
|
189
|
+
|
|
190
|
+
@contents = match[1]
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
attr_accessor :contents
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
|
|
197
|
+
### Class for tokens output by Arrow::HTMLTokenizer for the tags in an HTML
|
|
198
|
+
### document.
|
|
199
|
+
class HTMLTag < HTMLToken # :nodoc:
|
|
200
|
+
|
|
201
|
+
# The pattern for matching tag attribute key-value pairs
|
|
202
|
+
AttributePattern = %r{
|
|
203
|
+
\s*([-A-Za-z:]+)
|
|
204
|
+
(?:\s*=\s*(
|
|
205
|
+
"(?:[^"]|\\.)*" | # Match strings quoted with "
|
|
206
|
+
'(?:[^']|\\.)*' | # Match strings quoted with '
|
|
207
|
+
\S+ # Match non-whitespace
|
|
208
|
+
))?
|
|
209
|
+
}mx
|
|
210
|
+
|
|
211
|
+
#############################################################
|
|
212
|
+
### I N S T A N C E M E T H O D S
|
|
213
|
+
#############################################################
|
|
214
|
+
|
|
215
|
+
### Create a new HTMLTag from the specified raw source.
|
|
216
|
+
def initialize( raw )
|
|
217
|
+
unless (( match = /<\s*(\/)?(\w+)\s*([^>]*)>/.match(raw) ))
|
|
218
|
+
raise ArgumentError,
|
|
219
|
+
"Malformed HTMLTag: %p" % raw
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
@endtag = !match[1].nil?
|
|
223
|
+
@tagname = match[2]
|
|
224
|
+
@rawattrs = match[3] || ''
|
|
225
|
+
@attrs = nil
|
|
226
|
+
|
|
227
|
+
super
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
######
|
|
232
|
+
public
|
|
233
|
+
######
|
|
234
|
+
|
|
235
|
+
# The name of the tag
|
|
236
|
+
attr_reader :tagname
|
|
237
|
+
|
|
238
|
+
### Returns +true+ if this tag is an closing tag
|
|
239
|
+
def endtag?; @endtag; end
|
|
240
|
+
|
|
241
|
+
|
|
242
|
+
### Return the Hash of tag attributes belonging to this token.
|
|
243
|
+
def attrs
|
|
244
|
+
unless @attrs
|
|
245
|
+
@attrs = {}
|
|
246
|
+
@rawattrs.scan( AttributePattern ) {|name,value|
|
|
247
|
+
ns = nil
|
|
248
|
+
if /:/ =~ name
|
|
249
|
+
ns, name = name.split(/:/, 2)
|
|
250
|
+
if ns == 'html' then ns = nil end
|
|
251
|
+
end
|
|
252
|
+
cname = name.gsub(/-/, '_').downcase
|
|
253
|
+
cval = value.nil? ? true : value.gsub(/^["']|['"]$/, '')
|
|
254
|
+
|
|
255
|
+
if ns.nil?
|
|
256
|
+
@attrs[ cname.to_sym ] = cval
|
|
257
|
+
else
|
|
258
|
+
@attrs[ ns.to_sym ] ||= {}
|
|
259
|
+
@attrs[ ns.to_sym ][ name.to_sym ] = cval
|
|
260
|
+
end
|
|
261
|
+
}
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
return @attrs
|
|
265
|
+
end
|
|
266
|
+
|
|
267
|
+
|
|
268
|
+
### Return the tag attribute with the specified name (if it exists).
|
|
269
|
+
def []( name )
|
|
270
|
+
self.attrs[ name.gsub(/-/, '_').downcase.to_sym ]
|
|
271
|
+
end
|
|
272
|
+
|
|
273
|
+
|
|
274
|
+
### Return an HTML fragment that can be used to represent the token
|
|
275
|
+
### symbolically in a web-based introspection interface.
|
|
276
|
+
def to_html
|
|
277
|
+
tagopen, tagbody = @raw.split( /\s+/, 2 )
|
|
278
|
+
# self.log.debug "tagopen = %p, tagbody = %p" % [ tagopen, tagbody ]
|
|
279
|
+
|
|
280
|
+
tagopen = self.escape_html( tagopen ).sub( %r{^<(/)?(\w+)} ) {|match|
|
|
281
|
+
%Q{<#$1<span class="tag-token-name">#$2</span>}
|
|
282
|
+
}
|
|
283
|
+
|
|
284
|
+
unless tagbody.nil?
|
|
285
|
+
tagbody.sub!( />$/, '' )
|
|
286
|
+
tagbody = self.escape_html( tagbody ).gsub( AttributePattern ) {|match|
|
|
287
|
+
name, mid, val = match.split(/(\s*=\s*)/, 2)
|
|
288
|
+
|
|
289
|
+
val.gsub!( /(\[\?(?:[^\?]|\?(?!\]))+\?\])/s ) {|m|
|
|
290
|
+
%q{<span class="%s">%s</span>} %
|
|
291
|
+
[ 'tag-attr-directive', m ]
|
|
292
|
+
}
|
|
293
|
+
|
|
294
|
+
%q{<span class="%s">%s</span>%s<span class="%s">%s</span>} % [
|
|
295
|
+
'tag-token-attr-name',
|
|
296
|
+
name,
|
|
297
|
+
mid,
|
|
298
|
+
'tag-token-attr-value',
|
|
299
|
+
val,
|
|
300
|
+
]
|
|
301
|
+
}
|
|
302
|
+
tagbody << '>'
|
|
303
|
+
end
|
|
304
|
+
|
|
305
|
+
#self.log.debug "tagopen = %p; tagbody = %p" %
|
|
306
|
+
# [ tagopen, tagbody ]
|
|
307
|
+
super { [tagopen, tagbody].compact.join(" ") }
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
### Escape special characters in the given +string+ for display in an
|
|
311
|
+
### HTML inspection interface.
|
|
312
|
+
def escape_html( string )
|
|
313
|
+
return "nil" if string.nil?
|
|
314
|
+
string = string.inspect unless string.is_a?( String )
|
|
315
|
+
string.
|
|
316
|
+
gsub(/&/, '&').
|
|
317
|
+
gsub(/</, '<').
|
|
318
|
+
gsub(/>/, '>')
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
### Class for tokens output by Arrow::HTMLTokenizer for the processing
|
|
324
|
+
### instructions contained in an HTML document.
|
|
325
|
+
class ProcessingInstruction < HTMLToken # :nodoc:
|
|
326
|
+
def initialize( raw )
|
|
327
|
+
@instruction, @body = raw.gsub(/^\?|\?$/, '').split( /\s+/, 2 )
|
|
328
|
+
super
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
attr_accessor :instruction, :body
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
|
|
335
|
+
### Class for tokens output by Arrow::HTMLTokenizer for the doctype
|
|
336
|
+
### declaration of an HTML document.
|
|
337
|
+
class DocType < HTMLToken # :nodoc:
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
end # module Arrow
|
|
342
|
+
|
|
343
|
+
|
data/lib/arrow/logger.rb
ADDED
|
@@ -0,0 +1,488 @@
|
|
|
1
|
+
#!/usr/bin/env ruby
|
|
2
|
+
|
|
3
|
+
require 'configurability'
|
|
4
|
+
require 'arrow/mixins'
|
|
5
|
+
|
|
6
|
+
# A hierarchical logging class for the Arrow framework. It provides a
|
|
7
|
+
# generalized means of logging from inside Arrow classes, and then selectively
|
|
8
|
+
# outputting/formatting log messages from points within the hierarchy.
|
|
9
|
+
#
|
|
10
|
+
# A lot of concepts in this class were stolen from Log4r, though it's all
|
|
11
|
+
# original code, and works a bit differently.
|
|
12
|
+
#
|
|
13
|
+
# == Synopsis
|
|
14
|
+
#
|
|
15
|
+
# require 'arrow/object'
|
|
16
|
+
# require 'arrow/logger'
|
|
17
|
+
#
|
|
18
|
+
# logger = Arrow::Logger.global
|
|
19
|
+
# logfile = File.open( "global.log", "a" )
|
|
20
|
+
# logger.outputters << Arrow::Logger::Outputter.new(logfile)
|
|
21
|
+
# logger.level = :debug
|
|
22
|
+
#
|
|
23
|
+
# class MyClass < Arrow::Object
|
|
24
|
+
#
|
|
25
|
+
# def self::fooMethod
|
|
26
|
+
# Arrow::Logger.debug( "In server start routine" )
|
|
27
|
+
# Arrow::Logger.info( "Server is not yet configured." )
|
|
28
|
+
# Arrow::Logger.notice( "Server is starting up." )
|
|
29
|
+
# end
|
|
30
|
+
#
|
|
31
|
+
# def initialize
|
|
32
|
+
# self.log.info( "Initializing another MyClass object." )
|
|
33
|
+
# end
|
|
34
|
+
# end
|
|
35
|
+
#
|
|
36
|
+
# == VCS Id
|
|
37
|
+
#
|
|
38
|
+
# $Id: logger.rb,v ba725438313d 2010/08/09 02:08:40 ged $
|
|
39
|
+
#
|
|
40
|
+
# == Authors
|
|
41
|
+
#
|
|
42
|
+
# * Michael Granger <ged@FaerieMUD.org>
|
|
43
|
+
#
|
|
44
|
+
# Please see the file LICENSE in the top-level directory for licensing details.
|
|
45
|
+
#
|
|
46
|
+
class Arrow::Logger
|
|
47
|
+
extend Configurability
|
|
48
|
+
|
|
49
|
+
config_key :logging
|
|
50
|
+
|
|
51
|
+
require 'arrow/logger/outputter'
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
# Construct a log levels Hash on the fly
|
|
55
|
+
LEVELS = [
|
|
56
|
+
:debug,
|
|
57
|
+
:info,
|
|
58
|
+
:notice,
|
|
59
|
+
:warning,
|
|
60
|
+
:error,
|
|
61
|
+
:crit,
|
|
62
|
+
:alert,
|
|
63
|
+
:emerg,
|
|
64
|
+
].inject({}) {|hsh, sym| hsh[ sym ] = hsh.length; hsh}
|
|
65
|
+
LEVEL_NAMES = LEVELS.invert
|
|
66
|
+
|
|
67
|
+
### Module for adding internals debugging to the Logger class
|
|
68
|
+
module DebugLogger # :nodoc:
|
|
69
|
+
def debug_msg( *parts ) # :nodoc:
|
|
70
|
+
# $deferr.puts parts.join('') if $DEBUG
|
|
71
|
+
end
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
include DebugLogger
|
|
75
|
+
extend DebugLogger
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
#############################################################
|
|
80
|
+
### C L A S S M E T H O D S
|
|
81
|
+
#############################################################
|
|
82
|
+
|
|
83
|
+
# Loggers for Modules, keyed by Module
|
|
84
|
+
@logger_map = Hash.new do |h,mod|
|
|
85
|
+
h[ mod ] = self.new( mod )
|
|
86
|
+
end
|
|
87
|
+
class << self; attr_reader :logger_map ; end
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
### Configure logging from the 'logging' section of the config.
|
|
91
|
+
def self::configure( config )
|
|
92
|
+
|
|
93
|
+
self.reset
|
|
94
|
+
apacheoutputter = Arrow::Logger::Outputter.create( 'apache' )
|
|
95
|
+
|
|
96
|
+
config.each do |klass, setting|
|
|
97
|
+
level, uri = self.parse_log_setting( setting )
|
|
98
|
+
|
|
99
|
+
# Use the Apache log as the outputter if none is configured
|
|
100
|
+
if uri.nil?
|
|
101
|
+
outputter = apacheoutputter
|
|
102
|
+
else
|
|
103
|
+
outputter = Arrow::Logger::Outputter.create( uri )
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
# The 'global' entry configures the global logger
|
|
107
|
+
if klass == :global
|
|
108
|
+
self.global.level = level
|
|
109
|
+
self.global.outputters << outputter
|
|
110
|
+
next
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
# If the class bit is something like 'applet', then transform
|
|
114
|
+
# it into 'Arrow::Applet'
|
|
115
|
+
if klass.to_s.match( /^[a-z][a-zA-Z]+$/ )
|
|
116
|
+
realclass = "Arrow::%s" % klass.to_s.sub(/^([a-z])/){ $1.upcase }
|
|
117
|
+
else
|
|
118
|
+
realclass = klass.to_s
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
Arrow::Logger[ realclass ].level = level
|
|
122
|
+
Arrow::Logger[ realclass ].outputters << outputter
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
end
|
|
126
|
+
|
|
127
|
+
|
|
128
|
+
### Parse the configuration for a given class's logger. The configuration
|
|
129
|
+
### is in the form:
|
|
130
|
+
### <level> [<outputter_uri>]
|
|
131
|
+
### where +level+ is one of the logging levels defined by this class (see
|
|
132
|
+
### the LEVELS constant), and the optional +outputter_uri+ indicates which
|
|
133
|
+
### outputter to use, and how it should be configured. See
|
|
134
|
+
### Arrow::Logger::Outputter for more info.
|
|
135
|
+
###
|
|
136
|
+
### Examples:
|
|
137
|
+
### notice
|
|
138
|
+
### debug file:///tmp/broker-debug.log
|
|
139
|
+
### error dbi://www:password@localhost/www.errorlog?driver=postgresql
|
|
140
|
+
###
|
|
141
|
+
def self::parse_log_setting( setting )
|
|
142
|
+
level, rawuri = setting.split( ' ', 2 )
|
|
143
|
+
uri = rawuri.nil? ? nil : URI.parse( rawuri )
|
|
144
|
+
|
|
145
|
+
return level.to_sym, uri
|
|
146
|
+
end
|
|
147
|
+
|
|
148
|
+
|
|
149
|
+
### Return the Arrow::Logger for the given module +mod+, which can be a
|
|
150
|
+
### Module object, a Symbol, or a String.
|
|
151
|
+
def self::[]( mod=nil )
|
|
152
|
+
return self.global if mod.nil?
|
|
153
|
+
|
|
154
|
+
case mod
|
|
155
|
+
when Module
|
|
156
|
+
return self.logger_map[ mod ]
|
|
157
|
+
|
|
158
|
+
# If it's a String, try to map it to a class name, falling back on the global
|
|
159
|
+
# logger if that fails
|
|
160
|
+
when String
|
|
161
|
+
mod = mod.split('::').
|
|
162
|
+
inject( Object ) {|k, modname| k.const_get(modname) } rescue Object
|
|
163
|
+
return self.logger_map[ mod ]
|
|
164
|
+
else
|
|
165
|
+
|
|
166
|
+
return self.logger_map[ mod.class ]
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
|
|
172
|
+
### Return the global Arrow logger, setting it up if it hasn't been
|
|
173
|
+
### already.
|
|
174
|
+
def self::global
|
|
175
|
+
self.logger_map[ Object ]
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
### Reset the logging subsystem. Clears out any registered loggers and
|
|
180
|
+
### their associated outputters.
|
|
181
|
+
def self::reset
|
|
182
|
+
self.logger_map.clear
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
|
|
186
|
+
### Autoload global logging methods for the log levels
|
|
187
|
+
def self::method_missing( sym, *args )
|
|
188
|
+
return super unless LEVELS.key?( sym )
|
|
189
|
+
|
|
190
|
+
self.global.debug( "Autoloading class log method '#{sym}'." )
|
|
191
|
+
(class << self; self; end).class_eval do
|
|
192
|
+
define_method( sym ) do |*args|
|
|
193
|
+
self.global.send( sym, *args )
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
self.global.send( sym, *args )
|
|
198
|
+
end
|
|
199
|
+
|
|
200
|
+
|
|
201
|
+
#############################################################
|
|
202
|
+
### I N S T A N C E M E T H O D S
|
|
203
|
+
#############################################################
|
|
204
|
+
|
|
205
|
+
### Create and return a new Arrow::Logger object for the given +mod+ (a Module object). If
|
|
206
|
+
### It will be configured at the given +level+. Any +outputters+ that are specified will be
|
|
207
|
+
### added.
|
|
208
|
+
def initialize( mod, level=:info, *outputters )
|
|
209
|
+
@module = mod
|
|
210
|
+
@outputters = outputters
|
|
211
|
+
@trace = false
|
|
212
|
+
@level = nil
|
|
213
|
+
|
|
214
|
+
# Cached Array of modules and classes between
|
|
215
|
+
# this logger's module and Object
|
|
216
|
+
@supermods = nil
|
|
217
|
+
|
|
218
|
+
# Level to force messages written to this logger to
|
|
219
|
+
@forced_level = nil
|
|
220
|
+
|
|
221
|
+
self.level = level
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
|
|
225
|
+
######
|
|
226
|
+
public
|
|
227
|
+
######
|
|
228
|
+
|
|
229
|
+
# The module this logger is associated with
|
|
230
|
+
attr_reader :module
|
|
231
|
+
|
|
232
|
+
# The outputters attached to this branch of the logger tree.
|
|
233
|
+
attr_accessor :outputters
|
|
234
|
+
|
|
235
|
+
# Set to a true value to turn tracing on
|
|
236
|
+
attr_accessor :trace
|
|
237
|
+
|
|
238
|
+
# The integer level of the logger.
|
|
239
|
+
attr_reader :level
|
|
240
|
+
|
|
241
|
+
# The level to force messages written to this logger to
|
|
242
|
+
attr_accessor :forced_level
|
|
243
|
+
|
|
244
|
+
|
|
245
|
+
### Return a human-readable string representation of the object.
|
|
246
|
+
def inspect
|
|
247
|
+
"#<%s:0x%0x %s [level: %s, outputters: %d, trace: %s]>" % [
|
|
248
|
+
self.class.name,
|
|
249
|
+
self.object_id * 2,
|
|
250
|
+
self.readable_name,
|
|
251
|
+
self.readable_level,
|
|
252
|
+
self.outputters.length,
|
|
253
|
+
self.trace ? "on" : "off",
|
|
254
|
+
]
|
|
255
|
+
end
|
|
256
|
+
|
|
257
|
+
|
|
258
|
+
### Return a (more-detailed) human-readable string representation of the object.
|
|
259
|
+
def inspect_details( level=0 )
|
|
260
|
+
indent = ' ' * (level + 1)
|
|
261
|
+
|
|
262
|
+
prelude = "<< %s [level: %s, trace: %s] >>" % [
|
|
263
|
+
self.readable_name,
|
|
264
|
+
self.readable_level,
|
|
265
|
+
self.trace ? "on" : "off",
|
|
266
|
+
]
|
|
267
|
+
|
|
268
|
+
details = []
|
|
269
|
+
unless self.outputters.empty?
|
|
270
|
+
details << "Outputters:" << self.outputters.map {|op| op.inspect }
|
|
271
|
+
end
|
|
272
|
+
details = details.flatten.compact.map {|line| indent + line }
|
|
273
|
+
|
|
274
|
+
if level.zero?
|
|
275
|
+
return [ prelude, *details ].join( "\n" )
|
|
276
|
+
else
|
|
277
|
+
return [ prelude, *details ]
|
|
278
|
+
end
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
### Return the name of the logger formatted to be suitable for reading.
|
|
283
|
+
def readable_name
|
|
284
|
+
return '(global)' if self.module == Object
|
|
285
|
+
return self.module.inspect if self.module.name == ''
|
|
286
|
+
return self.module.name
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
|
|
290
|
+
### Return the logger's level as a Symbol.
|
|
291
|
+
def readable_level
|
|
292
|
+
return LEVEL_NAMES[ @level ]
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
|
|
296
|
+
### Set the level of this logger to +level+. The +level+ can be a
|
|
297
|
+
### String, a Symbol, or an Integer.
|
|
298
|
+
def level=( level )
|
|
299
|
+
# debug_msg ">>> Setting log level for %s to %p" %
|
|
300
|
+
# [ self.name.empty? ? "[Global]" : self.name, level ]
|
|
301
|
+
|
|
302
|
+
case level
|
|
303
|
+
when String
|
|
304
|
+
@level = LEVELS[ level.to_sym ]
|
|
305
|
+
when Symbol
|
|
306
|
+
@level = LEVELS[ level ]
|
|
307
|
+
when Integer
|
|
308
|
+
@level = level
|
|
309
|
+
else
|
|
310
|
+
@level = nil
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
# If the level wasn't set correctly, raise an error after setting
|
|
314
|
+
# the level to something reasonable.
|
|
315
|
+
if @level.nil?
|
|
316
|
+
@level = LEVELS[ :notice ]
|
|
317
|
+
raise ArgumentError, "Illegal log level specification: %p for %s" %
|
|
318
|
+
[ level, self.name ]
|
|
319
|
+
end
|
|
320
|
+
end
|
|
321
|
+
|
|
322
|
+
|
|
323
|
+
### Return the Arrow::Logger for this instance's module's parent class if it's a Class,
|
|
324
|
+
### and the global logger otherwise.
|
|
325
|
+
def superlogger
|
|
326
|
+
if @module == Object
|
|
327
|
+
return nil
|
|
328
|
+
elsif @module.respond_to?( :superclass )
|
|
329
|
+
Arrow::Logger[ @module.superclass ]
|
|
330
|
+
else
|
|
331
|
+
Arrow::Logger.global
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
|
|
336
|
+
### Return the Array of modules and classes the receiver's module includes
|
|
337
|
+
### or inherits, inclusive of the receiver's module itself.
|
|
338
|
+
def supermods
|
|
339
|
+
unless @supermods
|
|
340
|
+
objflag = false
|
|
341
|
+
@supermods = self.module.ancestors.partition {|mod| objflag ||= (mod == Object) }.last
|
|
342
|
+
@supermods << Object
|
|
343
|
+
end
|
|
344
|
+
|
|
345
|
+
return @supermods
|
|
346
|
+
end
|
|
347
|
+
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
### Return a uniquified Array of the loggers which are more-generally related
|
|
351
|
+
### hierarchically to the receiver, inclusive, and whose level is +level+ or
|
|
352
|
+
### lower.
|
|
353
|
+
def hierloggers( level=:emerg )
|
|
354
|
+
level = LEVELS[ level ] if level.is_a?( Symbol )
|
|
355
|
+
|
|
356
|
+
loggers = []
|
|
357
|
+
self.supermods.each do |mod|
|
|
358
|
+
logger = self.class.logger_map[ mod ]
|
|
359
|
+
next unless logger.level <= level
|
|
360
|
+
|
|
361
|
+
loggers << logger
|
|
362
|
+
yield( logger ) if block_given?
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
return loggers
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
### Return a uniquified Array of all outputters for this logger and all of the
|
|
370
|
+
### loggers above it in the logging hierarchy that are set to +level+ or lower.
|
|
371
|
+
### If called with a block, it will be called once for each outputter and the first
|
|
372
|
+
### logger to which it is attached.
|
|
373
|
+
def hieroutputters( level=LEVELS[:emerg] )
|
|
374
|
+
outputters = []
|
|
375
|
+
|
|
376
|
+
# Look for loggers which are higher in the hierarchy
|
|
377
|
+
self.hierloggers( level ) do |logger|
|
|
378
|
+
outpary = logger.outputters || []
|
|
379
|
+
newoutpary = outpary - (outpary & outputters)
|
|
380
|
+
|
|
381
|
+
# If there are any outputters which haven't already been seen,
|
|
382
|
+
# output to them.
|
|
383
|
+
unless newoutpary.empty?
|
|
384
|
+
# debug_msg "hieroutputters: adding: %s" %
|
|
385
|
+
# newoutpary.collect {|outp| outp.description}.join(", ")
|
|
386
|
+
if block_given?
|
|
387
|
+
newoutpary.each {|outputter| yield(outputter, logger)}
|
|
388
|
+
end
|
|
389
|
+
outputters += newoutpary
|
|
390
|
+
end
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
return outputters
|
|
394
|
+
end
|
|
395
|
+
|
|
396
|
+
|
|
397
|
+
### Write the given +args+ to any connected outputters if +level+ is
|
|
398
|
+
### less than or equal to this logger's level.
|
|
399
|
+
def write( level, *args )
|
|
400
|
+
# debug_msg "Writing message at %p from %s: %p" % [ level, caller(2).first, args ]
|
|
401
|
+
|
|
402
|
+
msg, frame = nil, nil
|
|
403
|
+
time = Time.now
|
|
404
|
+
|
|
405
|
+
# If tracing is turned on, pick the first frame in the stack that
|
|
406
|
+
# isn't in this file, or the last one if that fails to yield one.
|
|
407
|
+
if @trace
|
|
408
|
+
frame = caller(1).find {|fr| fr !~ %r{arrow/logger\.rb} } ||
|
|
409
|
+
caller(1).last
|
|
410
|
+
end
|
|
411
|
+
|
|
412
|
+
level = @forced_level if @forced_level
|
|
413
|
+
|
|
414
|
+
# Find the outputters that need to be written to, then write to them.
|
|
415
|
+
self.hieroutputters( level ) do |outp, logger|
|
|
416
|
+
# debug_msg "Got outputter %p" % outp
|
|
417
|
+
msg ||= args.collect {|obj| self.stringify_object(obj) }.join
|
|
418
|
+
outp.write( time, level, self.readable_name, frame, msg )
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
|
|
423
|
+
### Append the given +obj+ to the logger at +:debug+ level. This is for
|
|
424
|
+
### compatibility with objects that append to $stderr for their logging
|
|
425
|
+
### (e.g., net/protocols-based libraries).
|
|
426
|
+
def <<( obj )
|
|
427
|
+
self.write( :debug, obj )
|
|
428
|
+
return self
|
|
429
|
+
end
|
|
430
|
+
|
|
431
|
+
|
|
432
|
+
#########
|
|
433
|
+
protected
|
|
434
|
+
#########
|
|
435
|
+
|
|
436
|
+
### Dump the given object for output in the log.
|
|
437
|
+
def stringify_object( obj )
|
|
438
|
+
return case obj
|
|
439
|
+
when Exception
|
|
440
|
+
"%s:\n %s" % [ obj.message, obj.backtrace.join("\n ") ]
|
|
441
|
+
when String
|
|
442
|
+
obj
|
|
443
|
+
else
|
|
444
|
+
obj.inspect
|
|
445
|
+
end
|
|
446
|
+
end
|
|
447
|
+
|
|
448
|
+
|
|
449
|
+
### Auto-install logging methods (ie., methods whose names match one of
|
|
450
|
+
### Arrow::Logger::LEVELS.
|
|
451
|
+
def method_missing( sym, *args )
|
|
452
|
+
name = sym.to_s
|
|
453
|
+
level = name[/\w+/].to_sym
|
|
454
|
+
return super unless Arrow::Logger::LEVELS.member?( level )
|
|
455
|
+
code = nil
|
|
456
|
+
|
|
457
|
+
case name
|
|
458
|
+
when /^\w+\?/
|
|
459
|
+
code = self.make_level_predicate_method( level )
|
|
460
|
+
|
|
461
|
+
when /^\w+$/
|
|
462
|
+
code = self.make_writer_method( level )
|
|
463
|
+
|
|
464
|
+
else
|
|
465
|
+
return super
|
|
466
|
+
end
|
|
467
|
+
|
|
468
|
+
self.class.send( :define_method, sym, &code )
|
|
469
|
+
return self.method( sym ).call( *args )
|
|
470
|
+
end
|
|
471
|
+
|
|
472
|
+
|
|
473
|
+
### Return a Proc suitable for installing as a predicate method for the given
|
|
474
|
+
### logging level.
|
|
475
|
+
def make_level_predicate_method( level )
|
|
476
|
+
numeric_level = LEVELS[level]
|
|
477
|
+
Proc.new { self.level < numeric_level }
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
|
|
481
|
+
### Return a Proc suitable for installing as a log-writing method for the given
|
|
482
|
+
### logging level.
|
|
483
|
+
def make_writer_method( level )
|
|
484
|
+
Proc.new {|*args| self.write(level, *args)}
|
|
485
|
+
end
|
|
486
|
+
|
|
487
|
+
end # class Arrow::Logger
|
|
488
|
+
|