hobix 0.4
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.
- checksums.yaml +7 -0
- data/bin/hobix +90 -0
- data/lib/hobix/api.rb +91 -0
- data/lib/hobix/article.rb +22 -0
- data/lib/hobix/base.rb +477 -0
- data/lib/hobix/bixwik.rb +200 -0
- data/lib/hobix/commandline.rb +661 -0
- data/lib/hobix/comments.rb +99 -0
- data/lib/hobix/config.rb +39 -0
- data/lib/hobix/datamarsh.rb +110 -0
- data/lib/hobix/entry.rb +83 -0
- data/lib/hobix/facets/comments.rb +74 -0
- data/lib/hobix/facets/publisher.rb +314 -0
- data/lib/hobix/facets/trackbacks.rb +80 -0
- data/lib/hobix/linklist.rb +76 -0
- data/lib/hobix/out/atom.rb +92 -0
- data/lib/hobix/out/erb.rb +64 -0
- data/lib/hobix/out/okaynews.rb +55 -0
- data/lib/hobix/out/quick.rb +312 -0
- data/lib/hobix/out/rdf.rb +97 -0
- data/lib/hobix/out/redrum.rb +26 -0
- data/lib/hobix/out/rss.rb +115 -0
- data/lib/hobix/plugin/bloglines.rb +73 -0
- data/lib/hobix/plugin/calendar.rb +220 -0
- data/lib/hobix/plugin/flickr.rb +110 -0
- data/lib/hobix/plugin/recent_comments.rb +82 -0
- data/lib/hobix/plugin/sections.rb +91 -0
- data/lib/hobix/plugin/tags.rb +60 -0
- data/lib/hobix/publish/ping.rb +53 -0
- data/lib/hobix/publish/replicate.rb +283 -0
- data/lib/hobix/publisher.rb +18 -0
- data/lib/hobix/search/dictionary.rb +141 -0
- data/lib/hobix/search/porter_stemmer.rb +203 -0
- data/lib/hobix/search/simple.rb +209 -0
- data/lib/hobix/search/vector.rb +100 -0
- data/lib/hobix/storage/filesys.rb +398 -0
- data/lib/hobix/trackbacks.rb +94 -0
- data/lib/hobix/util/objedit.rb +193 -0
- data/lib/hobix/util/patcher.rb +155 -0
- data/lib/hobix/webapp/cli.rb +195 -0
- data/lib/hobix/webapp/htmlform.rb +107 -0
- data/lib/hobix/webapp/message.rb +177 -0
- data/lib/hobix/webapp/urigen.rb +141 -0
- data/lib/hobix/webapp/webrick-servlet.rb +90 -0
- data/lib/hobix/webapp.rb +723 -0
- data/lib/hobix/weblog.rb +860 -0
- data/lib/hobix.rb +223 -0
- metadata +87 -0
@@ -0,0 +1,107 @@
|
|
1
|
+
module Hobix
|
2
|
+
class WebApp
|
3
|
+
class QueryString
|
4
|
+
# decode self as application/x-www-form-urlencoded and returns
|
5
|
+
# HTMLFormQuery object.
|
6
|
+
def decode_as_application_x_www_form_urlencoded
|
7
|
+
# xxx: warning if invalid?
|
8
|
+
pairs = []
|
9
|
+
@escaped_query_string.scan(/([^&;=]*)=([^&;]*)/) {|key, val|
|
10
|
+
key.gsub!(/\+/, ' ')
|
11
|
+
key.gsub!(/%([0-9A-F][0-9A-F])/i) { [$1].pack("H*") }
|
12
|
+
val.gsub!(/\+/, ' ')
|
13
|
+
val.gsub!(/%([0-9A-F][0-9A-F])/i) { [$1].pack("H*") }
|
14
|
+
pairs << [key.freeze, val.freeze]
|
15
|
+
}
|
16
|
+
HTMLFormQuery.new(pairs)
|
17
|
+
end
|
18
|
+
# decode self as multipart/form-data and returns
|
19
|
+
# HTMLFormQuery object.
|
20
|
+
def decode_as_multipart_form_data( boundary )
|
21
|
+
# xxx: warning if invalid?
|
22
|
+
require 'tempfile'
|
23
|
+
pairs = []
|
24
|
+
boundary = "--" + boundary
|
25
|
+
eol = "\015\012"
|
26
|
+
str = @escaped_query_string.gsub( /(?:\r?\n|\A)#{ Regexp::quote( boundary ) }--#{ eol }.*/m, '' )
|
27
|
+
str.split( /(?:\r?\n|\A)#{ Regexp::quote( boundary ) }#{ eol }/m ).each do |part|
|
28
|
+
headers = {}
|
29
|
+
header, value = part.split( "#{eol}#{eol}", 2 )
|
30
|
+
next unless header and value
|
31
|
+
field_name, field_data = nil, {}
|
32
|
+
if header =~ /Content-Disposition: form-data;.*(?:\sname="([^"]+)")/m
|
33
|
+
field_name = $1
|
34
|
+
end
|
35
|
+
if header =~ /Content-Disposition: form-data;.*(?:\sfilename="([^"]+)")/m
|
36
|
+
body = Tempfile.new( "WebApp" )
|
37
|
+
body.binmode if defined? body.binmode
|
38
|
+
body.print value
|
39
|
+
body.rewind
|
40
|
+
field_data = {'filename' => $1, 'tempfile' => body}
|
41
|
+
field_data['type'] = $1 if header =~ /Content-Type: (.+?)(?:#{ eol }|\Z)/m
|
42
|
+
else
|
43
|
+
field_data = value.gsub( /#{ eol }\Z/, '' )
|
44
|
+
end
|
45
|
+
pairs << [field_name, field_data]
|
46
|
+
end
|
47
|
+
HTMLFormQuery.new(pairs)
|
48
|
+
end
|
49
|
+
end
|
50
|
+
|
51
|
+
# HTMLFormQuery represents a query submitted by HTML form.
|
52
|
+
class HTMLFormQuery
|
53
|
+
|
54
|
+
def HTMLFormQuery.each_string_key_pair(arg, &block) # :nodoc:
|
55
|
+
if arg.respond_to? :to_ary
|
56
|
+
arg = arg.to_ary
|
57
|
+
if arg.length == 2 && arg.first.respond_to?(:to_str)
|
58
|
+
yield WebApp.make_frozen_string(arg.first), arg.last
|
59
|
+
else
|
60
|
+
arg.each {|elt|
|
61
|
+
HTMLFormQuery.each_string_key_pair(elt, &block)
|
62
|
+
}
|
63
|
+
end
|
64
|
+
elsif arg.respond_to? :to_pair
|
65
|
+
arg.each_pair {|key, val|
|
66
|
+
yield WebApp.make_frozen_string(key), val
|
67
|
+
}
|
68
|
+
else
|
69
|
+
raise ArgumentError, "non-pairs argument: #{arg.inspect}"
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
def initialize(*args)
|
74
|
+
@param = []
|
75
|
+
HTMLFormQuery.each_string_key_pair(args) {|key, val|
|
76
|
+
@param << [key, val]
|
77
|
+
}
|
78
|
+
@param.freeze
|
79
|
+
end
|
80
|
+
|
81
|
+
def each
|
82
|
+
@param.each {|key, val|
|
83
|
+
yield key.dup, val.dup
|
84
|
+
}
|
85
|
+
end
|
86
|
+
|
87
|
+
def [](key)
|
88
|
+
if pair = @param.assoc(key)
|
89
|
+
return pair.last.dup
|
90
|
+
end
|
91
|
+
return nil
|
92
|
+
end
|
93
|
+
|
94
|
+
def lookup_all(key)
|
95
|
+
result = []
|
96
|
+
@param.each {|k, val|
|
97
|
+
result << val if k == key
|
98
|
+
}
|
99
|
+
return result
|
100
|
+
end
|
101
|
+
|
102
|
+
def keys
|
103
|
+
@param.map {|key, val| key }.uniq
|
104
|
+
end
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
@@ -0,0 +1,177 @@
|
|
1
|
+
module Hobix
|
2
|
+
class WebApp
|
3
|
+
# :stopdoc:
|
4
|
+
class Header
|
5
|
+
def Header.capitalize_field_name(field_name)
|
6
|
+
field_name.gsub(/[A-Za-z]+/) {|s| s.capitalize }
|
7
|
+
end
|
8
|
+
|
9
|
+
def initialize
|
10
|
+
@fields = []
|
11
|
+
end
|
12
|
+
|
13
|
+
def freeze
|
14
|
+
@fields.freeze
|
15
|
+
super
|
16
|
+
end
|
17
|
+
|
18
|
+
def dup
|
19
|
+
result = Header.new
|
20
|
+
@fields.each {|_, k, v|
|
21
|
+
result.add(k, v)
|
22
|
+
}
|
23
|
+
result
|
24
|
+
end
|
25
|
+
|
26
|
+
def clear
|
27
|
+
@fields.clear
|
28
|
+
end
|
29
|
+
|
30
|
+
def remove(field_name)
|
31
|
+
k1 = field_name.downcase
|
32
|
+
@fields.reject! {|k2, _, _| k1 == k2 }
|
33
|
+
nil
|
34
|
+
end
|
35
|
+
|
36
|
+
def add(field_name, field_body)
|
37
|
+
field_name = WebApp.make_frozen_string(field_name)
|
38
|
+
field_body = WebApp.make_frozen_string(field_body)
|
39
|
+
@fields << [field_name.downcase.freeze, field_name, field_body]
|
40
|
+
end
|
41
|
+
|
42
|
+
def set(field_name, field_body)
|
43
|
+
field_name = WebApp.make_frozen_string(field_name)
|
44
|
+
remove(field_name)
|
45
|
+
add(field_name, field_body)
|
46
|
+
end
|
47
|
+
|
48
|
+
def has?(field_name)
|
49
|
+
@fields.assoc(field_name.downcase) != nil
|
50
|
+
end
|
51
|
+
|
52
|
+
def [](field_name)
|
53
|
+
k1 = field_name.downcase
|
54
|
+
@fields.each {|k2, field_name, field_body|
|
55
|
+
return field_body.dup if k1 == k2
|
56
|
+
}
|
57
|
+
nil
|
58
|
+
end
|
59
|
+
|
60
|
+
def lookup_all(field_name)
|
61
|
+
k1 = field_name.downcase
|
62
|
+
result = []
|
63
|
+
@fields.each {|k2, field_name, field_body|
|
64
|
+
result << field_body.dup if k1 == k2
|
65
|
+
}
|
66
|
+
result
|
67
|
+
end
|
68
|
+
|
69
|
+
def each
|
70
|
+
@fields.each {|_, field_name, field_body|
|
71
|
+
field_name = field_name.dup
|
72
|
+
field_body = field_body.dup
|
73
|
+
yield field_name, field_body
|
74
|
+
}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
class Message
|
79
|
+
def initialize(header={}, body='')
|
80
|
+
@header_object = Header.new
|
81
|
+
case header
|
82
|
+
when Hash
|
83
|
+
header.each_pair {|k, v|
|
84
|
+
raise ArgumentError, "unexpected header field name: #{k.inspect}" unless k.respond_to? :to_str
|
85
|
+
raise ArgumentError, "unexpected header field body: #{v.inspect}" unless v.respond_to? :to_str
|
86
|
+
@header_object.add k.to_str, v.to_str
|
87
|
+
}
|
88
|
+
when Array
|
89
|
+
header.each {|k, v|
|
90
|
+
raise ArgumentError, "unexpected header field name: #{k.inspect}" unless k.respond_to? :to_str
|
91
|
+
raise ArgumentError, "unexpected header field body: #{v.inspect}" unless v.respond_to? :to_str
|
92
|
+
@header_object.add k.to_str, v.to_str
|
93
|
+
}
|
94
|
+
else
|
95
|
+
raise ArgumentError, "unexpected header argument: #{header.inspect}"
|
96
|
+
end
|
97
|
+
raise ArgumentError, "unexpected body: #{body.inspect}" unless body.respond_to? :to_str
|
98
|
+
@body_object = StringIO.new(body.to_str)
|
99
|
+
end
|
100
|
+
attr_reader :header_object, :body_object
|
101
|
+
|
102
|
+
def freeze
|
103
|
+
@header_object.freeze
|
104
|
+
@body_object.string.freeze
|
105
|
+
super
|
106
|
+
end
|
107
|
+
|
108
|
+
def output_header(out)
|
109
|
+
@header_object.each {|k, v|
|
110
|
+
out << "#{k}: #{v}\n"
|
111
|
+
}
|
112
|
+
end
|
113
|
+
|
114
|
+
def output_body(out)
|
115
|
+
out << @body_object.string
|
116
|
+
end
|
117
|
+
|
118
|
+
def output_message(out)
|
119
|
+
output_header(out)
|
120
|
+
out << "\n"
|
121
|
+
output_body(out)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
class Request < Message
|
126
|
+
def initialize(request_line=nil, header={}, body='')
|
127
|
+
@request_line = request_line
|
128
|
+
super header, body
|
129
|
+
end
|
130
|
+
attr_reader :request_method,
|
131
|
+
:server_name, :server_port,
|
132
|
+
:script_name, :path_info,
|
133
|
+
:query_string,
|
134
|
+
:server_protocol,
|
135
|
+
:remote_addr, :content_type, :request_uri, :action_uri
|
136
|
+
|
137
|
+
def make_request_header_from_cgi_env(env)
|
138
|
+
env.each {|k, v|
|
139
|
+
next if /\AHTTP_/ !~ k
|
140
|
+
k = Header.capitalize_field_name($')
|
141
|
+
k.gsub!(/_/, '-')
|
142
|
+
@header_object.add k, v
|
143
|
+
}
|
144
|
+
@request_method = env['REQUEST_METHOD']
|
145
|
+
@server_name = ( env['SERVER_NAME'] || '' ).gsub( /\:\d+$/, '' ) # lighttpd affixes port!!
|
146
|
+
@server_port = env['SERVER_PORT'].to_i
|
147
|
+
@script_name = env['SCRIPT_NAME'] || ''
|
148
|
+
@path_info = env['PATH_INFO'] || ''
|
149
|
+
@query_string = QueryString.primitive_new_for_raw_query_string(env['QUERY_STRING'] || '')
|
150
|
+
@server_protocol = env['SERVER_PROTOCOL'] || ''
|
151
|
+
@remote_addr = env['REMOTE_ADDR'] || ''
|
152
|
+
@content_type = env['CONTENT_TYPE'] || ''
|
153
|
+
|
154
|
+
# non-standard:
|
155
|
+
@request_uri = env['REQUEST_URI'] # Apache
|
156
|
+
|
157
|
+
# hobix action uri
|
158
|
+
@action_uri = ( env['PATH_INFO'] || env['REQUEST_URI'] ).
|
159
|
+
gsub( /^(#{ Regexp::quote( File::dirname( @script_name ) ) })?\/*/, '' ).
|
160
|
+
gsub( /\?.+$/, '' )
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
class Response < Message
|
165
|
+
def initialize(status_line='200 OK', header={}, body='')
|
166
|
+
@status_line = status_line
|
167
|
+
super header, body
|
168
|
+
end
|
169
|
+
attr_accessor :status_line
|
170
|
+
|
171
|
+
def output_cgi_status_field(out)
|
172
|
+
out << "Status: #{self.status_line}\n"
|
173
|
+
end
|
174
|
+
end
|
175
|
+
# :startdoc:
|
176
|
+
end
|
177
|
+
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Hobix
|
4
|
+
class WebApp
|
5
|
+
# :stopdoc:
|
6
|
+
class URIGen
|
7
|
+
def initialize(scheme, server_name, server_port, script_name, path_info)
|
8
|
+
@scheme = scheme
|
9
|
+
@server_name = server_name
|
10
|
+
@server_port = server_port
|
11
|
+
@script_name = script_name
|
12
|
+
@path_info = path_info
|
13
|
+
uri = "#{scheme}://#{server_name}:#{server_port}"
|
14
|
+
uri << script_name.gsub(%r{[^/]+}) {|segment| pchar_escape(segment) }
|
15
|
+
uri << path_info.gsub(%r{[^/]+}) {|segment| pchar_escape(segment) }
|
16
|
+
@base_uri = URI.parse(uri)
|
17
|
+
end
|
18
|
+
attr_reader :base_uri
|
19
|
+
|
20
|
+
def make_relative_uri(hash)
|
21
|
+
script = nil
|
22
|
+
path_info = nil
|
23
|
+
query = nil
|
24
|
+
fragment = nil
|
25
|
+
hash.each_pair {|k,v|
|
26
|
+
case k
|
27
|
+
when :script then script = v
|
28
|
+
when :path_info then path_info = v
|
29
|
+
when :query then query = v
|
30
|
+
when :fragment then fragment = v
|
31
|
+
else
|
32
|
+
raise ArgumentError, "unexpected: #{k} => #{v}"
|
33
|
+
end
|
34
|
+
}
|
35
|
+
|
36
|
+
if !script
|
37
|
+
script = @script_name
|
38
|
+
elsif %r{\A/} !~ script
|
39
|
+
script = @script_name.sub(%r{[^/]*\z}) { script }
|
40
|
+
while script.sub!(%r{/[^/]*/\.\.(?=/|\z)}, '')
|
41
|
+
end
|
42
|
+
script.sub!(%r{\A/\.\.(?=/|\z)}, '')
|
43
|
+
end
|
44
|
+
|
45
|
+
path_info = '/' + path_info if %r{\A[^/]} =~ path_info
|
46
|
+
|
47
|
+
dst = "#{script}#{path_info}"
|
48
|
+
dst.sub!(%r{\A/}, '')
|
49
|
+
dst.sub!(%r{[^/]*\z}, '')
|
50
|
+
dst_basename = $&
|
51
|
+
|
52
|
+
src = "#{@script_name}#{@path_info}"
|
53
|
+
src.sub!(%r{\A/}, '')
|
54
|
+
src.sub!(%r{[^/]*\z}, '')
|
55
|
+
|
56
|
+
while src[%r{\A[^/]*/}] == dst[%r{\A[^/]*/}]
|
57
|
+
if $~
|
58
|
+
src.sub!(%r{\A[^/]*/}, '')
|
59
|
+
dst.sub!(%r{\A[^/]*/}, '')
|
60
|
+
else
|
61
|
+
break
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
rel_path = '../' * src.count('/')
|
66
|
+
rel_path << dst << dst_basename
|
67
|
+
rel_path = './' if rel_path.empty?
|
68
|
+
|
69
|
+
rel_path.gsub!(%r{[^/]+}) {|segment| pchar_escape(segment) }
|
70
|
+
if /\A[A-Za-z][A-Za-z0-9+\-.]*:/ =~ rel_path # It seems absolute URI.
|
71
|
+
rel_path.sub!(/:/, '%3A')
|
72
|
+
end
|
73
|
+
|
74
|
+
if query
|
75
|
+
case query
|
76
|
+
when QueryString
|
77
|
+
query = query.instance_eval { @escaped_query_string }
|
78
|
+
when Hash
|
79
|
+
query = query.map {|k, v|
|
80
|
+
case v
|
81
|
+
when String
|
82
|
+
"#{form_escape(k)}=#{form_escape(v)}"
|
83
|
+
when Array
|
84
|
+
v.map {|e|
|
85
|
+
unless String === e
|
86
|
+
raise ArgumentError, "unexpected query value: #{e.inspect}"
|
87
|
+
end
|
88
|
+
"#{form_escape(k)}=#{form_escape(e)}"
|
89
|
+
}
|
90
|
+
else
|
91
|
+
raise ArgumentError, "unexpected query value: #{v.inspect}"
|
92
|
+
end
|
93
|
+
}.join(';')
|
94
|
+
else
|
95
|
+
raise ArgumentError, "unexpected query: #{query.inspect}"
|
96
|
+
end
|
97
|
+
unless query.empty?
|
98
|
+
query = '?' + uric_escape(query)
|
99
|
+
end
|
100
|
+
else
|
101
|
+
query = ''
|
102
|
+
end
|
103
|
+
|
104
|
+
if fragment
|
105
|
+
fragment = "#" + uric_escape(fragment)
|
106
|
+
else
|
107
|
+
fragment = ''
|
108
|
+
end
|
109
|
+
|
110
|
+
URI.parse(rel_path + query + fragment)
|
111
|
+
end
|
112
|
+
|
113
|
+
def make_absolute_uri(hash)
|
114
|
+
@base_uri + make_relative_uri(hash)
|
115
|
+
end
|
116
|
+
|
117
|
+
Alpha = 'a-zA-Z'
|
118
|
+
Digit = '0-9'
|
119
|
+
AlphaNum = Alpha + Digit
|
120
|
+
Mark = '\-_.!~*\'()'
|
121
|
+
Unreserved = AlphaNum + Mark
|
122
|
+
PChar = Unreserved + ':@&=+$,'
|
123
|
+
def pchar_escape(s)
|
124
|
+
s.gsub(/[^#{PChar}]/on) {|c| sprintf("%%%02X", c[0]) }
|
125
|
+
end
|
126
|
+
|
127
|
+
Reserved = ';/?:@&=+$,'
|
128
|
+
Uric = Reserved + Unreserved
|
129
|
+
def uric_escape(s)
|
130
|
+
s.gsub(/[^#{Uric}]/on) {|c| sprintf("%%%02X", c[0]) }
|
131
|
+
end
|
132
|
+
|
133
|
+
def form_escape(s)
|
134
|
+
s.gsub(/[#{Reserved}\x00-\x1f\x7f-\xff]/on) {|c|
|
135
|
+
sprintf("%%%02X", c[0])
|
136
|
+
}.gsub(/ /on) { '+' }
|
137
|
+
end
|
138
|
+
end
|
139
|
+
# :startdoc:
|
140
|
+
end
|
141
|
+
end
|
@@ -0,0 +1,90 @@
|
|
1
|
+
# webapp/webrick-servlet.rb provides an adaptor for a webapp and WEBrick.
|
2
|
+
#
|
3
|
+
# webapp/webrick-servlet.rb registers a handler for .webrick extension
|
4
|
+
# using WEBrick::HTTPServlet::FileHandler.add_handler.
|
5
|
+
# So WEBrick based HTTP server which require webapp/webrick-servlet.rb
|
6
|
+
# can run a web application using webapp which filename has .webrick
|
7
|
+
# extension.
|
8
|
+
#
|
9
|
+
# Such HTTP server can be defined as follows.
|
10
|
+
#
|
11
|
+
# require 'webapp/webrick-servlet'
|
12
|
+
# httpd = WEBrick::HTTPServer.new(:Port => 10080, :DocumentRoot => Dir.getwd)
|
13
|
+
# trap(:INT){ httpd.shutdown }
|
14
|
+
# httpd.start
|
15
|
+
#
|
16
|
+
# Apart from that, webapp/webrick-servlet.rb provides
|
17
|
+
# WebApp::WEBrickServletHandler.load_servlet which load WEBrick servlet
|
18
|
+
# using webapp.
|
19
|
+
#
|
20
|
+
# WebApp::WEBrickServletHandler.load_servlet can be used for constructing
|
21
|
+
# a web site with a single web application as follows.
|
22
|
+
#
|
23
|
+
# require 'webapp/webrick-servlet'
|
24
|
+
# servlet = ARGV.shift
|
25
|
+
# httpd = WEBrick::HTTPServer.new(:Port => 10080)
|
26
|
+
# trap(:INT){ httpd.shutdown }
|
27
|
+
# httpd.mount("/", WebApp::WEBrickServletHandler.load_servlet(servlet))
|
28
|
+
# httpd.start
|
29
|
+
#
|
30
|
+
# When above server accept a request to http://host:10080/foo/bar,
|
31
|
+
# the servlet takes /foo/bar as a path_info.
|
32
|
+
#
|
33
|
+
# Note that the servlet loading mechanism may be used without webapp
|
34
|
+
# because the mechanism itself is not webapp dependent.
|
35
|
+
|
36
|
+
require 'webrick'
|
37
|
+
|
38
|
+
module Hobix
|
39
|
+
class WebApp
|
40
|
+
class WEBrickServletHandler
|
41
|
+
LoadedServlets = {}
|
42
|
+
def WEBrickServletHandler.get_instance(config, name)
|
43
|
+
unless LoadedServlets[name]
|
44
|
+
LoadedServlets[name] = load_servlet(name)
|
45
|
+
end
|
46
|
+
LoadedServlets[name]
|
47
|
+
end
|
48
|
+
|
49
|
+
# load a WEBrick servlet written using webapp.
|
50
|
+
# WEBrickServletHandler.load_servlet returns a WEBrick servlet
|
51
|
+
# generated by WEBrick::HTTPServlet::ProcHandler.
|
52
|
+
def WEBrickServletHandler.load_servlet(path)
|
53
|
+
begin
|
54
|
+
Thread.current[:webrick_load_servlet] = true
|
55
|
+
load path, true
|
56
|
+
unless Thread.current[:webrick_load_servlet].respond_to? :call
|
57
|
+
raise "WEBrick servlet is not registered: #{path}"
|
58
|
+
end
|
59
|
+
procedure = Thread.current[:webrick_load_servlet]
|
60
|
+
return WEBrick::HTTPServlet::ProcHandler.new(procedure)
|
61
|
+
ensure
|
62
|
+
Thread.current[:webrick_load_servlet] = nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
68
|
+
WEBrick::HTTPServlet::FileHandler.add_handler('webrick',
|
69
|
+
Hobix::WebApp::WEBrickServletHandler)
|
70
|
+
|
71
|
+
if $0 == __FILE__
|
72
|
+
# usage: [-p port] [docroot|servlet]
|
73
|
+
require 'optparse'
|
74
|
+
port = 10080
|
75
|
+
ARGV.options {|q|
|
76
|
+
q.def_option('--help', 'show this message') {puts q; exit(0)}
|
77
|
+
q.def_option('--port=portnum', 'specify server port (default: 10080)') {|num| port = num.to_i }
|
78
|
+
q.parse!
|
79
|
+
}
|
80
|
+
docroot = ARGV.shift || Dir.getwd
|
81
|
+
httpd = WEBrick::HTTPServer.new(:Port => port)
|
82
|
+
trap(:INT){ httpd.shutdown }
|
83
|
+
if File.directory? docroot
|
84
|
+
httpd.mount("/", WEBrick::HTTPServlet::FileHandler, docroot, WEBrick::Config::HTTP[:DocumentRootOptions])
|
85
|
+
httpd.start
|
86
|
+
else
|
87
|
+
httpd.mount("/", Hobix::WebApp::WEBrickServletHandler.load_servlet(docroot))
|
88
|
+
httpd.start
|
89
|
+
end
|
90
|
+
end
|