oaf 0.3.0 → 0.3.1
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 +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
|
-
[](http://badge.fury.io/rb/oaf)
|
7
|
-
[](https://travis-ci.org/ryanuber/oaf)
|
8
|
-
[](https://coveralls.io/r/ryanuber/oaf)
|
9
|
-
[](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
|