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,117 @@
1
+ #!/usr/bin/ruby
2
+ #
3
+ # A manual filter to generate links from the page catalog.
4
+ #
5
+ # Authors:
6
+ # * Michael Granger <ged@FaerieMUD.org>
7
+ # * Mahlon E. Smith <mahlon@martini.nu>
8
+ #
9
+ #
10
+
11
+ ### Avoid declaring the class if the tasklib hasn't been loaded yet.
12
+ unless Object.const_defined?( :Manual )
13
+ raise LoadError, "not intended for standalone use: try the 'manual.rb' rake tasklib"
14
+ end
15
+
16
+
17
+
18
+ ### A filter for generating links from the page catalog. This allows you to refer to other pages
19
+ ### in the source and have them automatically updated as the structure of the manual changes.
20
+ ###
21
+ ### Links are XML processing instructions. Pages can be referenced in one of several ways:
22
+ ###
23
+ ### <?link Page Title ?>
24
+ ### <?link "click here":Page Title ?>
25
+ ### <?link Page Title #section_id ?>
26
+ ### <?link "click here":Page Title#section_id ?>
27
+ ###
28
+ ### This first form links to a page by title. Link text defaults to the page title unless an
29
+ ### optional quoted string is prepended. If you want to link to an anchor inside the page, include
30
+ ### its ID with a hash mark after the title.
31
+ ###
32
+ ### <?link path/to/Catalog.page ?>
33
+ ### <?link "click here":path/to/Catalog.page ?>
34
+ ### <?link path/to/Catalog.page#section_id ?>
35
+ ### <?link "click here":path/to/Catalog.page#section_id ?>
36
+ ###
37
+ ### The second form links to a page by its path relative to the base manual source directory.
38
+ ### Again, the link text defaults to the page title, or can be overriden via a prepended string,
39
+ ### and you can link into a page with an appended ID.
40
+ class LinksFilter < Manual::Page::Filter
41
+
42
+ # PI ::= '<?' PITarget (S (Char* - (Char* '?>' Char*)))? '?>'
43
+ LinkPI = %r{
44
+ <\?
45
+ link # Instruction Target
46
+ \s+
47
+ (?:"
48
+ (.*?) # Optional link text [$1]
49
+ ":)?
50
+ (.*?) # Title or path [$2]
51
+ \s*
52
+ (\#\w+)? # Fragment [$3]
53
+ \s+
54
+ \?>
55
+ }x
56
+
57
+
58
+ ######
59
+ public
60
+ ######
61
+
62
+ ### Process the given +source+ for <?link ... ?> processing-instructions, calling out
63
+ def process( source, page, metadata )
64
+ return source.gsub( LinkPI ) do |match|
65
+ # Grab the tag values
66
+ link_text = $1
67
+ reference = $2
68
+ fragment = $3
69
+
70
+ self.generate_link( page, reference, link_text, fragment )
71
+ end
72
+ end
73
+
74
+
75
+ ### Create an HTML link fragment from the parsed LinkPI.
76
+ def generate_link( current_page, reference, link_text=nil, fragment=nil )
77
+
78
+ if other_page = self.find_linked_page( current_page, reference )
79
+ href_path = other_page.sourcefile.relative_path_from( current_page.sourcefile.dirname )
80
+ href = href_path.to_s.gsub( '.page', '.html' )
81
+
82
+ if link_text
83
+ return %{<a href="#{href}#{fragment}">#{link_text}</a>}
84
+ else
85
+ return %{<a href="#{href}#{fragment}">#{other_page.title}</a>}
86
+ end
87
+ else
88
+ link_text ||= reference
89
+ error_message = "Could not find a link for reference '%s'" % [ reference ]
90
+ $stderr.puts( error_message )
91
+ return %{<a href="#" title="#{error_message}" class="broken-link">#{link_text}</a>}
92
+ end
93
+ end
94
+
95
+
96
+ ### Lookup a page +reference+ in the catalog. +reference+ can be either a
97
+ ### path to the .page file, relative to the manual root path, or a page title.
98
+ ### Returns a matching Page object, or nil if no match is found.
99
+ def find_linked_page( current_page, reference )
100
+
101
+ catalog = current_page.catalog
102
+
103
+ # Lookup by page path
104
+ if reference =~ /\.page$/
105
+ return catalog.uri_index[ reference ]
106
+
107
+ # Lookup by page title
108
+ else
109
+ return catalog.title_index[ reference ]
110
+ end
111
+ end
112
+ end
113
+
114
+
115
+
116
+
117
+
@@ -0,0 +1,448 @@
1
+ #
2
+ # Apache constants for testing, since the Apache module is really only loaded
3
+ # when mod_ruby.so is.
4
+ #
5
+
6
+ # :stopdoc:
7
+
8
+ require 'fileutils'
9
+ require 'uri'
10
+ require 'forwardable'
11
+
12
+ class Integer # :nodoc: all
13
+ def of
14
+ accum = []
15
+ self.times do |i|
16
+ accum << yield(i)
17
+ end
18
+ accum
19
+ end
20
+ end
21
+
22
+ module Apache # :nodoc: all
23
+
24
+ M_GET = 0
25
+ M_PUT = 1
26
+ M_POST = 2
27
+ M_DELETE = 3
28
+ M_CONNECT = 4
29
+ M_OPTIONS = 5
30
+ M_TRACE = 6
31
+ M_PATCH = 7
32
+ M_PROPFIND = 8
33
+ M_PROPPATCH = 9
34
+ M_MKCOL = 10
35
+ M_COPY = 11
36
+ M_MOVE = 12
37
+ M_LOCK = 13
38
+ M_UNLOCK = 14
39
+ M_INVALID = 26
40
+ METHODS = 64
41
+
42
+ METHOD_NUMBERS_TO_NAMES = {
43
+ M_CONNECT => 'CONNECT',
44
+ M_COPY => 'COPY',
45
+ M_DELETE => 'DELETE',
46
+ M_GET => 'GET',
47
+ M_INVALID => 'INVALID',
48
+ M_LOCK => 'LOCK',
49
+ M_MKCOL => 'MKCOL',
50
+ M_MOVE => 'MOVE',
51
+ M_OPTIONS => 'OPTIONS',
52
+ M_PATCH => 'PATCH',
53
+ M_POST => 'POST',
54
+ M_PROPFIND => 'PROFIND',
55
+ M_PROPPATCH => 'PROPATCH',
56
+ M_PUT => 'PUT',
57
+ M_TRACE => 'TRACE',
58
+ M_UNLOCK => 'UNLOCK',
59
+ }
60
+ METHOD_NAMES_TO_NUMBERS = METHOD_NUMBERS_TO_NAMES.invert
61
+
62
+ OPT_NONE = 0
63
+ OPT_INDEXES = 1
64
+ OPT_INCLUDES = 2
65
+ OPT_SYM_LINKS = 4
66
+ OPT_EXECCGI = 8
67
+ OPT_ALL = 15
68
+ OPT_UNSET = 16
69
+ OPT_INCNOEXEC = 32
70
+ OPT_SYM_OWNER = 64
71
+ OPT_MULTI = 128
72
+
73
+ SATISFY_ALL = 0
74
+ SATISFY_ANY = 1
75
+ SATISFY_NOSPEC = 2
76
+
77
+ REQUEST_NO_BODY = 0
78
+ REQUEST_CHUNKED_ERROR = 1
79
+ REQUEST_CHUNKED_DECHUNK = 2
80
+
81
+ REMOTE_HOST = 0
82
+ REMOTE_NAME = 1
83
+ REMOTE_NOLOOKUP = 2
84
+ REMOTE_DOUBLE_REV = 3
85
+
86
+ DONE = -2
87
+ DECLINED = -1
88
+ OK = 0
89
+
90
+ HTTP_CONTINUE = 100
91
+ HTTP_SWITCHING_PROTOCOLS = 101
92
+ HTTP_PROCESSING = 102
93
+
94
+ DOCUMENT_FOLLOWS = 200
95
+ HTTP_OK = 200
96
+ HTTP_CREATED = 201
97
+ HTTP_ACCEPTED = 202
98
+ HTTP_NON_AUTHORITATIVE = 203
99
+ HTTP_NO_CONTENT = 204
100
+ HTTP_RESET_CONTENT = 205
101
+ HTTP_PARTIAL_CONTENT = 206
102
+ PARTIAL_CONTENT = 206
103
+ HTTP_MULTI_STATUS = 207
104
+
105
+ HTTP_MULTIPLE_CHOICES = 300
106
+ MULTIPLE_CHOICES = 300
107
+ HTTP_MOVED_PERMANENTLY = 301
108
+ MOVED = 301
109
+ HTTP_MOVED_TEMPORARILY = 302
110
+ REDIRECT = 302
111
+ HTTP_SEE_OTHER = 303
112
+ HTTP_NOT_MODIFIED = 304
113
+ USE_LOCAL_COPY = 304
114
+ HTTP_USE_PROXY = 305
115
+ HTTP_TEMPORARY_REDIRECT = 307
116
+
117
+ BAD_REQUEST = 400
118
+ HTTP_BAD_REQUEST = 400
119
+ AUTH_REQUIRED = 401
120
+ HTTP_UNAUTHORIZED = 401
121
+ HTTP_PAYMENT_REQUIRED = 402
122
+ FORBIDDEN = 403
123
+ HTTP_FORBIDDEN = 403
124
+ HTTP_NOT_FOUND = 404
125
+ NOT_FOUND = 404
126
+ HTTP_METHOD_NOT_ALLOWED = 405
127
+ METHOD_NOT_ALLOWED = 405
128
+ HTTP_NOT_ACCEPTABLE = 406
129
+ NOT_ACCEPTABLE = 406
130
+ HTTP_PROXY_AUTHENTICATION_REQUIRED = 407
131
+ HTTP_REQUEST_TIME_OUT = 408
132
+ HTTP_CONFLICT = 409
133
+ HTTP_GONE = 410
134
+ HTTP_LENGTH_REQUIRED = 411
135
+ LENGTH_REQUIRED = 411
136
+ HTTP_PRECONDITION_FAILED = 412
137
+ PRECONDITION_FAILED = 412
138
+ HTTP_REQUEST_ENTITY_TOO_LARGE = 413
139
+ HTTP_REQUEST_URI_TOO_LARGE = 414
140
+ HTTP_UNSUPPORTED_MEDIA_TYPE = 415
141
+ HTTP_RANGE_NOT_SATISFIABLE = 416
142
+ HTTP_EXPECTATION_FAILED = 417
143
+ HTTP_UNPROCESSABLE_ENTITY = 422
144
+ HTTP_LOCKED = 423
145
+ HTTP_FAILED_DEPENDENCY = 424
146
+
147
+ HTTP_INTERNAL_SERVER_ERROR = 500
148
+ SERVER_ERROR = 500
149
+ HTTP_NOT_IMPLEMENTED = 501
150
+ NOT_IMPLEMENTED = 501
151
+ BAD_GATEWAY = 502
152
+ HTTP_BAD_GATEWAY = 502
153
+ HTTP_SERVICE_UNAVAILABLE = 503
154
+ HTTP_GATEWAY_TIME_OUT = 504
155
+ HTTP_VERSION_NOT_SUPPORTED = 505
156
+ HTTP_VARIANT_ALSO_VARIES = 506
157
+ VARIANT_ALSO_VARIES = 506
158
+ HTTP_INSUFFICIENT_STORAGE = 507
159
+ HTTP_NOT_EXTENDED = 510
160
+
161
+
162
+
163
+ # Simulate Apache::Table
164
+ class Table
165
+ extend Forwardable
166
+ def initialize( hash={} )
167
+ hash.each {|k,v| hash[k.downcase] = v}
168
+ @hash = hash
169
+ end
170
+
171
+ def_delegators :@hash, :clear, :each, :each_key, :each_value
172
+
173
+ def []( key )
174
+ @hash[ key.downcase ]
175
+ end
176
+ alias_method :get, :[]
177
+
178
+ def []=( key, val )
179
+ @hash[ key.downcase ] = val
180
+ end
181
+ alias_method :set, :[]=
182
+
183
+ def key?( key )
184
+ @hash.key?( key.downcase )
185
+ end
186
+
187
+ def merge( key, val )
188
+ key = key.downcase
189
+ @hash[key] = [@hash[key]] unless @hash[key].is_a?( Array )
190
+ @hash[key] << val
191
+ end
192
+ end
193
+
194
+
195
+ ### Dummy mod_ruby object base class
196
+ class ModRubySimObject
197
+ @derivatives = {}
198
+ class << self
199
+ attr_reader :derivatives
200
+ end
201
+
202
+ def self::inherited( mod )
203
+ @derivatives[ mod ] = caller( 1 ).first.split(/:/)
204
+ $stderr.puts "Registering simulated %s at %p" %
205
+ [ mod.name, @derivatives[mod] ] if $DEBUG
206
+ super
207
+ end
208
+
209
+
210
+ #######
211
+ private
212
+ #######
213
+
214
+ def generate_method( name, argcount )
215
+ return %q{def %s( %s ); end} % [ name, argcount.of {|i| "arg#{i}"}.join(", ") ]
216
+ end
217
+
218
+ def install_method( file, line, code )
219
+ $stderr.puts "Installing method at line %d in %s" % [ line, file ]
220
+ lines = File.readlines( file )
221
+ tmpfile = "#{file}.#{Process.pid}"
222
+ File.open( tmpfile, File::WRONLY|File::CREAT|File::EXCL ) do |fh|
223
+ fh.puts( lines[0 .. line - 1] )
224
+ fh.puts( code )
225
+ fh.puts( lines[line .. -1] )
226
+ end
227
+
228
+ FileUtils.mv( tmpfile, file )
229
+ end
230
+
231
+
232
+ ### Handle missing methods by auto-generating method definitions
233
+ def method_missing( sym, *args )
234
+ if (( source = Apache::ModRubySimObject.derivatives[ self.class ] ))
235
+ sourcefile = source[0]
236
+ sourceline = Integer( source[1] )
237
+
238
+ $stderr.puts "call to missing method %s" % [ sym ]
239
+
240
+ code = generate_method( sym, args.length )
241
+ install_method( sourcefile, sourceline, code )
242
+
243
+ eval( code )
244
+ self.__send__( sym, *args )
245
+ else
246
+ super
247
+ end
248
+ end
249
+
250
+ end
251
+
252
+ ###############
253
+ module_function
254
+ ###############
255
+
256
+ # Add a token to Apache's version string.
257
+ def add_version_component( *args )
258
+ end
259
+
260
+ # Change the server's current working directory to the directory part of the specified filename.
261
+ def chdir_file( str )
262
+ str = File.dirname( str ) if ! File.directory?( str )
263
+ Dir.chdir( str )
264
+ end
265
+
266
+ # Returns the current Apache::Request object.
267
+ def request
268
+ Apache::Request.new
269
+ end
270
+
271
+ # Returns the server's root directory (ie., the one set by the ServerRoot directive).
272
+ def server_root
273
+ Dir.pwd
274
+ end
275
+
276
+ # Returns the server built date string.
277
+ def server_built
278
+ return "Mar 20 2006 14:30:49"
279
+ end
280
+
281
+ # Returns the server version string.
282
+ def server_version
283
+ return "Apache/2.2.0 (Unix) mod_ruby/1.2.5 Ruby/1.8.4(2005-12-24)"
284
+ end
285
+
286
+ # Decodes a URL-encoded string.
287
+ def unescape_url( str )
288
+ return URI.unescape( str )
289
+ end
290
+
291
+
292
+ # Apache::Request
293
+ class Request < ModRubySimObject
294
+
295
+ INSTANCE_METHODS = %w{
296
+ << add_cgi_vars add_common_vars all_params allow_options
297
+ allow_overrides allowed allowed= args args= attributes auth_name
298
+ auth_name= auth_type auth_type= binmode bytes_sent cache_resp
299
+ cache_resp= cancel connection construct_url content_encoding
300
+ content_encoding= content_languages content_languages=
301
+ content_length content_type content_type= cookies cookies=
302
+ custom_response default_charset default_type disable_uploads=
303
+ disable_uploads? dispatch_handler dispatch_handler= eof eof?
304
+ err_headers_out error_message escape_html exception filename
305
+ filename= finfo get_basic_auth_pw get_client_block getc
306
+ hard_timeout header_only? headers_in headers_out hostname
307
+ initial? internal_redirect kill_timeout last log_reason
308
+ lookup_file lookup_uri main main? method_number next
309
+ note_auth_failure note_basic_auth_failure
310
+ note_digest_auth_failure notes options output_buffer param
311
+ params params_as_string paramtable parse path_info path_info=
312
+ post_max post_max= prev print printf protocol proxy? proxy_pass?
313
+ putc puts read register_cleanup remote_host remote_logname
314
+ replace request_method request_time requires reset_timeout
315
+ satisfies script_name script_path send_fd send_http_header
316
+ sent_http_header? server server_name server_port setup_cgi_env
317
+ setup_client_block should_client_block should_client_block?
318
+ signature soft_timeout status status= status_line status_line=
319
+ subprocess_env sync= sync_header sync_header= sync_output
320
+ sync_output= temp_dir temp_dir= the_request unparsed_uri
321
+ upload_hook upload_hook= upload_hook_data upload_hook_data=
322
+ uploads uploads_disabled? uri uri= user user= write
323
+ }
324
+
325
+ def self::instance_methods( include_superclass=true )
326
+ return INSTANCE_METHODS
327
+ end
328
+
329
+
330
+ def initialize( uri=nil )
331
+ @uri = uri
332
+ @server = nil
333
+ @allowed = Apache::M_GET | Apache::M_POST
334
+ @paramtable = {}
335
+ @sync_header = false
336
+ @content_type = 'text/html'
337
+ @hostname = 'localhost'
338
+ @path_info = ''
339
+ @headers_in = Apache::Table.new
340
+ @headers_out = Apache::Table.new
341
+ @options = {}
342
+ @uploads = {}
343
+ @method_number = Apache::M_GET
344
+ @connection = Apache::Connection.new
345
+ end
346
+
347
+ attr_writer :server
348
+ attr_accessor :allowed, :sync_header, :content_type, :uri,
349
+ :hostname, :paramtable, :cookies, :options, :uploads,
350
+ :path_info, :headers_in, :headers_out, :method_number,
351
+ :connection
352
+ alias_method :params, :paramtable
353
+ alias_method :unparsed_uri, :uri
354
+
355
+ def paramtable=( hash )
356
+ # :TODO: Munge the hash into an Apache::Table object
357
+ @paramtable = @params = hash.stringify_keys
358
+ end
359
+ alias_method :params=, :paramtable=
360
+
361
+ def param( key )
362
+ @paramtable[ key ]
363
+ end
364
+
365
+ def cookies=( hash )
366
+ # :TODO: Munge the hash into a hash of Apache::Cookie objects
367
+ @cookies = hash
368
+ end
369
+
370
+ def server
371
+ @server ||= Apache::Server.new
372
+ end
373
+
374
+ def request_method
375
+ return Apache::METHOD_NUMBERS_TO_NAMES[ @method_number ]
376
+ end
377
+
378
+ def request_method=( methodname )
379
+ @method_number = Apache::METHOD_NAMES_TO_NUMBERS[ methodname ] or
380
+ raise "No such HTTP method '%s'" % [methodname]
381
+ end
382
+
383
+ def remote_host( lookup=nil )
384
+ return '127.0.0.1'
385
+ end
386
+
387
+ def the_request
388
+ return 'GET / HTTP/1.1'
389
+ end
390
+
391
+ def status
392
+ return Apache::OK
393
+ end
394
+
395
+ end
396
+
397
+ class Server < ModRubySimObject
398
+ def initialize
399
+ @loglevel = 99 # No logging by default
400
+ end
401
+
402
+ attr_accessor :loglevel
403
+
404
+ def hostname
405
+ "localhost"
406
+ end
407
+
408
+ # Auto-generate log_* methods
409
+ [
410
+ :debug,
411
+ :info,
412
+ :notice,
413
+ :warn,
414
+ :error,
415
+ :crit,
416
+ :alert,
417
+ :emerg,
418
+ ].each do |sym|
419
+ define_method( "log_#{sym}" ) {|msg|
420
+ $stderr.puts "#{sym.to_s.upcase}: #{msg}" if $DEBUG
421
+ }
422
+ end
423
+
424
+ def admin
425
+ "jrandomhacker@localhost"
426
+ end
427
+ end
428
+
429
+ class Connection < ModRubySimObject
430
+ def remote_host
431
+ return '127.0.0.1'
432
+ end
433
+ end
434
+
435
+ class Cookie < ModRubySimObject
436
+ end
437
+
438
+ class MultiVal < ModRubySimObject
439
+ end
440
+
441
+ class Upload < ModRubySimObject
442
+ end
443
+
444
+ class ParamTable < ModRubySimObject
445
+ end
446
+
447
+ end
448
+