Module: Waves::Mapping
- Defined in:
- lib/mapping/mapping.rb,
lib/mapping/pretty_urls.rb
Overview
Mappings in Waves are the interface between the request dispatcher and your application code. The dispatcher matches each request against the mappings to determine a primary action and to collect sets of before, after, wrap, and always actions. The dispatcher also looks for an exception handler registered in the mappings when attempting a rescue.
Each mapping associates a block with a set of constraints. Mappings can be one of several types:
-
action (the actual request processing and response)
-
handle (exception handling)
-
before
-
after
-
wrap (registers its block as both a before and after action)
-
always (like an “ensure” clause in a rescue)
Actions are registered using path, url, or map. The other types may be registered using methods named after the type.
The available constraints are:
-
a string or regexp that the path or url must match
-
parameters to match against the HTTP request headers and the Rack-specific variables (e.g. ‘rack.url_scheme’)
-
an additional hash reserved for settings not related to the Rack request (e.g. giving Rack handers special instructions for certain requests. See threaded? )
The dispatcher evaluates mapping blocks in an instance of ResponseProxy, which provides access to foundational classes of a Waves application (i.e. controllers and views)
Examples
resource = '([\w\-]+)'
name = '([\w\-\_\.\+\@]+)'
path %r{^/#{resource}/#{name}/?$} do |resource, name|
"Hello from a #{resource} named #{name.capitalize}."
end
In this example, we are using binding regular expressions defined by resource
and name
. The matches are passed into the block as parameters. Thus, this rule, given the URL ‘/person/john’ will return:
Hello from a person named John.
The given block may simple return a string. The content type is inferred from the request if possible, otherwise it defaults to text
/html
.
path '/critters', :method => :post do
request.content_type
end
/critters # => 'text/html'
In this example, we match against a string and check to make sure that the request is a POST. If so, we return the request content_type. The request (and response) objects are available from within the block implicitly.
Invoking Controllers and Views
You may invoke a controller or view method for the primary application by using the corresponding methods, preceded by the use
directive.
Examples
path %r{^/#{resource}/#{name}/?$} do |resource, name|
resource( resource ) do
controller { find( name ) } | view { | instance | show( resource => instance ) }
end
end
In this example, we take the same rule from above but invoke a controller and view method. We use the resource
directive and the resource parameter to set the MVC instances we’re going to use. This is necessary to use the controller
or view
methods. Each of these take a block as arguments which are evaluated in the context of the instance. The view
method can further take an argument which is “piped” from the result of the controller block. This isn’t required, but helps to clarify the request processing. Within a view block, a hash may also be passed in to the view method, which is converted into instance variables for the view instance. In this example, the show
method is assigned to an instance variable with the same name as the resource type.
So given the same URL as above - /person/john - what will happen is the find
method for the Person
controller will be invoked and the result passed to the Person
view’s show
method, with @person holding the value returned.
Crucially, the controller does not need to know what variables the view depends on. This is the job of the mapping block, to act as the “glue” between the controller and view. The controller and view can thus be completely decoupled and become easier to reuse separately.
url 'http://admin.foobar.com:/' do
resource( :admin ) { view { console } }
end
In this example, we are using the url
method to map a subdomain of foobar.com
to the console method of the Admin view. In this case, we did not need a controller method, so we simply didn’t call one.
Mapping Modules
You may encapsulate sets of related rules into modules and simply include them into your mapping module. Some rule sets come packaged with Waves, such as PrettyUrls (rules for matching resources using names instead of ids). The simplest way to define such modules for reuse is by defining the included
class method for the rules module, and then define the rules using module_eval
. See the PrettyUrls module for an example of how to do this.
Important: Using pre-packaged mapping rules does not prevent you from adding to or overriding these rules. However, order does matter, so you should put your own rules ahead of those your may be importing. Also, place rules with constraints (for example, rules that require a POST) ahead of those with no constraints, otherwise the constrainted rules may never be called.
Defined Under Namespace
Modules: PrettyUrls
Instance Method Summary collapse
-
#[](request) ⇒ Object
Match the given request against the defined rules.
-
#after(path, options = {}, &block) ⇒ Object
Similar to before, except it runs its actions after any matching
url
orpath
actions. -
#always(path, options = {}, &block) ⇒ Object
Like after, but will run even when an exception is thrown.
-
#before(path, options = {}, &block) ⇒ Object
If the pattern matches and constraints given by the options hash are satisfied, run the block before running any
path
orurl
actions. -
#clear ⇒ Object
Clear all mapping rules.
-
#handle(exception, options = {}, &block) ⇒ Object
Maps an exception handler to a block.
-
#map(path, options = {}, params = {}, &block) ⇒ Object
Maps a request to a block.
-
#path(pat, options = {}, params = {}, &block) ⇒ Object
Match pattern against the
request.path
, along with satisfying any constraints specified by the options hash. -
#root(options = {}, params = {}, &block) ⇒ Object
Maps the root of the application to a block.
-
#threaded(pat, options = {}, params = {}, &block) ⇒ Object
Maps a request to a block that will be executed within it’s own thread.
-
#threaded?(request) ⇒ Boolean
Determines whether the request should be handled in a separate thread.
-
#url(pat, options = {}, params = {}, &block) ⇒ Object
Match pattern against the
request.url
, along with satisfying any constraints specified by the options hash. -
#wrap(path, options = {}, &block) ⇒ Object
Run the action before and after the matching
url
orpath
action.
Instance Method Details
#[](request) ⇒ Object
Match the given request against the defined rules. This is typically only called by a dispatcher object, so you shouldn’t typically use it directly.
226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 |
# File 'lib/mapping/mapping.rb', line 226 def []( request ) rx = { :before => [], :after => [], :always => [], :action => nil, :handlers => [] } ( filters[:before] + filters[:wrap] ).each do | , function | matches = match( request, , function ) rx[:before] << matches if matches end mapping.find do | , params, function | rx[:action] = match( request, , function ) break if rx[:action] end ( filters[:after] + filters[:wrap] ).each do | , function | matches = match( request, , function ) rx[:after] << matches if matches end filters[:always].each do | , function | matches = match( request, , function ) rx[:always] << matches if matches end handlers.each do | exception, , function | matches = match( request, , function ) rx[:handlers] << matches.unshift(exception) if matches end return rx end |
#after(path, options = {}, &block) ⇒ Object
Similar to before, except it runs its actions after any matching url
or path
actions. Note that after methods will run even if an exception is thrown during processing.
130 131 132 133 134 135 136 137 |
# File 'lib/mapping/mapping.rb', line 130 def after( path, = {}, &block ) if path.is_a? Hash = path else [:path] = path end filters[:after] << [ , block ] end |
#always(path, options = {}, &block) ⇒ Object
Like after, but will run even when an exception is thrown. Exceptions in always mappings are simply logged and ignored.
152 153 154 155 156 157 158 159 |
# File 'lib/mapping/mapping.rb', line 152 def always( path, = {}, &block ) if path.is_a? Hash = path else [:path] = path end filters[:always] << [ , block ] end |
#before(path, options = {}, &block) ⇒ Object
If the pattern matches and constraints given by the options hash are satisfied, run the block before running any path
or url
actions. You can have as many before
matches as you want - they will all run, unless one of them calls redirect, generates an unhandled exception, etc.
119 120 121 122 123 124 125 126 |
# File 'lib/mapping/mapping.rb', line 119 def before( path, = {}, &block ) if path.is_a? Hash = path else [:path] = path end filters[:before] << [ , block ] end |
#clear ⇒ Object
Clear all mapping rules
259 260 261 |
# File 'lib/mapping/mapping.rb', line 259 def clear @mapping = @filters = @handlers = nil; end |
#handle(exception, options = {}, &block) ⇒ Object
Maps an exception handler to a block.
194 195 196 |
# File 'lib/mapping/mapping.rb', line 194 def handle(exception, = {}, &block ) handlers << [exception,, block] end |
#map(path, options = {}, params = {}, &block) ⇒ Object
Maps a request to a block. Don’t use this method directly unless you know what you’re doing. Use path
or url
instead.
163 164 165 166 167 168 169 170 171 |
# File 'lib/mapping/mapping.rb', line 163 def map( path, = {}, params = {}, &block ) case path when Hash params = ; = path when String [:path] = path end mapping << [ , params, block ] end |
#path(pat, options = {}, params = {}, &block) ⇒ Object
Match pattern against the request.path
, along with satisfying any constraints specified by the options hash. If the pattern matches and the constraints are satisfied, run the block. Only one path
or url
match will be run (the first one).
176 177 178 |
# File 'lib/mapping/mapping.rb', line 176 def path( pat, = {}, params = {}, &block ) [:path] = pat; map( , params, &block ) end |
#root(options = {}, params = {}, &block) ⇒ Object
Maps the root of the application to a block. If an options hash is specified it must satisfy those constraints in order to run the block.
189 190 191 |
# File 'lib/mapping/mapping.rb', line 189 def root( = {}, params = {}, &block ) path( %r{^/?$}, , params, &block ) end |
#threaded(pat, options = {}, params = {}, &block) ⇒ Object
Maps a request to a block that will be executed within it’s own thread. This is especially useful when you’re running with an event driven server like thin or ebb, and this block is going to take a relatively long time.
202 203 204 205 |
# File 'lib/mapping/mapping.rb', line 202 def threaded( pat, = {}, params = {}, &block) params[:threaded] = true map( pat, , params, &block) end |
#threaded?(request) ⇒ Boolean
Determines whether the request should be handled in a separate thread. This is used by event driven servers like thin and ebb, and is most useful for those methods that take a long time to complete, like for example upload processes. E.g.:
threaded("/upload", :method => :post) do
handle_upload
end
You typically wouldn’t use this method directly.
216 217 218 219 220 221 222 |
# File 'lib/mapping/mapping.rb', line 216 def threaded?( request ) mapping.find do | , params, function | match = match( request, , function ) return params[:threaded] == true if match end return false end |
#url(pat, options = {}, params = {}, &block) ⇒ Object
Match pattern against the request.url
, along with satisfying any constraints specified by the options hash. If the pattern matches and the constraints are satisfied, run the block. Only one path
or url
match will be run (the first one).
183 184 185 |
# File 'lib/mapping/mapping.rb', line 183 def url( pat, = {}, params = {}, &block ) [:url] = pat; map( , params, &block ) end |
#wrap(path, options = {}, &block) ⇒ Object
Run the action before and after the matching url
or path
action.
140 141 142 143 144 145 146 147 148 |
# File 'lib/mapping/mapping.rb', line 140 def wrap( path, = {}, &block ) if path.is_a? Hash = path else [:path] = path end filters[:before] << [ , block ] filters[:after] << [ , block ] end |