scytrin-maveric 2 → 3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (2) hide show
  1. data/lib/maveric.rb +120 -82
  2. 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
- class Response < Exception
7
- DEFAULT, @r = [500, 'text/plain'], {}
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 = route, action || :index
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
- r, a = @routes.find{|(r,d)| r === env['PATH_INFO'] }
148
- new(env, a, r).response
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
- def new app
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.']]
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: scytrin-maveric
3
3
  version: !ruby/object:Gem::Version
4
- version: "2"
4
+ version: "3"
5
5
  platform: ruby
6
6
  authors:
7
7
  - scytrin