views:

745

answers:

2

I was looking at active_support.rb to try to understand the load process it uses. It uses three loading methods: load_all!, autoload and require. Why use three different ways of loading in the same file?

module ActiveSupport
  def self.load_all!
    [Dependencies, Deprecation, Gzip, MessageVerifier, Multibyte, SecureRandom, TimeWithZone]
  end

  autoload :BacktraceCleaner, 'active_support/backtrace_cleaner'
  autoload :Base64, 'active_support/base64'
  autoload :BasicObject, 'active_support/basic_object'
  autoload :BufferedLogger, 'active_support/buffered_logger'
  autoload :Cache, 'active_support/cache'
  autoload :Callbacks, 'active_support/callbacks'
  autoload :Deprecation, 'active_support/deprecation'
  autoload :Duration, 'active_support/duration'
  autoload :Gzip, 'active_support/gzip'
  autoload :Inflector, 'active_support/inflector'
  autoload :Memoizable, 'active_support/memoizable'
  autoload :MessageEncryptor, 'active_support/message_encryptor'
  autoload :MessageVerifier, 'active_support/message_verifier'
  autoload :Multibyte, 'active_support/multibyte'
  autoload :OptionMerger, 'active_support/option_merger'
  autoload :OrderedHash, 'active_support/ordered_hash'
  autoload :OrderedOptions, 'active_support/ordered_options'
  autoload :Rescuable, 'active_support/rescuable'
  autoload :SecureRandom, 'active_support/secure_random'
  autoload :StringInquirer, 'active_support/string_inquirer'
  autoload :TimeWithZone, 'active_support/time_with_zone'
  autoload :TimeZone, 'active_support/values/time_zone'
  autoload :XmlMini, 'active_support/xml_mini'
end

require 'active_support/vendor'
require 'active_support/core_ext'
require 'active_support/dependencies'
require 'active_support/json'

I18n.load_path << "#{File.dirname(__FILE__)}/active_support/locale/en.yml"
+2  A: 

I don't know exactly why Rails uses three different loading methods (actually two - see below). But I know, in general, why someone might.

Require means "load this right now". autoload means "load this when you need to use it". The usual reason to use both is that you have some files that you pretty much assume will be used in every program invocation; and others that are optional. For example, in a Rails application that uses no deprecated methods, you'll never need Deprecation; so why slow down the initial setup by loading that file?

In other cases, you might distinguish between files that will be needed early in the program's execution, and files that can wait. For example, you're not likely to need Gzip until the first request comes in. So by using autoload, you can trim some time off the initial setup, at the cost of a slight slowdown for the first request.

You might ask, well, why not just use autoload for everything? Why load anything before it's absolutely needed? One reason is that autoload only works for constants. So, for example, active_support/core_ext adds a bunch of methods to Numeric so you can write code like 3.days, 6.minutes, and 16.seconds.ago. There's no constant in 3.days, so you can't trigger an autoload on that expression. (And you can't autoload Numeric, because the base class has already been loaded - it's just the extensions you want to add.)

Finally, this class doesn't actually use three loading methods; it uses two, and provides one (sort of). load_all! is used by Rails::Initializer to

# Preload all frameworks specified by the Configuration#frameworks.
# Used by Passenger to ensure everything's loaded before forking and
# to avoid autoload race conditions in JRuby.

I don't know the details, and I don't know why these specific modules are preloaded (and not the others). But since this is meant to support specific environments, you can see why it might require code separate from the default loading mechanism.

A: 

The autoload ruby method can be used to associate a constant with a filename that will be loaded the first time you reference said constant. This keeps you from having to load the entire framework at startup.

It looks like the load_all! method is called from the rails initializer.rb, and is utilized to preload all of the frameworks that are configured to be pre-loaded. This works by calling each frameworks load_all! method, which is simply references an array of constants... which will trigger the autoload.

According to the comments in initializer.rb for preload_frameworks...

# Preload all frameworks specified by the Configuration#frameworks.
# Used by Passenger to ensure everything's loaded before forking and
# to avoid autoload race conditions in JRuby.

The require is to load the core required files for the particular framework.

Aaron Hinni