less aggressive explicit preloader
[has_many_polymorphs.git] / lib / has_many_polymorphs / autoload.rb
blob452cb931cfe6a0d618eceb3e504dfcdd07d5b201
2 require 'initializer' unless defined? ::Rails::Initializer 
3 require 'dispatcher' unless defined? ::ActionController::Dispatcher
5 module HasManyPolymorphs
7 =begin rdoc    
8 Searches for models that use <tt>has_many_polymorphs</tt> or <tt>acts_as_double_polymorphic_join</tt> and makes sure that they get loaded during app initialization. This ensures that helper methods are injected into the target classes. 
10 Note that you can override DEFAULT_OPTIONS via Rails::Configuration#has_many_polymorphs_options. For example, if you need an application extension to be required before has_many_polymorphs loads your models, add an <tt>after_initialize</tt> block in <tt>config/environment.rb</tt> that appends to the <tt>'requirements'</tt> key:
11   Rails::Initializer.run do |config|     
12     # your other configuration here
13     
14     config.after_initialize do
15       config.has_many_polymorphs_options['requirements'] << 'lib/my_extension_model'
16     end    
17   end
18   
19 =end
21   DEFAULT_OPTIONS = {
22     :file_pattern => "#{RAILS_ROOT}/app/models/**/*.rb",
23     :file_exclusions => ['svn', 'CVS', 'bzr'],
24     :methods => ['has_many_polymorphs', 'acts_as_double_polymorphic_join'],
25     :requirements => []}
26   
27   mattr_accessor :options
28   @@options = HashWithIndifferentAccess.new(DEFAULT_OPTIONS)      
30   # Dispatcher callback to load polymorphic relationships from the top down.
31   def self.autoload
33     _logger_debug "autoload hook invoked"
34       
35     files = Dir[options[:file_pattern]]
36     files += options[:requirements].map do |filename|
37       filename + ".rb"
38     end
39     
40     files.each do |filename|
41       next if filename =~ /#{options[:file_exclusions].join("|")}/
42       open filename do |file|
43         if file.grep(/#{options[:methods].join("|")}/).any?
44           begin
45             model = File.basename(filename)[0..-4].camelize
46             _logger_warn "preloading parent model #{model}"
47             model.constantize
48           rescue Object => e
49             _logger_warn "#{model} could not be preloaded: #{e.inspect}"
50           end
51         end
52       end
53     end
54   end  
55     
56 end
58 class Rails::Initializer #:nodoc:
59   # Make sure it gets loaded in the console, tests, and migrations
60   def after_initialize_with_autoload 
61     after_initialize_without_autoload
62     HasManyPolymorphs.autoload
63   end
64   alias_method_chain :after_initialize, :autoload 
65 end
67 Dispatcher.to_prepare(:has_many_polymorphs_autoload) do
68   # Make sure it gets loaded in the app
69   HasManyPolymorphs.autoload
70 end