maveric 0.2.0 → 0.3.0
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.
|
@@ -20,59 +20,66 @@
|
|
|
20
20
|
# conceptualization over algorithm implementation. It's usable, but kinda.
|
|
21
21
|
#
|
|
22
22
|
# Ahh, 0.2.0, wherein we reevaluate ourselves and our ways and eliminate the
|
|
23
|
-
# cruft and improve our efficiency. We have a new implementation of
|
|
24
|
-
# going on, they're now regexps. The ServerError class has been removed, now any
|
|
23
|
+
# cruft and improve our efficiency. We have a new implementation of Route
|
|
24
|
+
# going on, they're now regexps. The ServerError class has been removed, now any
|
|
25
|
+
# subclass of Exception can be raised. One of the larger differences is greater
|
|
25
26
|
# customization of Maveric and Controller instances through extending methods.
|
|
26
27
|
# These are touched upon in their respective docs. Have fun!
|
|
27
|
-
#
|
|
28
|
+
#
|
|
29
|
+
# I was hoping for a 0.2.1 with refined documentation, updated plugins, and a
|
|
30
|
+
# better execution path. Instead I got all of that as well as altering basic
|
|
31
|
+
# implementation details and adding pre and post processors for Controller and
|
|
32
|
+
# refinment of Maveric's. With the degree of changes we get 0.3.0! Nothing
|
|
33
|
+
# but good stuff yo.
|
|
34
|
+
#
|
|
28
35
|
# == Authors
|
|
29
|
-
#
|
|
36
|
+
#
|
|
30
37
|
# Maveric is designed and coded by {blink}[mailto:blinketje@gmail.com]
|
|
31
38
|
# of #ruby-lang on irc.freenode.net
|
|
32
|
-
#
|
|
39
|
+
#
|
|
33
40
|
# == Licence
|
|
34
|
-
#
|
|
41
|
+
#
|
|
35
42
|
# This software is licensed under the
|
|
36
43
|
# {CC-GNU LGPL}[http://creativecommons.org/licenses/LGPL/2.1/]
|
|
37
|
-
#
|
|
44
|
+
#
|
|
38
45
|
# == Disclaimer
|
|
39
|
-
#
|
|
46
|
+
#
|
|
40
47
|
# This software is provided "as is" and without any express or
|
|
41
48
|
# implied warranties, including, without limitation, the implied
|
|
42
49
|
# warranties of merchantability and fitness for a particular purpose.
|
|
43
50
|
# Authors are not responsible for any damages, direct or indirect.
|
|
44
|
-
#
|
|
51
|
+
#
|
|
45
52
|
# = Maveric: History
|
|
46
|
-
#
|
|
53
|
+
#
|
|
47
54
|
# Maveric was initially designed as a replacement for Camping in the style of a
|
|
48
|
-
# Model-View-Controller framework. Early implementations aimed to reduce the
|
|
55
|
+
# Model-View-Controller framework. Early implementations aimed to reduce the
|
|
49
56
|
# amount of "magic" to 0. Outstanding magic of Camping is that nothing is
|
|
50
57
|
# related due to the reading, gsub-ing, and eval-ing of the Camping source file
|
|
51
58
|
# Also, even the unobfuscated/unabridged version of Camping is a bit hard to
|
|
52
59
|
# follow at times.
|
|
53
|
-
#
|
|
54
|
-
# However, the result of this initial attempt was a spaghetti of winding code,
|
|
60
|
+
#
|
|
61
|
+
# However, the result of this initial attempt was a spaghetti of winding code,
|
|
55
62
|
# empty template modules, and rediculous inheritance paths between the template
|
|
56
|
-
# modules and a plethora of dynamically generated classes and modules. I got
|
|
63
|
+
# modules and a plethora of dynamically generated classes and modules. I got
|
|
57
64
|
# more complaints with that particular jumble of code than any other, evar.
|
|
58
|
-
#
|
|
59
|
-
# The next iteration of Maveric was a seeking of simplification and departure
|
|
60
|
-
# from the concept of cloning Camping and its functionality and settling for
|
|
65
|
+
#
|
|
66
|
+
# The next iteration of Maveric was a seeking of simplification and departure
|
|
67
|
+
# from the concept of cloning Camping and its functionality and settling for
|
|
61
68
|
# Camping-esqe. At this point, I started talking to ezmobius on #ruby-lang and
|
|
62
|
-
# their Merb project. We talked a bit about merging and brainstorming but my
|
|
69
|
+
# their Merb project. We talked a bit about merging and brainstorming but my
|
|
63
70
|
# lone wolf tendencies stirred me away from such an endeavour, but I came away
|
|
64
71
|
# a compatriot and inspiration for a new routing methodology inspired by Merb's.
|
|
65
|
-
# The result is the Route that's been stable since, only varying in method
|
|
72
|
+
# The result is the Route that's been stable since, only varying in method
|
|
66
73
|
# placement and data management.
|
|
67
|
-
#
|
|
74
|
+
#
|
|
68
75
|
# After building to a version that stood on it's owned and was able to run a
|
|
69
76
|
# variance of my website as functional as the Camping version. I noticed a few
|
|
70
77
|
# tendncies of my coding and refactored. I also redesigned the concept from a
|
|
71
78
|
# modules that included the Maveric module to that of subclassing Maveric, which
|
|
72
|
-
# is a Mongrel::HttpHandlerPlugin. This allowed the running of Maveric apps
|
|
79
|
+
# is a Mongrel::HttpHandlerPlugin. This allowed the running of Maveric apps
|
|
73
80
|
# without using Mongrel::CampingHandler as well as not worrying about namespace
|
|
74
81
|
# clobbering.
|
|
75
|
-
#
|
|
82
|
+
#
|
|
76
83
|
# Because ehird from #ruby-lang was whining about it so much I removed its
|
|
77
84
|
# dependancy on Mongrel sooner than later. Maveric should now be very maveric.
|
|
78
85
|
#
|
|
@@ -80,50 +87,54 @@
|
|
|
80
87
|
# I revised and refactored codes and algorithms into 0.2.0 which will hopefully
|
|
81
88
|
# be all that I want. Everything beyond 1.0.0 will be improvements and
|
|
82
89
|
# extensions.
|
|
83
|
-
#
|
|
90
|
+
#
|
|
84
91
|
# = Features
|
|
85
92
|
# * Optional sessions
|
|
86
93
|
# * Flexible and strong route setup
|
|
87
94
|
# * Sharing of a Controller between Maveric instances is facilitated
|
|
88
95
|
# * Inheritance is highly respected
|
|
89
|
-
#
|
|
96
|
+
#
|
|
90
97
|
# == Not so Maveric
|
|
91
98
|
#
|
|
92
|
-
#
|
|
93
|
-
#
|
|
94
|
-
#
|
|
99
|
+
# Maveric has additional classes to allow you to run Maveric behind different
|
|
100
|
+
# http server implementations. CGI, FastCGI, and Mongrel are supported. If
|
|
101
|
+
# another service exists that you'd like to have supported please submit a
|
|
102
|
+
# patch of a good reason why.
|
|
103
|
+
#
|
|
104
|
+
# NOTE: Beyond Maveric 0.1.0 extensions have not been touched, future releases
|
|
105
|
+
# should include updates. AFAIK they should work.
|
|
106
|
+
#
|
|
95
107
|
# For these examples we will utilize the simplest functional Maveric possible
|
|
96
108
|
# require 'maveric'
|
|
97
|
-
# class Maveric::
|
|
109
|
+
# class Maveric::Index < Maveric::Controller
|
|
98
110
|
# def get
|
|
99
|
-
# 'Hello'
|
|
111
|
+
# 'Hello, world!'
|
|
100
112
|
# end
|
|
101
113
|
# end
|
|
102
|
-
#
|
|
114
|
+
#
|
|
115
|
+
# To use CGI:
|
|
116
|
+
# Maveric.new.dispatch.to_s
|
|
117
|
+
#
|
|
118
|
+
# To use FastCGI:
|
|
119
|
+
# require 'maveric/fastcgi'
|
|
120
|
+
# ::Maveric::FCGI.new(MyMaveric)
|
|
121
|
+
#
|
|
103
122
|
# To use Mongrel:
|
|
104
123
|
# require 'maveric/mongrel'
|
|
105
124
|
# h = ::Mongrel::HttpHandler ip, port
|
|
106
125
|
# h.register mountpoint, ::Maveric::MongrelHandler.new(MyMaveric)
|
|
107
126
|
# h.join.run
|
|
108
|
-
#
|
|
109
|
-
# To use FastCGI:
|
|
110
|
-
# require 'maveric/fastcgi'
|
|
111
|
-
# ::Maveric::FCGI.new(MyMaveric)
|
|
112
|
-
#
|
|
113
|
-
# To use WEBrick, which I have come to loathe:
|
|
114
|
-
# server = ::WEBrick::HTTPServer.new(:Port => 9090)
|
|
115
|
-
# trap('INT'){ puts "Shutting down server."; server.stop }
|
|
116
|
-
# server.mount '/', ::Maveric::WEBrickServlet, Maveric
|
|
117
|
-
# server.start
|
|
118
|
-
#
|
|
127
|
+
#
|
|
119
128
|
# However, if your script is mounted at a point other than /, use the
|
|
120
129
|
# :path_prefix option to adjust your routes. This affects all routes generated
|
|
121
130
|
# from MyMaveric.
|
|
122
|
-
# ::Maveric::FCGI.new(MyMaveric, :path_prefix =>
|
|
123
|
-
#
|
|
131
|
+
# ::Maveric::FCGI.new(MyMaveric, :path_prefix => mountpoint
|
|
132
|
+
# h.register mountpoint, ::Maveric::MongrelHandler.
|
|
133
|
+
# new(MyMaveric, :path_prefix => mountpoint)
|
|
134
|
+
#
|
|
124
135
|
# --------------------------------
|
|
125
|
-
#
|
|
126
|
-
# NOTE: Due to rampant debugging and benchmarking there is a plethora of
|
|
136
|
+
#
|
|
137
|
+
# NOTE: Due to rampant debugging and benchmarking there is a plethora of
|
|
127
138
|
# pointless time checks in place. Anything greater than the WARN level on the
|
|
128
139
|
# logging output tends to output a good deal of information. DEBUG is not for
|
|
129
140
|
# the meek.
|
|
@@ -135,29 +146,19 @@ require 'maveric/extensions'
|
|
|
135
146
|
# = The Maveric: Yeargh.
|
|
136
147
|
# The Maveric may be used alone or may be used in a cadre of loosely aligned
|
|
137
148
|
# Maveric instances. The Maveric stands tall and proud, relying on it's fine
|
|
138
|
-
# family and it's inventory of goods to get things done with little magic or
|
|
149
|
+
# family and it's inventory of goods to get things done with little magic or
|
|
139
150
|
# trickery.
|
|
140
|
-
#
|
|
141
|
-
# = Usage
|
|
142
|
-
# We could technically have a running Maveric with:
|
|
143
|
-
#
|
|
144
|
-
# require 'maveric'
|
|
145
|
-
# class Maveric::Index < Maveric::Controller
|
|
146
|
-
# def get
|
|
147
|
-
# 'Hello, world!'
|
|
148
|
-
# end
|
|
149
|
-
# end
|
|
150
|
-
# maveric = Maveric.new # I'm a real boy now!
|
|
151
|
-
#
|
|
152
|
-
# but that's not very useful.
|
|
153
151
|
class Maveric
|
|
152
|
+
## Implementation details.
|
|
153
|
+
VERSION='0.3.0'
|
|
154
|
+
|
|
154
155
|
## Standard end of line for HTTP
|
|
155
156
|
EOL="\r\n"
|
|
156
157
|
## Group 1 wil contain a boundary for multipart/form-data bodies.
|
|
157
158
|
MP_BOUND_REGEX = /\Amultipart\/form-data.*boundary=\"?([^\";, ]+)\"?/n
|
|
158
159
|
|
|
159
|
-
# I hate putting utility methods here, rather than in some module, but
|
|
160
|
-
#
|
|
160
|
+
# I hate putting utility methods here, rather than in some module, but
|
|
161
|
+
# I don't see how to do it without getting messy.
|
|
161
162
|
class << self
|
|
162
163
|
## Builds a logging object if there's not one yet, then returns it.
|
|
163
164
|
def log
|
|
@@ -165,7 +166,8 @@ class Maveric
|
|
|
165
166
|
@@maveric_logger = Log4r::Logger.new 'mvc'
|
|
166
167
|
@@maveric_logger.outputters = Log4r::Outputter['stderr']
|
|
167
168
|
@@maveric_logger.level = Log4r::INFO
|
|
168
|
-
@@maveric_logger.info "#{self}
|
|
169
|
+
@@maveric_logger.info "#{self} #{::Maveric::VERSION}"+
|
|
170
|
+
" integrated at #{Time.now}"
|
|
169
171
|
end
|
|
170
172
|
@@maveric_logger
|
|
171
173
|
end
|
|
@@ -174,14 +176,14 @@ class Maveric
|
|
|
174
176
|
def escape(s)
|
|
175
177
|
s.to_s.gsub(/([^ a-zA-Z0-9_.-]+)/n) {
|
|
176
178
|
'%'+$1.unpack('H2'*$1.size).join('%').upcase
|
|
177
|
-
}.tr(' ', '+')
|
|
179
|
+
}.tr(' ', '+')
|
|
178
180
|
end
|
|
179
181
|
|
|
180
182
|
## Unescapes a URI escaped string.
|
|
181
183
|
def unescape(s)
|
|
182
184
|
s.tr('+', ' ').gsub(/((?:%[0-9a-fA-F]{2})+)/n){
|
|
183
185
|
[$1.delete('%')].pack('H*')
|
|
184
|
-
}
|
|
186
|
+
}
|
|
185
187
|
end
|
|
186
188
|
|
|
187
189
|
##
|
|
@@ -206,7 +208,7 @@ class Maveric
|
|
|
206
208
|
#
|
|
207
209
|
# Might need to be rehauled to match query_parse's behaviour.
|
|
208
210
|
def parse_multipart boundary, body
|
|
209
|
-
::Maveric.type_check :body, body, IO
|
|
211
|
+
::Maveric.type_check :body, body, IO, StringIO
|
|
210
212
|
values = {}
|
|
211
213
|
bound = /(?:\r?\n|\A)#{Regexp::quote('--'+boundary)}(?:--)?\r$/
|
|
212
214
|
until body.eof?
|
|
@@ -217,7 +219,7 @@ class Maveric
|
|
|
217
219
|
fv[:type] = $1
|
|
218
220
|
when /^Content-Disposition: form-data;/
|
|
219
221
|
$'.scan(/(?:\s(\w+)="([^"]+)")/) {|w| fv[w[0].intern] = w[1] }
|
|
220
|
-
end
|
|
222
|
+
end
|
|
221
223
|
end
|
|
222
224
|
|
|
223
225
|
o = unless fv[:filename] then ''
|
|
@@ -236,13 +238,15 @@ class Maveric
|
|
|
236
238
|
end
|
|
237
239
|
|
|
238
240
|
##
|
|
239
|
-
# I have a penchant for static typing,
|
|
241
|
+
# I have a penchant for static typing, so as a general assertion
|
|
240
242
|
# and insurance that the correct types of data are being passed I created
|
|
241
243
|
# this little checking method. It will test value to be an instance of
|
|
242
244
|
# any of the trailing class, or if the block provided evalutates as true.
|
|
243
245
|
def type_check name, value, *klasses, &test
|
|
244
|
-
|
|
245
|
-
|
|
246
|
+
return unless $DEBUG
|
|
247
|
+
# order of speed: #include?, #index, #any?
|
|
248
|
+
if i = klasses.any?{|k|value.is_a? k} then return i
|
|
249
|
+
elsif test and r = test[value] then return r
|
|
246
250
|
else
|
|
247
251
|
raise TypeError, "Expected #{klasses*' or '} for #{name},"+
|
|
248
252
|
" got #{value.class}:#{value.inspect}."
|
|
@@ -265,8 +269,6 @@ class Maveric
|
|
|
265
269
|
end
|
|
266
270
|
|
|
267
271
|
##
|
|
268
|
-
# Family is important.
|
|
269
|
-
#
|
|
270
272
|
# Sets up a new Maveric with everything it needs for normal
|
|
271
273
|
# operation. Many things are either copied or included from it's
|
|
272
274
|
# parent The logger is copied and Models and Views are included by
|
|
@@ -280,51 +282,51 @@ class Maveric
|
|
|
280
282
|
module_eval { include parent::Models }
|
|
281
283
|
const_set(:Views, Module.new).
|
|
282
284
|
module_eval { include parent::Views }
|
|
285
|
+
@adj_env = parent.adjust_env.dup
|
|
283
286
|
end
|
|
284
287
|
end
|
|
288
|
+
|
|
289
|
+
##
|
|
290
|
+
# If no argument is given, the array of actions is returned.
|
|
291
|
+
#
|
|
292
|
+
# If a Symbol or String is given with no block, in prepare_env, the
|
|
293
|
+
# corresponding method is called with the environment hash as an argument.
|
|
294
|
+
# If a block is given then, in prepare_env, that block will be called
|
|
295
|
+
# with the environment hash as the single argument.
|
|
296
|
+
#
|
|
297
|
+
# If you are specifying other options you must explicitly state
|
|
298
|
+
# :name => <chosen label> as an argument.
|
|
299
|
+
# Additional arguments include :test, which should be a Proc that
|
|
300
|
+
# accepts a single argument. The argument will be the environment
|
|
301
|
+
# hash and the boolean result of the block will determine if the
|
|
302
|
+
# block will run.
|
|
303
|
+
def adjust_env act={}, &block
|
|
304
|
+
::Maveric.type_check :act, act, Hash, Symbol, String
|
|
305
|
+
return @adj_env if act.is_a? Hash and act.empty?
|
|
306
|
+
act = {:name => act} unless act.is_a? Hash
|
|
307
|
+
act[:do] = block
|
|
308
|
+
@adj_env << act
|
|
309
|
+
end
|
|
285
310
|
end
|
|
311
|
+
@adj_env = []
|
|
286
312
|
|
|
287
313
|
##
|
|
288
|
-
# When instantiated, the Maveric
|
|
289
|
-
# nested Controllers and adds them by their
|
|
314
|
+
# When instantiated, the Maveric decends through its constants for
|
|
315
|
+
# nested Controllers and adds them by their routes.
|
|
290
316
|
def initialize opts={}
|
|
291
317
|
::Maveric.log.info "#{self.class} instantiated at #{Time.now}"
|
|
292
318
|
::Maveric.type_check :opts, opts, Hash
|
|
293
|
-
@options = opts
|
|
294
|
-
@
|
|
295
|
-
self.class.nested_controllers.
|
|
296
|
-
each {|c| add_routes c, c.routes, {:maveric => self} }
|
|
319
|
+
@options = {:path_prefix => '/'}.merge opts
|
|
320
|
+
@router = ::Maveric::Router.new
|
|
321
|
+
self.class.nested_controllers.each {|c| router.add c.routes, c }
|
|
297
322
|
end
|
|
298
323
|
|
|
299
|
-
attr_reader :options, :
|
|
300
|
-
|
|
301
|
-
## Returns an array of controllers that are being routed to.
|
|
302
|
-
def controllers
|
|
303
|
-
@routings.values.uniq
|
|
304
|
-
end
|
|
324
|
+
attr_reader :options, :router
|
|
305
325
|
|
|
306
326
|
##
|
|
307
|
-
#
|
|
308
|
-
# String.
|
|
309
|
-
def add_route controller, route, opts={}
|
|
310
|
-
::Maveric.log.info "#{self.class}#add_route"+
|
|
311
|
-
" #{controller.inspect} #{route.inspect}"
|
|
312
|
-
route = ::Maveric::Routing.new route, opts if route.instance_of? String
|
|
313
|
-
::Maveric.type_check :controller, controller, Class
|
|
314
|
-
::Maveric.type_check :route, route, ::Maveric::Routing
|
|
315
|
-
@routings[route] = controller
|
|
316
|
-
end
|
|
317
|
-
|
|
318
|
-
## Used for adding multiple routes via #add_route
|
|
319
|
-
def add_routes controller, routes, opts={}
|
|
320
|
-
routes.flatten.map {|route| add_route controller, route, opts }
|
|
321
|
-
end
|
|
322
|
-
|
|
323
|
-
##
|
|
324
|
-
# A Maveric's cue to start doing the heavy lifting. The env should be
|
|
327
|
+
# Maveric's cue to start doing the heavy lifting. The env should be
|
|
325
328
|
# a hash with the typical assignments from an HTTP environment or crying
|
|
326
329
|
# and whining will ensue. The req_body argument should be a StringIO.
|
|
327
|
-
# TODO: More doc! :P
|
|
328
330
|
def process req_body=$stdin, env=ENV, opts={}
|
|
329
331
|
::Maveric.log.info "#{self.class}#process\n "+
|
|
330
332
|
"[#{Time.now}] #{env['REMOTE_ADDR']} => #{env['REQUEST_URI']}"
|
|
@@ -334,28 +336,25 @@ class Maveric
|
|
|
334
336
|
prepare_environment env unless env.key? :maveric
|
|
335
337
|
raise RuntimeError, [404, "Page not found."] unless env[:route]
|
|
336
338
|
|
|
339
|
+
# If this is a POST request we need to load data from the body
|
|
337
340
|
if env['REQUEST_METHOD'] =~ /^post$/i
|
|
338
341
|
env[:params].update env.key?(:multipart_boundary) ?
|
|
339
342
|
parse_multipart(env[:multipart_boundary], req_body) :
|
|
340
343
|
::Maveric.query_parse(req_body.read)
|
|
341
344
|
end
|
|
342
345
|
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
::Maveric.log.warn "We have not implemented dynamic route dispatch "+
|
|
347
|
-
"just yet. Please explicitly state :controller."
|
|
348
|
-
raise "Dynamic dispatching failed."
|
|
349
|
-
else
|
|
350
|
-
raise TypeError, "Lapse in handling. Something fugly got dropped."+
|
|
351
|
-
" Notify Maveric coder please."
|
|
346
|
+
unless env[:route][:controller] < ::Maveric::Controller
|
|
347
|
+
raise TypeError, "Route Controller of "+
|
|
348
|
+
"#{env[:route][:controller].class}. Expecting ::Maveric::Controller."
|
|
352
349
|
end
|
|
350
|
+
|
|
351
|
+
env[:route][:controller].new req_body, env, opts
|
|
353
352
|
rescue # we catch exception.is_a? StandardError
|
|
354
353
|
::Maveric.log.error "#{Time.now}:\n#{$!.inspect}\n#{$!.backtrace*"\n"}"
|
|
355
354
|
begin
|
|
356
355
|
raise $! # this makes sense in a certain context...
|
|
357
356
|
# Here is where we should have transformational stuffs for accessorizing
|
|
358
|
-
# or customizing error pages. As long as someone doesn't get stupid
|
|
357
|
+
# or customizing error pages. As long as someone doesn't get stupid
|
|
359
358
|
# about it.
|
|
360
359
|
rescue
|
|
361
360
|
return $!
|
|
@@ -365,51 +364,53 @@ class Maveric
|
|
|
365
364
|
|
|
366
365
|
##
|
|
367
366
|
# The env argument should be a normal environment hash derived from HTTP.
|
|
368
|
-
# Runs through a list of sorted methods, looking for methods beginning with
|
|
369
|
-
# 'env_' followed by a number followed by a '_' and then whatever descriptive
|
|
370
|
-
# ending the programmer gives the method. It passes the env hash to those
|
|
371
|
-
# methods for them to update and mess around with the env in appropriate
|
|
372
|
-
# ways. See default/included methods for example usage.
|
|
373
|
-
# NOTE: Override the defaults at your own risk!
|
|
374
367
|
def prepare_environment env
|
|
375
368
|
::Maveric.type_check :env, env, Hash
|
|
376
369
|
env.update :maveric => self
|
|
377
|
-
|
|
370
|
+
self.class.adjust_env.
|
|
371
|
+
select {|act| act[:test].nil? or act[:test][env] }.
|
|
372
|
+
each {|act| act[:do] ? act[:do][env] : __send__(act[:name], env) }
|
|
378
373
|
end
|
|
379
374
|
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
375
|
+
### Does this count as magic? No, just defaults.
|
|
376
|
+
adjust_env :route do |env|
|
|
377
|
+
url = ::Maveric.unescape env['REQUEST_URI']
|
|
378
|
+
env[:route] = env[:maveric].router[url]
|
|
383
379
|
end
|
|
384
|
-
|
|
385
|
-
|
|
380
|
+
|
|
381
|
+
adjust_env :cookies do |env|
|
|
382
|
+
env[:cookies] = ::Maveric.query_parse env['HTTP_COOKIE'], ';,'
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
adjust_env :params do |env|
|
|
386
386
|
env[:params] = ::Maveric.query_parse env['QUERY_STRING']
|
|
387
387
|
end
|
|
388
|
-
|
|
389
|
-
|
|
388
|
+
|
|
389
|
+
adjust_env :multipart_detect do |env|
|
|
390
390
|
if not env.key? :multipart_boundary \
|
|
391
391
|
and env['REQUEST_METHOD'] =~ /^post$/i \
|
|
392
392
|
and env['CONTENT_TYPE'] =~ MP_BOUND_REGEX
|
|
393
393
|
env[:multipart_boundary] = $1
|
|
394
394
|
end
|
|
395
395
|
end
|
|
396
|
-
## What am I doing in this basket...
|
|
397
|
-
def env_0_route env
|
|
398
|
-
url = ::Maveric.unescape env['REQUEST_URI']
|
|
399
|
-
env[:route] = routings.eject do |(r,c)|
|
|
400
|
-
b=r.route(url) and {:controller=>c}.update b
|
|
401
|
-
end
|
|
402
|
-
end
|
|
403
396
|
|
|
404
|
-
##
|
|
397
|
+
##
|
|
398
|
+
# Holds views related methods and helpers
|
|
399
|
+
#
|
|
400
|
+
# As long as Controller#prepare_0_imports is not overridden, Views extends
|
|
401
|
+
# the Controller instance just before the action is called.
|
|
405
402
|
module Views
|
|
406
403
|
def path_to c, a={}
|
|
407
404
|
::Maveric.log.info "#{self.class}#path_to #{c} #{a.inspect}"
|
|
408
|
-
@env[:maveric].
|
|
405
|
+
@env[:maveric].router.to(c).eject{|r| r.build a }
|
|
409
406
|
end
|
|
410
407
|
end
|
|
411
408
|
|
|
412
|
-
##
|
|
409
|
+
##
|
|
410
|
+
# Repository for models. Still not really utilized.
|
|
411
|
+
#
|
|
412
|
+
# As long as Controller#prepare_0_imports is not overridden, Models extends
|
|
413
|
+
# the Controller instance just before the action is called.
|
|
413
414
|
module Models
|
|
414
415
|
end
|
|
415
416
|
end
|
|
@@ -419,19 +420,42 @@ end
|
|
|
419
420
|
# requests. The number of normal methods is kept low to prevent clobbering by
|
|
420
421
|
# user defined methods.
|
|
421
422
|
#
|
|
423
|
+
# === Placing a Controller
|
|
424
|
+
#
|
|
422
425
|
# They may be defined in any location, but if they are defined in a nested
|
|
423
426
|
# location within the Maveric class being used to serve at a particular
|
|
424
427
|
# location, on instantialization of the Maveric they will automatically
|
|
425
428
|
# be added at either the routes specified in their class definition or
|
|
426
429
|
# at the default route which is derived from their name and their nesting.
|
|
430
|
+
#
|
|
431
|
+
# === Working in Controller
|
|
432
|
+
#
|
|
433
|
+
# Within an instance of Controller: @env contains the environment hash; @in
|
|
434
|
+
# contains the request body, and @cookies contains a hash of cookie values.
|
|
435
|
+
#
|
|
436
|
+
# In addition @status, @header, and @body may be set to appropriate values
|
|
437
|
+
# for the response. Note that @headers should be a Hash, @status should be an
|
|
438
|
+
# Integer corresponding to a real HTTP status code, and @body should contain
|
|
439
|
+
# a String.
|
|
440
|
+
#
|
|
441
|
+
# Those are the only instance variables you should be warned against playing
|
|
442
|
+
# with frivously.
|
|
427
443
|
class Maveric::Controller
|
|
428
444
|
REQUEST_METHODS = [:post, :get, :put, :delete, :head] # CRUDY
|
|
445
|
+
@before = []
|
|
446
|
+
@after = []
|
|
429
447
|
|
|
430
448
|
class << self
|
|
431
|
-
##
|
|
449
|
+
## Family is important.
|
|
432
450
|
def inherited klass
|
|
433
|
-
|
|
451
|
+
parent = self
|
|
452
|
+
klass.class_eval do
|
|
453
|
+
@routes = []
|
|
454
|
+
@before = parent.before.dup
|
|
455
|
+
@after = parent.after.dup
|
|
456
|
+
end
|
|
434
457
|
end
|
|
458
|
+
|
|
435
459
|
## Removes currently set routes and adds the stated ones.
|
|
436
460
|
def set_routes r, o={}
|
|
437
461
|
::Maveric.type_check :r, r, String, Array
|
|
@@ -439,22 +463,79 @@ class Maveric::Controller
|
|
|
439
463
|
r = [r] unless r.is_a? Array
|
|
440
464
|
r.flatten.map{|e| add_route e }
|
|
441
465
|
end
|
|
466
|
+
|
|
442
467
|
## Add a route to the Controller.
|
|
443
468
|
def add_route r, o={}
|
|
444
|
-
::Maveric.type_check :r, r, String, ::Maveric::
|
|
445
|
-
r = ::Maveric::
|
|
469
|
+
::Maveric.type_check :r, r, String, ::Maveric::Route
|
|
470
|
+
r = ::Maveric::Route.new r, o if r.is_a? String
|
|
446
471
|
@routes << r
|
|
447
472
|
end
|
|
473
|
+
|
|
448
474
|
## Removes all currently set routes.
|
|
449
475
|
def clear_routes
|
|
450
476
|
@routes.clear
|
|
451
477
|
end
|
|
452
|
-
|
|
478
|
+
|
|
479
|
+
## Returns a default Route based on the #nesting_path if no routes.
|
|
453
480
|
def routes
|
|
454
481
|
@routes.empty? ?
|
|
455
|
-
::Maveric::
|
|
482
|
+
::Maveric::Route.new(nesting_path) :
|
|
456
483
|
@routes
|
|
457
484
|
end
|
|
485
|
+
|
|
486
|
+
##
|
|
487
|
+
# If no argument is given, the array of actions is returned.
|
|
488
|
+
#
|
|
489
|
+
# If a Symbol or String is given with no block, during Controller
|
|
490
|
+
# initialization before the action is called, the corresponding
|
|
491
|
+
# method is called with the Controller instance as an argument.
|
|
492
|
+
# If a block is given, the block is called with the controller
|
|
493
|
+
# instance as an argument instead.
|
|
494
|
+
#
|
|
495
|
+
# If you are specifying other options, you must explicitly state
|
|
496
|
+
# :name => <chosen label> as an argument.
|
|
497
|
+
# Additional arguments include :only and :exclude, whose values should
|
|
498
|
+
# be a Symbol or an Array of such that correspond with actions that
|
|
499
|
+
# they should only run on or not run on.
|
|
500
|
+
#
|
|
501
|
+
# NOTE: If you are referencing instance variables within the action,
|
|
502
|
+
# it is recommended that you create a method rather than a block.
|
|
503
|
+
def before act={}, &block
|
|
504
|
+
::Maveric.type_check :act, act, Hash, Symbol, String
|
|
505
|
+
return @before if act.is_a? Hash and act.empty?
|
|
506
|
+
act = {:name => act} unless act.is_a? Hash
|
|
507
|
+
act[:do] = block
|
|
508
|
+
act[:only]=[*act[:only]] if act.key? :only
|
|
509
|
+
act[:exclude]=[*act[:exclude]] if act.key? :exclude
|
|
510
|
+
@before << act
|
|
511
|
+
end
|
|
512
|
+
|
|
513
|
+
##
|
|
514
|
+
# If no argument is given, the array of actions is returned.
|
|
515
|
+
#
|
|
516
|
+
# If a Symbol or String is given with no block, during Controller
|
|
517
|
+
# initialization after the action is called, the corresponding
|
|
518
|
+
# method is called with the Controller instance as an argument.
|
|
519
|
+
# If a block is given, the block is called with the controller
|
|
520
|
+
# instance as an argument instead.
|
|
521
|
+
#
|
|
522
|
+
# If you are specifying other options, you must explicitly state
|
|
523
|
+
# :name => <chosen label> as an argument.
|
|
524
|
+
# Additional arguments include :only and :exclude, whose values should
|
|
525
|
+
# be a Symbol or an Array of such that correspond with actions that
|
|
526
|
+
# they should only run on or not run on.
|
|
527
|
+
#
|
|
528
|
+
# NOTE: If you are referencing instance variables within the action,
|
|
529
|
+
# it is recommended that you create a method rather than a block.
|
|
530
|
+
def after act={}, &block
|
|
531
|
+
::Maveric.type_check :act, act, Hash, Symbol, String
|
|
532
|
+
return @after if act.is_a? Hash and act.empty?
|
|
533
|
+
act = {:name => act} unless act.is_a? Hash
|
|
534
|
+
act[:do] = block
|
|
535
|
+
act[:only]=[*act[:only]] if act.key? :only
|
|
536
|
+
act[:exclude]=[*act[:exclude]] if act.key? :exclude
|
|
537
|
+
@after << act
|
|
538
|
+
end
|
|
458
539
|
end
|
|
459
540
|
|
|
460
541
|
##
|
|
@@ -462,22 +543,17 @@ class Maveric::Controller
|
|
|
462
543
|
#
|
|
463
544
|
# The response body is set with the result of the specified action method
|
|
464
545
|
# if the result is a String and @body has not been set to a String. The
|
|
465
|
-
# action method is determined by env[:route][:action],
|
|
466
|
-
# downcased form, or 'get' by default.
|
|
546
|
+
# action method is determined respectively by env[:route][:action],
|
|
547
|
+
# REQUEST_METHOD in downcased form, or 'get' by default.
|
|
467
548
|
#
|
|
468
|
-
#
|
|
469
|
-
# 'prepare_', a number, another '_', and an optional label are called.
|
|
470
|
-
# Similarly, after the action method is called, methods beginning with
|
|
471
|
-
# 'cleanup_', etc., are called.
|
|
472
|
-
#
|
|
473
|
-
# By the time the Controller is be instantiated, it should have @status,
|
|
549
|
+
# By the time the Controller.new is done running, it should have @status,
|
|
474
550
|
# @headers, and @body set. @status should be an Integer matching the
|
|
475
551
|
# http status code, @headers a string keyed hash of http headers, and @body
|
|
476
552
|
# to a string of the http response body.
|
|
477
|
-
def initialize req_body, env, opts={}
|
|
553
|
+
def initialize req_body=$stdin, env=ENV, opts={}
|
|
478
554
|
::Maveric.log.warn "Provided env has not been properly processed, results "+
|
|
479
555
|
"may vary!" unless ([:maveric, :route, :params, :cookies]-env.keys).empty?
|
|
480
|
-
::Maveric.type_check :req_body, req_body,
|
|
556
|
+
::Maveric.type_check :req_body, req_body, StringIO, IO
|
|
481
557
|
::Maveric.type_check :env, env, Hash
|
|
482
558
|
::Maveric.type_check :opts, opts, Hash
|
|
483
559
|
|
|
@@ -485,25 +561,49 @@ class Maveric::Controller
|
|
|
485
561
|
@env, @in = env, req_body
|
|
486
562
|
@cookies = @env[:cookies].dup
|
|
487
563
|
|
|
488
|
-
action
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
564
|
+
action ||= @env[:route][:action] rescue nil
|
|
565
|
+
action ||= @env['REQUEST_METHOD'].downcase rescue nil
|
|
566
|
+
action ||= 'get'
|
|
567
|
+
action = action.to_sym
|
|
568
|
+
|
|
493
569
|
raise NoMethodError, [503, "#{action} not implemented.", nil, @env] if \
|
|
494
570
|
REQUEST_METHODS.include? action and not respond_to? action
|
|
495
571
|
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
572
|
+
self.class.before.select do |act|
|
|
573
|
+
(act[:only].nil? or act[:only].include? action) and \
|
|
574
|
+
(act[:exclude].nil? or not act[:exclude].include? action)
|
|
575
|
+
end.each do |act|
|
|
576
|
+
act[:do] ? act[:do][self] : __send__(act[:name], self)
|
|
577
|
+
end
|
|
578
|
+
|
|
579
|
+
@body = __send__ action
|
|
580
|
+
|
|
581
|
+
self.class.after.select do |act|
|
|
582
|
+
(act[:only].nil? or act[:only].include? action) and \
|
|
583
|
+
(act[:exclude].nil? or not act[:exclude].include? action)
|
|
584
|
+
end.each do |act|
|
|
585
|
+
act[:do] ? act[:do][self] : __send__(act[:name], self)
|
|
586
|
+
end
|
|
500
587
|
|
|
501
588
|
::Maveric.log.debug self # omg, masochistic.
|
|
502
589
|
end
|
|
503
590
|
|
|
504
591
|
attr_reader :status, :headers, :body
|
|
505
592
|
|
|
506
|
-
##
|
|
593
|
+
## For quick and raw response outputting!
|
|
594
|
+
def to_http
|
|
595
|
+
response = "Status: #{@status}" + ::Maveric::EOL # Status message? :/
|
|
596
|
+
response << @headers.map{|k,v| "#{k}: #{v}" }*::Maveric::EOL
|
|
597
|
+
response << ::Maveric::EOL*2 + @body
|
|
598
|
+
end
|
|
599
|
+
|
|
600
|
+
private
|
|
601
|
+
|
|
602
|
+
##
|
|
603
|
+
# TODO: Doc me. ehird is confused
|
|
604
|
+
#
|
|
605
|
+
# This is a simple method, really. The only confusing part is the expressions
|
|
606
|
+
# just above the return. Controller#render calls itself. That is all.
|
|
507
607
|
def render view, s=''
|
|
508
608
|
::Maveric.log.debug "#{self.class}#render"+
|
|
509
609
|
" #{view.inspect}, #{s.inspect}" # s is painful to logs.
|
|
@@ -512,50 +612,72 @@ class Maveric::Controller
|
|
|
512
612
|
s = yield s if block_given?
|
|
513
613
|
s = __send__ view, s if respond_to? view
|
|
514
614
|
s = render :layout, s unless view.to_s[/^(_|layout$)/] \
|
|
515
|
-
or caller.any?{|l|l=~/`render'/} # i don't like this
|
|
615
|
+
or caller.any?{|l|l=~/`render'/} # i don't like this but it works
|
|
516
616
|
return s
|
|
517
617
|
end
|
|
518
618
|
|
|
519
|
-
## For quick and raw response printing!
|
|
520
|
-
def to_http
|
|
521
|
-
response = "Status: #{@status}" + ::Maveric::EOL
|
|
522
|
-
response << @headers.map{|k,v| "#{k}: #{v}" }*::Maveric::EOL
|
|
523
|
-
response << ::Maveric::EOL*2 + @body
|
|
524
|
-
end
|
|
525
|
-
|
|
526
619
|
##
|
|
620
|
+
# Standard Controller setup.
|
|
621
|
+
#
|
|
527
622
|
# Extends the Controller instance with the Views and Models modules of the
|
|
528
623
|
# pertinant Maveric instance.
|
|
529
|
-
def
|
|
530
|
-
extend @env[:maveric].class::Models
|
|
531
|
-
extend @env[:maveric].class::Views
|
|
624
|
+
def setup controller
|
|
625
|
+
controller.extend @env[:maveric].class::Models
|
|
626
|
+
controller.extend @env[:maveric].class::Views
|
|
532
627
|
end
|
|
628
|
+
|
|
533
629
|
##
|
|
630
|
+
# Standard Controller cleanup.
|
|
631
|
+
#
|
|
534
632
|
# Folds the datasets of @cookie to @headers if they have been altered or
|
|
535
633
|
# are new.
|
|
536
|
-
def
|
|
634
|
+
def cleanup controller
|
|
537
635
|
@cookies.each do |k,v|
|
|
538
636
|
next unless v != @env[:cookies][k]
|
|
539
637
|
@headers['Set-Cookie'] << "#{k}=#{::Maveric.escape(v)}"
|
|
540
638
|
end
|
|
541
639
|
end
|
|
640
|
+
|
|
641
|
+
before :setup
|
|
642
|
+
after :cleanup
|
|
542
643
|
end
|
|
543
644
|
|
|
544
645
|
##
|
|
545
646
|
# Instances of Route are used for determining how to act upon particular urls
|
|
546
647
|
# in each Maveric instance. They are magical and simply complex creatures.
|
|
547
|
-
class
|
|
648
|
+
# The Route class was inspired by Merb's implementation, which in turn were
|
|
649
|
+
# inspired by Rails. One thing I think Rails has done nicely, to a point.
|
|
650
|
+
#
|
|
651
|
+
# The String path is turned into a Regexp in a very straight-forward manner.
|
|
652
|
+
# Fragments of the path that begin with ':' followed by any number of
|
|
653
|
+
# characters that aren't a typical URI delimiter or reserved character, and
|
|
654
|
+
# optionally ending with another ':', are indicators of paramæters. The
|
|
655
|
+
# trailing ':' is useful if the parameter occurs within a string of similar
|
|
656
|
+
# characters.
|
|
657
|
+
#
|
|
658
|
+
# Parameters are replaced by default with the regexp of /(#{URI_CHAR}+)/ in
|
|
659
|
+
# the final Route. If a parameter symbol matches a key in the opts hash the
|
|
660
|
+
# associated value is placed into the Route instead.
|
|
661
|
+
#
|
|
662
|
+
class Maveric::Route < Regexp
|
|
663
|
+
## A negative class of URI delimiting and reserved characters.
|
|
548
664
|
URI_CHAR = '[^/?:,&#]'
|
|
665
|
+
## Standard pattern for finding parameters in provided paths.
|
|
549
666
|
PARAM_MATCH= %r~:(#{URI_CHAR}+):?~
|
|
550
|
-
|
|
551
|
-
# The
|
|
552
|
-
#
|
|
553
|
-
# characters that aren't a typical URI delimiter or reserved character, and
|
|
554
|
-
# optionally ending with another ':', are indicators of paramæters.
|
|
667
|
+
|
|
668
|
+
# NOTE: The following examples shows a return value of the equivalent regexp
|
|
669
|
+
# and not the result of Route#inspect.
|
|
555
670
|
#
|
|
556
|
-
#
|
|
557
|
-
#
|
|
558
|
-
#
|
|
671
|
+
# Route.new '/'
|
|
672
|
+
# => /^\/$/ # with no groups or derived values
|
|
673
|
+
# Route.new '/:value'
|
|
674
|
+
# => /^\/([^/?:,&#]+)$/ # with group 1 assigned to :value
|
|
675
|
+
# Route.new '/:val:ue'
|
|
676
|
+
# => /^\/([^/?:,&#]+)ue$/ # with group 1 assigned to :val
|
|
677
|
+
# Route.new '/:value', :value => 'print|find'
|
|
678
|
+
# => /^\/(print|find)$/
|
|
679
|
+
# Route.new '/:whtevr', :whtevr => '.*'
|
|
680
|
+
# => /^\/(.*)$/ # if you want a real catch-all
|
|
559
681
|
def initialize path, opts={}
|
|
560
682
|
::Maveric.type_check :path, path, String
|
|
561
683
|
::Maveric.type_check :opts, opts, Hash
|
|
@@ -563,31 +685,25 @@ class Maveric::Routing < Regexp
|
|
|
563
685
|
@path = path.dup.freeze
|
|
564
686
|
@options = opts.dup.freeze
|
|
565
687
|
|
|
566
|
-
@params =
|
|
567
|
-
regex = path.gsub PARAM_MATCH do
|
|
568
|
-
param = $1.to_sym
|
|
569
|
-
raise ArgumentError, "Duplicated parameters in path."+
|
|
570
|
-
" <#{param.inspect}>" if @params.include? param
|
|
571
|
-
@params << param
|
|
572
|
-
"(#{opts[param] || URI_CHAR+'+'})"
|
|
573
|
-
end
|
|
688
|
+
regex, @params = __compile path, opts
|
|
574
689
|
@params.freeze
|
|
575
|
-
super %r~^#{regex}$~iu
|
|
690
|
+
super %r~^#{regex}$~iu
|
|
691
|
+
freeze
|
|
576
692
|
|
|
577
693
|
::Maveric.log.debug self.inspect
|
|
578
694
|
end
|
|
579
695
|
|
|
580
|
-
attr_reader :path, :params
|
|
696
|
+
attr_reader :path, :params, :options
|
|
581
697
|
|
|
582
698
|
##
|
|
583
699
|
# If given a hash that contains all of and only contains keys matching its
|
|
584
700
|
# parameters then a path will be built by interpolating the hash values for
|
|
585
701
|
# their corresponding parameters.
|
|
586
|
-
#
|
|
587
|
-
# the
|
|
702
|
+
#
|
|
703
|
+
# NOTE: Should I or should I not pass the result to #route to ensure
|
|
704
|
+
# the generation of a compatible path?
|
|
588
705
|
def build arg
|
|
589
|
-
::Maveric.log.debug "#{self.class}#build"
|
|
590
|
-
" #{arg.inspect} : #{self.inspect}"
|
|
706
|
+
::Maveric.log.debug "#{self.class}#build #{arg.inspect} : #{@params}"
|
|
591
707
|
::Maveric.type_check :arg, arg, Hash
|
|
592
708
|
if @params.sort == arg.keys.sort
|
|
593
709
|
path = arg.inject(@path){|r,(k,v)| r.sub /:#{k}:?/, v }
|
|
@@ -595,12 +711,11 @@ class Maveric::Routing < Regexp
|
|
|
595
711
|
end
|
|
596
712
|
|
|
597
713
|
##
|
|
598
|
-
# When given a path that matches the
|
|
714
|
+
# When given a path that matches the Route itself, a hash is returned with
|
|
599
715
|
# keys being parameters and values being the associated value gathered from
|
|
600
716
|
# the path.
|
|
601
717
|
def route path
|
|
602
|
-
::Maveric.log.debug "#{self.class}#route"
|
|
603
|
-
" #{path.inspect} : #{self.inspect}"
|
|
718
|
+
::Maveric.log.debug "#{self.class}#route #{path.inspect} : #{self}"
|
|
604
719
|
::Maveric.type_check :path, path, String
|
|
605
720
|
if self =~ path
|
|
606
721
|
Hash[ *@params.zip($~.captures).flatten ].update(nil => self)
|
|
@@ -608,19 +723,92 @@ class Maveric::Routing < Regexp
|
|
|
608
723
|
end
|
|
609
724
|
|
|
610
725
|
##
|
|
611
|
-
# This is an attempt as path correction.
|
|
612
|
-
# generating path to be removed, from which a new
|
|
613
|
-
|
|
726
|
+
# This is an attempt as path correction. The String root is treated as a
|
|
727
|
+
# prefix to the generating path to be removed, from which a new Route will
|
|
728
|
+
# be generated.
|
|
729
|
+
#
|
|
730
|
+
# r = Route.new '/foo/bar/qux'
|
|
731
|
+
# r.reroot('/foo') == Route.new('/bar/qux')
|
|
732
|
+
# => true
|
|
733
|
+
def reroot root, opts={}
|
|
614
734
|
::Maveric.type_check :root, root, String
|
|
615
|
-
self.class.new @path.sub(/^#{root}
|
|
735
|
+
self.class.new @path.sub(/^#{root}\/?/,'/'), @options.merge(opts)
|
|
616
736
|
end
|
|
617
737
|
|
|
618
738
|
##
|
|
619
|
-
# As
|
|
739
|
+
# As Route is a subclass of a corelib class, the inspect isn't as
|
|
620
740
|
# informative as we'd like. So we override it.
|
|
621
741
|
def inspect
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
742
|
+
"#<%s:0x%x %s %s %s>" % [
|
|
743
|
+
self.class,
|
|
744
|
+
[object_id<<1].pack('i').unpack('I')[0],
|
|
745
|
+
super,
|
|
746
|
+
@params.inspect,
|
|
747
|
+
@path.inspect
|
|
748
|
+
]
|
|
749
|
+
end
|
|
750
|
+
|
|
751
|
+
private
|
|
752
|
+
|
|
753
|
+
##
|
|
754
|
+
# Builds a regex from path by parsing out fragments matching PARAM_MATCH
|
|
755
|
+
# and replacing them with either a corresponding symbol from the opts
|
|
756
|
+
# hash or the default regex.
|
|
757
|
+
def __compile path, opts
|
|
758
|
+
::Maveric.type_check :path, path, String
|
|
759
|
+
::Maveric.type_check :opts, opts, Hash
|
|
760
|
+
params = []
|
|
761
|
+
regex = path.gsub PARAM_MATCH do
|
|
762
|
+
param = $1.to_sym
|
|
763
|
+
raise ArgumentError, "Duplicated parameter in path."+
|
|
764
|
+
" <#{param.inspect}>" if params.include? param
|
|
765
|
+
params << param
|
|
766
|
+
"(#{opts[param] || URI_CHAR+'+'})"
|
|
767
|
+
end
|
|
768
|
+
[regex, params]
|
|
769
|
+
end
|
|
770
|
+
end
|
|
771
|
+
|
|
772
|
+
## Storage of routes and routing mechanisms.
|
|
773
|
+
class Maveric::Router
|
|
774
|
+
def initialize opts={}
|
|
775
|
+
@routings = Hash.new
|
|
776
|
+
end
|
|
777
|
+
|
|
778
|
+
## Returns a list of the controllers with listed routes.
|
|
779
|
+
def controllers
|
|
780
|
+
@routings.values.uniq
|
|
781
|
+
end
|
|
782
|
+
|
|
783
|
+
##
|
|
784
|
+
# Places one or more routes to a Controller. Will generate a new Route if
|
|
785
|
+
# a route is a String. Accepts an Array for routes to add several at a time.
|
|
786
|
+
def add routes, controller, opts={}
|
|
787
|
+
::Maveric.log.info "#{self.class}#add"+
|
|
788
|
+
" #{routes.inspect} #{controller.inspect}"
|
|
789
|
+
::Maveric.type_check :controller, controller, Class
|
|
790
|
+
::Maveric.type_check :routes, routes, Array, String, ::Maveric::Route
|
|
791
|
+
routes = [routes] unless routes.is_a? Array
|
|
792
|
+
routes.flatten.map do |route|
|
|
793
|
+
::Maveric.type_check :route, route, String, ::Maveric::Route
|
|
794
|
+
route = ::Maveric::Route.new route, opts if route.instance_of? String
|
|
795
|
+
@routings[route] = controller
|
|
796
|
+
end
|
|
797
|
+
end
|
|
798
|
+
|
|
799
|
+
## Return an array of routes mapped to a controller.
|
|
800
|
+
def to controller
|
|
801
|
+
@routings.map{|(r,d)| r if d == controller }.compact
|
|
802
|
+
end
|
|
803
|
+
|
|
804
|
+
##
|
|
805
|
+
# Matches the given path against the collection of routes.
|
|
806
|
+
# Returns nil the appropriate Route#route result with :controller
|
|
807
|
+
# mapped to the associated Controller.
|
|
808
|
+
def [] path
|
|
809
|
+
::Maveric.type_check :path, path, String
|
|
810
|
+
@routings.eject do |(r,c)|
|
|
811
|
+
b=r.route(path) and {:controller=>c}.update b
|
|
812
|
+
end
|
|
625
813
|
end
|
|
626
814
|
end
|
|
@@ -1,13 +1,9 @@
|
|
|
1
1
|
class Module
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
def to_s; "::#{__to_s}"; end
|
|
6
|
-
## Build a string akin toa relative url of the nesting structure.
|
|
7
|
-
def nesting_path
|
|
8
|
-
self.to_s.
|
|
2
|
+
## Build a string akin to the absolute path of the nesting structure.
|
|
3
|
+
def nesting_path
|
|
4
|
+
('::'+self.to_s). # '::' prepended for absolute path semantic
|
|
9
5
|
gsub(/([a-z])([A-Z])/, '\1_\2').
|
|
10
|
-
gsub(
|
|
6
|
+
gsub(/(::)+/, '/').
|
|
11
7
|
downcase
|
|
12
8
|
end
|
|
13
9
|
# ::nodoc::
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
metadata
CHANGED
|
@@ -3,13 +3,13 @@ rubygems_version: 0.9.0
|
|
|
3
3
|
specification_version: 1
|
|
4
4
|
name: maveric
|
|
5
5
|
version: !ruby/object:Gem::Version
|
|
6
|
-
version: 0.
|
|
7
|
-
date: 2007-01-
|
|
6
|
+
version: 0.3.0
|
|
7
|
+
date: 2007-01-26 00:00:00 -07:00
|
|
8
8
|
summary: A simple, non-magical, framework.
|
|
9
9
|
require_paths:
|
|
10
|
-
-
|
|
10
|
+
- lib/
|
|
11
11
|
email: blinketje@gmail.com
|
|
12
|
-
homepage:
|
|
12
|
+
homepage: http://maveric.rubyforge.org/
|
|
13
13
|
rubyforge_project:
|
|
14
14
|
description:
|
|
15
15
|
autorequire: maveric
|
|
@@ -29,12 +29,12 @@ post_install_message:
|
|
|
29
29
|
authors:
|
|
30
30
|
- blink
|
|
31
31
|
files:
|
|
32
|
-
- maveric.rb
|
|
33
|
-
- maveric/mongrel.rb
|
|
34
|
-
- maveric/fastcgi.rb
|
|
35
|
-
- maveric/webrick.rb
|
|
36
|
-
- maveric/sessions.rb
|
|
37
|
-
- maveric/extensions.rb
|
|
32
|
+
- lib/maveric.rb
|
|
33
|
+
- lib/maveric/mongrel.rb
|
|
34
|
+
- lib/maveric/fastcgi.rb
|
|
35
|
+
- lib/maveric/webrick.rb
|
|
36
|
+
- lib/maveric/sessions.rb
|
|
37
|
+
- lib/maveric/extensions.rb
|
|
38
38
|
test_files: []
|
|
39
39
|
|
|
40
40
|
rdoc_options: []
|