Class: Tap::Controller
- Inherits:
-
Object
- Object
- Tap::Controller
- Extended by:
- Lazydoc::Attributes
- Includes:
- Rack::Utils
- Defined in:
- lib/tap/controller.rb,
lib/tap/controller/utils.rb,
lib/tap/controller/extname.rb,
lib/tap/controller/rest_routes.rb
Overview
Declaring Actions
By default all public methods in subclasses are declared as actions. You can declare a private or protected method as an action by:
-
manually adding it directly to actions
-
defining it as a public method and then call private(:method) or protected(:method)
Similarly, public method can be made non-action by actions by:
-
manually deleting it from actions
-
define it private or protected then call public(:method)
Direct Known Subclasses
Tap::Controllers::App, Tap::Controllers::Data, Tap::Controllers::Server
Defined Under Namespace
Modules: Extname, RestRoutes, Utils
Constant Summary collapse
- ServerError =
Tap::Server::ServerError
Class Attribute Summary collapse
-
.actions ⇒ Object
readonly
An array of methods that can be called as actions.
-
.default_action ⇒ Object
readonly
The default action called for the request path ‘/’.
Instance Attribute Summary collapse
-
#request ⇒ Object
A Rack::Request wrapping env, set during call.
-
#response ⇒ Object
A Rack::Response.
-
#server ⇒ Object
References the Tap::Server running this controller.
Class Method Summary collapse
-
.call(env) ⇒ Object
Instantiates self and performs call.
-
.get(variable) ⇒ Object
Gets the value of an instance variable set via set.
-
.inherited(child) ⇒ Object
Initialize instance variables on the child and inherit as necessary.
- .nest(key, controller, &block) ⇒ Object
-
.set(variable, value) ⇒ Object
Sets an instance variable for self (ie the class), short for:.
-
.set_variables ⇒ Object
An array of variables set via set.
Instance Method Summary collapse
-
#action?(action) ⇒ Boolean
Returns true if action is registered as an action for self.
-
#call(env) ⇒ Object
Routes the request to an action and returns the response.
-
#dispatch(route) ⇒ Object
Inputs a route like [action, *args] and dispatches it to the action.
- #error(msg, status = 500) ⇒ Object
-
#initialize ⇒ Controller
constructor
Initializes a new instance of self.
- #module_render(path, obj, options = {}) ⇒ Object
- #not_found ⇒ Object
-
#redirect(uri, status = 302, headers = {}, body = "") ⇒ Object
Redirects to the specified uri.
-
#render(path, options = {}) ⇒ Object
Renders the class_file at path with the specified options.
-
#render_erb(template, options = {}, filename = nil) ⇒ Object
Renders the specified template as ERB using the options.
-
#render_layout(layout, content) ⇒ Object
Renders the specified layout with content as a local variable.
-
#route ⇒ Object
Returns the action, args, and extname for the request.path_info.
-
#uri(action = nil, params = nil, options = nil) ⇒ Object
Returns a uri to the specified action on self.
Constructor Details
#initialize ⇒ Controller
Initializes a new instance of self.
156 157 158 |
# File 'lib/tap/controller.rb', line 156 def initialize @request = @response = @server = nil end |
Class Attribute Details
.actions ⇒ Object (readonly)
An array of methods that can be called as actions. Actions must be stored as symbols. Actions are inherited.
40 41 42 |
# File 'lib/tap/controller.rb', line 40 def actions @actions end |
.default_action ⇒ Object (readonly)
The default action called for the request path ‘/’
43 44 45 |
# File 'lib/tap/controller.rb', line 43 def default_action @default_action end |
Instance Attribute Details
#request ⇒ Object
A Rack::Request wrapping env, set during call.
148 149 150 |
# File 'lib/tap/controller.rb', line 148 def request @request end |
#response ⇒ Object
A Rack::Response. If the action returns a string, it will be written to response and response will be returned by call. Otherwise, call returns the action result and response is ignored.
153 154 155 |
# File 'lib/tap/controller.rb', line 153 def response @response end |
#server ⇒ Object
References the Tap::Server running this controller.
145 146 147 |
# File 'lib/tap/controller.rb', line 145 def server @server end |
Class Method Details
.call(env) ⇒ Object
Instantiates self and performs call.
46 47 48 |
# File 'lib/tap/controller.rb', line 46 def call(env) new.call(env) end |
.get(variable) ⇒ Object
Gets the value of an instance variable set via set. Returns nil for variables that have not been set through set.
64 65 66 67 |
# File 'lib/tap/controller.rb', line 64 def get(variable) return nil unless set_variables.include?(variable) instance_variable_get("@#{variable}") end |
.inherited(child) ⇒ Object
Initialize instance variables on the child and inherit as necessary.
26 27 28 29 30 31 32 33 34 35 36 |
# File 'lib/tap/controller.rb', line 26 def inherited(child) # :nodoc: super set_variables.each do |variable| value = get(variable) value = value.dup if Configurable::Config.duplicable_value?(value) child.set(variable, value) end child.set(:define_action, true) end |
.nest(key, controller, &block) ⇒ Object
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 |
# File 'lib/tap/controller.rb', line 74 def nest(key, controller, &block) # generate a subclass if anything gets overridden if block_given? controller = Class.new(controller) controller.class_eval(&block) end # this check prevents a warning in cases where the nesting # class defines the nested class const_name = key.to_s.camelize unless const_defined?(const_name) && const_get(const_name) == subclass const_set(const_name, controller) end define_method(key) do |*args| instance = controller.new instance.server = server instance.controller_path = controller_path ? "#{controller_path}/#{key}" : key instance.request = request instance.response = response instance.dispatch(args) end end |
.set(variable, value) ⇒ Object
Sets an instance variable for self (ie the class), short for:
instance_variable_set(:@attribute, value)
Set variables inherited by subclasses. The value is duplicated on the subclass so the parent and child variable may be modified independently.
57 58 59 60 |
# File 'lib/tap/controller.rb', line 57 def set(variable, value) set_variables << variable instance_variable_set("@#{variable}", value) end |
.set_variables ⇒ Object
An array of variables set via set.
70 71 72 |
# File 'lib/tap/controller.rb', line 70 def set_variables @set_variables ||= [] end |
Instance Method Details
#action?(action) ⇒ Boolean
Returns true if action is registered as an action for self.
161 162 163 |
# File 'lib/tap/controller.rb', line 161 def action?(action) self.class.actions.include?(action.to_sym) end |
#call(env) ⇒ Object
Routes the request to an action and returns the response. Routing is simple and fixed (see route):
route calls
/ default_action (ie 'index')
/action/*args action(*args)
If the action returns a string, it will be written to response. Otherwise, call returns the result of action. This allows actions like:
class ActionsController < Tap::Controller
def simple
"html body"
end
def standard
response["Content-Type"] = "text/plain"
response << "text"
response.finish
end
def custom
[200, {"Content-Type" => "text/plain"}, ["text"]]
end
end
239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 |
# File 'lib/tap/controller.rb', line 239 def call(env) @server = env['tap.server'] @request = Rack::Request.new(env) @response = Rack::Response.new case result = dispatch(route) when String response.write result response.finish when nil response.finish else result end end |
#dispatch(route) ⇒ Object
Inputs a route like [action, *args] and dispatches it to the action.
271 272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/tap/controller.rb', line 271 def dispatch(route) action, *args = route if action == nil || action == "" action = self.class.default_action end unless action?(action) not_found end send(action, *args) end |
#error(msg, status = 500) ⇒ Object
388 389 390 |
# File 'lib/tap/controller.rb', line 388 def error(msg, status=500) raise ServerError.new(msg, status) end |
#module_render(path, obj, options = {}) ⇒ Object
365 366 367 368 369 370 371 372 |
# File 'lib/tap/controller.rb', line 365 def module_render(path, obj, ={}) [:file] = server.module_path(path, obj.class) locals = [:locals] ||= {} locals[:obj] ||= obj render end |
#not_found ⇒ Object
384 385 386 |
# File 'lib/tap/controller.rb', line 384 def not_found error("404 Error: page not found", 404) end |
#redirect(uri, status = 302, headers = {}, body = "") ⇒ Object
Redirects to the specified uri.
375 376 377 378 379 380 381 382 |
# File 'lib/tap/controller.rb', line 375 def redirect(uri, status=302, headers={}, body="") response.status = status response.headers.merge!(headers) response.body = body response['Location'] = [uri] response.finish end |
#render(path, options = {}) ⇒ Object
Renders the class_file at path with the specified options. Path can be omitted if options specifies an alternate path to render. Options:
template:: renders the template relative to the template directory
file:: renders the specified file
layout:: renders with the specified layout, or default_layout if true
locals:: a hash of local variables used in the template
293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 |
# File 'lib/tap/controller.rb', line 293 def render(path, ={}) , path = path, nil if path.kind_of?(Hash) # lookup template template_path = case when [:file] [:file] when [:template] server.template_path([:template]) else server.module_path(path, self.class) end unless template_path raise "could not find template: (path: #{path.inspect}, file: #{[:file].inspect}, template: #{[:template].inspect})" end # render template template = File.read(template_path) content = render_erb(template, , template_path) # render layout render_layout([:layout], content) end |
#render_erb(template, options = {}, filename = nil) ⇒ Object
Renders the specified template as ERB using the options. Options:
locals:: a hash of local variables used in the template
The filename used to identify errors in an erb template to a specific file and is completely options (but handy).
349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 |
# File 'lib/tap/controller.rb', line 349 def render_erb(template, ={}, filename=nil) # assign locals to the render binding # this almost surely may be optimized... locals = [:locals] binding = render_erb_binding locals.each_pair do |key, value| @assignment_value = value eval("#{key} = remove_instance_variable(:@assignment_value)", binding) end if locals erb = ERB.new(template, nil, "<>") erb.filename = filename erb.result(binding) end |
#render_layout(layout, content) ⇒ Object
Renders the specified layout with content as a local variable. If layout is true, the class default_layout will be rendered. Returns content if no layout is specified.
321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 |
# File 'lib/tap/controller.rb', line 321 def render_layout(layout, content) return content unless layout if layout == true layout = self.class.get(:default_layout) end if layout.kind_of?(Hash) locals = layout[:locals] ||= {} if locals.has_key?(:content) raise "layout already has local content assigned: #{layout.inspect}" end locals[:content] = content else layout = {:template => layout, :locals => {:content => content}} end render(layout) end |
#route ⇒ Object
Returns the action, args, and extname for the request.path_info. Routing is simple and fixed:
route returns
/ [:index, []]
/action/*args [:action, args]
The action and args are unescaped by route. An alternate default action may be specified using set. Override this method in subclasses for fancier routes.
265 266 267 268 |
# File 'lib/tap/controller.rb', line 265 def route blank, *route = request.path_info.split("/").collect {|arg| unescape(arg) } route end |
#uri(action = nil, params = nil, options = nil) ⇒ Object
Returns a uri to the specified action on self. The parameters will be built into a query string, if specified. By default the uri will not specify a protocol or host. Specifying an option hash will add these to the uri.
169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 |
# File 'lib/tap/controller.rb', line 169 def uri(action=nil, params=nil, =nil) if action.kind_of?(Hash) unless params.nil? && .nil? raise "extra arguments specified for uri hash syntax" end = action params = [:params] action = [:action] end uri = [] if request uri << request.env['SCRIPT_NAME'] end if action uri << '/' uri << action end unless params.nil? || params.empty? uri << '?' uri << build_query(params) end if scheme = ([:scheme] || request.scheme) port = ([:port] || request.port) if scheme == "https" && port != 443 || scheme == "http" && port != 80 uri.unshift ":#{port}" end uri.unshift([:host] || request.host) uri.unshift("://") uri.unshift(scheme) end uri.join end |