1. How to Load Core Extensions
1.1. Stand-Alone Active Support
In order to have the smallest default footprint possible, Active Support loads the minimum dependencies by default. It is broken in small pieces so that only the desired extensions can be loaded. It also has some convenience entry points to load related extensions in one shot, even everything.
Thus, after a simple require like:
require "active_support"
only the extensions required by the Active Support framework are loaded.
1.1.1. Cherry-picking a Definition
This example shows how to load Hash#with_indifferent_access. This extension enables the conversion of a Hash into an ActiveSupport::HashWithIndifferentAccess which permits access to the keys as either strings or symbols.
{ a: 1 }.with_indifferent_access["a"] # => 1
For every single method defined as a core extension this guide has a note that says where such a method is defined. In the case of with_indifferent_access the note reads:
That means that you can require it like this:
require "active_support"
require "active_support/core_ext/hash/indifferent_access"
Active Support has been carefully revised so that cherry-picking a file loads only strictly needed dependencies, if any.
1.1.2. Loading Grouped Core Extensions
The next level is to simply load all extensions to Hash. As a rule of thumb, extensions to SomeClass are available in one shot by loading active_support/core_ext/some_class.
Thus, to load all extensions to Hash (including with_indifferent_access):
require "active_support"
require "active_support/core_ext/hash"
1.1.3. Loading All Core Extensions
You may prefer just to load all core extensions, there is a file for that:
require "active_support"
require "active_support/core_ext"
1.1.4. Loading All Active Support
And finally, if you want to have all Active Support available just issue:
require "active_support/all"
That does not even put the entire Active Support in memory upfront indeed, some stuff is configured via autoload, so it is only loaded if used.
1.2. Active Support Within a Ruby on Rails Application
A Ruby on Rails application loads all Active Support unless config.active_support.bare is true. In that case, the application will only load what the framework itself cherry-picks for its own needs, and can still cherry-pick itself at any granularity level, as explained in the previous section.
2. Extensions to All Objects
2.1. blank? and present?
The following values are considered to be blank in a Rails application:
nilandfalse,strings composed only of whitespace (see note below),
empty arrays and hashes, and
any other object that responds to
empty?and is empty.
The predicate for strings uses the Unicode-aware character class [:space:], so for example U+2029 (paragraph separator) is considered to be whitespace.
Note that numbers are not mentioned. In particular, 0 and 0.0 are not blank.
For example, this method from ActionController::HttpAuthentication::Token::ControllerMethods uses blank? for checking whether a token is present:
def authenticate(controller, &login_procedure)
token, options = token_and_options(controller.request)
unless token.blank?
login_procedure.call(token, options)
end
end
The method present? is equivalent to !blank?. This example is taken from ActionDispatch::Http::Cache::Response:
def set_conditional_cache_control!
unless self["Cache-Control"].present?
# ...
end
end
Defined in active_support/core_ext/object/blank.rb.
2.2. presence
The presence method returns its receiver if present?, and nil otherwise. It is useful for idioms like this:
host = config[:host].presence || "localhost"
Defined in active_support/core_ext/object/blank.rb.
2.3. duplicable?
As of Ruby 2.5, most objects can be duplicated via dup or clone:
"foo".dup # => "foo"
"".dup # => ""
Rational(1).dup # => (1/1)
Complex(0).dup # => (0+0i)
1.method(:+).dup # => TypeError (allocator undefined for Method)
Active Support provides duplicable? to query an object about this:
"foo".duplicable? # => true
"".duplicable? # => true
Rational(1).duplicable? # => true
Complex(1).duplicable? # => true
1.method(:+).duplicable? # => false
Any class can disallow duplication by removing dup and clone or raising exceptions from them. Thus only rescue can tell whether a given arbitrary object is duplicable. duplicable? depends on the hard-coded list above, but it is much faster than rescue. Use it only if you know the hard-coded list is enough in your use case.
Defined in active_support/core_ext/object/duplicable.rb.
2.4. deep_dup
The deep_dup method returns a deep copy of a given object. Normally, when you dup an object that contains other objects, Ruby does not dup them, so it creates a shallow copy of the object. If you have an array with a string, for example, it will look like this:
array = ["string"]
duplicate = array.dup
duplicate.push "another-string"
# the object was duplicated, so the element was added only to the duplicate
array # => ["string"]
duplicate # => ["string", "another-string"]
duplicate.first.gsub!("string", "foo")
# first element was not duplicated, it will be changed in both arrays
array # => ["foo"]
duplicate # => ["foo, "another-string"]
As you can see, after duplicating the Array instance, we got another object, therefore we can modify it and the original object will stay unchanged. This is not true for array's elements, however. Since dup does not make a deep copy, the string inside the array is still the same object.
If you need a deep copy of an object, you should use deep_dup. Here is an example:
array = ["string"]
duplicate = array.deep_dup
duplicate.first.gsub!("string", "foo")
array # => ["string"]
duplicate # => ["foo"]
If the object is not duplicable, deep_dup will just return it:
number = 1
duplicate = number.deep_dup
number.object_id == duplicate.object_id # => true
Defined in active_support/core_ext/object/deep_dup.rb.
2.5. try
When you want to call a method on an object only if it is not nil, the simplest way to achieve it is with conditional statements, adding unnecessary clutter. The alternative is to use try. try is like Object#public_send except that it returns nil if sent to nil.
Here is an example:
# without try
unless @number.nil?
@number.next
end
# with try
@number.try(:next)
Another example is this code from ActiveRecord::ConnectionAdapters::AbstractAdapter where @logger could be nil. You can see that the code uses try and avoids an unnecessary check.
def log_info(sql, name, ms)
if @logger.try(:debug?)
name = "%s (%.1fms)" % [name || "SQL", ms]
@logger.debug(format_log_entry(name, sql.squeeze(" ")))
end
end
try can also be called without arguments but a block, which will only be executed if the object is not nil:
@person.try { |p| "#{p.first_name} #{p.last_name}" }
Note that try will swallow no-method errors, returning nil instead. If you want to protect against typos, use try! instead:
@number.try(:nest) # => nil
@number.try!(:nest) # NoMethodError: undefined method `nest' for 1:Integer
Defined in active_support/core_ext/object/try.rb.
2.6. class_eval(*args, &block)
You can evaluate code in the context of any object's singleton class using class_eval:
class Proc
def bind(object)
block, time = self, Time.current
object.class_eval do
method_name