rackful 0.1.2 → 0.1.3
Sign up to get free protection for your applications and to get access to all the features.
- data/example/config.ru +6 -3
- data/lib/rackful.rb +6 -6
- data/lib/{rackful_http_status.rb → rackful/http_status.rb} +39 -42
- data/lib/rackful/middleware.rb +3 -0
- data/lib/rackful/{header_spoofing.rb → middleware/header_spoofing.rb} +4 -5
- data/lib/rackful/{method_spoofing.rb → middleware/method_spoofing.rb} +0 -1
- data/lib/rackful/{relative_location.rb → middleware/relative_location.rb} +0 -1
- data/lib/rackful/path.rb +179 -0
- data/lib/{rackful_request.rb → rackful/request.rb} +6 -15
- data/lib/{rackful_resource.rb → rackful/resource.rb} +125 -101
- data/lib/{rackful_serializer.rb → rackful/serializer.rb} +159 -80
- data/lib/{rackful_server.rb → rackful/server.rb} +3 -8
- data/rackful.gemspec +3 -3
- metadata +57 -55
- data/example/config2.ru +0 -41
- data/lib/rackful_path.rb +0 -119
data/example/config.ru
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
# Load core functionality:
|
1
2
|
require 'rackful'
|
2
|
-
|
3
|
-
|
4
|
-
|
3
|
+
|
4
|
+
# Load extra middlewares: ({Rackful::MethodSpoofing}, {Rackful::HeaderSpoofing},
|
5
|
+
# Rackful::RelativeLocation})
|
6
|
+
require 'rackful/middleware'
|
7
|
+
|
5
8
|
require 'digest/md5'
|
6
9
|
|
7
10
|
# The class of the object we're going to serve:
|
data/lib/rackful.rb
CHANGED
@@ -1,6 +1,6 @@
|
|
1
|
-
require '
|
2
|
-
require '
|
3
|
-
require '
|
4
|
-
require '
|
5
|
-
require '
|
6
|
-
require '
|
1
|
+
require 'rackful/path.rb'
|
2
|
+
require 'rackful/request.rb'
|
3
|
+
require 'rackful/serializer.rb'
|
4
|
+
require 'rackful/resource.rb'
|
5
|
+
require 'rackful/http_status.rb'
|
6
|
+
require 'rackful/server.rb'
|
@@ -1,6 +1,6 @@
|
|
1
1
|
# Required for parsing:
|
2
|
-
require '
|
3
|
-
require '
|
2
|
+
require 'rackful/resource.rb'
|
3
|
+
require 'rackful/serializer.rb'
|
4
4
|
|
5
5
|
# Required for running
|
6
6
|
require 'rexml/rexml'
|
@@ -10,25 +10,30 @@ module Rackful
|
|
10
10
|
|
11
11
|
=begin markdown
|
12
12
|
Exception which represents an HTTP Status response.
|
13
|
-
@since 0.1.0
|
14
13
|
@abstract
|
15
14
|
=end
|
16
15
|
class HTTPStatus < RuntimeError
|
17
16
|
|
18
17
|
|
19
18
|
include Resource
|
19
|
+
|
20
|
+
|
20
21
|
attr_reader :status, :headers, :to_rackful
|
21
22
|
|
22
23
|
|
23
24
|
=begin markdown
|
24
|
-
@param
|
25
|
-
@param
|
26
|
-
@param
|
25
|
+
@param [Symbol, Integer] status e.g. `404` or `:not_found`
|
26
|
+
@param [String] message XHTML
|
27
|
+
@param [ { Symbol => Object }, { String => String } ] info
|
28
|
+
* If the Hash is indexed by {Symbol}s, then the values will be returned in
|
29
|
+
the response body.
|
30
|
+
* If the Hash is indexed by {String}s, the +key => value+ pairs are returned
|
31
|
+
as response headers.
|
27
32
|
=end
|
28
33
|
def initialize status, message = nil, info = {}
|
29
34
|
self.path = Request.current.path
|
30
35
|
@status = status_code status
|
31
|
-
raise "Wrong status: #{status}" if 0
|
36
|
+
raise "Wrong status: #{status}" if 0 === @status
|
32
37
|
message ||= ''
|
33
38
|
@headers = {}
|
34
39
|
@to_rackful = {}
|
@@ -53,30 +58,42 @@ class HTTPStatus < RuntimeError
|
|
53
58
|
errors.puts "Info: #{@to_rackful.inspect}"
|
54
59
|
end
|
55
60
|
end
|
61
|
+
|
62
|
+
|
63
|
+
def title
|
64
|
+
"#{status} #{HTTP_STATUS_CODES[status]}"
|
65
|
+
end
|
56
66
|
|
57
67
|
|
58
68
|
class XHTML < ::Rackful::XHTML
|
59
69
|
|
60
70
|
|
61
|
-
HTTP_STATUS_CODES = Rack::Utils::HTTP_STATUS_CODES
|
62
|
-
|
63
|
-
|
64
71
|
def header
|
65
|
-
<<EOS
|
66
|
-
<
|
67
|
-
</
|
68
|
-
<h1>HTTP/1.1 #{self.resource.status} #{HTTP_STATUS_CODES[self.resource.status]}</h1>
|
69
|
-
<div id="rackful_description">#{self.resource.message}</div>
|
72
|
+
super + <<EOS
|
73
|
+
<h1>HTTP/1.1 #{Rack::Utils.escape_html(resource.title)}</h1>
|
74
|
+
<div id="rackful_description">#{resource.message}</div>
|
70
75
|
EOS
|
71
76
|
end
|
72
77
|
|
73
78
|
|
74
|
-
def headers
|
75
|
-
|
76
|
-
|
79
|
+
def headers; self.resource.headers; end
|
80
|
+
|
81
|
+
|
82
|
+
end # class HTTPStatus::XHTML
|
77
83
|
|
78
84
|
|
79
|
-
|
85
|
+
#~ class JSON < ::Rackful::JSON
|
86
|
+
#~
|
87
|
+
#~
|
88
|
+
#~ def headers; self.resource.headers; end
|
89
|
+
#~
|
90
|
+
#~
|
91
|
+
#~ def each &block
|
92
|
+
#~ super( [ self.resource.message, self.resource.to_rackful ], &block )
|
93
|
+
#~ end
|
94
|
+
#~
|
95
|
+
#~
|
96
|
+
#~ end # class HTTPStatus::XHTML
|
80
97
|
|
81
98
|
|
82
99
|
add_serializer XHTML, 1.0
|
@@ -88,7 +105,6 @@ end # class Rackful::HTTPStatus
|
|
88
105
|
=begin markdown
|
89
106
|
@abstract Base class for HTTP status codes with only a simple text message, or
|
90
107
|
no message at all.
|
91
|
-
@since 0.1.0
|
92
108
|
=end
|
93
109
|
class HTTPSimpleStatus < HTTPStatus
|
94
110
|
|
@@ -101,7 +117,6 @@ class HTTPSimpleStatus < HTTPStatus
|
|
101
117
|
end
|
102
118
|
|
103
119
|
|
104
|
-
# @since 0.1.0
|
105
120
|
class HTTP201Created < HTTPStatus
|
106
121
|
|
107
122
|
def initialize locations
|
@@ -133,7 +148,6 @@ class HTTP201Created < HTTPStatus
|
|
133
148
|
end # class HTTP201Created
|
134
149
|
|
135
150
|
|
136
|
-
# @since 0.1.0
|
137
151
|
class HTTP202Accepted < HTTPStatus
|
138
152
|
|
139
153
|
def initialize location = nil
|
@@ -152,7 +166,6 @@ class HTTP202Accepted < HTTPStatus
|
|
152
166
|
end # class HTTP202Accepted
|
153
167
|
|
154
168
|
|
155
|
-
# @since 0.1.0
|
156
169
|
class HTTP301MovedPermanently < HTTPStatus
|
157
170
|
|
158
171
|
def initialize location
|
@@ -167,7 +180,6 @@ class HTTP301MovedPermanently < HTTPStatus
|
|
167
180
|
end
|
168
181
|
|
169
182
|
|
170
|
-
# @since 0.1.0
|
171
183
|
class HTTP303SeeOther < HTTPStatus
|
172
184
|
|
173
185
|
def initialize location
|
@@ -182,17 +194,15 @@ class HTTP303SeeOther < HTTPStatus
|
|
182
194
|
end
|
183
195
|
|
184
196
|
|
185
|
-
# @since 0.1.0
|
186
197
|
class HTTP304NotModified < HTTPStatus
|
187
198
|
|
188
|
-
def initialize
|
189
|
-
super( 304
|
199
|
+
def initialize
|
200
|
+
super( 304 )
|
190
201
|
end
|
191
202
|
|
192
203
|
end
|
193
204
|
|
194
205
|
|
195
|
-
# @since 0.1.0
|
196
206
|
class HTTP307TemporaryRedirect < HTTPStatus
|
197
207
|
|
198
208
|
def initialize location
|
@@ -207,17 +217,13 @@ class HTTP307TemporaryRedirect < HTTPStatus
|
|
207
217
|
end
|
208
218
|
|
209
219
|
|
210
|
-
# @since 0.1.0
|
211
220
|
class HTTP400BadRequest < HTTPSimpleStatus; end
|
212
221
|
|
213
|
-
# @since 0.1.0
|
214
222
|
class HTTP403Forbidden < HTTPSimpleStatus; end
|
215
223
|
|
216
|
-
# @since 0.1.0
|
217
224
|
class HTTP404NotFound < HTTPSimpleStatus; end
|
218
225
|
|
219
226
|
|
220
|
-
# @since 0.1.0
|
221
227
|
class HTTP405MethodNotAllowed < HTTPStatus
|
222
228
|
|
223
229
|
def initialize methods
|
@@ -228,7 +234,6 @@ class HTTP405MethodNotAllowed < HTTPStatus
|
|
228
234
|
end
|
229
235
|
|
230
236
|
|
231
|
-
# @since 0.1.0
|
232
237
|
class HTTP406NotAcceptable < HTTPStatus
|
233
238
|
|
234
239
|
def initialize content_types
|
@@ -239,17 +244,13 @@ class HTTP406NotAcceptable < HTTPStatus
|
|
239
244
|
end
|
240
245
|
|
241
246
|
|
242
|
-
# @since 0.1.0
|
243
247
|
class HTTP409Conflict < HTTPSimpleStatus; end
|
244
248
|
|
245
|
-
# @since 0.1.0
|
246
249
|
class HTTP410Gone < HTTPSimpleStatus; end
|
247
250
|
|
248
|
-
# @since 0.1.0
|
249
251
|
class HTTP411LengthRequired < HTTPSimpleStatus; end
|
250
252
|
|
251
253
|
|
252
|
-
# @since 0.1.0
|
253
254
|
class HTTP412PreconditionFailed < HTTPStatus
|
254
255
|
|
255
256
|
def initialize header = nil
|
@@ -265,24 +266,20 @@ class HTTP412PreconditionFailed < HTTPStatus
|
|
265
266
|
end
|
266
267
|
|
267
268
|
|
268
|
-
# @since 0.1.0
|
269
269
|
class HTTP415UnsupportedMediaType < HTTPStatus
|
270
270
|
|
271
271
|
def initialize media_types
|
272
|
-
super
|
272
|
+
super 415, '',
|
273
273
|
:'Supported media-type(s):' => media_types
|
274
274
|
end
|
275
275
|
|
276
276
|
end
|
277
277
|
|
278
278
|
|
279
|
-
# @since 0.1.0
|
280
279
|
class HTTP422UnprocessableEntity < HTTPSimpleStatus; end
|
281
280
|
|
282
|
-
# @since 0.1.0
|
283
281
|
class HTTP501NotImplemented < HTTPSimpleStatus; end
|
284
282
|
|
285
|
-
# @since 0.1.0
|
286
283
|
class HTTP503ServiceUnavailable < HTTPSimpleStatus; end
|
287
284
|
|
288
285
|
end # module Rackful
|
@@ -26,7 +26,6 @@ This can be useful if you want to specify certain request headers from within
|
|
26
26
|
a normal web browser.
|
27
27
|
@example Using this middleware
|
28
28
|
use Rackful::HeaderSpoofing
|
29
|
-
@since 0.0.1
|
30
29
|
=end
|
31
30
|
class Rackful::HeaderSpoofing
|
32
31
|
|
@@ -64,10 +63,10 @@ def before_call env
|
|
64
63
|
end
|
65
64
|
|
66
65
|
def after_call env
|
67
|
-
if original_query_string = env['rackful.header_spoofing.query_string']
|
68
|
-
env['rackful.header_spoofing.query_string'] = env['QUERY_STRING']
|
69
|
-
env['QUERY_STRING'] = original_query_string
|
70
|
-
end
|
66
|
+
#if original_query_string = env['rackful.header_spoofing.query_string']
|
67
|
+
#env['rackful.header_spoofing.query_string'] = env['QUERY_STRING']
|
68
|
+
#env['QUERY_STRING'] = original_query_string
|
69
|
+
#end
|
71
70
|
end
|
72
71
|
|
73
72
|
end # Rackful::HeaderSpoofing
|
@@ -29,7 +29,6 @@ Differences with {Rack::RelativeRedirect}:
|
|
29
29
|
- uses Rack::Request::base_url for creating absolute URIs.
|
30
30
|
- the `Location:` header, if present, is always rectified, independent of the
|
31
31
|
HTTP status code.
|
32
|
-
@since 0.0.1
|
33
32
|
=end
|
34
33
|
class Rackful::RelativeLocation
|
35
34
|
|
data/lib/rackful/path.rb
ADDED
@@ -0,0 +1,179 @@
|
|
1
|
+
# Required for parsing:
|
2
|
+
|
3
|
+
# Required for running:
|
4
|
+
require 'rack/utils'
|
5
|
+
|
6
|
+
|
7
|
+
# A String monkeypatch
|
8
|
+
# @private
|
9
|
+
class String
|
10
|
+
|
11
|
+
# @return [Rackful::Path]
|
12
|
+
def to_path; Rackful::Path.new(self); end
|
13
|
+
|
14
|
+
end
|
15
|
+
|
16
|
+
|
17
|
+
module Rackful
|
18
|
+
|
19
|
+
|
20
|
+
# Relative URI (a path)
|
21
|
+
class Path < String
|
22
|
+
|
23
|
+
|
24
|
+
# @return [self]
|
25
|
+
def to_path; self; end
|
26
|
+
|
27
|
+
|
28
|
+
# @return [Path] a copy of `self`, with a trailing slash.
|
29
|
+
def slashify
|
30
|
+
r = self.dup
|
31
|
+
r << '/' if '/' != r[-1,1]
|
32
|
+
r
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
# Adds a trailing slash to `self` if necessary.
|
37
|
+
# @return [self]
|
38
|
+
def slashify!
|
39
|
+
if '/' != self[-1,1]
|
40
|
+
self << '/'
|
41
|
+
else
|
42
|
+
nil
|
43
|
+
end
|
44
|
+
self
|
45
|
+
end
|
46
|
+
|
47
|
+
|
48
|
+
# @return [Path]a copy of `self` without a trailing slash.
|
49
|
+
def unslashify
|
50
|
+
r = self.dup
|
51
|
+
r = r.chomp( '/' ) if '/' == r[-1,1]
|
52
|
+
r
|
53
|
+
end
|
54
|
+
|
55
|
+
|
56
|
+
# Removes a trailing slash from `self`.
|
57
|
+
# @return [self]
|
58
|
+
def unslashify!
|
59
|
+
if '/' == self[-1,1]
|
60
|
+
self.chomp! '/'
|
61
|
+
else
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
self
|
65
|
+
end
|
66
|
+
|
67
|
+
|
68
|
+
# @param [Encoding] encoding the character encoding to presume for `self`
|
69
|
+
# @return [String] the unescaped version of `self`
|
70
|
+
def unescape( encoding = Encoding::UTF_8 ); Rack::Utils.unescape(self, encoding); end
|
71
|
+
|
72
|
+
|
73
|
+
# @return [Array<String>] Unencoded segments
|
74
|
+
def segments( encoding = Encoding::UTF_8 )
|
75
|
+
r = self.split('/').collect { |s| Rack::Utils.unescape( s, encoding ) }
|
76
|
+
r.shift
|
77
|
+
r
|
78
|
+
end
|
79
|
+
|
80
|
+
|
81
|
+
# Turns a relative URI (starting with `/`) into a relative path (starting with `./`)
|
82
|
+
# @param path [Path]
|
83
|
+
# @return [String] a relative URI
|
84
|
+
def relative base_path = Request.current.base_path
|
85
|
+
case self
|
86
|
+
when base_path
|
87
|
+
# RFC2396, Section 4.2
|
88
|
+
return ''
|
89
|
+
when %r{(?:\A|/)\.\.?(?:/|\z)}
|
90
|
+
# self has abnormal absolute path,
|
91
|
+
# like "/./", "/../", "/x/../", ...
|
92
|
+
return self.dup
|
93
|
+
end
|
94
|
+
|
95
|
+
src_path = base_path.scan(%r{(?:\A|[^/]+)/})
|
96
|
+
dst_path = self.scan(%r{(?:\A|[^/]+)/?})
|
97
|
+
|
98
|
+
# discard same parts
|
99
|
+
while !dst_path.empty? && dst_path.first == src_path.first
|
100
|
+
src_path.shift
|
101
|
+
dst_path.shift
|
102
|
+
end
|
103
|
+
|
104
|
+
tmp = dst_path.join
|
105
|
+
|
106
|
+
# calculate
|
107
|
+
if src_path.empty?
|
108
|
+
if tmp.empty?
|
109
|
+
return './'
|
110
|
+
elsif dst_path.first.include?(':') # (see RFC2396 Section 5)
|
111
|
+
return './' + tmp
|
112
|
+
else
|
113
|
+
return tmp
|
114
|
+
end
|
115
|
+
end
|
116
|
+
|
117
|
+
return '../' * src_path.size + tmp
|
118
|
+
end
|
119
|
+
|
120
|
+
|
121
|
+
end # class Path
|
122
|
+
|
123
|
+
|
124
|
+
end # module Rackful
|
125
|
+
|
126
|
+
|
127
|
+
#~ # Monkeypatch to this stdlib class.
|
128
|
+
#~ class URI::Generic
|
129
|
+
#~
|
130
|
+
#~ # @see http://www.w3.org/TR/html401/struct/links.html#adef-rel the HTML `rel` attribute.
|
131
|
+
#~ attr_accessor :rel
|
132
|
+
#~
|
133
|
+
#~ # @see http://www.w3.org/TR/html401/struct/links.html#adef-rev the HTML `rev` attribute.
|
134
|
+
#~ attr_accessor :rev
|
135
|
+
#~
|
136
|
+
#~ def to_xhtml base_path, encoding = Encoding::UTF_8
|
137
|
+
#~ retval = "<a href=\"#{self.route_from(base_path)}\"".encode encoding
|
138
|
+
#~ retval << " rel=\"#{self.rel}\"" if self.rel
|
139
|
+
#~ retval << " rev=\"#{self.rev}\"" if self.rev
|
140
|
+
#~ retval << '>'
|
141
|
+
#~ if self.relative? && ! self.query && ! self.fragment
|
142
|
+
#~ retval << Rack::Utils.escape_html(
|
143
|
+
#~ Rack::Utils.unescape( self.route_from(base_path).to_s, encoding )
|
144
|
+
#~ )
|
145
|
+
#~ else
|
146
|
+
#~ retval << self.to_s
|
147
|
+
#~ end
|
148
|
+
#~ retval << '</a>'
|
149
|
+
#~ retval
|
150
|
+
#~ end
|
151
|
+
#~
|
152
|
+
#~ # @return [URI::Generic]
|
153
|
+
#~ def slashify
|
154
|
+
#~ r = self.dup
|
155
|
+
#~ r.path = r.path.unslashify
|
156
|
+
#~ r
|
157
|
+
#~ end
|
158
|
+
#~
|
159
|
+
#~ # @return [self, nil]
|
160
|
+
#~ def slashify!
|
161
|
+
#~ self.path.slashify! && self
|
162
|
+
#~ end
|
163
|
+
#~
|
164
|
+
#~ # @return [URI::Generic]
|
165
|
+
#~ def unslashify
|
166
|
+
#~ r = self.dup
|
167
|
+
#~ r.path = r.path.unslashify
|
168
|
+
#~ r
|
169
|
+
#~ end
|
170
|
+
#~
|
171
|
+
#~ # @return [self, nil]
|
172
|
+
#~ def unslashify!
|
173
|
+
#~ self.path.unslashify! && self
|
174
|
+
#~ end
|
175
|
+
#~
|
176
|
+
#~ end # class ::URI::Generic
|
177
|
+
|
178
|
+
|
179
|
+
|