Class: Utopia::Controller::Middleware
- Inherits:
-
Object
- Object
- Utopia::Controller::Middleware
- Defined in:
- lib/utopia/controller/middleware.rb
Constant Summary collapse
- CONTROLLER_RB =
The controller filename.
"controller.rb".freeze
Instance Attribute Summary collapse
-
#app ⇒ Object
readonly
Returns the value of attribute app.
Instance Method Summary collapse
- #call(env) ⇒ Object
- #freeze ⇒ Object
-
#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.
26 27 28 29 30 31 32 33 |
# File 'lib/utopia/controller/middleware.rb', line 26 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.
35 36 37 |
# File 'lib/utopia/controller/middleware.rb', line 35 def app @app end |
Instance Method Details
#call(env) ⇒ Object
120 121 122 123 124 125 126 127 128 129 130 |
# File 'lib/utopia/controller/middleware.rb', line 120 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
37 38 39 40 41 42 43 44 |
# File 'lib/utopia/controller/middleware.rb', line 37 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.
84 85 86 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 118 |
# File 'lib/utopia/controller/middleware.rb', line 84 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.
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/utopia/controller/middleware.rb', line 54 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.
47 48 49 50 51 |
# File 'lib/utopia/controller/middleware.rb', line 47 def lookup_controller(path) @controller_cache.fetch_or_store(path.to_s) do load_controller_file(path) end end |