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

Changeset 4060

Show
Ignore:
Timestamp:
03/27/06 05:13:46 (3 years ago)
Author:
ulysses
Message:

Dependencies cleanup. Fixes #4221.

Files:

Legend:

Unmodified
Added
Removed
Modified
Copied
Moved
  • trunk/activesupport/CHANGELOG

    r4059 r4060  
    11*SVN* 
     2 
     3* When possible, avoid incorrectly obtaining constants from parent modules. Fixes #4221. [Nicholas Seckar] 
     4 
     5* Add more tests for dependencies; refactor existing cases. [Nicholas Seckar] 
     6 
     7* Move Module#parent and Module#as_load_path into core_ext. Add Module#parent. [Nicholas Seckar] 
    28 
    39* Add CachingTools::HashCaching to simplify the creation of nested, autofilling hashes. [Nicholas Seckar] 
  • trunk/activesupport/lib/active_support/core_ext/module.rb

    r3535 r4060  
    22require File.dirname(__FILE__) + '/module/attribute_accessors' 
    33require File.dirname(__FILE__) + '/module/delegation' 
     4require File.dirname(__FILE__) + '/module/introspection' 
     5require File.dirname(__FILE__) + '/module/loading' 
  • trunk/activesupport/lib/active_support/dependencies.rb

    r3668 r4060  
    7979  alias :rails_original_const_missing :const_missing 
    8080   
    81   def parent 
    82     parent_name = name.split('::')[0..-2] * '::' 
    83     parent_name.empty? ? Object : parent_name.constantize 
    84   end 
    85    
    86   def as_load_path 
    87     if self == Object || self == Kernel 
    88       '' 
    89     elsif is_a? Class 
    90       parent == self ? '' : parent.as_load_path 
    91     else 
    92       name.split('::').collect do |word| 
    93         word.underscore 
    94       end * '/' 
    95     end 
    96   end 
    97    
    9881  # Use const_missing to autoload associations so we don't have to 
    9982  # require_association when using single-table inheritance. 
     
    117100      end 
    118101       
    119       if parent && parent != self 
     102      # Attempt to access the name from the parent, unless we don't have a valid 
     103      # parent, or the constant is already defined in the parent. If the latter 
     104      # is the case, then we are being queried via self::class_id, and we should 
     105      # avoid returning the constant from the parent if possible. 
     106      if parent && parent != self && ! parents.any? { |p| p.const_defined?(class_id) } 
    120107        suppress(NameError) do 
    121108          return parent.send(:const_missing, class_id) 
  • trunk/activesupport/test/core_ext/module_test.rb

    r3535 r4060  
    8383    assert_raises(ArgumentError) { eval($noplace) } 
    8484  end 
     85   
     86  def test_parent 
     87    assert_equal Yz::Zy, Yz::Zy::Cd.parent 
     88    assert_equal Yz, Yz::Zy.parent 
     89    assert_equal Object, Yz.parent 
     90  end 
     91   
     92  def test_parents 
     93    assert_equal [Yz::Zy, Yz, Object], Yz::Zy::Cd.parents 
     94    assert_equal [Yz, Object], Yz::Zy.parents 
     95  end 
     96   
     97  def test_as_load_path 
     98    assert_equal 'yz/zy', Yz::Zy.as_load_path 
     99    assert_equal 'yz', Yz.as_load_path 
     100  end 
    85101end 
  • trunk/activesupport/test/dependencies_test.rb

    r3537 r4060  
    77  def teardown 
    88    Dependencies.clear 
     9  end 
     10   
     11  def with_loading(from_dir = nil) 
     12    prior_path = $LOAD_PATH.clone 
     13    $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/#{from_dir}" if from_dir 
     14    old_mechanism, Dependencies.mechanism = Dependencies.mechanism, :load 
     15    yield 
     16  ensure 
     17    $LOAD_PATH.clear 
     18    $LOAD_PATH.concat prior_path 
     19    Dependencies.mechanism = old_mechanism 
    920  end 
    1021 
     
    3041 
    3142  def test_dependency_which_raises_exception_isnt_added_to_loaded_set 
    32     old_mechanism, Dependencies.mechanism = Dependencies.mechanism, :load 
     43    with_loading do 
     44      filename = "#{File.dirname(__FILE__)}/dependencies/raises_exception" 
     45      $raises_exception_load_count = 0 
    3346 
    34     filename = "#{File.dirname(__FILE__)}/dependencies/raises_exception" 
    35     $raises_exception_load_count = 0 
     47      5.times do |count| 
     48        assert_raises(RuntimeError) { require_dependency filename } 
     49        assert_equal count + 1, $raises_exception_load_count 
    3650 
    37     5.times do |count| 
    38       assert_raises(RuntimeError) { require_dependency filename } 
    39       assert_equal count + 1, $raises_exception_load_count 
     51        assert !Dependencies.loaded.include?(filename) 
     52        assert !Dependencies.history.include?(filename) 
     53      end 
     54    end 
     55  end 
     56 
     57  def test_warnings_should_be_enabled_on_first_load 
     58    with_loading do 
     59      old_warnings, Dependencies.warnings_on_first_load = Dependencies.warnings_on_first_load, true 
     60 
     61      filename = "#{File.dirname(__FILE__)}/dependencies/check_warnings" 
     62      $check_warnings_load_count = 0 
    4063 
    4164      assert !Dependencies.loaded.include?(filename) 
    4265      assert !Dependencies.history.include?(filename) 
     66 
     67      silence_warnings { require_dependency filename } 
     68      assert_equal 1, $check_warnings_load_count 
     69      assert_equal true, $checked_verbose, 'On first load warnings should be enabled.' 
     70 
     71      assert Dependencies.loaded.include?(filename) 
     72      Dependencies.clear 
     73      assert !Dependencies.loaded.include?(filename) 
     74      assert Dependencies.history.include?(filename) 
     75 
     76      silence_warnings { require_dependency filename } 
     77      assert_equal 2, $check_warnings_load_count 
     78      assert_equal nil, $checked_verbose, 'After first load warnings should be left alone.' 
     79 
     80      assert Dependencies.loaded.include?(filename) 
     81      Dependencies.clear 
     82      assert !Dependencies.loaded.include?(filename) 
     83      assert Dependencies.history.include?(filename) 
     84 
     85      enable_warnings { require_dependency filename } 
     86      assert_equal 3, $check_warnings_load_count 
     87      assert_equal true, $checked_verbose, 'After first load warnings should be left alone.' 
     88 
     89      assert Dependencies.loaded.include?(filename) 
    4390    end 
    44   ensure 
    45     Dependencies.mechanism = old_mechanism 
    46   end 
    47  
    48   def test_warnings_should_be_enabled_on_first_load 
    49     old_mechanism, Dependencies.mechanism = Dependencies.mechanism, :load 
    50     old_warnings, Dependencies.warnings_on_first_load = Dependencies.warnings_on_first_load, true 
    51  
    52     filename = "#{File.dirname(__FILE__)}/dependencies/check_warnings" 
    53     $check_warnings_load_count = 0 
    54  
    55     assert !Dependencies.loaded.include?(filename) 
    56     assert !Dependencies.history.include?(filename) 
    57  
    58     silence_warnings { require_dependency filename } 
    59     assert_equal 1, $check_warnings_load_count 
    60     assert_equal true, $checked_verbose, 'On first load warnings should be enabled.' 
    61  
    62     assert Dependencies.loaded.include?(filename) 
    63     Dependencies.clear 
    64     assert !Dependencies.loaded.include?(filename) 
    65     assert Dependencies.history.include?(filename) 
    66  
    67     silence_warnings { require_dependency filename } 
    68     assert_equal 2, $check_warnings_load_count 
    69     assert_equal nil, $checked_verbose, 'After first load warnings should be left alone.' 
    70  
    71     assert Dependencies.loaded.include?(filename) 
    72     Dependencies.clear 
    73     assert !Dependencies.loaded.include?(filename) 
    74     assert Dependencies.history.include?(filename) 
    75  
    76     enable_warnings { require_dependency filename } 
    77     assert_equal 3, $check_warnings_load_count 
    78     assert_equal true, $checked_verbose, 'After first load warnings should be left alone.' 
    79  
    80     assert Dependencies.loaded.include?(filename) 
    81   ensure 
    82     Dependencies.mechanism = old_mechanism 
    83     Dependencies.warnings_on_first_load = old_warnings 
    8491  end 
    8592 
    8693  def test_mutual_dependencies_dont_infinite_loop 
    87     $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/dependencies" 
    88     old_mechanism, Dependencies.mechanism = Dependencies.mechanism, :load 
     94    with_loading 'dependencies' do 
     95      $mutual_dependencies_count = 0 
     96      assert_nothing_raised { require_dependency 'mutual_one' } 
     97      assert_equal 2, $mutual_dependencies_count 
    8998 
    90     $mutual_dependencies_count = 0 
    91     assert_nothing_raised { require_dependency 'mutual_one' } 
    92     assert_equal 2, $mutual_dependencies_count 
     99      Dependencies.clear 
    93100 
    94     Dependencies.clear 
    95  
    96     $mutual_dependencies_count = 0 
    97     assert_nothing_raised { require_dependency 'mutual_two' } 
    98     assert_equal 2, $mutual_dependencies_count 
    99   ensure 
    100     $LOAD_PATH.shift 
    101     Dependencies.mechanism = old_mechanism 
     101      $mutual_dependencies_count = 0 
     102      assert_nothing_raised { require_dependency 'mutual_two' } 
     103      assert_equal 2, $mutual_dependencies_count 
     104    end 
    102105  end 
    103106   
     
    107110   
    108111  def test_module_loading 
    109     begin 
    110       $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/autoloading_fixtures" 
    111       old_mechanism, Dependencies.mechanism = Dependencies.mechanism, :load 
    112      
     112    with_loading 'autoloading_fixtures' do 
    113113      assert_kind_of Module, A 
    114114      assert_kind_of Class, A::B 
    115115      assert_kind_of Class, A::C::D 
    116116      assert_kind_of Class, A::C::E::F 
    117     ensure 
    118       $LOAD_PATH.shift 
    119       Dependencies.mechanism = old_mechanism 
    120117    end 
    121118  end 
    122119   
    123   def test_non_existing_cost_raises_nameerrror 
    124     begin 
    125       $LOAD_PATH.unshift "#{File.dirname(__FILE__)}/autoloading_fixtures" 
    126       old_mechanism, Dependencies.mechanism = Dependencies.mechanism, :load 
    127       assert_raises(NameError) do 
    128         DoesNotExist 
    129       end 
    130      
    131       assert_raises(NameError) do 
    132         NoModule::DoesNotExist 
    133       end 
    134      
    135       assert_raises(NameError) do 
    136         A::DoesNotExist 
    137       end 
    138  
    139       assert_raises(NameError) do 
    140         A::B::DoesNotExist 
    141       end 
    142     ensure 
    143       $LOAD_PATH.shift 
    144       Dependencies.mechanism = old_mechanism 
     120  def test_non_existing_const_raises_name_error 
     121    with_loading 'autoloading_fixtures' do 
     122      assert_raises(NameError) { DoesNotExist } 
     123      assert_raises(NameError) { NoModule::DoesNotExist } 
     124      assert_raises(NameError) { A::DoesNotExist } 
     125      assert_raises(NameError) { A::B::DoesNotExist } 
    145126    end 
    146      
    147127  end 
     128   
     129  def test_directories_should_manifest_as_modules 
     130    with_loading 'autoloading_fixtures' do 
     131      assert_kind_of Module, ModuleFolder 
     132      Object.send :remove_const, :ModuleFolder 
     133    end 
     134  end 
     135   
     136  def test_nested_class_access 
     137    with_loading 'autoloading_fixtures' do 
     138      assert_kind_of Class, ModuleFolder::NestedClass 
     139      Object.send :remove_const, :ModuleFolder 
     140    end 
     141  end 
     142   
     143  def test_nested_class_can_access_sibling 
     144    with_loading 'autoloading_fixtures' do 
     145      sibling = ModuleFolder::NestedClass.class_eval "NestedSibling" 
     146      assert defined?(ModuleFolder::NestedSibling) 
     147      assert_equal ModuleFolder::NestedSibling, sibling 
     148      Object.send :remove_const, :ModuleFolder 
     149    end 
     150  end 
     151   
     152  def failing_test_access_thru_and_upwards_fails 
     153    with_loading 'autoloading_fixtures' do 
     154      assert ! defined?(ModuleFolder) 
     155      assert_raises(NameError) { ModuleFolder::Object } 
     156      assert_raises(NameError) { ModuleFolder::NestedClass::Object } 
     157      Object.send :remove_const, :ModuleFolder 
     158    end 
     159  end 
     160   
    148161end