scytrin-maveric 2 → 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/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.']]
|