public
Description: Ruby on Rails
Homepage: http://rubyonrails.org
Clone URL: git://github.com/rails/rails.git
Search Repo:
Fix broken traverse_to_controller

git-svn-id: http://svn-commit.rubyonrails.org/rails/branches/stable@4501 
5ecf4fe2-1ee6-0310-87b1-e25e094e27de
Nicholas Seckar (author)
Wed Jun 28 11:11:35 -0700 2006
commit  51f3283ef317f7a8e2e52a816703b2e1d61106c8
tree    2a0ded09a408cbf167b3169f16038b39e433fac5
parent  0c516b370b08e3e095fe24cc0e2b8d52fdecf9e0
...
 
 
 
 
 
 
 
1
2
3
...
1
2
3
4
5
6
7
8
9
10
0
@@ -1,3 +1,10 @@
0
+* Fix broken traverse_to_controller. We now:
0
+ Look for a _controller.rb file under RAILS_ROOT to load.
0
+ If we find it, we require_dependency it and return the controller it defined. (If none was defined we stop looking.)
0
+ 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.
0
+ Otherwise we check to see if a directory of the same name exists, and if it does we create a module for it.
0
+
0
+
0
 *1.12.2* (June 27th, 2006)
0
 
0
 * Refinement to avoid exceptions in traverse_to_controller.
...
224
225
226
227
228
229
230
231
232
233
 
 
234
235
236
237
238
239
240
241
242
243
244
245
 
 
 
 
 
246
247
 
248
249
250
251
252
253
254
255
256
257
258
 
 
 
 
 
 
 
 
259
260
261
262
263
 
264
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
265
266
267
...
224
225
226
 
227
228
229
230
231
232
233
234
235
 
 
 
 
 
 
 
 
 
 
 
236
237
238
239
240
241
242
243
244
245
246
247
 
 
 
 
 
 
 
248
249
250
251
252
253
254
255
256
257
258
259
 
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
0
@@ -224,44 +224,71 @@
0
           length = segments.length
0
           index = start_at
0
           mod_name = controller_name = segment = nil
0
-
0
           while index < length
0
             return nil unless /\A[A-Za-z][A-Za-z\d_]*\Z/ =~ (segment = segments[index])
0
             index += 1
0
             
0
             mod_name = segment.camelize
0
             controller_name = "#{mod_name}Controller"
0
+ path_suffix = File.join(segments[start_at..(index - 1)])
0
+ next_mod = nil
0
             
0
- begin
0
- # We use eval instead of const_get to avoid obtaining values from parent modules.
0
- controller = eval("mod::#{controller_name}", nil, __FILE__, __LINE__)
0
- expected_name = "#{mod.name}::#{controller_name}"
0
-
0
- # Detect the case when const_get returns an object from a parent namespace.
0
- if controller.is_a?(Class) && controller.ancestors.include?(ActionController::Base) && (mod == Object || controller.name == expected_name)
0
- return controller, (index - start_at)
0
- end
0
- rescue NameError => e
0
- raise unless /^uninitialized constant .*#{controller_name}$/ =~ e.message
0
+ # If the controller is already present, or if we load it, return it.
0
+ if mod.const_defined?(controller_name) || attempt_load(mod, controller_name, path_suffix + "_controller") == :defined
0
+ controller = mod.const_get(controller_name)
0
+ return nil unless controller.is_a?(Class) && controller.ancestors.include?(ActionController::Base) # it's not really a controller?
0
+ return [controller, (index - start_at)]
0
             end
0
             
0
+ # No controller? Look for the module
0
             if mod.const_defined? mod_name
0
               next_mod = mod.send(:const_get, mod_name)
0
               next_mod = nil unless next_mod.is_a?(Module)
0
             else
0
- suffix = File.join(segments[start_at..index])
0
- $:.each do |base|
0
- path = File.join(base, suffix)
0
- next unless File.directory? path
0
- next_mod = Module.new
0
- mod.send(:const_set, mod_name, next_mod)
0
- break
0
+ # Try to load a file that defines the module we want.
0
+ case attempt_load(mod, mod_name, path_suffix)
0
+ when :defined then next_mod = mod.const_get mod_name
0
+ when :dir then # We didn't find a file, but there's a dir.
0
+ next_mod = Module.new # So create a module for the directory
0
+ mod.send :const_set, mod_name, next_mod
0
+ else
0
+ return nil
0
               end
0
             end
0
             mod = next_mod
0
             
0
- return nil unless mod
0
+ return nil unless mod && mod.is_a?(Module)
0
           end
0
+ nil
0
+ end
0
+
0
+ protected
0
+
0
+ def safe_load_paths #:nodoc:
0
+ if defined?(RAILS_ROOT)
0
+ $LOAD_PATH.select do |base|
0
+ base = File.expand_path(base)
0
+ extended_root = File.expand_path(RAILS_ROOT)
0
+ base[0, extended_root.length] == extended_root
0
+ end
0
+ else
0
+ $LOAD_PATH
0
+ end
0
+ end
0
+
0
+ def attempt_load(mod, const_name, path)
0
+ has_dir = false
0
+ safe_load_paths.each do |load_path|
0
+ full_path = File.join(load_path, path)
0
+ file_path = full_path + '.rb'
0
+ if File.file?(file_path) # Found a .rb file? Load it up
0
+ require_dependency(file_path)
0
+ return :defined if mod.const_defined? const_name
0
+ else
0
+ has_dir ||= File.directory?(full_path)
0
+ end
0
+ end
0
+ return (has_dir ? :dir : nil)
0
         end
0
       end
0
     end
...
977
978
979
 
980
981
982
 
983
984
985
986
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
987
988
989
...
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
0
@@ -977,13 +977,71 @@
0
     load_path = $:.dup
0
     base = File.dirname(File.dirname(File.expand_path(__FILE__)))
0
     $: << File.join(base, 'fixtures')
0
+ Object.send :const_set, :RAILS_ROOT, File.join(base, 'fixtures/application_root')
0
     assert_equal nil, ActionController::Routing::ControllerComponent.traverse_to_controller(%w(dont_load pretty please))
0
   ensure
0
     $:[0..-1] = load_path
0
+ Object.send :remove_const, :RAILS_ROOT
0
   end
0
   
0
   def test_traverse_should_not_trip_on_non_module_constants
0
     assert_equal nil, ActionController::Routing::ControllerComponent.traverse_to_controller(%w(admin some_constant a))
0
+ end
0
+
0
+ # This is evil, but people do it.
0
+ def test_traverse_to_controller_should_pass_thru_classes
0
+ load_path = $:.dup
0
+ base = File.dirname(File.dirname(File.expand_path(__FILE__)))
0
+ $: << File.join(base, 'fixtures')
0
+ $: << File.join(base, 'fixtures/application_root/app/controllers')
0
+ $: << File.join(base, 'fixtures/application_root/app/models')
0
+ Object.send :const_set, :RAILS_ROOT, File.join(base, 'fixtures/application_root')
0
+ pair = ActionController::Routing::ControllerComponent.traverse_to_controller(%w(a_class_that_contains_a_controller poorly_placed))
0
+
0
+ # Make sure the container class was loaded properly
0
+ assert defined?(AClassThatContainsAController)
0
+ assert_kind_of Class, AClassThatContainsAController
0
+ assert_equal :you_know_it, AClassThatContainsAController.is_special?
0
+
0
+ # Make sure the controller was too
0
+ assert_kind_of Array, pair
0
+ assert_equal 2, pair[1]
0
+ klass = pair.first
0
+ assert_kind_of Class, klass
0
+ assert_equal :decidedly_so, klass.is_evil?
0
+ assert klass.ancestors.include?(ActionController::Base)
0
+ assert defined?(AClassThatContainsAController::PoorlyPlacedController)
0
+ assert_equal klass, AClassThatContainsAController::PoorlyPlacedController
0
+ ensure
0
+ $:[0..-1] = load_path
0
+ Object.send :remove_const, :RAILS_ROOT
0
+ end
0
+
0
+ def test_traverse_to_nested_controller
0
+ load_path = $:.dup
0
+ base = File.dirname(File.dirname(File.expand_path(__FILE__)))
0
+ $: << File.join(base, 'fixtures')
0
+ $: << File.join(base, 'fixtures/application_root/app/controllers')
0
+ Object.send :const_set, :RAILS_ROOT, File.join(base, 'fixtures/application_root')
0
+ pair = ActionController::Routing::ControllerComponent.traverse_to_controller(%w(module_that_holds_controllers nested))
0
+
0
+ assert_not_equal nil, pair
0
+
0
+ # Make sure that we created a module for the dir
0
+ assert defined?(ModuleThatHoldsControllers)
0
+ assert_kind_of Module, ModuleThatHoldsControllers
0
+
0
+ # Make sure the controller is ok
0
+ assert_kind_of Array, pair
0
+ assert_equal 2, pair[1]
0
+ klass = pair.first
0
+ assert_kind_of Class, klass
0
+ assert klass.ancestors.include?(ActionController::Base)
0
+ assert defined?(ModuleThatHoldsControllers::NestedController)
0
+ assert_equal klass, ModuleThatHoldsControllers::NestedController
0
+ ensure
0
+ $:[0..-1] = load_path
0
+ Object.send :remove_const, :RAILS_ROOT
0
   end
0
   
0
 end
...
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
0
@@ -1 +1,8 @@
0
+class AClassThatContainsAController::PoorlyPlacedController < ActionController::Base
0
+
0
+ def self.is_evil?
0
+ :decidedly_so
0
+ end
0
+
0
+end
...
 
 
 
...
1
2
3
0
@@ -1 +1,4 @@
0
+class ModuleThatHoldsControllers::NestedController < ActionController::Base
0
+
0
+end
...
 
 
 
 
 
 
 
...
1
2
3
4
5
6
7
0
@@ -1 +1,8 @@
0
+class AClassThatContainsAController #often < ActiveRecord::Base
0
+
0
+ def self.is_special?
0
+ :you_know_it
0
+ end
0
+
0
+end

Comments

    No one has commented yet.