oaf 0.3.0 → 0.3.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +8 -8
- data/bin/oaf +1 -1
- data/lib/oaf.rb +2 -2
- data/lib/oaf/{http/handler.rb → httphandler.rb} +6 -6
- data/lib/oaf/httpserver.rb +106 -0
- data/lib/oaf/util.rb +252 -256
- data/lib/oaf/version.rb +1 -1
- data/spec/oaf/http_spec.rb +14 -14
- metadata +6 -27
- data/.travis.yml +0 -8
- data/Gemfile +0 -2
- data/LICENSE +0 -20
- data/README.md +0 -150
- data/Rakefile +0 -6
- data/lib/oaf/http/server.rb +0 -110
- data/oaf.gemspec +0 -27
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
Y2M2YmMyNGY2Zjg4MmU2MWJjN2Y3ZDc0MzhjMDMxZmEyZjRkY2RkNw==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
ZjY4YTM5NjdiYzg3YzA0NTk4NmFjMzdiOGMzYzYwYmZjZWM0NWJkMA==
|
7
7
|
!binary "U0hBNTEy":
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
OWQ0NzRhMGJiYjYxNGQxNmJmNjFmZTBiMDRhODc4NmU0ZDFjNGQyZTExZDI2
|
10
|
+
ZjJhMDkyM2NkMGRhZmU0NzZmYWY2M2IwYjM1NzI2YmQ3NWJkMzc1MzJiMjk5
|
11
|
+
NzQwYmJiMjMyN2I0NzJlOWRkMDU3ZjRiYmRhZDA4MDk3NGNjYWE=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
YWVmMzQ5NWE1M2FiYzQ4YmQyM2E3YjdjMjkyOWZiMDkxMDJiMDA1NGI2YWU1
|
14
|
+
NTg0ODdlZGU0NTQ1NTljNjU5MGE2NjMwZGY0MTNjOTY4NDdkZmZiYjJmYjYx
|
15
|
+
MGVkMDZkMTg0MTlhMWYxZTUzMWI3YjMxMDJhY2M1ODM0MTdjZjM=
|
data/bin/oaf
CHANGED
data/lib/oaf.rb
CHANGED
@@ -21,16 +21,16 @@
|
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
|
23
23
|
require 'oaf/util'
|
24
|
-
require 'oaf/
|
24
|
+
require 'oaf/httpserver'
|
25
25
|
require 'webrick'
|
26
26
|
|
27
|
-
module Oaf
|
27
|
+
module Oaf
|
28
28
|
|
29
29
|
# Provides all required handlers to WEBrick for serving all basic HTTP
|
30
30
|
# methods. WEBrick handles GET, POST, HEAD, and OPTIONS out of the box,
|
31
31
|
# but to mock most RESTful applications we are going to want PUT and
|
32
32
|
# DELETE undoubtedly.
|
33
|
-
class
|
33
|
+
class HTTPHandler < WEBrick::HTTPServlet::AbstractServlet
|
34
34
|
|
35
35
|
# Remove the predefined WEBrick methods. WEBrick comes with some defaults
|
36
36
|
# for GET, POST, OPTIONS, and HEAD, but let's use our own instead.
|
@@ -64,12 +64,12 @@ module Oaf::HTTP
|
|
64
64
|
def process_request req, res
|
65
65
|
req_headers = req.header
|
66
66
|
req_query = req.query
|
67
|
-
req_body = Oaf::
|
67
|
+
req_body = Oaf::HTTPServer.get_request_body req
|
68
68
|
file = Oaf::Util.get_request_file @path, req.path, req.request_method
|
69
69
|
out = Oaf::Util.get_output(file, req.path, req_headers, req_body,
|
70
70
|
req_query)
|
71
|
-
res_headers, res_status, res_body = Oaf::
|
72
|
-
Oaf::
|
71
|
+
res_headers, res_status, res_body = Oaf::HTTPServer.parse_response out
|
72
|
+
Oaf::HTTPServer.set_response! res, res_headers, res_body, res_status
|
73
73
|
end
|
74
74
|
|
75
75
|
# A magic respond_to? implementation to trick WEBrick into thinking that any
|
@@ -0,0 +1,106 @@
|
|
1
|
+
# oaf - Care-free web app prototyping using files and scripts
|
2
|
+
# Copyright 2013 Ryan Uber <ru@ryanuber.com>
|
3
|
+
#
|
4
|
+
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
+
# a copy of this software and associated documentation files (the
|
6
|
+
# "Software"), to deal in the Software without restriction, including
|
7
|
+
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
+
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
+
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
+
# the following conditions:
|
11
|
+
#
|
12
|
+
# The above copyright notice and this permission notice shall be
|
13
|
+
# included in all copies or substantial portions of the Software.
|
14
|
+
#
|
15
|
+
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
+
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
+
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
+
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
+
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
+
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
+
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
+
|
23
|
+
require 'oaf/util'
|
24
|
+
require 'oaf/httphandler'
|
25
|
+
require 'webrick'
|
26
|
+
|
27
|
+
module Oaf::HTTPServer
|
28
|
+
extend self
|
29
|
+
|
30
|
+
# Given output from a script, parse HTTP response details and return them
|
31
|
+
# as a hash, including body, status, and headers.
|
32
|
+
#
|
33
|
+
# == Parameters:
|
34
|
+
# output::
|
35
|
+
# The output text data returned by a script.
|
36
|
+
#
|
37
|
+
# == Returns:
|
38
|
+
# A hash containing the HTTP response details (body, status, and headers).
|
39
|
+
#
|
40
|
+
def parse_response output
|
41
|
+
has_meta = false
|
42
|
+
headers = {'content-type' => 'text/plain'}
|
43
|
+
status = 200
|
44
|
+
headers, status, meta_size = Oaf::Util.parse_http_meta output
|
45
|
+
lines = output.split("\n")
|
46
|
+
body = lines.take(lines.length - meta_size).join("\n")+"\n"
|
47
|
+
[headers, status, body]
|
48
|
+
end
|
49
|
+
|
50
|
+
# Safely retrieves the request body, and assumes an empty string if it
|
51
|
+
# cannot be retrieved. This helps get around a nasty exception in WEBrick.
|
52
|
+
#
|
53
|
+
# == Parameters:
|
54
|
+
# req::
|
55
|
+
# A WEBrick::HTTPRequest object
|
56
|
+
#
|
57
|
+
# == Returns:
|
58
|
+
# A string containing the request body
|
59
|
+
#
|
60
|
+
def get_request_body req
|
61
|
+
if ['POST', 'PUT'].member? req.request_method
|
62
|
+
begin
|
63
|
+
result = req.body
|
64
|
+
rescue WEBrick::HTTPStatus::LengthRequired
|
65
|
+
result = '' # needs to be in rescue for coverage
|
66
|
+
end
|
67
|
+
end
|
68
|
+
result
|
69
|
+
end
|
70
|
+
|
71
|
+
# Consume HTTP response details and set them into a response object.
|
72
|
+
#
|
73
|
+
# == Parameters:
|
74
|
+
# res::
|
75
|
+
# A WEBrick::HTTPResponse object
|
76
|
+
# headers::
|
77
|
+
# A hash containing HTTP response headers
|
78
|
+
# body::
|
79
|
+
# A string containing the HTTP response body
|
80
|
+
# status::
|
81
|
+
# An integer indicating the response status
|
82
|
+
#
|
83
|
+
def set_response! res, headers, body, status
|
84
|
+
headers.each do |name, value|
|
85
|
+
res.header[name] = value
|
86
|
+
end
|
87
|
+
res.body = body
|
88
|
+
res.status = status
|
89
|
+
end
|
90
|
+
|
91
|
+
# Invokes the Webrick web server library to handle incoming requests, and
|
92
|
+
# routes them to the appropriate scripts if they exist on the filesystem.
|
93
|
+
#
|
94
|
+
# == Parameters:
|
95
|
+
# path::
|
96
|
+
# The path in which to search for files
|
97
|
+
# port::
|
98
|
+
# The TCP port to listen on
|
99
|
+
#
|
100
|
+
def serve path, port
|
101
|
+
server = WEBrick::HTTPServer.new :Port => port
|
102
|
+
server.mount '/', Oaf::HTTPHandler, path
|
103
|
+
trap 'INT' do server.shutdown end
|
104
|
+
server.start
|
105
|
+
end
|
106
|
+
end
|
data/lib/oaf/util.rb
CHANGED
@@ -20,285 +20,281 @@
|
|
20
20
|
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
21
|
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
22
|
|
23
|
-
module Oaf
|
23
|
+
module Oaf::Util
|
24
|
+
extend self
|
24
25
|
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
#
|
39
|
-
def is_http_header? line
|
40
|
-
line.split(':').length == 2
|
41
|
-
end
|
26
|
+
# Determines if a line of output looks anything like an HTTP header
|
27
|
+
# declaration.
|
28
|
+
#
|
29
|
+
# == Parameters:
|
30
|
+
# line::
|
31
|
+
# A line of text to examine
|
32
|
+
#
|
33
|
+
# == Returns:
|
34
|
+
# A boolean, true if it can be read as a header string, else false.
|
35
|
+
#
|
36
|
+
def is_http_header? line
|
37
|
+
line.split(':').length == 2
|
38
|
+
end
|
42
39
|
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
40
|
+
# Retrieves a hash in the form `name` => `value` from a string that
|
41
|
+
# describes an HTTP response header.
|
42
|
+
#
|
43
|
+
# == Parameters:
|
44
|
+
# line::
|
45
|
+
# A line of text to parse
|
46
|
+
#
|
47
|
+
# == Returns
|
48
|
+
# A hash in the form `name` => `value`, or `nil`
|
49
|
+
#
|
50
|
+
def get_http_header line
|
51
|
+
return nil if not is_http_header? line
|
52
|
+
parts = line.split(':')
|
53
|
+
{parts[0].strip => parts[1].strip}
|
54
|
+
end
|
58
55
|
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
56
|
+
# Retrieves the numeric value from a line of text as an HTTP status code.
|
57
|
+
#
|
58
|
+
# == Parameters:
|
59
|
+
# line::
|
60
|
+
# A line of text to parse
|
61
|
+
#
|
62
|
+
# == Returns:
|
63
|
+
# An integer if valid, else `nil`.
|
64
|
+
#
|
65
|
+
def get_http_status line
|
66
|
+
is_http_status?(line) ? line.to_i : nil
|
67
|
+
end
|
71
68
|
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
69
|
+
# Determines if an HTTP status code is valid per RFC2616
|
70
|
+
#
|
71
|
+
# == Parameters:
|
72
|
+
# code::
|
73
|
+
# A number to validate
|
74
|
+
#
|
75
|
+
# == Returns
|
76
|
+
# A boolean, true if valid, else false.
|
77
|
+
#
|
78
|
+
def is_http_status? code
|
79
|
+
(200..206).to_a.concat((300..307).to_a).concat((400..417).to_a) \
|
80
|
+
.concat((500..505).to_a).include? code.to_i
|
81
|
+
end
|
85
82
|
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
end
|
83
|
+
# Convert various pieces of data about the request into a single hash, which
|
84
|
+
# can then be passed on as environment data to a script.
|
85
|
+
#
|
86
|
+
# == Parameters:
|
87
|
+
# req_path::
|
88
|
+
# A string with the HTTP request path
|
89
|
+
# headers::
|
90
|
+
# A hash of request headers
|
91
|
+
# params::
|
92
|
+
# A hash of request parameters
|
93
|
+
# body::
|
94
|
+
# A string containing the request body
|
95
|
+
#
|
96
|
+
# == Returns:
|
97
|
+
# A flat hash containing namespaced environment parameters
|
98
|
+
#
|
99
|
+
def prepare_environment req_path, headers, params, body
|
100
|
+
result = Hash.new
|
101
|
+
{'header' => headers, 'param' => params}.each do |prefix, data|
|
102
|
+
data.each do |name, value|
|
103
|
+
result.merge! Oaf::Util.environment_item prefix, name, value
|
108
104
|
end
|
109
|
-
result.merge! Oaf::Util.environment_item 'request', 'path', req_path
|
110
|
-
result.merge Oaf::Util.environment_item 'request', 'body', body
|
111
105
|
end
|
106
|
+
result.merge! Oaf::Util.environment_item 'request', 'path', req_path
|
107
|
+
result.merge Oaf::Util.environment_item 'request', 'body', body
|
108
|
+
end
|
112
109
|
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
110
|
+
# Prepares a key for placement in the execution environment. This includes
|
111
|
+
# namespacing variables and converting characters to predictable and
|
112
|
+
# easy-to-use names.
|
113
|
+
#
|
114
|
+
# == Parameters:
|
115
|
+
# prefix::
|
116
|
+
# A prefix for the key. This helps with separation.
|
117
|
+
# key::
|
118
|
+
# The key to sanitize
|
119
|
+
#
|
120
|
+
# == Returns:
|
121
|
+
# A string with the prepared value
|
122
|
+
#
|
123
|
+
def prepare_key prefix, key
|
124
|
+
"oaf_#{prefix}_#{key.gsub('-', '_').downcase}"
|
125
|
+
end
|
129
126
|
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
127
|
+
# Formats a single environment item into a hash, which can be merged into a
|
128
|
+
# collective environment mapping later on.
|
129
|
+
#
|
130
|
+
# == Parameters:
|
131
|
+
# prefix::
|
132
|
+
# The prefix for the type of item being added.
|
133
|
+
# key::
|
134
|
+
# The key name of the environment property
|
135
|
+
# value::
|
136
|
+
# The value for the environment property
|
137
|
+
#
|
138
|
+
# == Returns:
|
139
|
+
# A hash with prepared values ready to merge into an environment hash
|
140
|
+
#
|
141
|
+
def environment_item prefix, key, value
|
142
|
+
{Oaf::Util.prepare_key(prefix, key) => Oaf::Util.flatten(value)}
|
143
|
+
end
|
147
144
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
end
|
172
|
-
elsif data.kind_of? String
|
173
|
-
result = data
|
174
|
-
else
|
175
|
-
result = ''
|
145
|
+
# Flatten a hash or array into a string. This is useful for preparing some
|
146
|
+
# data for passing in via the environment, because multi-dimension data
|
147
|
+
# structures are not supported for that.
|
148
|
+
#
|
149
|
+
# == Parameters:
|
150
|
+
# data::
|
151
|
+
# The data to flatten
|
152
|
+
#
|
153
|
+
# == Returns:
|
154
|
+
# A flattened string. It will be empty if the object passed in was not
|
155
|
+
# flatten-able.
|
156
|
+
#
|
157
|
+
def flatten data
|
158
|
+
result = ''
|
159
|
+
if data.kind_of? Hash
|
160
|
+
data.each do |key, val|
|
161
|
+
val = Oaf::Util.flatten val if not val.kind_of? String
|
162
|
+
result += "#{key}#{val}"
|
163
|
+
end
|
164
|
+
elsif data.kind_of? Array
|
165
|
+
data.each do |item|
|
166
|
+
item = Oaf::Util.flatten item if not item.kind_of? String
|
167
|
+
result += item
|
176
168
|
end
|
177
|
-
|
169
|
+
elsif data.kind_of? String
|
170
|
+
result = data
|
171
|
+
else
|
172
|
+
result = ''
|
178
173
|
end
|
174
|
+
result
|
175
|
+
end
|
179
176
|
|
180
|
-
|
181
|
-
|
182
|
-
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
|
194
|
-
|
195
|
-
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
end
|
205
|
-
size += size == 0 ? 2 : 1 # compensate for delimiter
|
177
|
+
# Given an array of text lines, iterate over each of them and determine if
|
178
|
+
# they may be interpreted as headers or status. If they can, add them to
|
179
|
+
# the result.
|
180
|
+
#
|
181
|
+
# == Parameters:
|
182
|
+
# text::
|
183
|
+
# Plain text data to examine
|
184
|
+
#
|
185
|
+
# == Returns:
|
186
|
+
# A 3-item structure containing headers, status, and the number of lines
|
187
|
+
# which the complete metadata (including the "---" delimiter) occupies.
|
188
|
+
#
|
189
|
+
def parse_http_meta text
|
190
|
+
headers = {}
|
191
|
+
status = 200
|
192
|
+
size = 0
|
193
|
+
parts = text.split /^---$/
|
194
|
+
if parts.length > 1
|
195
|
+
for part in parts.last.split "\n"
|
196
|
+
if Oaf::Util.is_http_header? part
|
197
|
+
headers.merge! Oaf::Util.get_http_header part
|
198
|
+
elsif Oaf::Util.is_http_status? part
|
199
|
+
status = Oaf::Util.get_http_status part
|
200
|
+
else next
|
206
201
|
end
|
202
|
+
size += size == 0 ? 2 : 1 # compensate for delimiter
|
207
203
|
end
|
208
|
-
[headers, status, size]
|
209
204
|
end
|
205
|
+
[headers, status, size]
|
206
|
+
end
|
210
207
|
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
208
|
+
# Return a default response string indicating that nothing could be
|
209
|
+
# done and no response files were found.
|
210
|
+
#
|
211
|
+
# == Returns:
|
212
|
+
# A string with response output for parsing.
|
213
|
+
#
|
214
|
+
def get_default_response
|
215
|
+
"oaf: Not Found\n---\n404"
|
216
|
+
end
|
220
217
|
|
221
|
-
|
222
|
-
|
223
|
-
|
224
|
-
|
225
|
-
|
226
|
-
|
227
|
-
|
228
|
-
|
229
|
-
|
230
|
-
|
231
|
-
|
232
|
-
|
233
|
-
|
234
|
-
|
235
|
-
|
236
|
-
|
237
|
-
|
238
|
-
|
239
|
-
|
240
|
-
|
241
|
-
|
242
|
-
end
|
218
|
+
# Returns the path to the file to use for the request. If the provided
|
219
|
+
# file path does not exist, this method will search for a file within
|
220
|
+
# the same directory matching the default convention "_*_".
|
221
|
+
#
|
222
|
+
# == Parameters:
|
223
|
+
# root::
|
224
|
+
# The root path to search within.
|
225
|
+
# req_path::
|
226
|
+
# The HTTP request path
|
227
|
+
# method::
|
228
|
+
# The HTTP method of the request
|
229
|
+
#
|
230
|
+
# == Returns:
|
231
|
+
# The path to a file to use, or `nil` if none is found.
|
232
|
+
#
|
233
|
+
def get_request_file root, req_path, method
|
234
|
+
file = File.join root, "#{req_path}.#{method}"
|
235
|
+
if not File.exist? file
|
236
|
+
Dir.glob(File.join(File.dirname(file), "_*_.#{method}")).each do |f|
|
237
|
+
file = f
|
238
|
+
break
|
243
239
|
end
|
244
|
-
File.exist?(file) ? file : nil
|
245
240
|
end
|
241
|
+
File.exist?(file) ? file : nil
|
242
|
+
end
|
246
243
|
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
|
251
|
-
|
252
|
-
|
253
|
-
|
254
|
-
|
255
|
-
|
256
|
-
|
257
|
-
|
258
|
-
|
259
|
-
|
260
|
-
|
261
|
-
|
262
|
-
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
end
|
269
|
-
wout.close
|
270
|
-
Process.wait pid
|
271
|
-
out.read
|
244
|
+
# Fork a new process, in which we can safely modify the running environment
|
245
|
+
# and run a command, sending data back to the parent process using an IO
|
246
|
+
# pipe. This can be done in a single line in ruby >= 1.9, but we will do it
|
247
|
+
# the hard way to maintain compatibility with older rubies.
|
248
|
+
#
|
249
|
+
# == Parameters:
|
250
|
+
# env::
|
251
|
+
# The environment data to use in the subprocess.
|
252
|
+
# command::
|
253
|
+
# The command to execute against the server
|
254
|
+
#
|
255
|
+
# == Returns:
|
256
|
+
# A string of stderr concatenated to stdout.
|
257
|
+
#
|
258
|
+
def run_buffered env, command
|
259
|
+
out, wout = IO.pipe
|
260
|
+
pid = fork do
|
261
|
+
out.close
|
262
|
+
ENV.replace env
|
263
|
+
wout.write %x(#{command} 2>&1)
|
264
|
+
at_exit { exit! }
|
272
265
|
end
|
266
|
+
wout.close
|
267
|
+
Process.wait pid
|
268
|
+
out.read
|
269
|
+
end
|
273
270
|
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
283
|
-
|
284
|
-
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
|
291
|
-
|
292
|
-
|
293
|
-
|
294
|
-
|
295
|
-
|
296
|
-
|
297
|
-
|
298
|
-
|
299
|
-
|
300
|
-
end
|
301
|
-
out
|
271
|
+
# Executes a file, or reads its contents if it is not executable, passing
|
272
|
+
# it the request headers and body as arguments, and returns the result.
|
273
|
+
#
|
274
|
+
# == Parameters:
|
275
|
+
# req_path::
|
276
|
+
# The HTTP request path
|
277
|
+
# file::
|
278
|
+
# The path to the file to use for output
|
279
|
+
# headers::
|
280
|
+
# The HTTP request headers to pass
|
281
|
+
# body::
|
282
|
+
# The HTTP request body to pass
|
283
|
+
# params::
|
284
|
+
# The HTTP request parameters to pass
|
285
|
+
#
|
286
|
+
# == Returns:
|
287
|
+
# The result from the file, or a default result if the file is not found.
|
288
|
+
#
|
289
|
+
def get_output file, req_path=nil, headers=[], body=[], params=[]
|
290
|
+
if file.nil?
|
291
|
+
out = Oaf::Util.get_default_response
|
292
|
+
elsif File.executable? file
|
293
|
+
env = Oaf::Util.prepare_environment req_path, headers, params, body
|
294
|
+
out = Oaf::Util.run_buffered env, file
|
295
|
+
else
|
296
|
+
out = File.open(file).read
|
302
297
|
end
|
298
|
+
out
|
303
299
|
end
|
304
300
|
end
|
data/lib/oaf/version.rb
CHANGED
data/spec/oaf/http_spec.rb
CHANGED
@@ -25,7 +25,7 @@ require 'spec_helper'
|
|
25
25
|
module Oaf
|
26
26
|
describe "Returning HTTP Responses" do
|
27
27
|
it "should return safe defaults if output is empty" do
|
28
|
-
headers, status, body = Oaf::
|
28
|
+
headers, status, body = Oaf::HTTPServer.parse_response ''
|
29
29
|
headers.should eq({})
|
30
30
|
status.should eq(200)
|
31
31
|
body.should eq("\n")
|
@@ -33,7 +33,7 @@ module Oaf
|
|
33
33
|
|
34
34
|
it "should return safe defaults when only body is present" do
|
35
35
|
text = "This is a test\n"
|
36
|
-
headers, status, body = Oaf::
|
36
|
+
headers, status, body = Oaf::HTTPServer.parse_response text
|
37
37
|
headers.should eq({})
|
38
38
|
status.should eq(200)
|
39
39
|
body.should eq("This is a test\n")
|
@@ -41,25 +41,25 @@ module Oaf
|
|
41
41
|
|
42
42
|
it "should return headers correctly" do
|
43
43
|
text = "---\nx-powered-by: oaf"
|
44
|
-
headers, status, body = Oaf::
|
44
|
+
headers, status, body = Oaf::HTTPServer.parse_response text
|
45
45
|
headers.should eq({'x-powered-by' => 'oaf'})
|
46
46
|
end
|
47
47
|
|
48
48
|
it "should return status correctly" do
|
49
49
|
text = "---\n201"
|
50
|
-
headers, status, body = Oaf::
|
50
|
+
headers, status, body = Oaf::HTTPServer.parse_response text
|
51
51
|
status.should eq(201)
|
52
52
|
end
|
53
53
|
|
54
54
|
it "should return body correctly" do
|
55
55
|
text = "This is a test\n---\n200"
|
56
|
-
headers, status, body = Oaf::
|
56
|
+
headers, status, body = Oaf::HTTPServer.parse_response text
|
57
57
|
body.should eq("This is a test\n")
|
58
58
|
end
|
59
59
|
|
60
60
|
it "should return body correctly when no metadata is present" do
|
61
61
|
text = "This is a test"
|
62
|
-
headers, status, body = Oaf::
|
62
|
+
headers, status, body = Oaf::HTTPServer.parse_response text
|
63
63
|
body.should eq("This is a test\n")
|
64
64
|
end
|
65
65
|
end
|
@@ -90,15 +90,15 @@ module Oaf
|
|
90
90
|
@webrick.should_receive(:start).once.and_return(true)
|
91
91
|
WEBrick::HTTPServer.stub(:new).and_return(@webrick)
|
92
92
|
@webrick.should_receive(:mount) \
|
93
|
-
.with('/', Oaf::
|
93
|
+
.with('/', Oaf::HTTPHandler, '/tmp').once \
|
94
94
|
.and_return(true)
|
95
|
-
Oaf::
|
95
|
+
Oaf::HTTPServer.serve '/tmp', 9000
|
96
96
|
end
|
97
97
|
|
98
98
|
it "should parse the request properly" do
|
99
99
|
req = Oaf::FakeReq.new :path => @f1request
|
100
100
|
res = Oaf::FakeRes.new
|
101
|
-
handler = Oaf::
|
101
|
+
handler = Oaf::HTTPHandler.new Oaf::FakeServlet.new, @tempdir1
|
102
102
|
handler.process_request req, res
|
103
103
|
res.body.should eq("This is a test.\n")
|
104
104
|
res.status.should eq(201)
|
@@ -108,7 +108,7 @@ module Oaf
|
|
108
108
|
it "should accept containable methods properly" do
|
109
109
|
req = Oaf::FakeReq.new({:path => @f2request, :method => 'PUT'})
|
110
110
|
res = Oaf::FakeRes.new
|
111
|
-
handler = Oaf::
|
111
|
+
handler = Oaf::HTTPHandler.new Oaf::FakeServlet.new, @tempdir1
|
112
112
|
handler.process_request req, res
|
113
113
|
res.body.should eq("Containable Test\n")
|
114
114
|
res.status.should eq(202)
|
@@ -118,8 +118,8 @@ module Oaf
|
|
118
118
|
it "should respond to any HTTP method" do
|
119
119
|
req = Oaf::FakeReq.new :path => @f1request
|
120
120
|
res = Oaf::FakeRes.new
|
121
|
-
Oaf::
|
122
|
-
handler = Oaf::
|
121
|
+
Oaf::HTTPHandler.any_instance.stub(:process_request).and_return(true)
|
122
|
+
handler = Oaf::HTTPHandler.new Oaf::FakeServlet.new, @tempdir1
|
123
123
|
handler.should_receive(:process_request).with(req, res).once
|
124
124
|
handler.respond_to?(:do_GET).should be_true
|
125
125
|
handler.respond_to?(:do_get).should be_false
|
@@ -130,8 +130,8 @@ module Oaf
|
|
130
130
|
it "should call our custom methods for built-ins" do
|
131
131
|
req = Oaf::FakeReq.new :path => @f1request
|
132
132
|
res = Oaf::FakeRes.new
|
133
|
-
Oaf::
|
134
|
-
handler = Oaf::
|
133
|
+
Oaf::HTTPHandler.any_instance.stub(:process_request).and_return(true)
|
134
|
+
handler = Oaf::HTTPHandler.new Oaf::FakeServlet.new, @tempdir1
|
135
135
|
handler.should_receive(:process_request).with(req, res).exactly(4).times
|
136
136
|
handler.do_GET(req, res)
|
137
137
|
handler.do_POST(req, res)
|
metadata
CHANGED
@@ -1,29 +1,15 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: oaf
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryan Uber
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2013-09-
|
11
|
+
date: 2013-09-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
|
-
- !ruby/object:Gem::Dependency
|
14
|
-
name: bundler
|
15
|
-
requirement: !ruby/object:Gem::Requirement
|
16
|
-
requirements:
|
17
|
-
- - ! '>='
|
18
|
-
- !ruby/object:Gem::Version
|
19
|
-
version: '0'
|
20
|
-
type: :runtime
|
21
|
-
prerelease: false
|
22
|
-
version_requirements: !ruby/object:Gem::Requirement
|
23
|
-
requirements:
|
24
|
-
- - ! '>='
|
25
|
-
- !ruby/object:Gem::Version
|
26
|
-
version: '0'
|
27
13
|
- !ruby/object:Gem::Dependency
|
28
14
|
name: rake
|
29
15
|
requirement: !ruby/object:Gem::Requirement
|
@@ -81,25 +67,18 @@ dependencies:
|
|
81
67
|
- !ruby/object:Gem::Version
|
82
68
|
version: '0'
|
83
69
|
description: Care-free web app prototyping using files and scripts
|
84
|
-
email:
|
85
|
-
- ru@ryanuber.com
|
70
|
+
email: ru@ryanuber.com
|
86
71
|
executables:
|
87
72
|
- oaf
|
88
73
|
extensions: []
|
89
74
|
extra_rdoc_files: []
|
90
75
|
files:
|
91
|
-
- .travis.yml
|
92
|
-
- Gemfile
|
93
|
-
- LICENSE
|
94
|
-
- README.md
|
95
|
-
- Rakefile
|
96
76
|
- bin/oaf
|
97
|
-
- lib/oaf.rb
|
98
|
-
- lib/oaf/
|
99
|
-
- lib/oaf/http/server.rb
|
77
|
+
- lib/oaf/httphandler.rb
|
78
|
+
- lib/oaf/httpserver.rb
|
100
79
|
- lib/oaf/util.rb
|
101
80
|
- lib/oaf/version.rb
|
102
|
-
- oaf.
|
81
|
+
- lib/oaf.rb
|
103
82
|
- spec/oaf/http_spec.rb
|
104
83
|
- spec/oaf/util_spec.rb
|
105
84
|
- spec/spec_helper.rb
|
data/.travis.yml
DELETED
data/Gemfile
DELETED
data/LICENSE
DELETED
@@ -1,20 +0,0 @@
|
|
1
|
-
MIT LICENSE
|
2
|
-
|
3
|
-
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
-
a copy of this software and associated documentation files (the
|
5
|
-
"Software"), to deal in the Software without restriction, including
|
6
|
-
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
-
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
-
permit persons to whom the Software is furnished to do so, subject to
|
9
|
-
the following conditions:
|
10
|
-
|
11
|
-
The above copyright notice and this permission notice shall be
|
12
|
-
included in all copies or substantial portions of the Software.
|
13
|
-
|
14
|
-
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
-
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
-
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
-
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
-
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
-
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
-
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
DELETED
@@ -1,150 +0,0 @@
|
|
1
|
-
Oaf
|
2
|
-
---
|
3
|
-
|
4
|
-
Care-free web app prototyping using files and scripts
|
5
|
-
|
6
|
-
[![Gem Version](https://badge.fury.io/rb/oaf.png)](http://badge.fury.io/rb/oaf)
|
7
|
-
[![Build Status](https://travis-ci.org/ryanuber/oaf.png)](https://travis-ci.org/ryanuber/oaf)
|
8
|
-
[![Coverage Status](https://coveralls.io/repos/ryanuber/oaf/badge.png)](https://coveralls.io/r/ryanuber/oaf)
|
9
|
-
[![Code Climate](https://codeclimate.com/github/ryanuber/oaf.png)](https://codeclimate.com/github/ryanuber/oaf)
|
10
|
-
|
11
|
-
[Documentation](http://rubydoc.info/gems/oaf/frames)
|
12
|
-
|
13
|
-
`Oaf` provides stupid-easy way of creating dynamic web applications by setting
|
14
|
-
all best practices and security considerations aside until you are sure that you
|
15
|
-
want to invest your time doing so.
|
16
|
-
|
17
|
-
`Oaf` was created as a weekend project to create a small, simple HTTP server
|
18
|
-
program that uses script execution as its primary mechanism for generating
|
19
|
-
responses.
|
20
|
-
|
21
|
-
Example
|
22
|
-
-------
|
23
|
-
|
24
|
-
Create an executable file named `hello.GET`:
|
25
|
-
|
26
|
-
```
|
27
|
-
#!/bin/bash
|
28
|
-
echo "Hello, ${USER}!"
|
29
|
-
```
|
30
|
-
|
31
|
-
Start the server by running the `oaf` command, then make a request:
|
32
|
-
|
33
|
-
```
|
34
|
-
$ curl localhost:9000/hello
|
35
|
-
Hello, ryanuber!
|
36
|
-
```
|
37
|
-
|
38
|
-
Installation
|
39
|
-
------------
|
40
|
-
|
41
|
-
Oaf is available on [rubygems](http://rubygems.org/gems/oaf), which means you
|
42
|
-
can do:
|
43
|
-
|
44
|
-
```
|
45
|
-
gem install oaf
|
46
|
-
```
|
47
|
-
|
48
|
-
### Accepted files
|
49
|
-
|
50
|
-
`Oaf` will run *ANY* file with the executable bit set, be it shell, Python, Ruby,
|
51
|
-
compiled binary, or whatever else you might have.
|
52
|
-
|
53
|
-
`Oaf` can also use plain text files.
|
54
|
-
|
55
|
-
### How file permissions affect output
|
56
|
-
|
57
|
-
* If the file in your request is executable, the output of its execution will
|
58
|
-
be used as the return data.
|
59
|
-
* If the file is *NOT* executable, then the contents of the file will be used
|
60
|
-
as the return data.
|
61
|
-
|
62
|
-
### Nested methods
|
63
|
-
|
64
|
-
You can create nested methods using simple directories. Example:
|
65
|
-
|
66
|
-
```
|
67
|
-
$ ls ./examples/
|
68
|
-
hello.GET
|
69
|
-
|
70
|
-
$ curl http://localhost:8000/examples/hello
|
71
|
-
Hello, world!
|
72
|
-
```
|
73
|
-
|
74
|
-
### HTTP Methods
|
75
|
-
Files must carry the extension of the HTTP method used to invoke them.
|
76
|
-
Oaf should support any HTTP method, including custom methods.
|
77
|
-
|
78
|
-
### Headers and Status
|
79
|
-
You can indicate HTTP headers and status using stdout from your script.
|
80
|
-
|
81
|
-
```
|
82
|
-
#!/bin/bash
|
83
|
-
cat <<EOF
|
84
|
-
Hello, world!
|
85
|
-
---
|
86
|
-
content-type: text/plain
|
87
|
-
200
|
88
|
-
EOF
|
89
|
-
```
|
90
|
-
|
91
|
-
Separated by 3 dashes on a line of their own (`---`), the very last block
|
92
|
-
of output can contain headers and response status.
|
93
|
-
|
94
|
-
### Getting request headers, query parameters, and body
|
95
|
-
|
96
|
-
Headers, query parameters, and request body are all passed to executables using
|
97
|
-
the environment. To defeat overlap in variables, they are namespaced using a
|
98
|
-
prefix. The environment variables are as follows:
|
99
|
-
|
100
|
-
* Headers: `oaf_header_*`
|
101
|
-
* Request parameters: `oaf_param_*`
|
102
|
-
* Request body: `oaf_request_body`
|
103
|
-
* Request path: `oaf_request_path`
|
104
|
-
|
105
|
-
Below is a quick example of a shell script which makes use of the request data:
|
106
|
-
|
107
|
-
```
|
108
|
-
#!/bin/bash
|
109
|
-
echo "You passed the Accept header: $oaf_header_accept"
|
110
|
-
echo "You passed the 'message' value: $oaf_param_message"
|
111
|
-
echo "You passed the request body: $oaf_request_body"
|
112
|
-
echo "This method is located at: $oaf_request_path"
|
113
|
-
```
|
114
|
-
|
115
|
-
Headers query parameter names are converted to all-lowercase, and dashes are
|
116
|
-
replaced with underscores. This is due to the way the environment works. For
|
117
|
-
example, if you wanted to get at the `Content-Type` header, you could with the
|
118
|
-
environment variable `$oaf_header_content_type`.
|
119
|
-
|
120
|
-
### Catch-all methods
|
121
|
-
|
122
|
-
Catch-all's can be defined by naming a file inside of a directory, beginning and
|
123
|
-
ending with underscores (`_`). So for example, `test/_default_.GET` will match:
|
124
|
-
`GET /test/anything`, `GET /test/blah`, etc.
|
125
|
-
|
126
|
-
If you want to define a top-level method for `/test`, you would do so in the
|
127
|
-
file at `/test.GET`.
|
128
|
-
|
129
|
-
Q&A
|
130
|
-
---
|
131
|
-
|
132
|
-
**Why are the headers and status at the bottom of the response?**
|
133
|
-
Because it is much easier to echo these last. Since Oaf reads response
|
134
|
-
data directly from stdout/stderr, it is very easy for debug or error messages
|
135
|
-
to interfere with them. By specifying the headers and status last, we minimize
|
136
|
-
the chances of unexpected output damaging the response, as all processing is
|
137
|
-
already complete.
|
138
|
-
|
139
|
-
**Why the name `Oaf`?**
|
140
|
-
It's a bit of a clumsy and "oafish" approach at web application prototyping. I
|
141
|
-
constantly find myself trying to write server parts of programs before I have
|
142
|
-
even completed basic functionality, and sometimes even before I have a clear
|
143
|
-
idea of what it is I want the program to do.
|
144
|
-
|
145
|
-
Acknowledgements
|
146
|
-
----------------
|
147
|
-
|
148
|
-
`Oaf` is inspired by [Stubb](https://github.com/knuton/stubb). A number of ideas
|
149
|
-
and conventions were borrowed from it. Kudos to
|
150
|
-
[@knuton](https://github.com/knuton) for having a great idea.
|
data/Rakefile
DELETED
data/lib/oaf/http/server.rb
DELETED
@@ -1,110 +0,0 @@
|
|
1
|
-
# oaf - Care-free web app prototyping using files and scripts
|
2
|
-
# Copyright 2013 Ryan Uber <ru@ryanuber.com>
|
3
|
-
#
|
4
|
-
# Permission is hereby granted, free of charge, to any person obtaining
|
5
|
-
# a copy of this software and associated documentation files (the
|
6
|
-
# "Software"), to deal in the Software without restriction, including
|
7
|
-
# without limitation the rights to use, copy, modify, merge, publish,
|
8
|
-
# distribute, sublicense, and/or sell copies of the Software, and to
|
9
|
-
# permit persons to whom the Software is furnished to do so, subject to
|
10
|
-
# the following conditions:
|
11
|
-
#
|
12
|
-
# The above copyright notice and this permission notice shall be
|
13
|
-
# included in all copies or substantial portions of the Software.
|
14
|
-
#
|
15
|
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
16
|
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
17
|
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
18
|
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
19
|
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
20
|
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
21
|
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
22
|
-
|
23
|
-
require 'oaf/util'
|
24
|
-
require 'oaf/http/handler'
|
25
|
-
require 'webrick'
|
26
|
-
|
27
|
-
module Oaf::HTTP
|
28
|
-
|
29
|
-
module Server
|
30
|
-
extend Oaf
|
31
|
-
extend self
|
32
|
-
|
33
|
-
# Given output from a script, parse HTTP response details and return them
|
34
|
-
# as a hash, including body, status, and headers.
|
35
|
-
#
|
36
|
-
# == Parameters:
|
37
|
-
# output::
|
38
|
-
# The output text data returned by a script.
|
39
|
-
#
|
40
|
-
# == Returns:
|
41
|
-
# A hash containing the HTTP response details (body, status, and headers).
|
42
|
-
#
|
43
|
-
def parse_response output
|
44
|
-
has_meta = false
|
45
|
-
headers = {'content-type' => 'text/plain'}
|
46
|
-
status = 200
|
47
|
-
headers, status, meta_size = Oaf::Util.parse_http_meta output
|
48
|
-
lines = output.split("\n")
|
49
|
-
body = lines.take(lines.length - meta_size).join("\n")+"\n"
|
50
|
-
[headers, status, body]
|
51
|
-
end
|
52
|
-
|
53
|
-
# Safely retrieves the request body, and assumes an empty string if it
|
54
|
-
# cannot be retrieved. This helps get around a nasty exception in WEBrick.
|
55
|
-
#
|
56
|
-
# == Parameters:
|
57
|
-
# req::
|
58
|
-
# A WEBrick::HTTPRequest object
|
59
|
-
#
|
60
|
-
# == Returns:
|
61
|
-
# A string containing the request body
|
62
|
-
#
|
63
|
-
def get_request_body req
|
64
|
-
if ['POST', 'PUT'].member? req.request_method
|
65
|
-
begin
|
66
|
-
result = req.body
|
67
|
-
rescue WEBrick::HTTPStatus::LengthRequired
|
68
|
-
result = '' # needs to be in rescue for coverage
|
69
|
-
end
|
70
|
-
end
|
71
|
-
result
|
72
|
-
end
|
73
|
-
|
74
|
-
# Consume HTTP response details and set them into a response object.
|
75
|
-
#
|
76
|
-
# == Parameters:
|
77
|
-
# res::
|
78
|
-
# A WEBrick::HTTPResponse object
|
79
|
-
# headers::
|
80
|
-
# A hash containing HTTP response headers
|
81
|
-
# body::
|
82
|
-
# A string containing the HTTP response body
|
83
|
-
# status::
|
84
|
-
# An integer indicating the response status
|
85
|
-
#
|
86
|
-
def set_response! res, headers, body, status
|
87
|
-
headers.each do |name, value|
|
88
|
-
res.header[name] = value
|
89
|
-
end
|
90
|
-
res.body = body
|
91
|
-
res.status = status
|
92
|
-
end
|
93
|
-
|
94
|
-
# Invokes the Webrick web server library to handle incoming requests, and
|
95
|
-
# routes them to the appropriate scripts if they exist on the filesystem.
|
96
|
-
#
|
97
|
-
# == Parameters:
|
98
|
-
# path::
|
99
|
-
# The path in which to search for files
|
100
|
-
# port::
|
101
|
-
# The TCP port to listen on
|
102
|
-
#
|
103
|
-
def serve path, port
|
104
|
-
server = WEBrick::HTTPServer.new :Port => port
|
105
|
-
server.mount '/', Oaf::HTTP::Handler, path
|
106
|
-
trap 'INT' do server.shutdown end
|
107
|
-
server.start
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
data/oaf.gemspec
DELETED
@@ -1,27 +0,0 @@
|
|
1
|
-
lib = File.expand_path("../lib", __FILE__)
|
2
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
3
|
-
require 'oaf/version'
|
4
|
-
|
5
|
-
Gem::Specification.new do |s|
|
6
|
-
s.name = 'oaf'
|
7
|
-
s.version = Oaf::VERSION
|
8
|
-
s.summary = 'Web app prototyping'
|
9
|
-
s.description = 'Care-free web app prototyping using files and scripts'
|
10
|
-
s.authors = ["Ryan Uber"]
|
11
|
-
s.email = ['ru@ryanuber.com']
|
12
|
-
s.files = %x(git ls-files).split($/)
|
13
|
-
s.homepage = 'https://github.com/ryanuber/oaf'
|
14
|
-
s.license = 'MIT'
|
15
|
-
s.executables = s.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
16
|
-
s.test_files = s.files.grep(%r{^spec/})
|
17
|
-
s.require_paths = ['lib']
|
18
|
-
|
19
|
-
s.required_ruby_version = '>= 1.8'
|
20
|
-
|
21
|
-
s.add_runtime_dependency 'bundler'
|
22
|
-
|
23
|
-
s.add_development_dependency 'rake'
|
24
|
-
s.add_development_dependency 'rspec'
|
25
|
-
s.add_development_dependency 'simplecov'
|
26
|
-
s.add_development_dependency 'coveralls'
|
27
|
-
end
|