Class: Maveric::Controller

Inherits:
Object
  • Object
show all
Defined in:
lib/maveric.rb,
lib/maveric/sessions.rb

Overview

Controllers are the classes that do the actual handling and processing of requests. The number of normal methods is kept low to prevent clobbering by user defined methods.

Placing a Controller

They may be defined in any location, but if they are defined in a nested location within the Maveric class being used to serve at a particular location, on instantialization of the Maveric they will automatically be added at either the routes specified in their class definition or at the default route which is derived from their name and their nesting.

Working in Controller

Within an instance of Controller: @env contains the environment hash; @in contains the request body, and @cookies contains a hash of cookie values.

In addition @status, @header, and @body may be set to appropriate values for the response. Note that @headers should be a Hash, @status should be an Integer corresponding to a real HTTP status code, and @body should contain a String.

The instance variable @action contains a Symbol corresponding to the Controller method being called. The result of this call is assigned to Those are the only instance variables you should be warned against playing with frivously. All instance variables are initially assigned before the before actions have been run, with the exception of @body which is set after @action is called.

It’s recommended all work be done within methods of Controller, rather than overriding the inherited methods of Controller, but really it’s up to you.

NOTE: Due to the extension of the Controller instance by the View and Models modules of the operating Maveric, one must take care not to overlap method names. I hope to remove this ‘feature’ in a future version.

Constant Summary collapse

REQUEST_METHODS =

CRUDY

[:post, :get, :put, :delete, :head]

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(req_body = $stdin, env = ENV, opts = {}) ⇒ Controller

Within the initialization of controller, resulting in the object returned by the call to Maveric#dispatch, you are the busy bee. This hive has several instance variables which are set down for you to derive all the information you might need.

  • @env contains the HTTP environment hash with the special keys of:

    • :maveric, who’s value is the Maveric instance the request has called upon

    • :route, which contains a struct instance which was returned by Route#match that helped us get here.

    • :params, containing a hash of QUERY_STRING data. If REQUEST_METHOD is ‘post’ then parameter data from the request bod is overlayed.

    • :cookies, which contains hashed data parsed from HTTP_COOKIE.

    • plugins or extensions to Maveric may add other special hash pairs to @env, such as :session, by ‘maveric/sessions’.

  • @cookies contains a hash header. If you plan on adding or altering cookie data, do it here.

  • @in contains a reference to the input stream of the http request. Note that if REQUEST_METHOD is ‘post’ then it has probably already been read.

  • @action is the controller instance method to be called. The returned value of the call should be a string, which will be assigned to @body.

  • @status, by default is 200. And @headers, which by default only sets Content-Type to ‘text/html’.

By the time the Controller.new is done running, it will have @status, @headers, and @body set. @status should be an Integer matching the http status code, @headers a string keyed hash of http headers, and @body to a string of the http response body.



572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
# File 'lib/maveric.rb', line 572

def initialize req_body=$stdin, env=ENV, opts={}
  @status, @headers = 200, {'Content-Type'=>'text/html'}
  @env, @in = env, req_body
  @cookies = @env[:cookies].dup

  if @env[:maveric]
    extend @env[:maveric].class::Models
    extend @env[:maveric].class::Views
  end

  action ||= @env[:route].action rescue nil
  action ||= @env[:route].route.opts[:default_action] rescue nil
  action ||= @env['REQUEST_METHOD'].downcase rescue nil
  action ||= 'get'
  @action = action.to_sym

  before @action, self
  @body = __send__ @action
  after @action, self
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(m, *a, &b) ⇒ Object (private)

Provides a better error report if the method is a standard http method.

Raises:

  • (NoMethodError)


626
627
628
629
630
# File 'lib/maveric.rb', line 626

def method_missing m, *a, &b
  raise NoMethodError, [503, "#{m} not implemented.", nil, @env] if \
    REQUEST_METHODS.include? m
  super
end

Instance Attribute Details

#bodyObject (readonly)

Returns the value of attribute body.



593
594
595
# File 'lib/maveric.rb', line 593

def body
  @body
end

#headersObject (readonly)

Returns the value of attribute headers.



593
594
595
# File 'lib/maveric.rb', line 593

def headers
  @headers
end

#statusObject (readonly)

Returns the value of attribute status.



593
594
595
# File 'lib/maveric.rb', line 593

def status
  @status
end

Class Method Details

.add_route(r, o = {}) ⇒ Object

Add a route to the Controller.



450
451
452
453
454
# File 'lib/maveric.rb', line 450

def add_route r, o={}
  # As each route may have its own specific options, we need to hold them
  # seperately so we don't clobber.
  @routes << [r, o]
end

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

If no argument is given, the array of actions is returned.

If a Symbol or String is given with no block, during Controller initialization after the action is called, the corresponding method is called with the Controller instance as an argument. If a block is given, the block is called with the controller instance as an argument instead.

Additional arguments include :only and :exclude, whose values should be a Symbol or an Array of such that correspond with actions that they should only run on or not run on.

NOTE: If you are referencing instance variables within the action, it is recommended that you create a method rather than a block.



517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
# File 'lib/maveric.rb', line 517

def after action=nil, opts={}, &block
  if action.is_a? Symbol
    if opts.is_a? ::Maveric::Controller
      @after.each do |act|
        next unless (act[:only].nil? or act[:only].include? action) \
          and (act[:exclude].nil? or not act[:exclude].include? action)
        (act[:run] || controller.method(act[:name]))[opts]
      end
    else # opts should be a Hash
      opts[:only] = [*opts[:only]] if opts.key? :only
      opts[:exclude] = [*opts[:exclude]] if opts.key? :exclude
      @after << opts.update(:name => action, :run => block)
    end
  else @after end
end

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

If no arguments are given, the array of actions is returned. The first argument should be a Symbol and should be the name of the action.

If the second argument is omitted or a collection of hashed options, then an action is added to the array of actions with action as its name. If a block is provided it will be run, else the controller instance method of the same name of the action will be run. For conditional execution of the action you may provide a list of what actions it should exclusively run on or not run on, via :only and :exclude respectively.

If the second argument is an instance of Controller then the actions are conditionally, on the basis of :only and :exclude lists, run on the controller.

NOTE: If you are referencing instance variables within the action, it is recommended that you create a method rather than a block. Unless you want to do instance_eval fun, but anyways.



486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
# File 'lib/maveric.rb', line 486

def before action=nil, opts={}, &block
  if action.is_a? Symbol
    if opts.is_a? ::Maveric::Controller
      @before.each do |act|
        next unless (act[:only].nil? or act[:only].include? action) \
          and (act[:exclude].nil? or not act[:exclude].include? action)
        (act[:run] || controller.method(act[:name]))[opts]
      end
    else # opts should be a Hash
      opts[:only] = [*opts[:only]] if opts.key? :only
      opts[:exclude] = [*opts[:exclude]] if opts.key? :exclude
      @before << opts.update(:name => action, :run => block)
    end
  else @before end
end

.clear_routesObject

Removes all currently set routes.



457
458
459
# File 'lib/maveric.rb', line 457

def clear_routes
  @routes.clear
end

.inherited(klass) ⇒ Object

Family is important.



434
435
436
437
438
439
440
441
# File 'lib/maveric.rb', line 434

def inherited klass
  parent = self
  klass.class_eval do
    @before = parent.before.dup
    @after = parent.after.dup
    @routes = []
  end
end

.routesObject

Unless routes have been set for this Controller, #routes returns nil.



462
463
464
465
# File 'lib/maveric.rb', line 462

def routes
  return nil if @routes.empty?
  @routes
end

.set_routes(r, o = {}) ⇒ Object

Removes currently set routes and adds the stated ones.



444
445
446
447
# File 'lib/maveric.rb', line 444

def set_routes r, o={}
  clear_routes
  [r].flatten.map{|e| add_route e, o }
end

Instance Method Details

#after(*a, &b) ⇒ Object

Alias to Controller.after



540
541
542
# File 'lib/maveric.rb', line 540

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

#before(*a, &b) ⇒ Object

Alias to Controller.before



535
536
537
# File 'lib/maveric.rb', line 535

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

#session_cleanup(controller) ⇒ Object

Touches the session and includes it into the http headers.



104
105
106
107
108
# File 'lib/maveric/sessions.rb', line 104

def session_cleanup controller
  return unless @env[:session]
  @env[:session].touch
  @headers['Set-Cookie'] = [@env[:session].to_s(@env)]
end

#to_aObject

A simple way to retrive pertinant data



596
597
598
# File 'lib/maveric.rb', line 596

def to_a # to_splat in 1.9
  [@status, @headers, @body]
end

#to_http(raw = true) ⇒ Object

For quick and raw response outputting!



601
602
603
604
605
606
607
608
# File 'lib/maveric.rb', line 601

def to_http raw=true
  response = if not raw then 'Status:'
    elsif @env and @env.key? 'HTTP_VERSION' then @env['HTTP_VERSION']
    else 'HTTP/1.1' end
  response += " #{self.status}" + ::Maveric::EOL # Status message? :/
  response << self.headers.map{|k,v| "#{k}: #{v}" }*::Maveric::EOL
  response << ::Maveric::EOL*2 + self.body
end