Class: Kenji::Controller
- Inherits:
-
Object
- Object
- Kenji::Controller
- Defined in:
- lib/kenji/controller.rb
Instance Attribute Summary collapse
-
#kenji ⇒ Object
use the reader freely to grab the kenji object.
Class Method Summary collapse
-
.all(path, &block) ⇒ Object
Route all methods for given path.
-
.before(&block) ⇒ Object
This lets you define before blocks.
-
.delete(path, &block) ⇒ Object
Route DELETE.
- .fallback(&block) ⇒ Object
-
.get(path, &block) ⇒ Object
Route GET.
-
.pass(path, controller) ⇒ Object
This lets us pass the routing down to another controller for a sub-path.
-
.post(path, &block) ⇒ Object
Route POST.
-
.put(path, &block) ⇒ Object
Route PUT.
-
.route(*methods, path, &block) ⇒ Object
Route a given path to the correct block, for any given methods.
Instance Method Summary collapse
- #attempt_fallback(path) ⇒ Object
-
#call(method, path) ⇒ Object
Most likely only used by Kenji itself.
-
#log(*args) ⇒ Object
Utility method: this can be used to log to stderr cleanly.
Instance Attribute Details
#kenji ⇒ Object
use the reader freely to grab the kenji object
6 7 8 |
# File 'lib/kenji/controller.rb', line 6 def kenji @kenji end |
Class Method Details
.all(path, &block) ⇒ Object
Route all methods for given path
41 42 43 |
# File 'lib/kenji/controller.rb', line 41 def self.all(path, &block) route(:get, :post, :put, :delete, path, &block) end |
.before(&block) ⇒ Object
This lets you define before blocks.
class MyController < Kenji::Controller
before do
# eg. ensure authentication, you can use kenji.respond in here.
end
end
101 102 103 104 105 106 |
# File 'lib/kenji/controller.rb', line 101 def self.before(&block) define_method(:_tmp_before_action, &block) block = instance_method(:_tmp_before_action) remove_method(:_tmp_before_action) (@befores ||= []) << block end |
.delete(path, &block) ⇒ Object
Route DELETE
34 35 36 |
# File 'lib/kenji/controller.rb', line 34 def self.delete(path, &block) route(:delete, path, &block) end |
.fallback(&block) ⇒ Object
45 46 47 48 |
# File 'lib/kenji/controller.rb', line 45 def self.fallback(&block) define_method(:fallback, &block) nil # void method end |
.get(path, &block) ⇒ Object
Route GET
19 20 21 |
# File 'lib/kenji/controller.rb', line 19 def self.get(path, &block) route(:get, path, &block) end |
.pass(path, controller) ⇒ Object
This lets us pass the routing down to another controller for a sub-path.
class MyController < Kenji::Controller
pass '/admin/*', AdminController
# regular routes
end
81 82 83 84 85 86 87 88 89 90 |
# File 'lib/kenji/controller.rb', line 81 def self.pass(path, controller) node = (@passes ||= {}) segments = path.split('/') segments = segments.drop(1) if segments.first == '' # discard leading /'s empty segment segments.each do |segment| node = (node[segment.to_sym] ||= {}) break if segment == '*' end node[:@controller] = controller end |
.post(path, &block) ⇒ Object
Route POST
24 25 26 |
# File 'lib/kenji/controller.rb', line 24 def self.post(path, &block) route(:post, path, &block) end |
.put(path, &block) ⇒ Object
Route PUT
29 30 31 |
# File 'lib/kenji/controller.rb', line 29 def self.put(path, &block) route(:put, path, &block) end |
.route(*methods, path, &block) ⇒ Object
Route a given path to the correct block, for any given methods
Note: this works by building a tree for the path, each node being a path segment or variable segment, and the leaf @action being the block
55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/kenji/controller.rb', line 55 def self.route(*methods, path, &block) # bind the block to self as an instance method, so its context is correct define_method(:_tmp_route_action, &block) block = instance_method(:_tmp_route_action) remove_method(:_tmp_route_action) # store the block for each method methods.each do |method| node = ((@routes ||= {})[method] ||= {}) segments = path.split('/') segments = segments.drop(1) if segments.first == '' # discard leading /'s empty segment segments.each do |segment| # lazily create tree segment = ':' if segment =~ /^:/ # discard :variable name node = (node[segment.to_sym] ||= {}) end node[:@action] = block # store block as leaf in @action end nil # void method end |
Instance Method Details
#attempt_fallback(path) ⇒ Object
155 156 157 158 159 160 161 162 163 164 165 |
# File 'lib/kenji/controller.rb', line 155 def attempt_fallback(path) if respond_to? :fallback if self.class.instance_method(:fallback).arity == 1 return fallback(path) else return fallback end else kenji.respond(404, 'Not found!') end end |
#call(method, path) ⇒ Object
Most likely only used by Kenji itself. Override to implement your own routing, if you’d like.
112 113 114 115 116 117 118 119 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 |
# File 'lib/kenji/controller.rb', line 112 def call(method, path) self.class.befores.each {|b| b.bind(self).call } segments = path.split('/') segments = segments.drop(1) if segments.first == '' # discard leading /'s empty segment # check for passes node = self.class.passes remaining_segments = segments.dup f = fetch_passes(node, remaining_segments) if f[:match] && f[:controller] instance = f[:controller].new instance.kenji = kenji if instance.respond_to?(:kenji=) f[:variables].each do |k, v| instance.instance_variable_set(:"@#{k}", v) end return instance.call(method, f[:remaining_segments].join('/')) end # regular routing node = self.class.routes[method] || {} variables = [] searching = true segments.each do |segment| # traverse tree to find if searching && node[segment.to_sym] node = node[segment.to_sym] # attempt to move down to the plain text segment elsif searching && node[:':'] node = node[:':'] # attempt to find a variable segment variables << segment # either we've found a variable, or the `unless` below will trigger else return attempt_fallback(path) # route failed to match variable or segment node so attempt fallback end end if node && action = node[:@action] # the block is stored in the @action leaf return action.bind(self).call(*variables) else # or, fallback if necessary store the block for each method return attempt_fallback(path) end end |
#log(*args) ⇒ Object
Utility method: this can be used to log to stderr cleanly.
170 171 172 |
# File 'lib/kenji/controller.rb', line 170 def log(*args) kenji.stderr.puts(*args) end |