Class: Utopia::Controller::Middleware
- Inherits:
-
Protocol::HTTP::Middleware
- Object
- Protocol::HTTP::Middleware
- Utopia::Controller::Middleware
- Defined in:
- lib/utopia/controller/middleware.rb
Overview
Dispatches requests to filesystem-backed controller classes.
Constant Summary collapse
- CONTROLLER_RB =
The controller filename.
"controller.rb".freeze
Instance Method Summary collapse
-
#call(request) ⇒ Object
Attach controller variables while processing the request.
-
#freeze ⇒ Object
Freeze this object and its internal state.
-
#initialize(app, root: Utopia::default_root, base: Controller::Base) ⇒ Middleware
constructor
A new instance of Middleware.
-
#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) ⇒ Middleware
Returns a new instance of Middleware.
29 30 31 32 33 34 35 36 37 |
# File 'lib/utopia/controller/middleware.rb', line 29 def initialize(app, root: Utopia::default_root, base: Controller::Base) super(app) @root = root @controller_cache = Concurrent::Map.new @base = base end |
Instance Method Details
#call(request) ⇒ Object
Attach controller variables while processing the request.
127 128 129 130 131 132 133 134 135 |
# File 'lib/utopia/controller/middleware.rb', line 127 def call(request) request.variables ||= Variables.new if result = invoke_controllers(request) return Utopia::Response.wrap(result) end return @delegate.call(request) end |
#freeze ⇒ Object
Freeze this object and its internal state.
41 42 43 44 45 46 47 48 |
# File 'lib/utopia/controller/middleware.rb', line 41 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.
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 118 119 120 121 122 |
# File 'lib/utopia/controller/middleware.rb', line 88 def invoke_controllers(request) request_path = request.path # 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.variables 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 the remaining path. Preserve those rewrites at the request boundary: request.path = controller_path # 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.
58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 |
# File 'lib/utopia/controller/middleware.rb', line 58 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) # 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.
51 52 53 54 55 |
# File 'lib/utopia/controller/middleware.rb', line 51 def lookup_controller(path) @controller_cache.fetch_or_store(path.to_s) do load_controller_file(path) end end |