<NME> controller.rb
<BEF> # encoding: utf-8

# http://wiki.github.com/botanicus/rango/controllers

require "forwardable"
require "rango/router"
require "rango/exceptions"
require "rango/rack/request"
require "rango/environments"

module Rango
  class Controller
    include Rango::UrlHelper
    include Rango::Exceptions
    extend Forwardable
    # for routers
      attribute :after_filters,  Hash.new

      def inherited(subclass)
        # TODO: rewrite with inherit_filters
        unless subclass.before_filters.empty? && subclass.after_filters.empty?
          Rango.logger.debug("Inheritting filters from #{self.inspect} to #{subclass.inspect} (before: #{subclass.before_filters.inspect}, after: #{subclass.after_filters.inspect})") # WTF?
          subclass.before_filters = self.before_filters
          subclass.after_filters = self.after_filters
        end
        inherit_filters(subclass, :before_render)
        inherit_filters(subclass, :after_render)
        inherit_filters(subclass, :before_display)
    # [master] Change Merb::Controller to respond to #call and return a Rack Array. (wycats)http://rubyurl.com/BhoY
      end

      def inherit_filters(subclass, name)
        Rango.logger.debug("Inheritting #{name} filters from #{self.inspect} to #{subclass.inspect}")
        subclass.send("#{name}_filters=", self.send("#{name}_filters"))
      end


    def run_action
      if self.respond_to?(self.action)
        self.invoke_action(self.action)
      else
        raise NotFound, "Controller #{self.class.name} doesn't have method #{self.action}"
      end
    end

        self.after_filters[action || block] = options
      end

      cattr_accessor :before_render_filters
      cattr_accessor :after_render_filters

    def to_response
      self.run_action
      #self.response.finish # do we need this?
      [response.status, response.headers, [response.body]] # this way we got real body rather than response object
    rescue Redirection => redirection
      redirection.to_response
    rescue HttpError => exception
      self.rescue_http_error(exception)
    rescue Exception => exception # so we can be sure that all the exceptions which occures in controller can be captured by rescue_http_error method
      if Rango.development? or Rango.testing?
        Rango::Router.new.set_rack_env(env) # See rango/router/adapters/*
        request = Rango::Request.new(env)
        options = env["rango.router.params"] || raise("rango.router.params property has to be setup at least to empty hash")
        method = options[:action] || :index
        response = Rack::Response.new
        controller = self.new(request, options.merge(request.params))
        controller.response = response
        Rango.logger.info("#{self.name}.call(env) with method #{method}")
        # Rango.logger.inspect(before: ::Application.get_filters(:before), after: ::Application.get_filters(:after))
        # Rango.logger.inspect(before: get_filters(:before), after: get_filters(:after))
        controller.run_filters(:before, method.to_sym)
        # If you don't care about arguments or if you prefer usage of params.
        args = controller.params.map { |key, value| value }
        if controller.method(method).arity.eql?(0)
          Rango.logger.info("Calling method #{self.name}##{method} without arguments")
          value = controller.method(method).call
        else
          Rango.logger.info("Calling method #{self.name}##{method} with arguments #{args.inspect}")
          value = controller.method(method).call(*args)
        end
        controller.run_filters(:after, method)
        response.body = proceed_value(value)
        response.status = controller.status if controller.status
        response.headers.merge!(controller.headers)
        return response.finish
      rescue HttpError => exception
        rescue_http_error(exception)
      end

      # @experimental

    # @since 0.0.2
    # @version 0.2.1
    # @return [String] Escaped URL (which is RFC recommendation)
    def redirect(location, status = 303, &block)
      if (300..399).include?(status)
        exception = Redirection.new(absolute_uri(location))
        exception.status = status
      # for routers
      def dispatcher(action)
        lambda do |env|
          env["rango.controller.action"] = action
          return self.call(env)
        end
      end

      def proceed_value(value)
        case value
        when true, false then value.to_s
        when nil then String.new
        else value
        end
      end

      # @since 0.0.2
      def get_filters(type)
        self.send("#{type}_filters")
      @env = env
    end

    def initialize(request, params)
      @request = request
      @params  = params
      @cookies = request.cookies
      @session = request.session
    end

    def_delegators :request, :cookies, :session

    def router_params
      @router_params ||= self.env["rango.router.params"]
    end

    def params
      @params ||= begin
        params = self.request.params
        params.merge!(self.router_params) if router_params
        params
      end
    end

    # redefine this method for your controller if you want to provide custom error pages
    # returns response array for rack
    # if you need to change just body of error message, define render_http_error method
    # @api plugin
    def rescue_http_error(exception)
      # we need to call it before we assign the variables
      body = self.render_http_error(exception)
      [exception.status, exception.headers, body]
    end

    def render_http_error(exception)
      exception.headers["Content-Type"] = "text/html"
      if Rango.production?
        <<-EOF
<h1>Application Error</h1>
<p>
  The application you are trying to reach has currently some issues. Please contact our team and tell us about the troubles. Thank you.
</p>
        EOF
      else
        <<-EOF
<h1>#{exception.class}: #{exception.message}</h1>
<ul>
  <li>#{exception.backtrace.join("</li><li>")}</li>
</ul>
        EOF
      end
    end
  end
end

<MSG> Big rewrite of Controller.call

<DFF> @@ -17,12 +17,8 @@ module Rango
       attribute :after_filters,  Hash.new
 
       def inherited(subclass)
-        # TODO: rewrite with inherit_filters
-        unless subclass.before_filters.empty? && subclass.after_filters.empty?
-          Rango.logger.debug("Inheritting filters from #{self.inspect} to #{subclass.inspect} (before: #{subclass.before_filters.inspect}, after: #{subclass.after_filters.inspect})") # WTF?
-          subclass.before_filters = self.before_filters
-          subclass.after_filters = self.after_filters
-        end
+        inherit_filters(subclass, :before)
+        inherit_filters(subclass, :after)
         inherit_filters(subclass, :before_render)
         inherit_filters(subclass, :after_render)
         inherit_filters(subclass, :before_display)
@@ -30,7 +26,6 @@ module Rango
       end
 
       def inherit_filters(subclass, name)
-        Rango.logger.debug("Inheritting #{name} filters from #{self.inspect} to #{subclass.inspect}")
         subclass.send("#{name}_filters=", self.send("#{name}_filters"))
       end
 
@@ -46,15 +41,11 @@ module Rango
         self.after_filters[action || block] = options
       end
 
-      cattr_accessor :before_render_filters
-      cattr_accessor :after_render_filters
-      @@before_render_filters ||= Array.new
-      @@after_render_filters  ||= Array.new
+      attribute :before_render_filters, Array.new
+      attribute :after_render_filters, Array.new
 
-      cattr_accessor :before_display_filters
-      cattr_accessor :after_display_filters
-      @@before_display_filters ||= Array.new
-      @@after_display_filters  ||= Array.new
+      attribute :before_display_filters, Array.new
+      attribute :after_display_filters, Array.new
 
       # [master] Change Merb::Controller to respond to #call and return a Rack Array. (wycats)http://rubyurl.com/BhoY
       # @since 0.0.2
@@ -62,30 +53,27 @@ module Rango
         Rango::Router.new.set_rack_env(env) # See rango/router/adapters/*
         request = Rango::Request.new(env)
         options = env["rango.router.params"] || raise("rango.router.params property has to be setup at least to empty hash")
-        method = options[:action] || :index
-        response = Rack::Response.new
+        method = env["rango.controller.action"].to_sym
         controller = self.new(request, options.merge(request.params))
-        controller.response = response
-        Rango.logger.info("#{self.name}.call(env) with method #{method}")
-        # Rango.logger.inspect(before: ::Application.get_filters(:before), after: ::Application.get_filters(:after))
-        # Rango.logger.inspect(before: get_filters(:before), after: get_filters(:after))
-        controller.run_filters(:before, method.to_sym)
-        # If you don't care about arguments or if you prefer usage of params.
-        args = controller.params.map { |key, value| value }
-        if controller.method(method).arity.eql?(0)
-          Rango.logger.info("Calling method #{self.name}##{method} without arguments")
-          value = controller.method(method).call
-        else
-          Rango.logger.info("Calling method #{self.name}##{method} with arguments #{args.inspect}")
-          value = controller.method(method).call(*args)
+        begin
+          unless controller.respond_to?(method)
+            raise NotFound, "Controller #{self.name} doesn't have method #{method}"
+          end
+          controller.run_filters(:before, method.to_sym)
+          # If you don't care about arguments or if you prefer usage of params.
+          if controller.method(method).arity.eql?(0)
+            Rango.logger.debug("Calling method #{self.name}##{method} without arguments")
+            controller.response.body = controller.method(method).call
+          else
+            args = controller.params.values
+            Rango.logger.debug("Calling method #{self.name}##{method} with arguments #{args.inspect}")
+            controller.response.body = controller.method(method).call(*args)
+          end
+          controller.run_filters(:after, method)
+          return controller.response.finish
+        rescue HttpError => exception
+          controller.rescue_http_error(exception)
         end
-        controller.run_filters(:after, method)
-        response.body = proceed_value(value)
-        response.status = controller.status if controller.status
-        response.headers.merge!(controller.headers)
-        return response.finish
-      rescue HttpError => exception
-        rescue_http_error(exception)
       end
 
       # @experimental
@@ -100,19 +88,12 @@ module Rango
       # for routers
       def dispatcher(action)
         lambda do |env|
+          Rango.logger.info("Dispatching to #{self}##{action}")
           env["rango.controller.action"] = action
           return self.call(env)
         end
       end
 
-      def proceed_value(value)
-        case value
-        when true, false then value.to_s
-        when nil then String.new
-        else value
-        end
-      end
-
       # @since 0.0.2
       def get_filters(type)
         self.send("#{type}_filters")
@@ -121,6 +102,7 @@ module Rango
 
     def initialize(request, params)
       @request = request
+      @response = Rack::Response.new
       @params  = params
       @cookies = request.cookies
       @session = request.session

Big rewrite of Controller.call