ActiveSupport

ActiveSupport is the libraryof utilitymethods that Rails uses. We examine them in detail here for two reasons. First, theycan be useful to our application code—we can directlyuse manyof these libraries and methods to our advantage when writing Rails applications. Secondly, we can learn many things about Ruby programming by dissecting these parts. They are small and relatively easy to digest.

dependencies.rb

Dependencies autoloads missing constants by trying to find the file associated with the constant. When you attempt to access a nonexistent constant, such as Message, Dependencies will try to find and load message.rb from any directory in Dependencies.load_paths.

Dependencies defines Module#const_missing and Class#const_missing, which both proxy to Dependencies.load_missing_constant(const_parent, const_id). That method searches the load paths for a file with the appropriate name; if found, Dependencies loads the file and ensures that it defined the appropriate constant.

Alternatively, Rails will create an empty module to satisfy nesting in the case of nested models and controllers. If a directorynamed app/models/store/ exists, Store will be created as an empty module, by the following process:

deprecation.rb

The ActiveSupport::Deprecation module provides a method bywhich old APIs are marked for removal. At its core, it is just a fancywarning mechanism. When old APIs are used, they generate a warning in development or test mode. Deprecation warnings are invoked through the Active Support::Deprecation.warn(message, callstack) method. The ActiveSupport::Deprecation.silence method silences those warnings for the duration of the provided block.

The deprecate class method provides an easy way to mark a method as deprecated while still making it available. It decorates the given method with the deprecation warning.

	def find_first(conditions = nil, orderings = nil, joins = nil) # :nodoc:
	  find(:first, :conditions => conditions, :order => orderings, :joins => joins)
	end
	deprecate :find_first => "use find(:first, ...)"

ActiveSupport::Deprecation.behavior is a Proc that is called when a deprecation warning is triggered. It takes two arguments: the deprecation message and the callstack. It can be replaced to modify the default behavior. By default, in the test environment, deprecation warnings print to the standard error stream. In development, they go to the logger. In production, deprecation warnings are silenced.

inflections.rb, inflector.rb

The Inflector module provides a set of simple transformations on English words to facilitate ActiveRecord's manipulations of class and table names. Following the policy of "convention over configuration," for example, a model class named Message would correspond to a table name of messages.

The core of Inflector is the pluralization rules, contained in inflections.rb. The default set of rules is fairly broad, but additional rules can be added easily in config/initializers/ inflections.rb or a similar configuration file, after the framework loads:

Inflector.inflections do |inflect|
	  inflect.plural /^(ox)$/i, '\1\2en'
	  inflect.singular /^(ox)en/i, '\1'

	  inflect.irregular 'octopus', 'octopi'

	  inflect.uncountable "equipment"
	end 

Inflector.inflections yields a singleton instance of the inflections object. Rules are prepended to the list of inflections, so these rules will override the default as long as they are loaded after the Rails framework. Another consequence of the load order is that the rules should be ordered from most general to most specific within a block; the last appropriate inflection rule seen will be used.

The regular expression captures and backreferences ensure that initial capitals are handled correctly; the initial letters (upper-or lowercase) are captured with a case-insensitive regex and substituted into the replacement. The irregular and uncountable rules take care of that work for us:

	"ox".pluralize        # => "oxen"
	"Ox".pluralize        # => "Oxen"
	"Octopus".pluralize   # => "Octopi"
	"Equipment".pluralize # => "Equipment"

Inflector's module methods, which actuallyperform the transformations, are proxied from the core extensions to String and Integer; they are usually not called directly on the Inflector module object. [18] See the respective sections in the Core Extensions documentation later in the chapter for more information.

json.rb, json/encoders.rb, json/encoders/core.rb

JSON (JavaScript Object Notation, pronounced "Jason") is a lightweight subset of Java-Script's notation for literal objects (hash tables) used for data interchange on the Web. Active Support::JSON provides encoders for most basic Ruby data types. The encoders are proxied by the Object#to_json method, added by Core Extensions.

	(1..5).to_json # => "[1, 2, 3, 4, 5]"
	{:a => 1, :b => [2, 3]}.to_json # => "{b: [2, 3], a: 1}"

The JSON library protects against circular references, which cannot be encoded into JSON:

	a = {}
	b = {:a => a}
	a[:b] = b
	a # => {:b=>{:a=>{...}}}

	a.to_json
	# !> ActiveSupport::JSON::CircularReferenceError: object references itself

whiny_nil.rb

The extensions to NilClass are an ingenious part of ActiveSupport. They are designed to help trap unexpected nil values as earlyas possible, and to provide more sensible error messages to the developer when nil is encountered.

Without these extensions, calling one of Array's instance methods on an object that happened to be nil would generate a standard NoMethodError if NilClass did not also contain the method. This could be frustrating to track down, especiallyif the method was called from deep in the framework.

Whiny Nil intercepts those NoMethodErrors with method_missing and makes a suggestion about the type of object the developer may have been expecting (either Array or ActiveRecord::Base), based on the name of the method called.

	nil.sort
	# !> NoMethodError: You have a nil object when you didn't expect it!
	# !> You might have expected an instance of Array.

	nil.save
	# !> NoMethodError: You have a nil object when you didn't expect it!
	# !> You might have expected an instance of ActiveRecord::Base.

The Whiny Nil extensions also redefine NilClass#id, which raises an error. Without this extension, nil.id would return 4 (Ruby's immediate representation of nil, the same as nil.object_id). This would be confusing when chaining methods together. Under the Whiny Nil system, this raises a more informative exception:

	nil.id
	# !> RuntimeError: Called id for nil, which would mistakenly be 4 -
	# !> if you really wanted the id of nil, use object_id

The Whiny Nil system can be turned off in the Rails configuration bysetting config.whiny_ nils to false.



[18] "thing".pluralize reads better than Inflector.pluralize("thing").