From d7014bc7eaa62c36f045a503cdad64e4ebbc2687 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 2 Mar 2012 01:32:08 +0100 Subject: Optimize path helpers. --- actionpack/lib/action_dispatch/routing/mapper.rb | 6 +- .../lib/action_dispatch/routing/route_set.rb | 65 ++++++++++++++++++---- actionpack/lib/action_dispatch/routing/url_for.rb | 5 ++ 3 files changed, 64 insertions(+), 12 deletions(-) (limited to 'actionpack/lib/action_dispatch/routing') diff --git a/actionpack/lib/action_dispatch/routing/mapper.rb b/actionpack/lib/action_dispatch/routing/mapper.rb index 02a27110e4..80fcdab643 100644 --- a/actionpack/lib/action_dispatch/routing/mapper.rb +++ b/actionpack/lib/action_dispatch/routing/mapper.rb @@ -446,7 +446,11 @@ module ActionDispatch _route = @set.named_routes.routes[name.to_sym] _routes = @set app.routes.define_mounted_helper(name) - app.routes.class_eval do + app.routes.singleton_class.class_eval do + define_method :mounted? do + true + end + define_method :_generate_prefix do |options| prefix_options = options.slice(*_route.segment_keys) # we must actually delete prefix segment keys to avoid passing them to next url_for diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 0ec4e41470..0e5bf46ee4 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -191,14 +191,55 @@ module ActionDispatch selector = url_helper_name(name, kind) hash_access_method = hash_access_name(name, kind) - @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1 - remove_possible_method :#{selector} - def #{selector}(*args) - url_for(#{hash_access_method}(*args)) - end - END_EVAL + if optimize_helper?(kind, route) + @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1 + remove_possible_method :#{selector} + def #{selector}(*args) + if args.size == #{route.required_parts.size} && !args.last.is_a?(Hash) && _optimized_routes? + options = #{options.inspect}.merge!(url_options) + options[:path] = "#{optimized_helper(route)}" + ActionDispatch::Http::URL.url_for(options) + else + url_for(#{hash_access_method}(*args)) + end + end + END_EVAL + else + @module.module_eval <<-END_EVAL, __FILE__, __LINE__ + 1 + remove_possible_method :#{selector} + def #{selector}(*args) + url_for(#{hash_access_method}(*args)) + end + END_EVAL + end + helpers << selector end + + # If we are generating a path helper and we don't have a *path segment. + # We can optimize the routes generation to a string interpolation if + # it meets the appropriated runtime conditions. + # + # TODO We are enabling this only for path helpers, remove the + # kind == :path and fix the failures to enable it for url as well. + def optimize_helper?(kind, route) #:nodoc: + kind == :path && route.ast.grep(Journey::Nodes::Star).empty? + end + + # Generates the interpolation to be used in the optimized helper. + def optimized_helper(route) + string_route = route.ast.to_s + + while string_route.gsub!(/\([^\)]*\)/, "") + true + end + + route.required_parts.each_with_index do |part, i| + string_route.gsub!(part.inspect, "\#{Journey::Router::Utils.escape_fragment(args[#{i}].to_param)}") + end + + string_route + end end attr_accessor :formatter, :set, :named_routes, :default_scope, :router @@ -557,6 +598,10 @@ module ActionDispatch RESERVED_OPTIONS = [:host, :protocol, :port, :subdomain, :domain, :tld_length, :trailing_slash, :anchor, :params, :only_path, :script_name] + def mounted? + false + end + def _generate_prefix(options = {}) nil end @@ -568,19 +613,17 @@ module ActionDispatch user, password = extract_authentication(options) path_segments = options.delete(:_path_segments) - script_name = options.delete(:script_name) - - path = (script_name.blank? ? _generate_prefix(options) : script_name.chomp('/')).to_s + script_name = options.delete(:script_name).presence || _generate_prefix(options) path_options = options.except(*RESERVED_OPTIONS) path_options = yield(path_options) if block_given? - path_addition, params = generate(path_options, path_segments || {}) - path << path_addition + path, params = generate(path_options, path_segments || {}) params.merge!(options[:params] || {}) ActionDispatch::Http::URL.url_for(options.merge!({ :path => path, + :script_name => script_name, :params => params, :user => user, :password => password diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index ee6616c5d3..191a2cb995 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -152,6 +152,11 @@ module ActionDispatch protected + def _optimized_routes? + return @_optimized_routes if defined?(@_optimized_routes) + @_optimized_routes = default_url_options.empty? && !_routes.mounted? && _routes.default_url_options.empty? + end + def _with_routes(routes) old_routes, @_routes = @_routes, routes yield -- cgit v1.2.3