Ruby on Rails | Screencasts | Download | Documentation | Weblog | Community | Source

Ticket #8469: inferencing_url_helpers.diff

File inferencing_url_helpers.diff, 12.9 kB (added by protocool, 2 years ago)

Code and tests - no documentation

  • actionpack/test/controller/inferencing_helpers_test.rb

    old new  
     1require File.dirname(__FILE__) + '/../abstract_unit' 
     2require File.join(File.dirname(__FILE__), 'inferencing_helpers_controller') 
     3 
     4class InferencingHelpersBaseTest < Test::Unit::TestCase 
     5  include ActionView::Helpers::UrlHelper 
     6 
     7  def setup 
     8    @request    = ActionController::TestRequest.new 
     9    @response   = ActionController::TestResponse.new 
     10    @controller = InferencingHelpersController.new 
     11  end 
     12 
     13  def test_truth; assert true; end 
     14 
     15  protected 
     16  def with_nested_resource_expectation 
     17    with_routing do |set| 
     18      set.draw do |map| 
     19        # NOTE - we set the name_prefix to nil so that the 
     20        # controller's show_xxx methods are a little less noisy 
     21        map.resources :widgets do |widget| 
     22          widget.resources :flanges, :name_prefix => nil do |flange| 
     23            flange.resources :grommets, :name_prefix => nil 
     24          end 
     25        end 
     26        # Make sure our get() calls can route properly 
     27        map.inferencing_helpers 'inferencing_helpers/:action', :controller => 'inferencing_helpers' 
     28      end 
     29      yield 
     30      assert_equal expected_result, @response.body unless expected_result.nil? 
     31    end 
     32  end 
     33end 
     34 
     35class InferencingHelpersFlangeTest < InferencingHelpersBaseTest 
     36  def test_specified_positional_path 
     37    with_nested_resource_expectation { get :show_specified_positional_path } 
     38  end 
     39 
     40  def test_segments_specified_only_in_options 
     41    with_nested_resource_expectation { get :show_segments_specified_only_in_options } 
     42  end 
     43 
     44  def test_inferred_positional_path 
     45    with_nested_resource_expectation { get :show_inferred_positional_path } 
     46  end 
     47 
     48  def test_instance_id_inference 
     49    with_nested_resource_expectation { get :show_instance_id_inference } 
     50  end 
     51 
     52  def test_inference_precedence 
     53    with_nested_resource_expectation { get :show_inference_precedence } 
     54  end 
     55 
     56  protected  
     57  def expected_result 
     58    '/widgets/a_widget/flanges/a_flange' 
     59  end 
     60end 
     61 
     62class InferencingHelpersGrommetTest < InferencingHelpersBaseTest 
     63  def test_deep_inferred_positional_path 
     64    with_nested_resource_expectation { get :show_deep_inferred_positional_path } 
     65  end 
     66 
     67  def test_positionals_always_overrides_instance_variables 
     68    with_nested_resource_expectation { get :show_positionals_always_overrides_instance_variables } 
     69  end 
     70 
     71  def test_options_always_overrides_instance_variables 
     72    with_nested_resource_expectation { get :show_options_always_overrides_instance_variables } 
     73  end 
     74 
     75  def test_positionals_always_overrides_options 
     76    with_nested_resource_expectation { get :show_positionals_always_overrides_options } 
     77  end 
     78 
     79  protected 
     80  def expected_result 
     81    '/widgets/a_widget/flanges/a_flange/grommets/a_grommet' 
     82  end 
     83end 
     84 
     85class InferencingHelpersAdditionalParamsTest < InferencingHelpersBaseTest 
     86  def test_additional_params_with_positionals 
     87    with_nested_resource_expectation { get :show_additional_params_with_positionals } 
     88  end 
     89 
     90  def test_additional_params_with_segments_only_in_options 
     91    with_nested_resource_expectation { get :show_additional_params_with_just_options } 
     92  end 
     93 
     94  def test_additional_params_with_mixed_segments 
     95    with_nested_resource_expectation { get :show_additional_params_with_mixed_args } 
     96  end 
     97 
     98  def test_additional_params_with_segments_inferred 
     99    with_nested_resource_expectation { get :show_additional_params_with_segments_inferred } 
     100  end 
     101 
     102  protected 
     103  def expected_result 
     104    '/widgets/a_widget/flanges/a_flange/grommets?another=param' 
     105  end 
     106end 
     107 
     108class InferencingHelpersExtraTest < InferencingHelpersBaseTest 
     109  def test_collection_helpers_need_no_arguments 
     110    with_nested_resource_expectation do 
     111      get :show_collection_helpers_need_no_arguments 
     112      assert_equal '/widgets/a_widget/flanges/a_flange/grommets', @response.body 
     113    end 
     114  end 
     115 
     116  def test_explosion_because_id_segment_is_never_inferred 
     117    with_nested_resource_expectation do 
     118      assert_raises ActionController::RoutingError do 
     119        get :show_explosion_because_id_segment_is_never_inferred 
     120      end 
     121    end 
     122  end 
     123 
     124  def test_explosion_because_no_inference_strategy_available 
     125    with_nested_resource_expectation do 
     126      assert_raises ActionController::RoutingError do 
     127        get :show_explosion_because_no_inference_strategy_available 
     128      end 
     129    end 
     130  end 
     131 
     132  def test_explosion_because_too_many_positionals 
     133    with_nested_resource_expectation do 
     134      assert_raises ArgumentError do 
     135        get :show_explosion_because_too_many_positionals 
     136      end 
     137    end 
     138  end 
     139 
     140  protected 
     141  def expected_result 
     142    nil # no automatic assertion please 
     143  end 
     144end 
  • actionpack/test/controller/inferencing_helpers_controller.rb

    old new  
     1class InferencingHelpersController < ActionController::Base 
     2  self.view_paths = [ "#{File.dirname(__FILE__)}/../fixtures/" ] 
     3 
     4  def self.controller_path; 'inferencing_helpers' end 
     5  def rescue_action(e) raise e end 
     6 
     7  # Test routes are set up as follows: 
     8  # map.resources :widgets do |widget| 
     9  #   widget.resources :flanges, :name_prefix => nil do |flange| 
     10  #     flange.resources :grommets, :name_prefix => nil 
     11  #   end 
     12  # end 
     13 
     14  def show_specified_positional_path 
     15    # test expects '/widgets/a_widget/flanges/a_flange' 
     16    render :inline => "<%= flange_path('a_widget', 'a_flange') %>" 
     17  end 
     18 
     19  def show_segments_specified_only_in_options 
     20    # test expects '/widgets/a_widget/flanges/a_flange' 
     21    render :inline => "<%= flange_path(:widget_id => 'a_widget', :id => 'a_flange') %>" 
     22  end 
     23 
     24  def show_inferred_positional_path 
     25    # test expects '/widgets/a_widget/flanges/a_flange' 
     26    @widget = 'a_widget' 
     27    render :inline => "<%= flange_path('a_flange') %>" 
     28  end 
     29 
     30  def show_instance_id_inference 
     31    # test expects '/widgets/a_widget/flanges/a_flange' 
     32    @widget_id = 'a_widget' 
     33    render :inline => "<%= flange_path('a_flange') %>" 
     34  end 
     35 
     36  def show_inference_precedence 
     37    # test expects '/widgets/a_widget/flanges/a_flange' 
     38    @widget_id = 'bogus_widget' 
     39    @widget = 'a_widget' 
     40    render :inline => "<%= flange_path('a_flange') %>" 
     41  end 
     42 
     43  def show_deep_inferred_positional_path 
     44    # test expects '/widgets/a_widget/flanges/a_flange/grommets/a_grommet' 
     45    @widget = 'a_widget' 
     46    render :inline => "<%= grommet_path('a_flange','a_grommet') %>" 
     47  end 
     48 
     49  def show_positionals_always_overrides_instance_variables 
     50    # test expects '/widgets/a_widget/flanges/a_flange/grommets/a_grommet' 
     51    @widget = 'bogus_widget' 
     52    @flange = 'bogus_flange' 
     53    render :inline => "<%= grommet_path('a_widget', 'a_flange', 'a_grommet') %>" 
     54  end 
     55 
     56  def show_options_always_overrides_instance_variables 
     57    # test expects '/widgets/a_widget/flanges/a_flange/grommets/a_grommet' 
     58    @widget = 'bogus_widget' 
     59    @flange = 'bogus_flange' 
     60    render :inline => "<%= grommet_path('a_grommet', :widget_id => 'a_widget', :flange_id => 'a_flange') %>" 
     61  end 
     62 
     63  def show_positionals_always_overrides_options 
     64    # test expects '/widgets/a_widget/flanges/a_flange/grommets/a_grommet' 
     65    render :inline => "<%= grommet_path('a_widget', 'a_flange', 'a_grommet', :widget_id => 'bogus_widget', :flange_id => 'bogus_flange') %>" 
     66  end 
     67 
     68  def show_additional_params_with_positionals 
     69    # test expects '/widgets/a_widget/flanges/a_flange/grommets?another=param' 
     70    render :inline => "<%= grommets_path('a_widget', 'a_flange', :another => 'param') %>" 
     71  end 
     72 
     73  def show_additional_params_with_just_options 
     74    # test expects '/widgets/a_widget/flanges/a_flange/grommets?another=param' 
     75    render :inline => "<%= grommets_path(:widget_id => 'a_widget', :flange_id => 'a_flange', :another => 'param') %>" 
     76  end 
     77 
     78  def show_additional_params_with_mixed_args 
     79    # test expects '/widgets/a_widget/flanges/a_flange/grommets?another=param' 
     80    render :inline => "<%= grommets_path('a_flange', :widget_id => 'a_widget', :another => 'param') %>" 
     81  end 
     82 
     83  def show_additional_params_with_segments_inferred 
     84    # test expects '/widgets/a_widget/flanges/a_flange/grommets?another=param' 
     85    @widget = 'a_widget' 
     86    @flange = 'a_flange' 
     87    render :inline => "<%= grommets_path(:another => 'param') %>" 
     88  end 
     89 
     90  def show_collection_helpers_need_no_arguments 
     91    # test expects '/widgets/a_widget/flanges/a_flange/grommets' 
     92    @widget = 'a_widget' 
     93    @flange = 'a_flange' 
     94    render :inline => "<%= grommets_path() %>" 
     95  end 
     96 
     97  def show_explosion_because_id_segment_is_never_inferred 
     98    # test expects ActionController::RoutingError 
     99    @widget = 'a_widget' 
     100    @flange = 'a_flange' 
     101    @grommet = @id = @grommet_id = 'a_grommet' 
     102    render :inline => "<%= grommet_path() %>" 
     103  end 
     104 
     105  def show_explosion_because_no_inference_strategy_available 
     106    # test expects ActionController::RoutingError 
     107    # @widget is required by the route but is missing here 
     108    @flange = 'a_flange' 
     109    render :inline => "<%= grommet_path('a_grommet') %>" 
     110  end 
     111 
     112  def show_explosion_because_too_many_positionals 
     113    # test expects ArgumentError 
     114    render :inline => "<%= grommet_path('a_widget', 'a_flange', 'a_grommet', 'extra_positional') %>" 
     115  end 
     116end 
  • actionpack/lib/action_controller/routing.rb

    old new  
    11291129           
    11301130          def define_url_helper(route, name, kind, options) 
    11311131            selector = url_helper_name(name, kind) 
    1132              
     1132            hash_access_method = hash_access_name(name, kind) 
     1133 
    11331134            # The segment keys used for positional paramters 
    11341135            segment_keys = route.segments.collect do |segment| 
    11351136              segment.key if segment.respond_to? :key 
    11361137            end.compact 
    1137             hash_access_method = hash_access_name(name, kind) 
    1138              
     1138 
     1139            # Build the inference cases for each positional parameter 
     1140            inference_cases = [] 
     1141            segment_keys.each_with_index do |segment_key, index| 
     1142              next if segment_key == :id # never infer :id 
     1143              inference_cases << build_url_helper_inference_case(segment_key, index) 
     1144            end 
     1145 
    11391146            @module.send :module_eval, <<-end_eval # We use module_eval to avoid leaks 
    1140               def #{selector}(*args) 
    1141                 opts = if args.empty? || Hash === args.first 
    1142                   args.first || {} 
     1147            def #{selector}(*args) 
     1148              opts = #{hash_access_method}(Hash === args.last ? args.pop : nil) 
     1149              raise ArgumentError, "expected a maximum of #{segment_keys.length} positional arguments for route" if args.length > #{segment_keys.length} 
     1150 
     1151              offset = #{segment_keys.length} - args.length 
     1152              #{segment_keys.inspect}.each_with_index do |key, index| 
     1153                if (index - offset) >= 0 
     1154                  # supplied positional args always take precedence 
     1155                  opts[key] = args[index - offset] 
    11431156                else 
    1144                   # allow ordered parameters to be associated with corresponding 
    1145                   # dynamic segments, so you can do 
    1146                   # 
    1147                   #   foo_url(bar, baz, bang) 
    1148                   # 
    1149                   # instead of 
    1150                   # 
    1151                   #   foo_url(:bar => bar, :baz => baz, :bang => bang) 
    1152                   args.zip(#{segment_keys.inspect}).inject({}) do |h, (v, k)| 
    1153                     h[k] = v 
    1154                     h 
     1157                  # never overwrite an explicitly passed param with an inferred one 
     1158                  next if opts.has_key?(key) 
     1159                  case index 
     1160                  #{inference_cases} 
     1161                  when nil  
     1162                    # bogus when condition to stop ruby from complaining at compile time 
     1163                    # for routes that have no inference cases 
    11551164                  end 
    11561165                end 
    1157                  
    1158                 url_for(#{hash_access_method}(opts)) 
    11591166              end 
     1167              url_for(opts) 
     1168            end 
    11601169            end_eval 
     1170             
    11611171            @module.send(:protected, selector) 
    11621172            helpers << selector 
    11631173          end 
    1164            
     1174 
     1175          def build_url_helper_inference_case(key, index) 
     1176            key_without_id = key.to_s.gsub(/_id$/,'').to_sym 
     1177            <<-end_eval 
     1178            when #{index} 
     1179              if inferred_val = @#{key_without_id} || @#{key} 
     1180                opts[key] = inferred_val 
     1181              end 
     1182            end_eval 
     1183          end 
    11651184      end 
    11661185   
    11671186      attr_accessor :routes, :named_routes