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

Changeset 5307

Show
Ignore:
Timestamp:
10/15/06 23:32:31 (2 years ago)
Author:
ulysses
Message:

Add 'unloadable', a method used to mark any constant as requiring an unload after each request.

Files:

Legend:

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

    r5287 r5307  
    11*SVN* 
     2 
     3* Add 'unloadable', a method used to mark any constant as requiring an unload after each request. [Nicholas Seckar] 
    24 
    35* Make core_ext/string/access.rb multibyte safe. Closes #6388 [Manfred Stienstra] 
  • trunk/activesupport/lib/active_support/dependencies.rb

    r5303 r5307  
    3939  self.autoloaded_constants = [] 
    4040   
     41  # An array of constant names that need to be unloaded on every request. Used 
     42  # to allow arbitrary constants to be marked for unloading. 
     43  mattr_accessor :explicitly_unloadable_constants 
     44  self.explicitly_unloadable_constants = [] 
     45   
    4146  # Set to true to enable logging of const_missing and file loads 
    4247  mattr_accessor :log_activity 
     
    6166    log_call 
    6267    loaded.clear 
    63     remove_autoloaded_constants! 
     68    remove_unloadable_constants! 
    6469  end 
    6570 
     
    253258  end 
    254259   
    255   # Remove the constants that have been autoloaded. 
    256   def remove_autoloaded_constants! 
    257     until autoloaded_constants.empty? 
    258       const = autoloaded_constants.shift 
    259       next unless qualified_const_defined? const 
    260       names = const.split('::') 
    261       if names.size == 1 || names.first.empty? # It's under Object 
    262         parent = Object 
    263       else 
    264         parent = (names[0..-2] * '::').constantize 
    265       end 
    266       log "removing constant #{const}" 
    267       parent.send :remove_const, names.last 
    268       true 
    269     end 
     260  # Remove the constants that have been autoloaded, and those that have been 
     261  # marked for unloading. 
     262  def remove_unloadable_constants! 
     263    autoloaded_constants.each { |const| remove_constant const } 
     264    autoloaded_constants.clear 
     265    explicitly_unloadable_constants.each { |const| remove_constant const } 
    270266  end 
    271267   
     
    275271    return false unless qualified_const_defined? name 
    276272    return autoloaded_constants.include?(name) 
     273  end 
     274   
     275  # Will the provided constant descriptor be unloaded? 
     276  def will_unload?(const_desc) 
     277    autoloaded?(desc) || 
     278      explicitly_unloadable_constants.include?(to_constant_name(const_desc)) 
     279  end 
     280   
     281  # Mark the provided constant name for unloading. This constant will be 
     282  # unloaded on each request, not just the next one. 
     283  def mark_for_unload(const_desc) 
     284    name = to_constant_name const_desc 
     285    if explicitly_unloadable_constants.include? name 
     286      return false 
     287    else 
     288      explicitly_unloadable_constants << name 
     289      return true 
     290    end 
    277291  end 
    278292   
     
    296310      when String then desc.starts_with?('::') ? desc[2..-1] : desc 
    297311      when Symbol then desc.to_s 
    298       when Module then desc.name 
     312      when Module 
     313        raise ArgumentError, "Anonymous modules have no name to be referenced by" if desc.name.blank? 
     314        desc.name 
    299315      else raise TypeError, "Not a valid constant descriptor: #{desc.inspect}" 
    300316    end 
     317  end 
     318   
     319  def remove_constant(const) 
     320    return false unless qualified_const_defined? const 
     321     
     322    names = const.split('::') 
     323    if names.size == 1 || names.first.empty? # It's under Object 
     324      parent = Object 
     325    else 
     326      parent = (names[0..-2] * '::').constantize 
     327    end 
     328     
     329    log "removing constant #{const}" 
     330    parent.send :remove_const, names.last 
     331    return true 
    301332  end 
    302333   
     
    329360    Dependencies.load_missing_constant self, class_id 
    330361  end 
     362   
     363  def unloadable(const_desc = self) 
     364    super(const_desc) 
     365  end 
     366   
    331367end 
    332368 
     
    367403    raise 
    368404  end 
     405 
     406  # Mark the given constant as unloadable. Unloadable constants are removed each 
     407  # time dependencies are cleared. 
     408  #  
     409  # Note that marking a constant for unloading need only be done once. Setup 
     410  # or init scripts may list each unloadable constant that may need unloading; 
     411  # each constant will be removed for every subsequent clear, as opposed to for 
     412  # the first clear. 
     413  #  
     414  # The provided constant descriptor may be a (non-anonymous) module or class, 
     415  # or a qualified constant name as a string or symbol. 
     416  #  
     417  # Returns true if the constant was not previously marked for unloading, false 
     418  # otherwise. 
     419  def unloadable(const_desc) 
     420    Dependencies.mark_for_unload const_desc 
     421  end 
     422 
    369423end 
    370424 
  • trunk/activesupport/test/dependencies_test.rb

    r5053 r5307  
    2525    Dependencies.load_paths = prior_load_paths 
    2626    Dependencies.mechanism = old_mechanism 
     27    Dependencies.explicitly_unloadable_constants = [] 
    2728  end 
    2829 
     
    454455  end 
    455456   
     457  def test_unloadable 
     458    with_loading 'autoloading_fixtures' do 
     459      Object.const_set :M, Module.new 
     460      M.unloadable 
     461       
     462      Dependencies.clear 
     463      assert ! defined?(M) 
     464       
     465      Object.const_set :M, Module.new 
     466      Dependencies.clear 
     467      assert ! defined?(M), "Dependencies should unload unloadable constants each time" 
     468    end 
     469  end 
     470   
     471  def test_unloadable_should_fail_with_anonymous_modules 
     472    with_loading 'autoloading_fixtures' do 
     473      m = Module.new 
     474      assert_raises(ArgumentError) { m.unloadable } 
     475    end 
     476  end 
     477   
     478  def test_unloadable_should_return_change_flag 
     479    with_loading 'autoloading_fixtures' do 
     480      Object.const_set :M, Module.new 
     481      assert_equal true, M.unloadable 
     482      assert_equal false, M.unloadable 
     483    end 
     484  end 
     485   
    456486end