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

Changeset 4501

Show
Ignore:
Timestamp:
06/28/06 18:11:35 (2 years ago)
Author:
ulysses
Message:

Fix broken traverse_to_controller

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • branches/stable/actionpack/CHANGELOG

    r4496 r4501  
     1* Fix broken traverse_to_controller. We now: 
     2  Look for a _controller.rb file under RAILS_ROOT to load. 
     3  If we find it, we require_dependency it and return the controller it defined. (If none was defined we stop looking.) 
     4  If we don't find it, we look for a .rb file under RAILS_ROOT to load. If we find it, and it loads a constant we keep looking. 
     5  Otherwise we check to see if a directory of the same name exists, and if it does we create a module for it. 
     6 
     7 
    18*1.12.2* (June 27th, 2006) 
    29 
  • branches/stable/actionpack/lib/action_controller/routing.rb

    r4458 r4501  
    225225          index = start_at 
    226226          mod_name = controller_name = segment = nil 
    227            
    228227          while index < length 
    229228            return nil unless /\A[A-Za-z][A-Za-z\d_]*\Z/ =~ (segment = segments[index]) 
     
    232231            mod_name = segment.camelize 
    233232            controller_name = "#{mod_name}Controller" 
     233            path_suffix = File.join(segments[start_at..(index - 1)]) 
     234            next_mod = nil 
    234235             
    235             begin 
    236               # We use eval instead of const_get to avoid obtaining values from parent modules. 
    237               controller = eval("mod::#{controller_name}", nil, __FILE__, __LINE__) 
    238               expected_name = "#{mod.name}::#{controller_name}" 
    239                
    240               # Detect the case when const_get returns an object from a parent namespace. 
    241               if controller.is_a?(Class) && controller.ancestors.include?(ActionController::Base) && (mod == Object || controller.name == expected_name) 
    242                 return controller, (index - start_at) 
    243               end 
    244             rescue NameError => e 
    245               raise unless /^uninitialized constant .*#{controller_name}$/ =~ e.message                             
     236            # If the controller is already present, or if we load it, return it. 
     237            if mod.const_defined?(controller_name) || attempt_load(mod, controller_name, path_suffix + "_controller") == :defined 
     238              controller = mod.const_get(controller_name) 
     239              return nil unless controller.is_a?(Class) && controller.ancestors.include?(ActionController::Base) # it's not really a controller? 
     240              return [controller, (index - start_at)] 
    246241            end 
    247242             
     243            # No controller? Look for the module 
    248244            if mod.const_defined? mod_name 
    249245              next_mod = mod.send(:const_get, mod_name) 
    250246              next_mod = nil unless next_mod.is_a?(Module) 
    251247            else 
    252               suffix = File.join(segments[start_at..index]) 
    253               $:.each do |base| 
    254                 path = File.join(base, suffix) 
    255                 next unless File.directory? path 
    256                 next_mod = Module.new 
    257                 mod.send(:const_set, mod_name, next_mod) 
    258                 break 
     248              # Try to load a file that defines the module we want. 
     249              case attempt_load(mod, mod_name, path_suffix) 
     250                when :defined then next_mod = mod.const_get mod_name 
     251                when :dir then # We didn't find a file, but there's a dir. 
     252                  next_mod = Module.new # So create a module for the directory 
     253                  mod.send :const_set, mod_name, next_mod 
     254                else 
     255                  return nil 
    259256              end 
    260257            end 
    261258            mod = next_mod 
    262259             
    263             return nil unless mod 
    264           end 
     260            return nil unless mod && mod.is_a?(Module) 
     261          end 
     262          nil 
     263        end 
     264         
     265      protected 
     266         
     267        def safe_load_paths #:nodoc: 
     268          if defined?(RAILS_ROOT) 
     269            $LOAD_PATH.select do |base| 
     270              base = File.expand_path(base) 
     271              extended_root = File.expand_path(RAILS_ROOT) 
     272              base[0, extended_root.length] == extended_root 
     273            end 
     274          else 
     275            $LOAD_PATH 
     276          end 
     277        end 
     278         
     279        def attempt_load(mod, const_name, path) 
     280          has_dir = false 
     281          safe_load_paths.each do |load_path| 
     282            full_path = File.join(load_path, path) 
     283            file_path = full_path + '.rb' 
     284            if File.file?(file_path) # Found a .rb file? Load it up 
     285              require_dependency(file_path) 
     286              return :defined if mod.const_defined? const_name 
     287            else 
     288              has_dir ||= File.directory?(full_path) 
     289            end 
     290          end 
     291          return (has_dir ? :dir : nil) 
    265292        end 
    266293      end 
  • branches/stable/actionpack/test/controller/routing_test.rb

    r4457 r4501  
    978978    base = File.dirname(File.dirname(File.expand_path(__FILE__))) 
    979979    $: << File.join(base, 'fixtures') 
     980    Object.send :const_set, :RAILS_ROOT, File.join(base, 'fixtures/application_root') 
    980981    assert_equal nil, ActionController::Routing::ControllerComponent.traverse_to_controller(%w(dont_load pretty please)) 
    981982  ensure 
    982983    $:[0..-1] = load_path 
     984    Object.send :remove_const, :RAILS_ROOT 
    983985  end 
    984986   
     
    987989  end 
    988990   
     991  # This is evil, but people do it. 
     992  def test_traverse_to_controller_should_pass_thru_classes 
     993    load_path = $:.dup 
     994    base = File.dirname(File.dirname(File.expand_path(__FILE__))) 
     995    $: << File.join(base, 'fixtures') 
     996    $: << File.join(base, 'fixtures/application_root/app/controllers') 
     997    $: << File.join(base, 'fixtures/application_root/app/models') 
     998    Object.send :const_set, :RAILS_ROOT, File.join(base, 'fixtures/application_root') 
     999    pair = ActionController::Routing::ControllerComponent.traverse_to_controller(%w(a_class_that_contains_a_controller poorly_placed)) 
     1000     
     1001    # Make sure the container class was loaded properly 
     1002    assert defined?(AClassThatContainsAController) 
     1003    assert_kind_of Class, AClassThatContainsAController 
     1004    assert_equal :you_know_it, AClassThatContainsAController.is_special? 
     1005     
     1006    # Make sure the controller was too 
     1007    assert_kind_of Array, pair 
     1008    assert_equal 2, pair[1] 
     1009    klass = pair.first 
     1010    assert_kind_of Class, klass 
     1011    assert_equal :decidedly_so, klass.is_evil? 
     1012    assert klass.ancestors.include?(ActionController::Base) 
     1013    assert defined?(AClassThatContainsAController::PoorlyPlacedController) 
     1014    assert_equal klass, AClassThatContainsAController::PoorlyPlacedController 
     1015  ensure 
     1016    $:[0..-1] = load_path 
     1017    Object.send :remove_const, :RAILS_ROOT 
     1018  end 
     1019   
     1020  def test_traverse_to_nested_controller 
     1021    load_path = $:.dup 
     1022    base = File.dirname(File.dirname(File.expand_path(__FILE__))) 
     1023    $: << File.join(base, 'fixtures') 
     1024    $: << File.join(base, 'fixtures/application_root/app/controllers') 
     1025    Object.send :const_set, :RAILS_ROOT, File.join(base, 'fixtures/application_root') 
     1026    pair = ActionController::Routing::ControllerComponent.traverse_to_controller(%w(module_that_holds_controllers nested)) 
     1027     
     1028    assert_not_equal nil, pair 
     1029     
     1030    # Make sure that we created a module for the dir 
     1031    assert defined?(ModuleThatHoldsControllers) 
     1032    assert_kind_of Module, ModuleThatHoldsControllers 
     1033 
     1034    # Make sure the controller is ok 
     1035    assert_kind_of Array, pair 
     1036    assert_equal 2, pair[1] 
     1037    klass = pair.first 
     1038    assert_kind_of Class, klass 
     1039    assert klass.ancestors.include?(ActionController::Base) 
     1040    assert defined?(ModuleThatHoldsControllers::NestedController) 
     1041    assert_equal klass, ModuleThatHoldsControllers::NestedController 
     1042  ensure 
     1043    $:[0..-1] = load_path 
     1044    Object.send :remove_const, :RAILS_ROOT 
     1045  end 
     1046   
    9891047end 
    9901048