Class: Utopia::Controller
- Inherits:
-
Object
- Object
- Utopia::Controller
- Defined in:
- lib/utopia/controller.rb,
lib/utopia/controller/base.rb,
lib/utopia/controller/actions.rb,
lib/utopia/controller/respond.rb,
lib/utopia/controller/rewrite.rb,
lib/utopia/controller/variables.rb
Overview
A middleware which loads controller classes and invokes functionality based on the requested path.
Defined Under Namespace
Modules: Actions, Respond, Rewrite Classes: Base, Variables
Constant Summary
- CONTROLLER_RB =
The controller filename.
'controller.rb'.freeze
Instance Attribute Summary collapse
-
#app ⇒ Object
readonly
Returns the value of attribute app.
Class Method Summary collapse
Instance Method Summary collapse
-
#call(env) ⇒ Object
-
#freeze ⇒ Object
-
#initialize(app, root: Utopia::default_root, base: Controller::Base) ⇒ Controller
constructor
A new instance of Controller.
-
#invoke_controllers(request) ⇒ Object
Invoke the controller layer for a given request.
-
#load_controller_file(uri_path) ⇒ Object
Loads the controller file for the given relative url_path.
-
#lookup_controller(path) ⇒ Object
Fetch the controller for the given relative path.
Constructor Details
#initialize(app, root: Utopia::default_root, base: Controller::Base) ⇒ Controller
Returns a new instance of Controller
59 60 61 62 63 64 65 66 |
# File 'lib/utopia/controller.rb', line 59 def initialize(app, root: Utopia::default_root, base: Controller::Base) @app = app @root = root @controller_cache = Concurrent::Map.new @base = base end |
Instance Attribute Details
#app ⇒ Object (readonly)
Returns the value of attribute app
68 69 70 |
# File 'lib/utopia/controller.rb', line 68 def app @app end |
Class Method Details
.[](request) ⇒ Object
53 54 55 |
# File 'lib/utopia/controller.rb', line 53 def self.[] request request.env[VARIABLES_KEY] end |
Instance Method Details
#call(env) ⇒ Object
156 157 158 159 160 161 162 163 164 165 166 |
# File 'lib/utopia/controller.rb', line 156 def call(env) env[VARIABLES_KEY] ||= Variables.new request = Rack::Request.new(env) if result = invoke_controllers(request) return result end return @app.call(env) end |
#freeze ⇒ Object
70 71 72 73 74 75 76 77 |
# File 'lib/utopia/controller.rb', line 70 def freeze return self if frozen? @root.freeze @base.freeze super end |
#invoke_controllers(request) ⇒ Object
Invoke the controller layer for a given request. The request path may be rewritten.
120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 |
# File 'lib/utopia/controller.rb', line 120 def invoke_controllers(request) request_path = Path.from_string(request.path_info) # The request path must be absolute. We could handle this internally but it is probably better for this to be an error: raise ArgumentError.new("Invalid request path #{request_path}") unless request_path.absolute? # The controller path contains the current complete path being evaluated: controller_path = Path.new # Controller instance variables which eventually get processed by the view: variables = request.env[VARIABLES_KEY] while request_path.components.any? # We copy one path component from the relative path to the controller path at a time. The controller, when invoked, can modify the relative path (by assigning to relative_path.components). This allows for controller-relative rewrites, but only the remaining path postfix can be modified. controller_path.components << request_path.components.shift if controller = lookup_controller(controller_path) # Don't modify the original controller: controller = controller.clone # Append the controller to the set of controller variables, updates the controller with all current instance variables. variables << controller if result = controller.process!(request, request_path) return result end end end # Controllers can directly modify relative_path, which is copied into controller_path. The controllers may have rewriten the path so we update the path info: request.env[Rack::PATH_INFO] = controller_path.to_s # No controller gave a useful result: return nil end |
#load_controller_file(uri_path) ⇒ Object
Loads the controller file for the given relative url_path.
87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 |
# File 'lib/utopia/controller.rb', line 87 def load_controller_file(uri_path) base_path = File.join(@root, uri_path.components) controller_path = File.join(base_path, CONTROLLER_RB) # puts "load_controller_file(#{path.inspect}) => #{controller_path}" if File.exist?(controller_path) klass = Class.new(@base) # base_path is expected to be a string representing a filesystem path: klass.const_set(:BASE_PATH, base_path.freeze) # uri_path is expected to be an instance of Path: klass.const_set(:URI_PATH, uri_path.dup.freeze) klass.const_set(:CONTROLLER, self) klass.class_eval(File.read(controller_path), controller_path) # Give the controller a useful name: # Controllers.define(klass) # We lock down the controller class to prevent unsafe modifications: klass.freeze # Create an instance of the controller: return klass.new else return nil end end |
#lookup_controller(path) ⇒ Object
Fetch the controller for the given relative path. May be cached.
80 81 82 83 84 |
# File 'lib/utopia/controller.rb', line 80 def lookup_controller(path) @controller_cache.fetch_or_store(path.to_s) do load_controller_file(path) end end |