rackful 0.1.2 → 0.1.3
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.
- 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
|
+
|