Kiss A simpler, smarter web application framework for Ruby

Kiss Subclass of Object

Description

Kiss - An MVC web application framework for Ruby, built on:

  • Erubis template engine
  • Sequel database ORM library
  • Rack web server abstraction

Attributes

envread-only
attributes below are request-specific
exception_cacheread-only
attributes below are request-specific
hostread-only
attributes below are request-specific
protocolread-only
attributes below are request-specific
requestread-only
attributes below are request-specific

Public Class Methods

absolute_path(filename) source

Converts passed-in filename to absolute path if it does not start with ’/’.

    # File lib/kiss.rb, line 313
    def absolute_path(filename)
      filename = ( filename =~ /\A\// ? '' : (Dir.pwd + '/') ) + filename
    end
    
call(env) source

Creates new controller instance to handle Rack request.

    # File lib/kiss.rb, line 108
    def call(env)
      new.call(env)
    end
    
digest_class(type) source

Returns Digest class used to generate digest of specified type.

    # File lib/kiss.rb, line 342
    def digest_class(type)
      type = type.to_sym
      @@digest[type] ? Digest.const_get(type) : nil
    end
    
directory_exists?(dir) source

Returns true if specified path is a directory. Cache result if file_cache_no_reload option is set; otherwise, always check filesystem.

    # File lib/kiss.rb, line 281
    def directory_exists?(dir)
      @@options[:file_cache_no_reload] ? (
        @@directory_cache.has_key?(path) ?
          @@directory_cache[dir] :
          @@directory_cache[dir] = File.directory?(dir)
        ) : File.directory?(dir)
    end
    
file_cache(path, report_change = false) {|contents| ...} source

Given a file path, caches or returns the file’s contents or the return value of the passed block applied to the file’s contents. If file is not found, the file’s contents are nil.

    # File lib/kiss.rb, line 405
    def file_cache(path, report_change = false)
      raise 'nil file path cannot be cached' unless path
      
      if @@file_cache.has_key?(path) && @@options[:file_cache_no_reload]
        # already loaded this path, and no_reload option is on; don't re-cache
        change = false
      elsif !@@file_cache.has_key?(path)
        # haven't loaded this path yet
        change = true
        if !File.file?(path)
          # nil path, of file doesn't exist
          @@file_cache_time[path] = nil
          contents = nil
        else
          # file exists; mark cache time and read file
          @@file_cache_time[path] = Time.now
          contents = File.read(path)
        end
      else
        # we've read this path before; may need to re-cache
        if !File.file?(path)
          if @@file_cache_time[path]
            # file cached as existing but has been removed; update cache to show no file
            change = true
            @@file_cache_time[path] = nil
            contents = nil
          else
            change = false
          end
        elsif !@@file_cache_time[path] ||
              @@file_cache_time[path] < File.mtime(path) ||
              ( File.symlink?(path) && (@@file_cache_time[path] < File.lstat(path).mtime) )
          # cache shows file missing, or file has been modified since cached
          change = true
          @@file_cache_time[path] = Time.now
          contents = File.read(path)
        else
          # cached file is still current; don't re-cache
          change = false
        end
      end
      
      if change
        @@file_cache[path] ||= block_given? ? yield(contents) : contents
      end
      
      report_change ? [@@file_cache[path], change] : @@file_cache[path]
    end
    
html_escape(obj) source

Returns string representation of object with HTML entities escaped.

    # File lib/kiss.rb, line 324
    def html_escape(obj)
      Rack::Utils.escape_html(
        obj.is_a?(String) ? obj : obj.inspect
      ).gsub(/^(\s+)/) {'&nbsp;' * $1.length}
    end
    
html_prepend(addition,document,tag) source

prepend addition just inside the specified tag of document

    # File lib/kiss.rb, line 318
    def html_prepend(addition,document,tag)
      document = document.body unless document.is_a?(String)
      document.sub(/(\<#{tag}[^\>]*\>)/i, '\1'+addition)
    end
    
load(loader_options = nil) source

Load and set up Kiss application from config file options and any passed-in options.

    # File lib/kiss.rb, line 162
    def load(loader_options = nil)
      # store cached files
      @@file_cache = {}
      @@directory_cache = {}
      @@file_cache_time = {}
      
      loader_options ||= {}
      # if loader_options is string, then it specifies environment
      # else it should be a hash of config options
      if loader_options.is_a?(String)
        loader_options = { :environment => loader_options }
      end
    
      # environment
      @@environment = loader_options[:environment]
    
      # directories
      script_dir = $0.sub(/[^\/]+\Z/,'')
      script_dir = '' if script_dir == './'
      @@project_dir = script_dir + (loader_options[:project_dir] || loader_options[:root_dir] || '..')
      Dir.chdir(@@project_dir)
    
      @@config_dir = loader_options[:config_dir] || 'config'
    
      # get environment name from config/environment
      if (@@environment.nil?) && File.file?(env_file = @@config_dir+'/environment')
        @@environment = File.read(env_file).sub(/\s+\Z/,'')
      end
    
      # init options
      @@options = {
        :layout => '/_layout'
      }
      @@lib_dirs = ['lib']
      @@gem_dirs = ['gems']
      @@require = []
      @@authenticate_exclude = ['/login','/logout']
    
      # common (shared) config
      if (File.file?(config_file = @@config_dir+'/common.yml'))
        merge_options( YAML::load(File.read(config_file)) )
      end
      # environment config
      if (File.file?(config_file = "#{@@config_dir}/environments/#{@@environment}.yml"))
        merge_options( YAML::load(File.read(config_file)) )
      end
    
      merge_options( loader_options )
    
      # set class vars from options
      @@action_dir = @@options[:action_dir] || 'actions'
      @@template_dir = @@options[:template_dir] ? @@options[:template_dir] : @@action_dir
    
      @@asset_dir = @@public_dir = @@options[:asset_dir] || @@options[:public_dir] || 'public_html'
    
      @@model_dir = @@options[:model_dir] || 'models'
      
      @@evolution_dir = @@options[:evolution_dir] || 'evolutions'
    
      @@email_template_dir = @@options[:email_template_dir] || 'email_templates'
      @@upload_dir = @@options[:upload_dir] || 'uploads'
      
      @@cookie_name = @@options[:cookie_name] || @@default_cookie_name
      @@default_action = @@options[:default_action] || @@default_action
      @@action_root_class = @@options[:action_class] || Class.new(Kiss::Action)
      
      # exception log
      @@exception_log_file = @@options[:exception_log] ? ::File.open(@@options[:exception_log],'a') : nil
      
      # default layout
      @@layout = @@options[:layout]
    
      # app_url: URL of the app actions root
      @@protocol = ENV['HTTPS'] == 'on' ? 'https' : 'http'
      @@app_host = @@options[:app_host] ? (@@protocol + '://' + @@options[:app_host]) : ''
      @@app_uri = @@options[:app_uri] || ''
      @@app_url =  @@app_host + @@app_uri
      
      # asset host: hostname of static assets
      # (remove http:// prefix if present)
      @@asset_host = @@options[:asset_host]
      @@asset_host.sub!(/^http:\/\//,'') if @@asset_host
    
      # public_uri: uri of requests to serve from public_dir
      @@asset_uri = @@options[:asset_uri] || @@options[:public_uri] || ''
      @@rack_file = Rack::File.new(@@asset_dir) if @@asset_uri
    
      # include lib dirs
      $LOAD_PATH.unshift(*( @@lib_dirs.flatten.select {|dir| File.directory?(dir) } ))
    
      # add gem dir to rubygems search path
      Gem.path.unshift(*( @@gem_dirs.flatten.select {|dir| File.directory?(dir) } ))
    
      # require libs
      @@require.flatten.each {|lib| require lib }
    
      # session class
      @@session_class = @@options[:session_class] ?
        (@@session_class = (@@options[:session_class].class == Class) ?
          @@options[:session_class] : @@options[:session_class].to_const
        ) : nil
    
      # load extensions to action class
      action_extension_path = @@action_dir + '/_action.rb'
      if File.file?(action_extension_path)
        @@action_root_class.class_eval(File.read(action_extension_path),action_extension_path) rescue nil
      end
      
      @@action_classes = {}
    
      # database
      @@database_config = @@options[:database]
      @@database_pool = []
    
      self
    end
    
mdy_to_ymd(date) source

Converts date strings from m/d/y to y/m/d. Useful for MySQL.

    # File lib/kiss.rb, line 348
    def mdy_to_ymd(date)
      return '0000-00-00' unless date && date =~ /\S/
      date.sub!(/\A\D+/,'')
      date.sub!(/\D+\Z/,'')
    
      month, day, year = date.split(/\D+/,3).each {|s| s.to_i}
    
      return 0 unless month && day
      
      current_year = Time.now.year
      if !year || year.length == 0
        # use current year if year is missing.
        year = current_year
      else
        # convert two-digit years to four-digit years
        year = year.to_i
        if year < 100
          year += 1900
          year += 100 if year < current_year - 95
        end
      end
    
      return sprintf("%04d-%02d-%02d",year,month.to_i,day.to_i)
    end
    
merge_options(config_options) source

Merges specified options into previously defined/merged Kiss options.

    # File lib/kiss.rb, line 290
    def merge_options(config_options)
      if config_options
        if env_vars = config_options.delete(:ENV)
          env_vars.each_pair {|k,v| ENV[k] = v }
        end
        if lib_dirs = config_options.delete(:lib_dirs)
          @@lib_dirs.push( lib_dirs )
        end
        if gem_dirs = config_options.delete(:gem_dirs)
          @@gem_dirs.push( gem_dirs )
        end
        if require_libs = config_options.delete(:require)
          @@require.push( require_libs )
        end
        if auth_exclude = config_options.delete(:authenticate_exclude)
          @@authenticate_exclude.push( *(auth_exclude.map { |action| action =~ /\A\// ? action : '/'+action }) )
        end
    
        @@options.merge!( config_options )
      end
    end
    
mime_type(extension) source

Returns MIME type corresponding to passed-in extension.

    # File lib/kiss.rb, line 337
    def mime_type(extension)
      Rack::File::MIME_TYPES[extension] || @@mime_types[extension]
    end
    
new(options = nil) source

Creates a new controller instance, and also configures the application with the specified options.

    # File lib/kiss.rb, line 459
  def initialize(options = nil)
    if @@options
      self.class.merge_options(options) if options
    else
      self.class.load(options)
    end
    
    @exception_cache = {}
    @debug_messages = []
    @benchmarks = []
    @files_cached_this_request = {}
  end
    
random_text(length) source

Generates string of random text of the specified length.

    # File lib/kiss.rb, line 392
    def random_text(length)
      chars = ('A'..'Z').to_a + ('0'..'9').to_a  # array
  
      text = ''
      size = chars.size
      length.times { text += chars[rand(size)] }
    
      text
    end
    
run(options = nil) source

Runs Kiss application found at project_dir (default: ’..’), with options read from config files plus additional options if passed in.

    # File lib/kiss.rb, line 114
    def run(options = nil)
      begin
        if @@options
          merge_options(options) if options
        else
          load(options)
        end
      
        app = self
        builder_options = @@options[:rack_builder] || []
        rack = Rack::Builder.new do
          builder_options.each do |builder_option|
            if builder_option.is_a?(Array)
              builder_args = builder_option
              builder_option = builder_args.shift
            else
              builder_args = []
            end
        
            unless builder_option.is_a?(Class)
              builder_option = Rack.const_get(builder_option.to_s)
            end
            
            use(builder_option,*builder_args)
          end
          
          run app
        end.to_app
        
        handler = @@options[:rack_handler] || Rack::Handler::WEBrick
        if !handler.is_a?(Class)
          handler = Rack::Handler.const_get(handler.to_s)
        end
        handler.run(rack,@@options[:rack_handler_options] || {:Port => 4000})
      rescue StandardError, LoadError, SyntaxError => e
        if @@options[:rack_handler] == :CGI
          print "Content-type: text/html\n\n"
          print $debug_messages.to_s + Kiss::ExceptionReport.generate(e)
        else
          print "Content-type: text/plain\n\n"
          puts "exception:\n" + e.message
          puts "\ntraceback:\n" + e.backtrace.join("\n")
        end
      end
    end
    
url_escape(string) source

Escapes string for use in URLs.

    # File lib/kiss.rb, line 331
    def url_escape(string)
        # encode space to '+'; don't encode letters, numbers, periods
      string.gsub(/([^A-Za-z0-9\.])/) { sprintf("%%%02X", $&.unpack("C")[0]) }
    end
    
validate_value(value, format, required = false, label = nil) source

Validates value against specified format. If required is true, value must contain a non-whitespace character. If required is false, value need not match format if and only if value contains only whitespace.

    # File lib/kiss.rb, line 376
    def validate_value(value, format, required = false, label = nil)
      if required && (value !~ /\S/)
        # value required
        raise "#{label || 'value'} required"
      elsif format && (value =~ /\S/)
        format = Kiss::Format.lookup(format)
      
        begin
          format.validate(value)
        rescue Kiss::Format::ValidateError => e
          raise e.class, "#{label} validation error: #{e.message}"
        end
      end
    end
    

Public Instance Methods

app_url(options = {}) source

Returns URL/URI of app root (corresponding to top level of action_dir).

    # File lib/kiss.rb, line 852
  def app_url(options = {})
    options.empty? ? (@app_url ||= @protocol + '://' + @app_host + @app_uri) :
      (options[:protocol] || @protocol) + '://' + (options[:host] || @app_host) + 
      (options[:uri] || @app_uri)
  end
    
asset_url(options = {}) source

Alias for pub_url

bench(label = nil, context = Kernel.caller[0]) source

Starts a new benchmark timer, with optional label. Benchmark results will be shown at top of application response body.

    # File lib/kiss.rb, line 831
  def bench(label = nil, context = Kernel.caller[0])
    stop_benchmark(context)
    @benchmarks.push(
      :label => label,
      :start_time => Time.now,
      :start_context => context
    )
  end
    
call(env) source

Processes and responds to a request received via Rack. Should only be called once for each controller instance (i.e. each controller instance should handle at most one request, then be discarded). Returns array of response code, headers, and body.

    # File lib/kiss.rb, line 493
  def call(env)
    @env = env
    
    # if @@rack_file && (
    #   (env["PATH_INFO"] == '/favicon.ico') ||
    #    (env["PATH_INFO"].sub!(Regexp.new("\\A#{@@asset_uri}"),''))
    # )
    #   return @@rack_file.call(env)
    # end
    
    # catch and report exceptions in this block
    
    code, headers, body = begin
      @request = Rack::Request.new(env)
      @response = Rack::Response.new
    
      @protocol, @app_host = (@request.server rescue '').split(/\:\/\//, 2)
      @app_host = @@options[:app_host] if @@options[:app_host]
      @app_uri = @@options[:app_uri] || @request.script_name || ''
    
      @host ||= @request.host rescue ''
    
      path = @request.path_info || '/'
      params = @request.params
      
      catch :kiss_request_done do
        action_handler = invoke_action(path,params)
        extension = action_handler.extension
        
        if content_type = options[:content_type] || (extension ? Kiss.mime_type(extension) : nil)
          @response['Content-Type'] = "#{content_type}; #{options[:document_encoding] || 'utf-8'}"
        end
        
        send_response(action_handler.output, action_handler.output_options)
      end
      finalize_session if @session
      
      @response.finish
    rescue StandardError, LoadError, SyntaxError => e
      body = Kiss::ExceptionReport.generate(e, env, @exception_cache, @db ? @db.last_query : nil)
      if @@exception_log_file
        @@exception_log_file.print(body + "\n--- End of exception report --- \n\n")
      end
      [500, {
        "Content-Type" => "text/html",
        "Content-Length" => body.length.to_s,
        "X-Kiss-Error-Type" => e.class.name,
        "X-Kiss-Error-Message" => e.message.sub(/\n.*/m,'')
      }, body]
    end
    
    if @debug_messages.size > 0
      extend Kiss::Debug
      body = prepend_debug(body)
      headers['Content-Length'] = body.length.to_s
    end
    
    if @benchmarks.size > 0
      stop_benchmark
      extend Kiss::Bench
      body = prepend_benchmarks(body)
      headers['Content-Length'] = body.length.to_s
    end
    
    if @db
      @db.kiss_controller = nil
      @@database_pool.push(@db)
    end
    
    [code,headers,body]
  end
    
check_evolution_number() source

Check whether there exists a file in evolution_dir whose number is greater than app’s current evolution number. If so, raise an error to indicate need to apply new evolutions.

    # File lib/kiss.rb, line 736
  def check_evolution_number
    version = evolution_number
    if Kiss.directory_exists?(@@evolution_dir) &&
        Dir.entries(@@evolution_dir).select { |f| f =~ /\A0*#{version+1}_/ }.size > 0
      raise "current evolution #{version} is outdated; apply evolutions or update evolution number"
    end
  end
    
database() source

Acquires and returns a database connection object from the connection pool, opening a new connection if the pool is empty.

Tip: `db’ is a shorthand alias for `database’.

    # File lib/kiss.rb, line 649
  def database
    @db ||= @@database_pool.shift || begin
      raise 'database config missing' unless @@database_config
      
      # open database connection (if not already open)
      @db = @@database_config.is_a?(String) ? (Sequel.open @@database_config) :
        @@database_config.is_a?(Hash) ? (Sequel.open @@database_config) : @@database_config
      
      @@db_extras_loaded ||= begin
        @db.class.class_eval do
          attr_accessor :kiss_controller, :kiss_model_cache
          
          @last_query = nil
          def last_query   #:nodoc:
            @last_query
          end
  
          alias_method :execute_old, :execute
          def execute(sql, *args, &block)   #:nodoc:
            @last_query = sql
            execute_old(sql, *args, &block)
          end
        end
        
        require 'kiss/model'
        Kiss::ModelCache.model_dir = @@model_dir
        
        if @db.class.name == 'Sequel::MySQL::Database'
          # add fetch_arrays, all_arrays methods
          require 'kiss/sequel_mysql'
          # turn off convert_tinyint_to_bool, unless options say otherwise
          Sequel.convert_tinyint_to_bool = false unless @@options[:convert_tinyint_to_bool]
        end
        
        true
      end
      
      # TODO: rewrite evolution file exists check for speed
      check_evolution_number
      
      # create model cache for this database connection
      @db.kiss_model_cache = Kiss::ModelCache.new(@db)
      @db.kiss_controller = self
      
      @db
    end
  end
    
Also aliased as: db
db() source

Alias for database

dbm() source

Alias for models

debug(object, context = Kernel.caller[0]) source

Adds debug message to inspect object. Debug messages will be shown at top of application response body.

    # File lib/kiss.rb, line 823
  def debug(object, context = Kernel.caller[0])
    @debug_messages.push( [object.inspect, context] )
    object
  end
    
Also aliased as: trace
evolution_number() source

Returns app’s current evolution number.

    # File lib/kiss.rb, line 724
  def evolution_number
    evolution_number_table.first.version
  end
    
evolution_number=(version) source

Sets app’s current evolution number.

    # File lib/kiss.rb, line 729
  def evolution_number=(version)
    load unless @@options
    evolution_number_table.update(:version => version)
  end
    
evolution_number_table() source

Returns Sequel dataset to evolution_number table, which specifies app’s current evolution number. Creates evolution_number table if it does not exist.

    # File lib/kiss.rb, line 713
  def evolution_number_table
    unless db.table_exists?(:evolution_number)
      db.create_table :evolution_number do
        column :version, :integer, :null=> false
      end
      db[:evolution_number].insert(:version => 0)
    end
    db[:evolution_number]
  end
    
exception_cache(data = nil) source

Adds data to be displayed in “Cache” section of Kiss exception reports.

    # File lib/kiss.rb, line 868
  def exception_cache(data = nil)
    @exception_cache.merge!(data) if data
    @exception_cache
  end
    
Also aliased as: set_exception_cache
file_cache(path, *args, &block) source

If file has already been cached in handling the current request, retrieve from cache and do not check filesystem for updates. Else cache file via Kiss.file_cache.

    # File lib/kiss.rb, line 635
  def file_cache(path, *args, &block)
    return @@file_cache[path] if @files_cached_this_request[path]
    @files_cached_this_request[path] = true
    
    self.class.file_cache(path, *args, &block)
  end
    
finalize_session() source

Saves session to session store, if session data has changed since load.

    # File lib/kiss.rb, line 776
  def finalize_session
    @session.save if @session_fingerprint != Marshal.dump(@session.data).hash
  end
    
get_action_handler(path,params) source

Parses request URI to determine action path and arguments, then instantiates action class to create action handler.

    # File lib/kiss.rb, line 570
  def get_action_handler(path,params)
    action_subdir = '/'
    action_uri = ''
    action = nil
    args = []
    
    redirect_url(app_url + '/') if path == ''
    
    path += @@default_action if path =~ /\/\Z/
    
    parts = path.sub(/^\/*/,'').split('/')
    
    action_class = Kiss::Action.get_subclass('/', @@action_dir + '/_action.rb', self) ||
      Kiss::Action
    
    while part = parts.shift
      action_uri += '/' + part
      
      if part =~ /\A(\d+)\Z/ || part =~ /\A\=([\w\.\-]+)\Z/
        args << $1
        next
      end
      
      raise 'bad action path' if part !~ /\A[a-z][\w\-\.]*\Z/i
      
      test_path = @@action_dir + action_subdir + part
      if Kiss.directory_exists?(test_path)
        action_subdir += part + '/'
        action_class = action_class.get_subclass(
          part + '/',
          @@action_dir + action_subdir + '_action.rb',
          self
        )
        next
      end
      
      if part =~ /\A(.+)\.(\w+)\Z/
        extension = $2
        part = $1
      else
        extension = 'rhtml'
      end
      
      action = action_subdir + part
      
      action_class = action_class.get_subclass(part, @@action_dir + action + '.rb', self)
      break
    end
    
    # if no action, must have traversed all parts to a directory
    # add a trailing slash and try again
    redirect_url(app_url + action_subdir) unless action
    
    # keep rest of path_info in args
    args.push(*parts)
    
    # return action path and action handler (instance of action class)
    [action, action_class.new(self,action,action_uri,action_subdir,extension,args,params)]
  end
    
invoke_action(path,params,render_options = {}) source

Not documented

    # File lib/kiss.rb, line 472
  def invoke_action(path,params,render_options = {})
    action, action_handler = get_action_handler(path,params)
    catch :kiss_action_done do
      action_handler.expand_login
    
      if @@options[:authenticate_all]
        if (!@@authenticate_exclude.is_a?(Array) ||
            @@authenticate_exclude.select {|a| a == action}.size == 0)
          action_handler.authenticate
        end
      end
    
      action_handler.call
      action_handler.render(render_options)
    end
    action_handler
  end
    
login() source

Returns a Kiss::Login object containing data from session.login.

    # File lib/kiss.rb, line 781
  def login
    @login ||= Kiss::Login.new(session)
  end
    
models() source

Kiss Model cache, used to invoke and store Kiss database models.

Example: models[:users] == database model for `users’ table

Tip: `dbm’ (stands for `database models’) is a shorthand alias for `models’.

    # File lib/kiss.rb, line 704
  def models
    # make sure we have a database connection
    # create new model cache unless exists already
    db.kiss_model_cache
  end
    
Also aliased as: dbm
new_email(options = {}) source

Returns new Kiss::Mailer object using specified options.

    # File lib/kiss.rb, line 875
  def new_email(options = {})
    mailer = Kiss::Mailer.new(options)
    mailer.controller = self
    mailer
  end
    
pub_url(options = {}) source

Returns URL/URI of app’s static assets (asset_host or public_uri).

    # File lib/kiss.rb, line 859
  def pub_url(options = {})
    options.empty? ?
      (@pub ||= (@@asset_host ? @protocol + '://' + @@asset_host : '') + @@asset_uri) :
      (options[:protocol] || @protocol) + '://' + (options[:host] || @@asset_host) + 
        (options[:uri] || @@asset_uri)
  end
    
Also aliased as: asset_url
redirect_url(url) source

Sends HTTP 302 response to redirect client browser agent to specified URL.

    # File lib/kiss.rb, line 810
  def redirect_url(url)
    @response.status = 302
    @response['Location'] = url
    @response.body = ''
    
    throw :kiss_request_done
  end
    
send_file(path, mime_type = nil) source

Outputs a Kiss::StaticFile object as response to Rack. Used to return static files efficiently.

    # File lib/kiss.rb, line 790
  def send_file(path, mime_type = nil)
    @response = Kiss::StaticFile.new(path,mime_type)
    
    throw :kiss_request_done
  end
    
send_response(output = '',options = {}) source

Prepares Rack::Response object to return application response to Rack. Raises Kiss::ActionDone exception to bypass caller stack and return directly to Kiss#call.

    # File lib/kiss.rb, line 799
  def send_response(output = '',options = {})
    @response['Content-Length'] = output.length.to_s
    @response.body = output
    
    throw :kiss_request_done
    
    # back to Kiss#call, which finalizes session and returns @response
    # (throws exception if no @response set)
  end
    
session() source

Retrieves or generates session data object, based on session ID from cookie value.

    # File lib/kiss.rb, line 748
  def session
    @session ||= begin
      @@session_class ? begin
        @@session_setup ||= begin
          # setup session storage
          @@session_class.setup_storage(self)
          true
        end
        
        session = @@session_class.persist(self,@request.cookies[@@cookie_name])
        @session_fingerprint = Marshal.dump(session.data).hash
    
        cookie_vars = {
          :value => session.values[:session_id],
          :path => @@options[:cookie_path] || @app_uri,
          :domain => @@options[:cookie_domain] || @request.host
        }
        cookie_vars[:expires] = Time.now + @@options[:cookie_lifespan] if @@options[:cookie_lifespan]
    
        # set_cookie here or at render time
        @response.set_cookie @@cookie_name, cookie_vars
      
        session
      end : {}
    end
  end
    
set_exception_cache(data = nil) source

Alias for exception_cache

stop_benchmark(end_context = nil) source

Stops last benchmark timer, if still running.

    # File lib/kiss.rb, line 841
  def stop_benchmark(end_context = nil)
    if @benchmarks[-1] && !@benchmarks[-1][:end_time]
      @benchmarks[-1][:end_time] = Time.now
      @benchmarks[-1][:end_context] = end_context
    end
  end
    
trace(object, context = Kernel.caller[0]) source

Alias for debug

Disabled; run with $DEBUG to generate this.