Class: Merb::Router::Behavior

Inherits:
Object
  • Object
show all
Includes:
Resources
Defined in:
lib/merb-core/dispatch/router/behavior.rb,
lib/merb-core/dispatch/router/resources.rb

Defined Under Namespace

Modules: Resources Classes: Error, Proxy

Instance Method Summary collapse

Methods included from Resources

#resource, #resources

Constructor Details

#initialize(proxy = nil, conditions = {}, params = {}, defaults = {}, identifiers = {}, options = {}, blocks = []) ⇒ Behavior

Behavior objects are used for the Route building DSL. Each object keeps track of the current definitions for the level at which it is defined. Each time a method is called on a Behavior object that accepts a block, a new instance of the Behavior class is created.

Parameters

proxy<Proxy>

This is the object initialized by Merb::Router.prepare that tracks the current Behavior object stack so that Behavior methods can be called without explicitly calling them on an instance of Behavior.

conditions<Hash>

The initial route conditions. See #match.

params<Hash>

The initial route parameters. See #to.

defaults<Hash>

The initial route default parameters. See #defaults.

options<Hash>

The initial route options. See #options.

blocks<Array>

The stack of deferred routing blocks for the route

Returns

Behavior

The initialized Behavior object




108
109
110
111
112
113
114
115
116
117
118
# File 'lib/merb-core/dispatch/router/behavior.rb', line 108

def initialize(proxy = nil, conditions = {}, params = {}, defaults = {}, identifiers = {}, options = {}, blocks = []) #:nodoc:
  @proxy       = proxy
  @conditions  = conditions
  @params      = params
  @defaults    = defaults
  @identifiers = identifiers
  @options     = options
  @blocks      = blocks

  stringify_condition_values
end

Instance Method Details

#capture(&block) ⇒ Object

Capture any new routes that have been added within the block.

This utility method lets you track routes that have been added; it doesn’t affect how/which routes are added.

&block

A context in which routes are generated.



529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
# File 'lib/merb-core/dispatch/router/behavior.rb', line 529

def capture(&block)
  captured_routes = {}
  name_prefix     = [@options[:name_prefix]].flatten.compact.map { |p| "#{p}_"}
  current_names   = Merb::Router.named_routes.keys
  
  behavior = Behavior.new(@proxy, @conditions, @params, @defaults, @identifiers, @options, @blocks)
  with_behavior_context(behavior, &block)
  
  Merb::Router.named_routes.reject { |k,v| current_names.include?(k) }.each do |name, route|
    name = route.name.to_s.sub("#{name_prefix}", '').to_sym unless name_prefix.empty?
    captured_routes[name] = route
  end
  
  captured_routes
end

#default(defaults = {}, &block) ⇒ Object Also known as: defaults

Sets default values for route parameters. If no value for the key can be extracted from the request, then the value provided here will be used.

Parameters

defaults<Hash>

The default values for named segments.

&block

All routes defined in the block will be scoped to the defaults defined by the #default method.

Block parameters

r<Behavior>

optional - The defaults behavior object.




281
282
283
284
# File 'lib/merb-core/dispatch/router/behavior.rb', line 281

def default(defaults = {}, &block)
  behavior = Behavior.new(@proxy, @conditions, @params, @defaults.merge(defaults), @identifiers, @options, @blocks)
  with_behavior_context(behavior, &block)
end

#default_routes(params = {}, &block) ⇒ Object

Creates the most common routes /:controller/:action/:id.format when called with no arguments. You can pass a hash or a block to add parameters or override the default behavior.

Parameters

params<Hash>

This optional hash can be used to augment the default settings

&block

When passing a block a new behavior is yielded and more refinement is possible.

Returns

Route

the default route

Examples

# Passing an extra parameter "mode" to all matches
r.default_routes :mode => "default"

# specifying exceptions within a block
r.default_routes do |nr|
  nr.defer_to do |request, params|
    nr.match(:protocol => "http://").to(:controller => "login",
      :action => "new") if request.env["REQUEST_URI"] =~ /\/private\//
  end
end



428
429
430
# File 'lib/merb-core/dispatch/router/behavior.rb', line 428

def default_routes(params = {}, &block)
  match("/:controller(/:action(/:id))(.:format)").to(params, &block).name(:default)
end

#defer(deferred_block, &block) ⇒ Object

Takes a Proc as a parameter and applies it as a deferred proc for all the routes defined in the block. This is mostly interesting for plugin developers.



458
459
460
461
462
# File 'lib/merb-core/dispatch/router/behavior.rb', line 458

def defer(deferred_block, &block)
  blocks = @blocks + [CachedProc.new(deferred_block)]
  behavior = Behavior.new(@proxy, @conditions, @params, @defaults, @identifiers, @options, blocks)
  with_behavior_context(behavior, &block)
end

#defer_to(params = {}, &block) ⇒ Object

Takes a block and stores it for deferred conditional routes. The block takes the request object and the params hash as parameters.

Parameters

params<Hash>

Parameters and conditions associated with this behavior.

&conditional_block

A block with the conditions to be met for the behavior to take effect.

Returns

Route

The default route.

Examples

defer_to do |request, params|
  params.merge :controller => 'here',
    :action => 'there' if request.xhr?
end



451
452
453
# File 'lib/merb-core/dispatch/router/behavior.rb', line 451

def defer_to(params = {}, &block)
  defer(block).to_route(params)
end

#fixatable(enable = true) ⇒ Object

Parameters

enabled<Boolean>

True enables fixation on the route.



498
499
500
501
# File 'lib/merb-core/dispatch/router/behavior.rb', line 498

def fixatable(enable = true)
  @route.fixation = enable
  self
end

#full_name(name) ⇒ Object

Names this route in Router. Name must be a Symbol. The current name_prefix is ignored.

Parameters

symbol<Symbol>

The name of the route.

Raises

ArgumentError

symbol is not a Symbol.



487
488
489
490
491
492
493
494
# File 'lib/merb-core/dispatch/router/behavior.rb', line 487

def full_name(name)
  if @route
    @route.name = name
    self
  else
    register.full_name(name)
  end
end

#identify(identifiers = {}, &block) ⇒ Object

Sets a method for instances of specified Classes to be called before insertion into a route. This is useful when using models and want a specific method to be called on it (For example, for ActiveRecord::Base it would be #to_param).

The default method called on objects is #to_s.

Paramters

identifiers<Hash>

The keys are Classes and the values are the method that instances of the specified class should have called on.

&block

All routes defined in the block will be call the specified methods during generation.

Block parameters

r<Behavior>

The identify behavior object. This is optional




388
389
390
391
392
393
394
395
396
397
# File 'lib/merb-core/dispatch/router/behavior.rb', line 388

def identify(identifiers = {}, &block)
  identifiers = if Hash === identifiers
    @identifiers.merge(identifiers)
  else
    { Object => identifiers }
  end
  
  behavior = Behavior.new(@proxy, @conditions, @params, @defaults, identifiers.freeze, @options, @blocks)
  with_behavior_context(behavior, &block)
end

#match(path = {}, conditions = {}, &block) ⇒ Object

Defines the conditions that are required to match a Request. Each condition is applied to a method of the Request object. Conditions can also be applied to segments of the path.

If #match is passed a block, it will create a new route scope with the conditions passed to it and yield to the block such that all routes that are defined in the block have the conditions applied to them.

Parameters

path<String, Regexp>

The pattern against which Merb::Request path is matched.

When path is a String, any substring that is wrapped in parenthesis is considered optional and any segment that begins with a colon, ex.: “:login”, defines both a capture and a named param. Extra conditions can then be applied each named param individually.

When path is a Regexp, the pattern is left untouched and the Merb::Request path is matched against it as is.

path is optional.

conditions<Hash>

Additional conditions that the request must meet in order to match. The keys must be the names of previously defined path segments or be methods that the Merb::Request instance will respond to. The value is the string or regexp that matched the returned value. Conditions are inherited by child routes.

&block

All routes defined in the block will be scoped to the conditions defined by the #match method.

Block parameters

r<Behavior>

optional - The match behavior object.

Returns

Behavior

A new instance of Behavior with the specified path and conditions.

Tip: When nesting always make sure the most inner sub-match registers a Route and doesn’t just returns new Behaviors.

Examples

# registers /foo/bar to controller => "foo", :action => "bar"
# and /foo/baz to controller => "foo", :action => "baz"
match("/foo") do
  match("/bar").to(:controller => "foo", :action => "bar")
  match("/baz").to(:controller => "foo", :action => "caz")
end

# Checks the format of the segments against the specified Regexp
match("/:string/:number", :string => /[a-z]+/, :number => /\d+/).
  to(:controller => "string_or_numbers")

# Equivalent to the default_route
match("/:controller(/:action(:id))(.:format)").register

#match only if the browser string contains MSIE or Gecko
match("/foo", :user_agent => /(MSIE|Gecko)/ )
     .to(:controller => 'foo', :action => 'popular')

# Route GET and POST requests to different actions (see also #resources)
r.match('/foo', :method => :get).to(:action => 'show')
r.match('/foo', :method => :post).to(:action => 'create')

# match also takes regular expressions

r.match(%r[/account/([a-z]{4,6})]).to(:controller => "account",
   :action => "show", :id => "[1]")

r.match(%r{/?(en|es|fr|be|nl)?}).to(:language => "[1]") do
  match("/guides/:action/:id").to(:controller => "tour_guides")
end

Raises:



199
200
201
202
203
204
205
206
207
# File 'lib/merb-core/dispatch/router/behavior.rb', line 199

def match(path = {}, conditions = {}, &block)
  path, conditions = path[:path], path if Hash === path
  conditions[:path] = merge_paths(path)

  raise Error, "The route has already been committed. Further conditions cannot be specified" if @route

  behavior = Behavior.new(@proxy, @conditions.merge(conditions), @params, @defaults, @identifiers, @options, @blocks)
  with_behavior_context(behavior, &block)
end

#name(prefix, name = nil) ⇒ Object

Names this route in Router. Name must be a Symbol.

Parameters

symbol<Symbol>

The name of the route.

Raises

ArgumentError

symbol is not a Symbol.



471
472
473
474
475
476
477
# File 'lib/merb-core/dispatch/router/behavior.rb', line 471

def name(prefix, name = nil)
  unless name
    name, prefix = prefix, nil
  end

  full_name([prefix, @options[:name_prefix], name].flatten.compact.join('_'))
end

#namespace(name_or_path, opts = {}, &block) ⇒ Object

Creates a namespace for a route. This way you can have logical separation to your routes.

Parameters

name_or_path<String, Symbol>

The name or path of the namespace.

options<Hash>

Optional hash, set :path if you want to override what appears on the url

&block

All routes defined in the block will be scoped to the namespace defined by the #namespace method.

Block parameters

r<Behavior>

The namespace behavior object. This is optional

Examples

namespace :admin do
  resources :accounts
  resource :email
end

# /super_admin/accounts
namespace(:admin, :path=>"super_admin") do
  resources :accounts
end

Raises:



352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
# File 'lib/merb-core/dispatch/router/behavior.rb', line 352

def namespace(name_or_path, opts = {}, &block)
  name = name_or_path.to_s # We don't want this modified ever
  path = opts.has_key?(:path) ? opts[:path] : name

  raise Error, "The route has already been committed. Further options cannot be specified" if @route

  # option keys could be nil
  opts[:controller_prefix] = name unless opts.has_key?(:controller_prefix)
  opts[:name_prefix]       = name unless opts.has_key?(:name_prefix)
  opts[:resource_prefix]   = opts[:name_prefix] unless opts.has_key?(:resource_prefix)

  behavior = self
  behavior = behavior.match("/#{path}") unless path.nil? || path.empty?
  behavior.options(opts, &block)
end

#redirect(url, opts = {}) ⇒ Object

Sets the current route as a redirect.

Parameters

path<String

The path to redirect to

options<Hash>

Options for the redirect The supported options are:

  • :permanent: Whether or not the redirect should be permanent.

    The default value is false.
    

Raises:



514
515
516
517
518
519
520
521
# File 'lib/merb-core/dispatch/router/behavior.rb', line 514

def redirect(url, opts = {})
  raise Error, "The route has already been committed." if @route

  status = opts[:permanent] ? 301 : 302
  @route = Route.new(@conditions, {:url => url.freeze, :status => status.freeze}, @blocks, :redirects => true)
  @route.register
  self
end

#to(params = {}, &block) ⇒ Object Also known as: with, register

Creates a Route from one or more Behavior objects, unless a block is passed in.

Parameters

params<Hash>

The parameters the route maps to.

&block

All routes defined in the block will be scoped to the params defined by the #to method.

Block parameters

r<Behavior>

optional - The to behavior object.

Returns

Route

It registers a new route and returns it.

Examples

match('/:controller/:id).to(:action => 'show')

to(:controller => 'simple') do
  match('/test').to(:action => 'index')
  match('/other').to(:action => 'other')
end

Raises:



234
235
236
237
238
239
240
241
242
243
244
# File 'lib/merb-core/dispatch/router/behavior.rb', line 234

def to(params = {}, &block)
  raise Error, "The route has already been committed. Further params cannot be specified" if @route

  behavior = Behavior.new(@proxy, @conditions, @params.merge(params), @defaults, @identifiers, @options, @blocks)
  
  if block_given?
    with_behavior_context(behavior, &block)
  else
    behavior.to_route
  end
end

#with_proxy(&block) ⇒ Object

So that Router can have a default route




548
549
550
551
552
553
# File 'lib/merb-core/dispatch/router/behavior.rb', line 548

def with_proxy(&block) #:nodoc:
  proxy = Proxy.new
  proxy.push Behavior.new(proxy, @conditions, @params, @defaults, @identifiers, @options, @blocks)
  proxy.instance_eval(&block)
  proxy
end