renee-core 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,112 +0,0 @@
1
- class Renee
2
- class Core
3
- class Application
4
- # Collection of useful methods for responding within a {Renee::Core} app.
5
- module Responding
6
- # Codes used by Symbol lookup in interpret_response.
7
- # @example
8
- # halt :unauthorized # would return a 401.
9
- #
10
- HTTP_CODES = {
11
- :ok => 200,
12
- :created => 201,
13
- :accepted => 202,
14
- :no_content => 204,
15
- :no_content => 204,
16
- :bad_request => 400,
17
- :unauthorized => 401,
18
- :payment_required => 403,
19
- :not_found => 404,
20
- :method_not_found => 405,
21
- :not_acceptable => 406,
22
- :gone => 410,
23
- :error => 500,
24
- :not_implemented => 501}.freeze
25
-
26
- # Halts current processing to the top-level calling Renee application and uses that as a response.
27
- # @param [Object...] response The response to use.
28
- # @see #interpret_response
29
- def halt(*response)
30
- throw :halt, interpret_response(response.size == 1 ? response.first : response)
31
- end
32
-
33
- ##
34
- # Creates a response by allowing the response header, body and status to be passed into the block.
35
- #
36
- # @param [Array] body The contents to return.
37
- # @param [Integer] status The status code to return.
38
- # @param [Hash] header The headers to return.
39
- # @param [Proc] &blk The response options to specify
40
- #
41
- # @example
42
- # respond { status 200; body "Yay!" }
43
- # respond("Hello", 200, "foo" => "bar")
44
- #
45
- def respond(body=[], status=200, header={}, &blk)
46
- Renee::Core::Response.new(body, status, header).tap { |r| r.instance_eval(&blk) if block_given? }.finish
47
- end
48
-
49
- ##
50
- # Creates a response by allowing the response header, body and status to be passed into the block.
51
- #
52
- # @example
53
- # respond! { status 200; body "Yay!" }
54
- #
55
- # @param (see #respond)
56
- # @see #respond
57
- def respond!(*args, &blk)
58
- halt respond(*args, &blk)
59
- end
60
-
61
- # Interprets responses returns by #halt.
62
- #
63
- # * If it is a Symbol, it will be looked up in {HTTP_CODES}.
64
- # * If it is a Symbol, it will use Rack::Response to return the value.
65
- # * If it is a Symbol, it will either be used as a Rack response or as a body and status code.
66
- # * If it is an Integer, it will use Rack::Response to return the status code.
67
- # * Otherwise, #to_s will be called on it and it will be treated as a Symbol.
68
- #
69
- # @param [Object] response This can be either a Symbol, String, Array or any Object.
70
- #
71
- def interpret_response(response)
72
- case response
73
- when Array then
74
- case response.size
75
- when 3 then response
76
- when 2 then Renee::Core::Response.new(response[1], HTTP_CODES[response[0]] || response[0]).finish
77
- else raise "I don't know how to render #{response.inspect}"
78
- end
79
- when String then Renee::Core::Response.new(response).finish
80
- when Integer then Renee::Core::Response.new("Status code #{response}", response).finish
81
- when Symbol then interpret_response(HTTP_CODES[response] || response.to_s)
82
- when Proc then instance_eval(&response)
83
- else raise "Unable to render #{response.inspect}"
84
- end
85
- end
86
-
87
- # Returns a rack-based response for redirection.
88
- # @param [String] path The URL to redirect to.
89
- # @param [Integer] code The HTTP code to use.
90
- # @example
91
- # r = Renee::Core.new { get { halt redirect '/index' } }
92
- # r.call(Rack::MockResponse("/")) # => [302, {"Location" => "/index"}, []]
93
- def redirect(path, code = 302)
94
- response = ::Rack::Response.new
95
- response.redirect(path, code)
96
- response.finish
97
- end
98
-
99
- # Halts with a rack-based response for redirection.
100
- # @see #redirect
101
- # @param [String] path The URL to redirect to.
102
- # @param [Integer] code The HTTP code to use.
103
- # @example
104
- # r = Renee::Core.new { get { redirect! '/index' } }
105
- # r.call(Rack::MockResponse("/")) # => [302, {"Location" => "/index"}, []]
106
- def redirect!(path, code = 302)
107
- halt redirect(path, code)
108
- end
109
- end
110
- end
111
- end
112
- end
@@ -1,319 +0,0 @@
1
- class Renee
2
- class Core
3
- class Application
4
- # Collection of useful methods for routing within a {Renee::Core} app.
5
- module Routing
6
- include Chaining
7
-
8
- # Match a path to respond to.
9
- #
10
- # @param [String] p
11
- # path to match.
12
- # @param [Proc] blk
13
- # block to yield
14
- #
15
- # @example
16
- # path('/') { ... } #=> '/'
17
- # path('test') { ... } #=> '/test'
18
- #
19
- # path 'foo' do
20
- # path('bar') { ... } #=> '/foo/bar'
21
- # end
22
- #
23
- # @api public
24
- def path(p, &blk)
25
- p = p[1, p.size] if p[0] == ?/
26
- extension_part = detected_extension ? "|\\.#{Regexp.quote(detected_extension)}" : ""
27
- part(/^\/#{Regexp.quote(p)}(\/?|$)(?=\/|$#{extension_part})/, &blk)
28
- end
29
- chain_method :path
30
-
31
- # Like #path, but requires the entire path to be consumed.
32
- # @see #path
33
- def whole_path(p, &blk)
34
- path(p) { complete(&blk) }
35
- end
36
- chain_method :whole_path
37
-
38
- # Like #path, but doesn't automatically match trailing-slashes.
39
- # @see #path
40
- def exact_path(p, &blk)
41
- p = p[1, part.size] if p[0] == ?/
42
- part(/^\/#{Regexp.quote(p)}/, &blk)
43
- end
44
- chain_method :exact_path
45
-
46
- # Like #path, but doesn't look for leading slashes.
47
- def part(p, &blk)
48
- p = /\/?#{Regexp.quote(p)}/ if p.is_a?(String)
49
- if match = env['PATH_INFO'][p]
50
- with_path_part(match) { blk.call }
51
- end
52
- end
53
- chain_method :part
54
-
55
- # Match parts off the path as variables. The parts matcher can conform to either a regular expression, or be an Integer, or
56
- # simply a String.
57
- # @param[Object] type the type of object to match for. If you supply Integer, this will only match integers in addition to casting your variable for you.
58
- # @param[Object] default the default value to use if your param cannot be successfully matched.
59
- #
60
- # @example
61
- # path '/' do
62
- # variable { |id| halt [200, {}, id] }
63
- # end
64
- # GET /hey #=> [200, {}, 'hey']
65
- #
66
- # @example
67
- # path '/' do
68
- # variable(:integer) { |id| halt [200, {}, "This is a numeric id: #{id}"] }
69
- # end
70
- # GET /123 #=> [200, {}, 'This is a numeric id: 123']
71
- #
72
- # @example
73
- # path '/test' do
74
- # variable { |foo, bar| halt [200, {}, "#{foo}-#{bar}"] }
75
- # end
76
- # GET /test/hey/there #=> [200, {}, 'hey-there']
77
- #
78
- # @api public
79
- def variable(type = nil, &blk)
80
- complex_variable(type, '/', 1, &blk)
81
- end
82
- alias_method :var, :variable
83
- chain_method :variable, :var
84
-
85
- # Same as variable except you can match multiple variables with the same type.
86
- # @param [Range, Integer] count The number of parameters to capture.
87
- # @param [Symbol] type The type to use for match.
88
- def multi_variable(count, type = nil, &blk)
89
- complex_variable(type, '/', count, &blk)
90
- end
91
- alias_method :multi_var, :multi_variable
92
- alias_method :mvar, :multi_variable
93
- chain_method :multi_variable, :multi_var, :mvar
94
-
95
- # Same as variable except it matches indefinitely.
96
- # @param [Symbol] type The type to use for match.
97
- def repeating_variable(type = nil, &blk)
98
- complex_variable(type, '/', nil, &blk)
99
- end
100
- alias_method :glob, :repeating_variable
101
- chain_method :repeating_variable, :glob
102
-
103
- # Match parts off the path as variables without a leading slash.
104
- # @see #variable
105
- # @api public
106
- def partial_variable(type = nil, &blk)
107
- complex_variable(type, nil, 1, &blk)
108
- end
109
- alias_method :part_var, :partial_variable
110
- chain_method :partial_variable, :part_var
111
-
112
- # Match an extension.
113
- #
114
- # @example
115
- # extension('html') { |path| halt [200, {}, path] }
116
- #
117
- # @api public
118
- def extension(ext, &blk)
119
- if detected_extension && match = detected_extension[ext]
120
- if match == detected_extension
121
- (ext_match = env['PATH_INFO'][/\/?\.#{match}/]) ?
122
- with_path_part(ext_match, &blk) : blk.call
123
- end
124
- end
125
- end
126
- alias_method :ext, :extension
127
- chain_method :extension, :ext
128
-
129
- # Match no extension.
130
- #
131
- # @example
132
- # no_extension { |path| halt [200, {}, path] }
133
- #
134
- # @api public
135
- def no_extension(&blk)
136
- blk.call if detected_extension.nil?
137
- end
138
- chain_method :no_extension
139
-
140
- # Match any remaining path.
141
- #
142
- # @example
143
- # remainder { |path| halt [200, {}, path] }
144
- #
145
- # @api public
146
- def remainder(&blk)
147
- with_path_part(env['PATH_INFO']) { |var| blk.call(var) }
148
- end
149
- alias_method :catchall, :remainder
150
- chain_method :remainder, :catchall
151
-
152
- # Respond to a GET request and yield the block.
153
- #
154
- # @example
155
- # get { halt [200, {}, "hello world"] }
156
- #
157
- # @api public
158
- def get(path = nil, &blk)
159
- request_method('GET', path, &blk)
160
- end
161
- chain_method :get
162
-
163
- # Respond to a POST request and yield the block.
164
- #
165
- # @example
166
- # post { halt [200, {}, "hello world"] }
167
- #
168
- # @api public
169
- def post(path = nil, &blk)
170
- request_method('POST', path, &blk)
171
- end
172
- chain_method :post
173
-
174
- # Respond to a PUT request and yield the block.
175
- #
176
- # @example
177
- # put { halt [200, {}, "hello world"] }
178
- #
179
- # @api public
180
- def put(path = nil, &blk)
181
- request_method('PUT', path, &blk)
182
- end
183
- chain_method :put
184
-
185
- # Respond to a DELETE request and yield the block.
186
- #
187
- # @example
188
- # delete { halt [200, {}, "hello world"] }
189
- #
190
- # @api public
191
- def delete(path = nil, &blk)
192
- request_method('DELETE', path, &blk)
193
- end
194
- chain_method :delete
195
-
196
- # Match only when the path has been completely consumed.
197
- #
198
- # @example
199
- # complete { halt [200, {}, "hello world"] }
200
- #
201
- # @api public
202
- def complete(&blk)
203
- if env['PATH_INFO'] == '' || is_index_request
204
- with_path_part(env['PATH_INFO']) { blk.call }
205
- end
206
- end
207
- chain_method :complete
208
-
209
- # Match variables within the query string.
210
- #
211
- # @param [Array, Hash] q
212
- # Either an array or hash of things to match query string variables. If given
213
- # an array, if you pass the values for each key as parameters to the block given.
214
- # If given a hash, then every value must be able to be matched by a registered type.
215
- #
216
- # @example
217
- # query(:key => :integer) { |h| halt [200, {}, "hello world #{h[:key]}"] }
218
- #
219
- # @example
220
- # query(:key) { |val| halt [200, {}, "key is #{val}"] }
221
- #
222
- # @api public
223
- def query(q, &blk)
224
- case q
225
- when Hash then blk.call(Hash[q.map{|(k, v)| [k, transform(v, request[k.to_s]) || return]}])
226
- when Array then blk.call(*q.map{|qk| request[qk.to_s] or return })
227
- else query([q], &blk)
228
- end
229
- end
230
- chain_method :query
231
-
232
- # Yield block if the query string matches.
233
- #
234
- # @param [String] qs
235
- # The query string to match.
236
- #
237
- # @example
238
- # path 'test' do
239
- # query_string 'foo=bar' do
240
- # halt [200, {}, 'matched']
241
- # end
242
- # end
243
- # GET /test?foo=bar #=> 'matched'
244
- #
245
- # @api public
246
- def query_string(qs, &blk)
247
- blk.call if qs === env['QUERY_STRING']
248
- end
249
- chain_method :query_string
250
-
251
- private
252
- def complex_variable(type, prefix, count)
253
- matcher = variable_matcher_for_type(type)
254
- path = env['PATH_INFO'].dup
255
- vals = []
256
- var_index = 0
257
- variable_matching_loop(count) do
258
- path.start_with?(prefix) ? path.slice!(0, prefix.size) : break if prefix
259
- if match = matcher[path]
260
- path.slice!(0, match.first.size)
261
- vals << match.last
262
- end
263
- end
264
- return unless count.nil? || count === vals.size
265
- with_path_part(env['PATH_INFO'][0, env['PATH_INFO'].size - path.size]) do
266
- if count == 1
267
- yield(vals.first)
268
- else
269
- yield(vals)
270
- end
271
- end
272
- end
273
-
274
- def variable_matching_loop(count)
275
- case count
276
- when Range then count.max.times { break unless yield }
277
- when nil then loop { break unless yield }
278
- else count.times { break unless yield }
279
- end
280
- end
281
-
282
- def variable_matcher_for_type(type)
283
- if settings.variable_types.key?(type)
284
- settings.variable_types[type]
285
- else
286
- regexp = case type
287
- when nil, String
288
- detected_extension ?
289
- /(([^\/](?!#{Regexp.quote(detected_extension)}$))+)(?=$|\/|\.#{Regexp.quote(detected_extension)})/ :
290
- /([^\/]+)(?=$|\/)/
291
- when Regexp
292
- type
293
- else
294
- raise "Unexpected variable type #{type.inspect}"
295
- end
296
- proc do |path|
297
- if match = /^#{regexp.to_s}/.match(path)
298
- [match[0]]
299
- end
300
- end
301
- end
302
- end
303
-
304
- def with_path_part(part)
305
- old_path_info, old_script_name = env['PATH_INFO'], env['SCRIPT_NAME']
306
- script_part, env['PATH_INFO'] = old_path_info[0, part.size], old_path_info[part.size, old_path_info.size]
307
- env['SCRIPT_NAME'] += script_part
308
- yield script_part
309
- env['PATH_INFO'], env['SCRIPT_NAME'] = old_path_info, old_script_name
310
- end
311
-
312
- def request_method(method, path = nil, &blk)
313
- path ? whole_path(path) { blk.call } : complete { blk.call } if env['REQUEST_METHOD'] == method
314
- end
315
- chain_method :request_method
316
- end
317
- end
318
- end
319
- end
@@ -1,20 +0,0 @@
1
- class Renee
2
- class Core
3
- class Application
4
- # Module used for transforming arbitrary values using the registerd variable types.
5
- # @see #register_variable_name.
6
- #
7
- module Transform
8
- # Transforms a value according to the rules specified by #register_variable_name.
9
- # @param [Symbol] name The name of the variable type.
10
- # @param [String] value The value to transform.
11
- # @return The transformed value or nil.
12
- def transform(type, value)
13
- if settings.variable_types.key?(type) and m = settings.variable_types[type][value]
14
- m.first == value ? m.last : nil
15
- end
16
- end
17
- end
18
- end
19
- end
20
- end