Class: Maveric

Inherits:
Object
  • Object
show all
Includes:
Mongrel::HttpHandlerPlugin
Defined in:
lib/maveric.rb,
lib/maveric/mongrel.rb,
lib/maveric/sessions.rb

Overview

Includes Mongrel::HttpHandlerPlugin into Maveric, allowing the use of Maveric subclasses as HttpHandlers in the context of Mongrel.

Defined Under Namespace

Modules: Models, Views Classes: Controller, Route, SimpleSessions, WEBrickServlet

Constant Summary collapse

VERSION =

Implementation details.

'0.4.0'
EOL =

Standard end of line for HTTP

"\r\n"
MP_BOUND_REGEX =

Group 1 wil contain a boundary for multipart/form-data bodies.

/\Amultipart\/form-data.*boundary=\"?([^\";, ]+)\"?/n

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(opts = {}) ⇒ Maveric

Sets @options from opts and initializes @routes. Adds routes from nested Controllers.



262
263
264
265
266
267
268
269
270
271
# File 'lib/maveric.rb', line 262

def initialize opts={}
  @options = {:path_prefix => self.class.to_path(true)}
  @options.update opts
  @routes = Set.new
  self.class.nested_controllers.each do |cont|
    routes = cont.routes
    routes ||= [[cont.to_path(0).sub(/^#{self.class.to_path(0)}\/?/,'/'),{}]]
    routes.each {|route,ropts| add_route cont, route, ropts }
  end
end

Instance Attribute Details

#optionsObject (readonly)

Returns the value of attribute options.



294
295
296
# File 'lib/maveric.rb', line 294

def options
  @options
end

#routesObject (readonly)

Returns the value of attribute routes.



294
295
296
# File 'lib/maveric.rb', line 294

def routes
  @routes
end

Class Method Details

.FCGI(maveric, opts = {}) ⇒ Object

Maveric::FCGI(MyMaveric.new)



7
8
9
10
11
12
13
14
15
16
17
18
# File 'lib/maveric/fastcgi.rb', line 7

def Maveric.FCGI maveric, opts={}
  ::FCGI.each do |req|
    req.out << "Status: 200 OK" + ::Maveric::EOL*2 if $DEBUG
    req.out << response = begin
      maveric.dispatch(req.in, req.env).to_http
    rescue
      "Status: 500 Server Error omgwtf!"+::Maveric::EOL*2+
      "#{$!}\n#{$!.backtrace*"\n"}"
    end
    req.finish
  end
end

.inherited(klass) ⇒ Object

Sets up a new Maveric with everything it needs for normal operation. Many things are either copied or included from it’s parent. Models and Views are included by their respective modules.



219
220
221
222
223
224
225
226
227
228
229
# File 'lib/maveric.rb', line 219

def inherited klass
  super
  parent = self
  klass.class_eval do
    const_set(:Models, Module.new).
      module_eval { include parent::Models }
    const_set(:Views, Module.new).
      module_eval { include parent::Views }
    @prepare_env = parent.prepare_env.dup
  end
end

.nested_controllers(realm = self, stk = []) ⇒ Object

A recursive method to hunt out subclasses of Controller nested within a Maveric subclass. Used in the setting up of autoroutes. Disregards everything within a nested Maveric subclass.



204
205
206
207
208
209
210
211
212
213
# File 'lib/maveric.rb', line 204

def nested_controllers realm=self, stk=[]
  stk << realm #We don't need to visit the same thing twice.
  realm.constants.map do |c|
    next if stk.include?(c = realm.const_get(c)) or not c.is_a? Module
    a = []
    a << c if c < ::Maveric::Controller
    a += nested_controllers c, stk unless c < ::Maveric
    a
  end.compact.flatten
end

.parse_multipart(boundary, body) ⇒ Object

Parse a multipart/form-data entity. Adapated from cgi.rb. The body argument may either be a StringIO or a IO of subclass thereof.

Might need to be rehauled to match query_parse’s behaviour.



170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
# File 'lib/maveric.rb', line 170

def parse_multipart boundary, body
  values = {}
  bound = /(?:\r?\n|\A)#{Regexp::quote('--'+boundary)}(?:--)?\r$/
  until body.eof?
    fv = {}
    until body.eof? or /^#{EOL}$/ =~ l
      case l = body.readline
      when /^Content-Type: (.+?)(\r$|\Z)/m
        fv[:type] = $1
      when /^Content-Disposition: form-data;/
        $'.scan(/(?:\s(\w+)="([^"]+)")/) {|w| fv[w[0].intern] = w[1] }
      end
    end

    o = fv[:filename] ? '' : fv[:tempfile] = Tempfile.new('MVC').binmode
    body.inject do |buf, line|
      o << buf.chomp and break if bound =~ line
      o << buf
      line
    end # Merb and Camping do it faster.

    fv[:tempfile].rewind if fv.key? :tempfile
    values[fv[:name]] = fv.key?(:filename) ? fv : o
  end
  body.rewind rescue nil # FCGI::Stream fun.
  values
end

.prepare_env(action = nil, opts = {}, &block) ⇒ Object

Actions are kept in an array to maintain running order.

This is where you’d add environmental preprocessors to a Maveric. Please note that actions are copied to subclasses at definition time.

If action is a Symbol and no block is provided, in #prepare_environment, the corresponding method is called with the environment hash as an argument. If a block is given then that block will be called with the environment hash as the single argument.

Additional arguments honored include :test, which should be a Proc that accepts a single argument. The argument will be the environment hash and the boolean result of the block will determine if the action will be run upon the environment.



247
248
249
250
251
# File 'lib/maveric.rb', line 247

def prepare_env action=nil, opts={}, &block
  if action.is_a? Symbol
    @prepare_env << opts.update(:name => action, :run => block)
  else @prepare_env end
end

.query_parse(qs, delim = '&;') ⇒ Object

Parses a query string by breaking it up around the delimiting characters. You can also use this to parse cookies by changing the characters used in the second parameter (which defaults to ‘;,’).

This will return a hash of parameters, values being contained in an array. As a warning, the default value is an empty array, not nil.



157
158
159
160
161
162
163
# File 'lib/maveric.rb', line 157

def query_parse(qs, delim = '&;')
  (qs||'').split(/[#{delim}] */n).inject({}) { |h,p|
    k, v = URI.decode(p).split('=',2)
    (h[k]||=[]) << v
    h
  }
end

.session(id) ⇒ Object

Return a session via Session#session



88
89
90
# File 'lib/maveric/sessions.rb', line 88

def self.session id
  @sessions.session id
end

.sessionsObject

Return the standard session set.



83
84
85
# File 'lib/maveric/sessions.rb', line 83

def self.sessions
  @sessions
end

Instance Method Details

#add_route(controller, path, opts = {}) ⇒ Object

Passes arguments to ::Maveric::Route.new and adds the result to @routes.



274
275
276
# File 'lib/maveric.rb', line 274

def add_route controller, path, opts={}
  @routes << ::Maveric::Route.new(controller, path, opts)
end

#dispatch(req_body = $stdin, env = ENV, opts = {}) ⇒ Object

Maveric’s cue to start doing the heavy lifting. env should be a hash with the typical assignments from an HTTP environment or crying and whining will ensue. req_body should be an IO compatible instance.



300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
# File 'lib/maveric.rb', line 300

def dispatch req_body=$stdin, env=ENV, opts={}
  begin
    prepare_environment env unless env.key? :maveric
    raise RuntimeError, [404, "Page not found."] unless env[:route]

    # If this is a POST request we need to load data from the body
    if env['REQUEST_METHOD'] =~ /^post$/i
      params = env.key?(:multipart_boundary) ?
        parse_multipart(env[:multipart_boundary], req_body) :
        ::Maveric.query_parse(req_body.read)
      env[:params].update params
    end

    env[:route].controller.new(req_body, env, opts)
  rescue StandardError => e
    error(e)
  end
end

#error(err = $!) ⇒ Object

Override for custom error handling and/or styling.



320
321
322
# File 'lib/maveric.rb', line 320

def error err=$!
  err
end

#match(path) ⇒ Object

Returns the first non nil result of Route#match across @routes. Will remove the option setting of :path_prefix form the beginning of the path.



281
282
283
284
285
# File 'lib/maveric.rb', line 281

def match path
  path = path.sub(/^#{@options[:path_prefix]}\/?/, '/') if \
    @options.key? :path_prefix
  @routes.eject {|route| route.match path }
end

#path_to(controller, args = {}) ⇒ Object

Returns the first non nil result of Route#path_to across the subset of



290
291
292
# File 'lib/maveric.rb', line 290

def path_to controller, args={}
  @routes.eject {|route| route.controller == controller and route.path_to args }
end

#prepare_env(*a, &b) ⇒ Object

Alias to Maveric.prepare_env



255
256
257
# File 'lib/maveric.rb', line 255

def prepare_env(*a, &b)
  self.class.prepare_env(*a, &b)
end

#prepare_environment(env) ⇒ Object

env should be a normal environment hash derived from HTTP. Run through actions specified by Maveric.prepare_env in the order stated, testing env against act if present to determine if it will be used, and runs the action on env.



329
330
331
332
333
334
335
336
337
338
339
# File 'lib/maveric.rb', line 329

def prepare_environment env
  # DEV-NOTE: This method is seperated from prepare_env, in contrast to
  # #before and #after in Controller, due to the fact one Maveric instance
  # exists for each service, rather than for each occurance of env per
  # request.
  env.update :maveric => self
  prepare_env.each do |act|
    next unless act[:test].nil? or act[:test][env]
    (act[:run] || method(act[:name]))[env]
  end
end

#process(request, response) ⇒ Object

Runs #dispatch on the request and filters the resulting Controller instance to the response object.



12
13
14
15
16
17
18
# File 'lib/maveric/mongrel.rb', line 12

def process request, response
  reply = dispatch request.body, request.params
  response.start reply.status do |head,out|
    reply.headers.each {|k,v| head[k] = v }
    out.write reply.body
  end
end

#request_begins(params) ⇒ Object

Runs #prepare_enviroment on the env to get things moving.



21
22
23
# File 'lib/maveric/mongrel.rb', line 21

def request_begins params
  prepare_environment params
end

#set_session(env) ⇒ Object

Uses env to find the session_id, and retrives the data to set the values or env.



95
96
97
98
# File 'lib/maveric/sessions.rb', line 95

def set_session env
  session_id = env[:cookies][::Maveric::SimpleSessions::COOKIE_NAME].first
  env[:session] = ::Maveric.session session_id 
end