scytrin-maveric 2 → 3
Sign up to get free protection for your applications and to get access to all the features.
- data/lib/maveric.rb +120 -82
- metadata +1 -1
data/lib/maveric.rb
CHANGED
@@ -3,85 +3,22 @@ require 'uri'
|
|
3
3
|
require 'rack'
|
4
4
|
|
5
5
|
module Maveric
|
6
|
-
|
7
|
-
|
8
|
-
def self.[] e; @r[e]; end
|
9
|
-
def self.[]= e, v; @r[e]=v; end
|
10
|
-
def initialize err
|
11
|
-
@status, @headers, @body = if resp = Response[err] then resp else
|
12
|
-
[ DEFAULT[0],
|
13
|
-
{ 'Content-Type' => DEFAULT[1],
|
14
|
-
'Content-Length' => err.length.to_s },
|
15
|
-
err]
|
16
|
-
end
|
17
|
-
super @body
|
18
|
-
end
|
19
|
-
def each; @body.each{|line| yield line }; end
|
20
|
-
def to_a; [@status, @headers, self]; end # to_splat in 1.9
|
21
|
-
alias_method :finish, :to_a
|
22
|
-
end
|
23
|
-
|
24
|
-
module Views
|
25
|
-
attr_reader :maveric
|
26
|
-
TEMPLATES = {}
|
27
|
-
end
|
28
|
-
|
29
|
-
module Helpers
|
30
|
-
protected
|
31
|
-
|
32
|
-
# Powerhouse method to build a response. TODO: doc
|
33
|
-
def respond *args, &blk
|
34
|
-
headers = Hash === args.last ? args.pop : {}
|
35
|
-
seed = (Symbol === args.last && args.last) ? '' : args.pop
|
36
|
-
views, args = args.reverse.partition{|e| Symbol === e }
|
37
|
-
|
38
|
-
bad = views.map{|e|e.to_s} - self.class::Views.instance_methods
|
39
|
-
raise ArgumentError, 'Invalid views: '+bad.inspect unless bad.empty?
|
40
|
-
warn 'Invalid arguments: '+args.inspect unless args.empty?
|
41
|
-
|
42
|
-
response = Rack::Response.new
|
43
|
-
response.headers.update self.class.headers
|
44
|
-
response.headers.update headers.
|
45
|
-
reject{|(k,v)| !k.is_a? String or !v.is_a? String }
|
46
|
-
response.extend self.class::Views
|
47
|
-
response.instance_variable_set '@maveric', self
|
48
|
-
|
49
|
-
catch :response do
|
50
|
-
yield response if block_given?
|
51
|
-
body = views.inject(seed){|b,v| response.__send__(v,b) }.to_s
|
52
|
-
response.length = Rack::Utils.bytesize body
|
53
|
-
response.body = body.to_a
|
54
|
-
return response.finish
|
55
|
-
end
|
56
|
-
end
|
57
|
-
|
58
|
-
private
|
59
|
-
|
60
|
-
# Provides a simple way of generating a redirection response, relative to
|
61
|
-
# the current url.
|
62
|
-
def redirect uri
|
63
|
-
uri = URI(uri).normalize
|
64
|
-
uri = URI(@request.url).merge uri
|
65
|
-
[ 303, { 'Location'=>uri.to_s,
|
66
|
-
'Content-Type'=>'text/plain',
|
67
|
-
'Content-Length'=>'0'
|
68
|
-
}, [] ]
|
69
|
-
end
|
70
|
-
end
|
6
|
+
# Should contain methods to be shared amongst various maverics
|
7
|
+
module Helpers; end
|
71
8
|
|
9
|
+
# Should contain various views to be utilized by various maverics
|
10
|
+
module Views; attr_reader :maveric; TEMPLATES = {}; end
|
72
11
|
|
73
12
|
|
74
13
|
# The current instance is stored in the passed environment under the key
|
75
14
|
# 'maveric'. A Rack::Request of the current request is provided at @request.
|
76
|
-
|
77
|
-
# If no action is provided, @action is set as :index.
|
78
|
-
def initialize env, action=nil, route=nil
|
15
|
+
def initialize env
|
79
16
|
env['maveric'] = self
|
80
17
|
@request = Rack::Request.new env
|
81
|
-
@route, @action =
|
18
|
+
@route, @action = self.class.routes.empty? ?
|
19
|
+
[nil, :index] : self.class.routes.find{|(r,d)| r === env['PATH_INFO'] }
|
82
20
|
extend self.class::Helpers
|
83
21
|
self.init_hook if self.respond_to? :init_hook
|
84
|
-
p [ @request.script_name, @route, @action ]
|
85
22
|
end
|
86
23
|
attr_reader :request, :route, :action
|
87
24
|
|
@@ -110,12 +47,68 @@ module Maveric
|
|
110
47
|
end
|
111
48
|
|
112
49
|
|
50
|
+
private
|
51
|
+
|
52
|
+
|
53
|
+
# Powerhouse method to build a response. TODO: doc
|
54
|
+
def respond *args, &blk
|
55
|
+
headers = Hash === args.last ? args.pop : {}
|
56
|
+
seed = (Symbol === args.last && args.last) ? '' : args.pop
|
57
|
+
views, args = args.reverse.partition{|e| Symbol === e }
|
58
|
+
|
59
|
+
bad = views.map{|e|e.to_s} - self.class::Views.instance_methods
|
60
|
+
raise ArgumentError, 'Invalid views: '+bad.inspect unless bad.empty?
|
61
|
+
warn 'Invalid arguments: '+args.inspect unless args.empty?
|
62
|
+
|
63
|
+
response = Rack::Response.new
|
64
|
+
response.headers.update self.class.headers
|
65
|
+
response.headers.update headers.
|
66
|
+
reject{|(k,v)| !k.is_a? String or !v.is_a? String }
|
67
|
+
response.extend self.class::Views
|
68
|
+
response.instance_variable_set '@maveric', self
|
69
|
+
|
70
|
+
catch :response do
|
71
|
+
yield response if block_given?
|
72
|
+
body = views.inject(seed){|b,v| response.__send__(v,b) }.to_s
|
73
|
+
response.length = Rack::Utils.bytesize body
|
74
|
+
response.body = body.to_a
|
75
|
+
return response.finish
|
76
|
+
end
|
77
|
+
end
|
78
|
+
|
79
|
+
|
80
|
+
# Provides a simple way of generating a redirection response, relative to
|
81
|
+
# the current url.
|
82
|
+
def redirect uri
|
83
|
+
uri = URI(uri).normalize
|
84
|
+
uri = URI(@request.url).merge uri
|
85
|
+
[ 303, { 'Location'=>uri.to_s,
|
86
|
+
'Content-Type'=>'text/plain',
|
87
|
+
'Content-Length'=>'0'
|
88
|
+
}, [] ]
|
89
|
+
end
|
90
|
+
|
91
|
+
|
92
|
+
def routes_to dest
|
93
|
+
self.class.routes.select{|(r,d)| d === dest }
|
94
|
+
end
|
95
|
+
|
96
|
+
|
97
|
+
def route_to dest
|
98
|
+
routes_to(dest).find{|(r,d)| String === d }
|
99
|
+
end
|
100
|
+
|
101
|
+
|
102
|
+
|
113
103
|
# Methods provided to construct a maveric
|
114
104
|
module Class
|
115
105
|
# Default headers for Maveric instantiation.
|
116
106
|
attr_reader :routes, :headers
|
117
107
|
attr_writer :mount
|
118
108
|
|
109
|
+
# Scours through './templates', unless provided an alternate directory,
|
110
|
+
# and adds templates and a method to maveric::Views. Currently handles
|
111
|
+
# haml and erb files.
|
119
112
|
def add_templates directory='templates/*'
|
120
113
|
Dir.glob directory do |file| p file
|
121
114
|
next unless File.readable? file and tmpl = File.read(file)
|
@@ -143,9 +136,15 @@ module Maveric
|
|
143
136
|
end
|
144
137
|
end
|
145
138
|
|
139
|
+
# Instantiates a maveric with the provided environment, then calls
|
140
|
+
# maveric#response
|
146
141
|
def call env
|
147
|
-
|
148
|
-
|
142
|
+
new(env).response
|
143
|
+
end
|
144
|
+
|
145
|
+
def routing mountpoint, routes
|
146
|
+
@mount = mountpoint
|
147
|
+
routes.each{|d,a| route d, *a }
|
149
148
|
end
|
150
149
|
|
151
150
|
def route d, *a
|
@@ -156,25 +155,32 @@ module Maveric
|
|
156
155
|
@mount || self.name.downcase.gsub(/^|::/, '/')
|
157
156
|
end
|
158
157
|
|
159
|
-
def inspect
|
160
|
-
"#<Maveric:#{self.name} '#{mount}'>"
|
161
|
-
end
|
162
|
-
|
163
158
|
def self.extend_object obj
|
164
159
|
obj.instance_variable_set '@routes', []
|
165
160
|
obj.instance_variable_set '@headers', Rack::Utils::HeaderHash.new
|
166
161
|
super
|
167
162
|
end
|
163
|
+
|
164
|
+
def inspect
|
165
|
+
"#{self.name}:'#{mount}':#{routes.inspect}"
|
166
|
+
end
|
168
167
|
end
|
169
168
|
|
169
|
+
|
170
|
+
|
170
171
|
@maverics = [] unless defined? @maverics
|
171
172
|
@last_hash = nil
|
172
173
|
@map = nil
|
173
174
|
class << self
|
174
175
|
attr_reader :maverics
|
175
176
|
|
177
|
+
def inspect
|
178
|
+
"Maveric#{maverics.inspect}"
|
179
|
+
end
|
180
|
+
|
176
181
|
# Generates a Rack::URLMap compatible hash composed of all maverics and
|
177
|
-
# their mount points.
|
182
|
+
# their mount points. Will be regenerated if the list of maverics have
|
183
|
+
# changed.
|
178
184
|
def map
|
179
185
|
return @map if @map and @last_hash == @maverics.hash
|
180
186
|
@last_hash = @maverics.hash
|
@@ -195,7 +201,9 @@ module Maveric
|
|
195
201
|
self.urlmap.call env
|
196
202
|
end
|
197
203
|
|
198
|
-
|
204
|
+
# Returns itself, or a Rack::Cascade when provided an app
|
205
|
+
def new app=nil
|
206
|
+
return self unless app
|
199
207
|
Rack::Cascade.new [app, self]
|
200
208
|
end
|
201
209
|
|
@@ -226,15 +234,42 @@ module Maveric
|
|
226
234
|
return obj
|
227
235
|
end
|
228
236
|
end
|
237
|
+
|
238
|
+
|
239
|
+
|
240
|
+
# Response is an Exception class that can be raised from within a call to
|
241
|
+
# maveric#response, with 401, 403, and 404 errors provided.
|
242
|
+
#
|
243
|
+
# <tt>raise Maveric::Response, 404</tt> will look up 404 via Response#[] and
|
244
|
+
# if a value is found, it is utilized to set the status, headers, and body.
|
245
|
+
#
|
246
|
+
# <tt>raise Maveric::Response, 'Bad stuff'</tt> will generate a plain-text
|
247
|
+
# 500 response with the message as the body of the response.
|
248
|
+
#
|
249
|
+
# Additional or replacement responses should be set via Response#[]= and
|
250
|
+
# should be valid rack responses.
|
251
|
+
class Response < Exception
|
252
|
+
DEFAULT, @r = [500, 'text/plain'], {}
|
253
|
+
def self.[] e; @r[e]; end
|
254
|
+
def self.[]= e, v; @r[e]=v; end
|
255
|
+
def initialize err
|
256
|
+
resp = Response[err] || [ DEFAULT[0],
|
257
|
+
{ 'Content-Type' => DEFAULT[1], 'Content-Length' => err.length.to_s },
|
258
|
+
err]
|
259
|
+
@status, @headers, @body = resp
|
260
|
+
super @body
|
261
|
+
end
|
262
|
+
def each; @body.each{|line| yield line }; end
|
263
|
+
def to_a; [@status, @headers, self]; end # to_splat in 1.9
|
264
|
+
alias_method :finish, :to_a
|
265
|
+
end
|
229
266
|
end
|
230
267
|
|
268
|
+
|
269
|
+
|
231
270
|
class Rack::Request
|
232
271
|
# Allows the request to provide the current maveric.
|
233
272
|
def maveric; @env['maveric']; end
|
234
|
-
# Allows the request to provide the current session.
|
235
|
-
def session; @env['rack.session']; end
|
236
|
-
# Same as the standard Rack::Request method.
|
237
|
-
def url; site_root + fullpath; end
|
238
273
|
# Provides the compliment to #fullpath.
|
239
274
|
def site_root
|
240
275
|
url = scheme + "://" + host
|
@@ -243,8 +278,11 @@ class Rack::Request
|
|
243
278
|
scheme == "http" && port != 80
|
244
279
|
url
|
245
280
|
end
|
281
|
+
def url; site_root + fullpath; end
|
246
282
|
end
|
247
283
|
|
284
|
+
|
285
|
+
|
248
286
|
Maveric::Response[401] = [401,
|
249
287
|
{'Content-Type'=>'text/plain','Content-Length'=>'13'},
|
250
288
|
['Unauthorized.']]
|