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/http/url.rb | 4 +- 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 ++ 4 files changed, 67 insertions(+), 13 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/http/url.rb b/actionpack/lib/action_dispatch/http/url.rb index 80ffbe575b..f9dae5dad7 100644 --- a/actionpack/lib/action_dispatch/http/url.rb +++ b/actionpack/lib/action_dispatch/http/url.rb @@ -40,7 +40,9 @@ module ActionDispatch rewritten_url << ":#{options.delete(:port)}" if options[:port] end - path = options.delete(:path) || '' + path = "" + path << options.delete(:script_name).to_s.chomp("/") + path << options.delete(:path).to_s params = options[:params] || {} params.reject! {|k,v| v.to_param.nil? } 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 From cd5dabab95924dfaf3af8c429454f1a46d9665c1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sergey=20Nartimov=20+=20Jos=C3=A9=20Valim?= Date: Fri, 2 Mar 2012 15:01:20 +0100 Subject: Optimize url helpers. --- actionpack/lib/action_dispatch/routing/route_set.rb | 17 ++++++++--------- actionpack/lib/action_dispatch/routing/url_for.rb | 7 +++++-- 2 files changed, 13 insertions(+), 11 deletions(-) (limited to 'actionpack/lib/action_dispatch') diff --git a/actionpack/lib/action_dispatch/routing/route_set.rb b/actionpack/lib/action_dispatch/routing/route_set.rb index 0e5bf46ee4..c4d87ea3d9 100644 --- a/actionpack/lib/action_dispatch/routing/route_set.rb +++ b/actionpack/lib/action_dispatch/routing/route_set.rb @@ -195,7 +195,7 @@ module ActionDispatch @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? + if args.size == #{route.required_parts.size} && !args.last.is_a?(Hash) && optimize_routes_generation? options = #{options.inspect}.merge!(url_options) options[:path] = "#{optimized_helper(route)}" ActionDispatch::Http::URL.url_for(options) @@ -216,14 +216,9 @@ module ActionDispatch 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. + # Clause check about when we need to generate an optimized helper. def optimize_helper?(kind, route) #:nodoc: - kind == :path && route.ast.grep(Journey::Nodes::Star).empty? + route.ast.grep(Journey::Nodes::Star).empty? && route.requirements.except(:controller, :action).empty? end # Generates the interpolation to be used in the optimized helper. @@ -364,7 +359,7 @@ module ActionDispatch # Rails.application.routes.url_helpers.url_for(args) @_routes = routes class << self - delegate :url_for, :to => '@_routes' + delegate :url_for, :optimize_routes_generation?, :to => '@_routes' end # Make named_routes available in the module singleton @@ -602,6 +597,10 @@ module ActionDispatch false end + def optimize_routes_generation? + !mounted? && default_url_options.empty? + end + def _generate_prefix(options = {}) nil end diff --git a/actionpack/lib/action_dispatch/routing/url_for.rb b/actionpack/lib/action_dispatch/routing/url_for.rb index 191a2cb995..94db36ce1f 100644 --- a/actionpack/lib/action_dispatch/routing/url_for.rb +++ b/actionpack/lib/action_dispatch/routing/url_for.rb @@ -102,6 +102,9 @@ module ActionDispatch super end + # Hook overriden in controller to add request information + # with `default_url_options`. Application logic should not + # go into url_options. def url_options default_url_options end @@ -152,9 +155,9 @@ module ActionDispatch protected - def _optimized_routes? + def optimize_routes_generation? return @_optimized_routes if defined?(@_optimized_routes) - @_optimized_routes = default_url_options.empty? && !_routes.mounted? && _routes.default_url_options.empty? + @_optimized_routes = _routes.optimize_routes_generation? && default_url_options.empty? end def _with_routes(routes) -- cgit v1.2.3