tracks/vendor/rails/actionpack/lib/action_controller/routing/optimisations.rb
Luke Melia 901a58f8a3 Upgraded to Rails 2.1. This can have wide ranging consequences, so please help track down any issues introduced by the upgrade. Requires environment.rb modifications.
Changes you will need to make:

 * In your environment.rb, you will need to update references to a few files per environment.rb.tmpl
 * In your environment.rb, you will need to specify the local time zone of the computer that is running your Tracks install.

Other notes on my changes:

 * Modified our code to take advantage of Rails 2.1's slick time zone support.
 * Upgraded will_paginate for compatibility
 * Hacked the Selenium on Rails plugin, which has not been updated in some time and does not support Rails 2.1
 * Verified that all tests pass on my machine, including Selenium tests -- I'd like confirmation from others, too.
2008-06-17 01:13:25 -04:00

120 lines
4.3 KiB
Ruby

module ActionController
module Routing
# Much of the slow performance from routes comes from the
# complexity of expiry, <tt>:requirements</tt> matching, defaults providing
# and figuring out which url pattern to use. With named routes
# we can avoid the expense of finding the right route. So if
# they've provided the right number of arguments, and have no
# <tt>:requirements</tt>, we can just build up a string and return it.
#
# To support building optimisations for other common cases, the
# generation code is separated into several classes
module Optimisation
def generate_optimisation_block(route, kind)
return "" unless route.optimise?
OPTIMISERS.inject("") do |memo, klazz|
memo << klazz.new(route, kind).source_code
memo
end
end
class Optimiser
attr_reader :route, :kind
def initialize(route, kind)
@route = route
@kind = kind
end
def guard_condition
'false'
end
def generation_code
'nil'
end
def source_code
if applicable?
"return #{generation_code} if #{guard_condition}\n"
else
"\n"
end
end
# Temporarily disabled <tt>:url</tt> optimisation pending proper solution to
# Issues around request.host etc.
def applicable?
true
end
end
# Given a route
#
# map.person '/people/:id'
#
# If the user calls <tt>person_url(@person)</tt>, we can simply
# return a string like "/people/#{@person.to_param}"
# rather than triggering the expensive logic in +url_for+.
class PositionalArguments < Optimiser
def guard_condition
number_of_arguments = route.segment_keys.size
# if they're using foo_url(:id=>2) it's one
# argument, but we don't want to generate /foos/id2
if number_of_arguments == 1
"(!defined?(default_url_options) || default_url_options.blank?) && defined?(request) && request && args.size == 1 && !args.first.is_a?(Hash)"
else
"(!defined?(default_url_options) || default_url_options.blank?) && defined?(request) && request && args.size == #{number_of_arguments}"
end
end
def generation_code
elements = []
idx = 0
if kind == :url
elements << '#{request.protocol}'
elements << '#{request.host_with_port}'
end
elements << '#{request.relative_url_root if request.relative_url_root}'
# The last entry in <tt>route.segments</tt> appears to *always* be a
# 'divider segment' for '/' but we have assertions to ensure that
# we don't include the trailing slashes, so skip them.
(route.segments.size == 1 ? route.segments : route.segments[0..-2]).each do |segment|
if segment.is_a?(DynamicSegment)
elements << segment.interpolation_chunk("args[#{idx}].to_param")
idx += 1
else
elements << segment.interpolation_chunk
end
end
%("#{elements * ''}")
end
end
# This case is mostly the same as the positional arguments case
# above, but it supports additional query parameters as the last
# argument
class PositionalArgumentsWithAdditionalParams < PositionalArguments
def guard_condition
"(!defined?(default_url_options) || default_url_options.blank?) && defined?(request) && request && args.size == #{route.segment_keys.size + 1} && !args.last.has_key?(:anchor) && !args.last.has_key?(:port) && !args.last.has_key?(:host)"
end
# This case uses almost the same code as positional arguments,
# but add an args.last.to_query on the end
def generation_code
super.insert(-2, '?#{args.last.to_query}')
end
# To avoid generating "http://localhost/?host=foo.example.com" we
# can't use this optimisation on routes without any segments
def applicable?
super && route.segment_keys.size > 0
end
end
OPTIMISERS = [PositionalArguments, PositionalArgumentsWithAdditionalParams]
end
end
end