ActiveSupport
is a Rails library containing utility classes and extensions to Ruby’s built-in libraries. It usually doesn’t get much attention on its own—you might even call its modules the supporting cast members of the Rails ensemble.
However, ActiveSupport
’s low profile doesn’t diminish its importance in day-to-day Rails programming. To ensure that this book is 100 percent useful as a programming companion, here is a complete, enhanced version of the Rails ActiveSupport
API reference, supplemented where appropriate with real-life example usages and commentary.
Direct extensions of Ruby classes and modules are listed under headings according to class or module name. Extensions made via mixin module appear under headings according to their ActiveSupport
module name.
This API reference was prepared based on revision 7360 of Edge Rails (prior to Rails 2.0). A few obscure methods have been judged inconsequential and omitted because they are old and currently unused in the Rails codebase.
Provides methods for converting Ruby arrays into other formats.
Two formats are supported, :default
and :db
.
The :default
format delegates to the normal to_s
method for an array, which simply concatenates the contents into one mashed-up string.
The much more interesting :db
option returns "null"
if the array is empty, or concatenates the id
fields of its member elements into a comma-delimited string like this:
collect { |element| element.id }.join(",")
Converts its string elements into a slash-delimited string (used to generate URL paths).
>> ["riding","high","and","I","want","to","make"].to_param => "riding/high/and/I/want/to/make"
Converts the array to a comma-separated sentence in which the last element is joined by the connector word.
>> %w(alcohol tobacco firearms).to_sentence => "alcohol, tobacco, and firearms"
The following options are available for to_sentence:
:connector
—. The word used to join the last element in arrays with two or more elements (default: “and”).
:skip_last_comma
—. Set this option to true
to return “a, b and c” instead of “a, b, and c.”
As covered in Chapter 15, “XML and ActiveResource,” the to_xml
method on Array
can be used to create an XML collection by iteratively calling to_xml
on its members, and wrapping the entire thing in an enclosing element.
All of the array elements must respond to to_xml
.
>> ["riding","high"].to_xml RuntimeError: Not all elements respond to to_xml
The preceding example yields the Builder
object to an optional block so that arbitrary markup can be inserted at the bottom of the generated XML, as the last child of the enclosing element.
The following code
{:foo => "foo", :bar => :bar}.to_xml do |xml| xml.did_it "again" end
outputs the following XML:
<?xml version="1.0" encoding="UTF-8"?> <hash> <bar:bar/> <foo>foo</foo> <did_it>again</did_it> </hash>
:builder
—. Defaults to a new instance of Builder::XmlMarkup
. Specify explicitly if you’re calling to_xml
on this array as part of a larger XML construction routine.
:children
—. Sets the name to use for element tags explicitly. Defaults to singularized version of the :root
name by default.
:dasherize
—. Whether or not to turn underscores to dashes in tag names (defaults to true
).
:indent
—. Indent level to use for generated XML (defaults to two spaces).
:root
—. The tag name to use for the enclosing element. If no :root
is supplied and all members of the array are of the same class, the dashed, pluralized form of the first element’s class name is used as a default. Otherwise the default :root
is records
.
:skip_instruct
—. Whether or not to generate an XML instruction tag by calling instruct!
on Builder
.
:skip_types
—. Whether or not to include a type="array"
attribute on the enclosing element.
Provides a method for extracting Rails-style options from a variable-length set of argument parameters.
Extracts options from a variable set of arguments. It’s a bang method because it removes and returns the last element in the array if it’s a hash; otherwise, it returns a blank hash and the source array is unmodified.
def options(*args) args.extract_options! end options(1, 2) # => {} options(1, 2, :a => :b) # => {:a=>:b}
Provides a couple of methods used for splitting array elements into logical groupings.
A true Rails superstar, the in_groups_of
method splits an array into groups of the specified number
size, padding any remaining slots. The fill_with
parameter is used for padding and defaults to nil
.
If a block is provided, it is called with each group; otherwise, a two-dimensional array is returned.
>> %w(1 2 3 4 5 6 7).in_groups_of(3) => [[1, 2, 3], [4, 5, 6], [7, nil, nil] >> %w(1 2 3).in_groups_of(2, ' ') {|group| puts group } [1, 2] [3, " "] >> %w(1 2 3).in_groups_of(2, false) {|group| puts group } [1, 2] [3]
The in_groups_of
method is particularly useful for batch-processing model objects and generating table rows in view templates.
Provides a method that simplifies the caching of method invocations using nested default hashes. According to the API docs, “This pattern is useful, common practice in Ruby, and unsightly when done manually.”
That may be the case, but this module appears to be somewhat useless, since its sole method, hash_cache
, is not automatically accessible in any Rails context, and examination of the Rails codebase reveals that it is not used internally (except in its unit tests).
Dynamically creates a nested hash structure used to cache calls to method_name
. The cache method is named method_name
_cache
unless :as => :
alternate_name
is given.
For example, the following slow_method
def slow_method(a, b) a ** b end
can be cached by calling hash_cache :slow_method
, which will define the method slow_method_cache
.
We can then calculate (and cache) the result of a ** b
using this syntax:
slow_method_cache[a][b]
The hash structure is created using nested calls to Hash.new
with initializer blocks, so the hash structure returned by slow_method_cache
for the example looks like this:
Hash.new do |as, a| as[a] = Hash.new do |bs, b| bs[b] = slow_method(a, b) end end
The implementation of hash_cache
uses heavy Ruby metaprogramming. Generated code is compressed into a single line to maintain sensible backtrace signatures in the case of exceptions.
Rails extends Ruby’s Class
object with a number of methods.
Defines one or more class attribute reader and writer methods in the style of the native attr*
accessors for instance attributes. Used extensively throughout the Rails codebase to save option settings. Values are shared by reference with subclasses, which is very different than class_inheritable_accessor
.
Allows attributes to be shared within an inheritance hierarchy, but each descendant gets a copy of its parents’ attributes, instead of just a pointer to the same. This means that the child can add elements to, for example, an array without those additions being shared with either its parent, siblings, or children, which is unlike the regular class-level attributes, which are shared across the entire hierarchy.
Convenience method that sets up an inheritable reader and writer and defaults it to an empty array so that you don’t have to initialize it yourself.
Convenience method that sets up an inheritable reader and writer and defaults it to an empty hash so that you don’t have to initialize it yourself.
The const_missing
callback is invoked when Ruby can’t find a specified constant in the current scope, which is what makes Rails autoclassloading possible. See the Dependencies
module for more detail.
Removes the constant associated with the specified classes so that they effectively become inaccessible and unusable.
Enables the use of calculations with Date
objects.
Rails extends the existing +
operator so that a since
calculation is performed when the other
argument is an instance of ActiveSupport::Duration
(the type of object returned by methods such as 10.minutes
and 9.months
).
>> Date.today + 1.day == Date.today.tomorrow => true
Provides precise Date
calculations for years, months, and days. The options
parameter takes a hash with any of these keys: :months
, :days
, :years
.
>> Date.new(2006, 2, 28) == Date.new(2005, 2, 28).advance(:years => 1) => true
Converts Date
to a Time
(or DateTime
if necessary) with the time portion set to the beginning of the day (0:00) and then subtracts the specified number of seconds.
>> Time.local(2005, 2, 20, 23, 59, 15) == Date.new(2005, 2, 21).ago(45) => true
Converts Date
to a Time
(or DateTime
if necessary) with the time portion set to the beginning of the day (0:00).
>> Time.local(2005,2,21,0,0,0) == Date.new(2005,2,21).beginning_of_day => true
Returns a new DateTime
representing the start of the month (1st of the month; time set to 0:00).
>> Date.new(2005, 2, 1) == Date.new(2005,2,21).beginning_of_month => true
Returns a new Date
/DateTime
representing the start of the calendar-based quarter (1st of January, April, July, and October).
>> Date.new(2005, 4, 1) == Date.new(2005, 6, 30).beginning_of_quarter => true
Returns a new Date
(or DateTime
) representing the beginning of the week. (Calculation is Monday-based.)
>> Date.new(2005, 1, 31) == Date.new(2005, 2, 4).beginning_of_week => true
Returns a new Date
/DateTime
representing the start of the calendar year (1st of January).
>> Date.new(2005, 1, 1) == Date.new(2005, 2, 22).beginning_of_year => true
Returns a new Date
/DateTime
representing the last day of the calendar month.
>> Date.new(2005, 3, 31) == Date.new(2005,3,20).end_of_month => true
Returns a new Date
where one or more of the elements have been changed according to the options parameter.
The valid options are :year
, :month
, and :day
.
>> Date.new(2007, 5, 12).change(:day => 1) == Date.new(2007, 5, 1) => true >> Date.new(2007, 5, 12).change(:year => 2005, :month => 1) == Date.new(2005, 1, 12) => true
Converts Date
to a Time
(or DateTime
if necessary) with the time portion set to the end of the day (23:59:59).
>> Time.local(2005,2,21,23,59,59) == Date.new(2005, 2, 21).end_of_day => true
Converts Date
to a Time
(or DateTime
if necessary) with the time portion set to the beginning of the day (0:00) and then adds the specified number of seconds.
>> Time.local(2005, 2, 21, 0, 0, 45) == Date.new(2005, 2, 21).since(45) => true
Returns a new Date
(or DateTime
) representing the time a number of specified months ago.
>> Date.new(2005, 1, 1) == Date.new(2005, 3, 1).months_ago(2) => true
Returns a new Date
(or DateTime
) representing the time a number of specified months into the past or the future. Supply a negative number of months to go back to the past.
>> Date.today.months_ago(1) == Date.today.months_since(-1) => true
Returns a new Date
(or DateTime
) representing the start of the given day in the following calendar week. Default day of the week may be overridden with a symbolized day name.
>> Date.new(2005, 3, 4) == Date.new(2005, 2, 22).next_week(:friday) => true
Convenience method that returns a new Date
(or DateTime
) representing the time one day in the future.
>> Date.new(2007, 3, 2) == Date.new(2007, 2, 28).tomorrow.tomorrow => true
Returns a new Date
(or DateTime
) representing the time a number of specified years ago.
>> Date.new(2000, 6, 5) == Date.new(2007, 6, 5).years_ago(7) => true
Returns a new Date
(or DateTime
) representing the time a number of specified years into the future.
>> Date.new(2007, 6, 5) == Date.new(2006, 6, 5).years_since(1) => true
This module mixes methods into Date
that are useful for getting dates in different convenient string representations and as other objects.
The DATE_FORMATS
constant holds a hash of formats used in conjunction with the to_formatted_s
method.
DATE_FORMATS = { :short => "%e %b", :long => "%B %e, %Y", :db => "%Y-%m-%d", :long_ordinal => lambda {|date| date.strftime("%B #{date.day.ordinalize}, %Y") }, # => "April 25th, 2007" :rfc822 => "%e %b %Y" }
Converts a Date
object into its string representation, according to the predefined formats in the DATE_FORMATS
constant. (Aliased as to_s
. Original to_s
is aliased as to_default_s
.)
def test_to_s date = Date.new(2005, 2, 21) assert_equal "2005-02-21", date.to_s assert_equal "21 Feb", date.to_s(:short) assert_equal "February 21, 2005", date.to_s(:long) assert_equal "February 21st, 2005", date.to_s(:long_ordinal) assert_equal "2005-02-21", date.to_s(:db) assert_equal "21 Feb 2005", date.to_s(:rfc822) end
Converts a Date
object into a Ruby Time
object; time is set to beginning of day. The time zone can be :local
or :utc
.
>> Time.local(2005, 2, 21) == Date.new(2005, 2, 21).to_time => true
Enables the use of time calculations within DateTime
itself.
Convenience methods that all represent the start of a day (00:00). Implemented simply as change(:hour => 0)
.
Uses Date
to provide precise Time
calculations for years, months, and days. The options
parameter takes a hash with any of the keys :months
, :days
, and :years
.
Returns a new DateTime
representing the time a number of seconds ago. The opposite of since
.
Returns a new DateTime
where one or more of the elements have been changed according to the options
parameter. The valid date options are :year
, :month
, :day
. The valid time options are :hour
, :min
, :sec
, :offset
, and :start
.
Convenience method that represents the end of a day (23:59:59). Implemented simply as change(:hour => 23, :min => 59, :sec => 59)
.
Overrides the default inspect method with a human-readable one that looks like this:
Mon, 21 Feb 2005 14:30:00 +0000
Returns self
to be able to keep Time
, Date
, and DateTime
classes interchangeable on conversions.
Contains the logic for Rails’ automatic classloading mechanism, which is what makes it possible to reference any constant in the Rails varied loadpaths without ever needing to issue a require
directive.
This module extends itself, a cool hack that you can use with modules that you want to use elsewhere in your codebase in a functional manner:
module Dependencies extend self
As a result, you can call methods directly on the module constant, à la Java static class methods, like this:
Dependencies.search_for_file('.erb')
You shouldn’t need to use this module in day-to-day Rails coding—it’s mostly for internal use by Rails and plugins. On occasion, it might also be useful to understand the workings of this module when debugging tricky class-loading problems.
Several of these attributes are set based on Configuration
settings declared in your various environment files, as described in Chapter 1, “Rails Environments and Configuration.”
An array of qualified constant names that have been loaded. Adding a name to this array will cause it to be unloaded the next time Dependencies
are cleared.
An array of constant names that need to be unloaded on every request. Used to allow arbitrary constants to be marked for unloading.
The Set
of directories from which automatically loaded constants are loaded only once. All directories in this set must also be present in +load_paths+
.
The Set
of directories from which Rails may automatically load files. Files under these directories will be reloaded on each request in development mode, unless the directory also appears in load_once_paths
.
Set this option to true
to enable logging of const_missing
and file loads. (Defaults to false
.)
A setting that determines whether files are loaded (default) or required. This attribute determines whether Rails reloads classes per request, as in development mode.
Invokes depend_on
with swallow_load_errors
set to true
. Wrapped by the require_association
method of Object
.
Attempts to autoload the provided module name by searching for a directory matching the expected path suffix
. If found, the module is created and assigned to into
’s constants with the name +const_name+
. Provided that the directory was loaded from a reloadable base path, it is added to the set of constants that are to be unloaded.
Checks whether the provided path_suffix
corresponds to an autoloadable module. Instead of returning a Boolean, the autoload base for this module is returned.
Searches for the file_name
specified and uses require_or_load
to establish a new dependency. The swallow_load_errors
argument specifies whether LoadError
should be suppressed. Wrapped by the require_dependency
method of Object
.
Loads the file at the specified path
. The const_paths
is a set of fully qualified constant names to load. When the file is loading, Dependencies
will watch for the addition of these constants. Each one that is defined will be marked as autoloaded, and will be removed when Dependencies.clear
is next called.
If the second parameter is left off, Dependencies
will construct a set of names that the file at path
may define. See loadable_constants_for_path
for more details.
Loads the constant named const_name
, which is missing from mod
. If it is not possible to load the constant from mod
, try its parent module by calling const_missing
on it.
Returns an array of constants, based on a specified filesystem path
to a Ruby file, which would cause Dependencies
to attempt to load the file.
Marks the specified constant
for unloading. The constant will be unloaded on each request, not just the next one.
Runs the provided block and detects the new constants that were loaded during its execution. Constants may only be regarded as new once. If the block calls new_constants_in
again, the constants defined within the inner call will not be reported in this one.
If the provided block does not run to completion, and instead raises an exception, any new constants are regarded as being only partially defined and will be removed immediately.
Removes the constants that have been autoloaded, and those that have been marked for unloading.
Implements the main classloading mechanism. Wrapped by the require_or_load
method of Object
.
This module provides Rails core and application developers with a formal mechanism to be able to explicitly state what methods are deprecated. (Deprecation means to mark for future deletion.) Rails will helpfully log a warning message when deprecated methods are called.
All you do to mark a method as deprecated is to call deprecate
and pass it the name of the method as a symbol. Make sure to add your call to deprecate
after the method definition.
deprecate :subject_of_regret
The deprecate
method is mixed into Ruby’s Module
class so that it’s available everywhere.
This module provides assertions that allow testing deprecation of methods.
Asserts that the code in the block triggered a deprecation warning. The optional match
argument allows the assertion to be more specific to a given method name. Just supply a regular expression to use in matching the name of the method(s) expected to be deprecated.
def test_that_subject_of_regret_is_deprecated assert_deprecated do subject_of_regret end end
Provides accurate date and time measurements using the advance
method of Date
and Time
. It mainly supports the methods on Numeric
, such as in this example:
1.month.ago # equivalent to Time.now.advance(:months => -1)
Adds another Duration
or a Numeric
to this Duration
. Numeric
values are treated as seconds.
Subtracts another Duration
or a Numeric
to this Duration
. Numeric
values are treated as seconds.
Alias for since
, which reads a little bit more naturally when using the default Time.now
as the time
argument.
expiration = 1.year.from_now
Calculates the time resulting from a Duration
expression and formats it as a string appropriate for display in the console. (Remember that IRB and the Rails console automatically invoke inspect
on objects returned to them. You can use that trick with your own objects.)
>> 10.years.ago => Sun Aug 31 17:34:15 -0400 1997
Calculates a new Time
or Date
that is as far in the future as this Duration
represents.
expiration = 1.year.since(account.created_at)
Alias for ago
. Reads a little more naturally when specifying a time
argument instead of using the default value, Time.now
.
membership_duration = created_at.until(expires_at)
Collects an enumerable into sets, grouped by the result of a block. Useful, for example, for grouping records by date like this:
latest_transcripts.group_by(&:day).each do |day, transcripts| puts "[#{day}] #{transcripts.map(&:class).join ', '}" end "[2006-03-01] Transcript" "[2006-02-28] Transcript" "[2006-02-27] Transcript, Transcript" "[2006-02-26] Transcript, Transcript" "[2006-02-25] Transcript" "[2006-02-24] Transcript, Transcript" "[2006-02-23] Transcript"
Uses Ruby’s own group_by
in versions 1.9 and above.
Calculates a sum from the elements of an enumerable, based on a block.
payments.sum(&:price)
It’s easier to understand than Ruby’s clumsier inject
method:
payments.inject { |sum, p| sum + p.price }
Use full block syntax (instead of the to_proc
hack) to do more complicated calculations:
payments.sum { |p| p.price * p.tax_rate }
Also, sum
can calculate results without the use of a block:
[5, 15, 10].sum # => 30
The default identity (a fancy way of saying, “the sum of an empty list”) is 0
. However, you can override it with anything you want by passing a default
argument:
[].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
Converts an enumerable to a hash, based on a block that identifies the keys. The most common usage is with a single attribute name:
>> people.index_by(&:login) => { "nextangle" => <Person ...>, "chad" => <Person ...>}
Use full block syntax (instead of the to_proc
hack) to generate more complex keys:
>> people.index_by { |p| "#{p.first_name} #{p.last_name}" } => {"Chad Fowler" => <Person ...>, "David Hansson" => <Person ...>}
Extensions to Ruby’s Exception
class.
Returns the backtrace of an exception without lines pointing to files in the following directories: generated
, vendor
, dispatch
, ruby
, or script
.
Remember that everything in Ruby is an object, even the literal false
, which is a special reference to a singleton instance of the FalseClass
.
Provides an atomic_write
method to Ruby’s File
class.
Writes to a file atomically, by writing to a temp file first and then renaming to the target file_name
. Useful for situations where you need to absolutely prevent other processes or threads from seeing half-written files.
File.atomic_write("important.file") do |file| file.write("hello") end
If your temp
directory is not on the same filesystem as the file you’re trying to write, you can provide a different temporary directory with the temp_dir
argument.
File.atomic_write("/data/something.imporant", "/data/tmp") do |f| file.write("hello") end
Hashes are used throughout Rails, yet ActiveSupport only adds one extra method directly to their class.
Provides a from_xml
method that can quickly turn properly formatted XML into a nested hash structure.
Parses arbitrary strings of XML markup into nested Ruby arrays and hashes. Works great for quick-and-dirty integration of REST-style web services.
Here’s a quick example in the console with some random XML content. The XML only has to be well-formed markup.
>> xml = %(<people> <person id="1"> <name><family>Boss</family> <given>Big</given></name> <email>[email protected]</email> </person> <person id="2"> <name> <family>Worker</family> <given>Two</given></name> <email>[email protected]</email> </person> </people>) => "<people>...</people>" >> h = Hash.from_xml(xml) => {"people"=>{"person"=>[{"name"=>{"given"=>"Big", "family"=>"Boss"}, "id"=>"1", "email"=>"[email protected]"}, {"name"=>{"given"=>"Two", "family"=>"Worker"}, "id"=>"2", "email"=>"[email protected]"}]}}
Now you can easily access the data from the XML:
>> h["people"]["person"].first["name"]["given"] => "Big"
Provides methods for transformations of hashes into other forms.
The XML_TYPE_NAMES
hash shows how Ruby classes are mapped to XML schema types.
XML_TYPE_NAMES = { "Fixnum" => "integer", "Bignum" => "integer", "BigDecimal" => "decimal", "Float" => "float", "Date" => "date", "DateTime" => "datetime", "Time" => "datetime", "TrueClass" => "boolean", "FalseClass" => "boolean" }
The XML_FORMATTING
hash contains the set of procs that are used to convert certain kinds of Ruby objects to XML string value representations.
XML_FORMATTING = { "date" => Proc.new { |date| date.to_s(:db) }, "datetime" => Proc.new { |time| time.xmlschema }, "binary" => Proc.new { |binary| Base64.encode64(binary) }, "yaml" => Proc.new { |yaml| yaml.to_yaml } }
The XML_PARSING
hash contains the set of procs used to convert XML string values into Ruby objects.
XML_PARSING = { "date" => Proc.new { |date| ::Date.parse(date) }, "datetime" => Proc.new { |time| ::Time.parse(time).utc }, "integer" => Proc.new { |integer| integer.to_i }, "float" => Proc.new { |float| float.to_f }, "decimal" => Proc.new { |number| BigDecimal(number) }, "boolean" => Proc.new do |boolean| %w(1 true).include?(boolean.strip) end, "string" => Proc.new { |string| string.to_s }, "yaml" => Proc.new { |yaml| YAML::load(yaml) rescue yaml }, "base64Binary" => Proc.new { |bin| Base64.decode64(bin) }, "file" => Proc.new do |file, entity| f = StringIO.new(Base64.decode64(file)) eval "def f.original_filename() '#{entity["name"]}' || 'untitled' end" eval "def f.content_type() '#{entity["content_type"]}' || 'application/octet-stream' end" f end } XML_PARSING.update( "double" => XML_PARSING["float"], "dateTime" => XML_PARSING["datetime"] )
Collects the keys and values of a hash and composes a URL-style query string using ampersand and equal-sign characters.
>> {:foo => "hello", :bar => "goodbye"}.to_query => "bar=goodbye&foo=hello"
Collects the keys and values of a hash and composes a simple XML representation.
>> print ({:greetings => { :english => "hello", :spanish => "hola"}}).to_xml <?xml version="1.0" encoding="UTF-8"?> <hash> <greetings> <english>hello</english> <spanish>hola</spanish> </greetings> </hash>
See the description of the Array::Conversions to_xml
method for a full list of options.
Provides a method for getting the difference between one hash and another.
Returns a hash that includes everything but the given keys. Useful for quickly excluding certain key values from a hash like this:
@person.update_attributes(params[:person].except(:admin))
Provides methods that operate on the keys of a hash. The stringify
and symbolize
methods are used liberally throughout the Rails codebase, which is why it generally doesn’t matter if you pass option names as strings or symbols.
You can use assert_valid_keys
method in your own application code, which takes Rails-style option hashes.
Raises an ArgumentError
if the hash contains any keys not specified in valid_keys
.
def my_method(some_value, options={}) options.assert_valid_keys(:my_conditions, :my_order, ...) ... end
Allows for reverse merging where it’s the keys in the calling hash that win over those in the other_hash
. This is particularly useful for initializing an incoming option hash with default values like this:
def setup(options = {}) options.reverse_merge! :size => 25, :velocity => 10 end
In the example, the default :size
and :velocity
are only set if the options passed in don’t already have those keys set.
Methods to slice a hash to include only the specified keys. Useful for limiting an options hash to valid keys before passing to a method, like this:
def search(criteria = {}) assert_valid_keys(:mass, :velocity, :time) end search(options.slice(:mass, :velocity, :time))
A subclass of Hash
used internally by Rails. As stated in the source file:
This class has dubious semantics and we only have it so that people can write
params[:key]
instead ofparams['key']
.
The Inflections
class transforms words from singular to plural, class names to table names, modularized class names to ones without, and class names to foreign keys. The default inflections for pluralization, singularization, and uncountable words are kept in activesupport/lib/active_support/inflections.rb
.
A singleton instance of Inflections
is yielded by Inflector.inflections
, which can then be used to specify additional inflection rules in your config/environment.rb
file.
Here are some examples:
Inflector.inflections do |inflect| inflect.plural /^(ox)$/i, '1en' inflect.singular /^(ox)en/i, '1' inflect.irregular 'octopus', 'octopi' inflect.uncountable "equipment" end
New rules are added at the top. So in the example, the irregular rule for octopus will now be the first of the pluralization and singularization rules that are checked when an inflection happens. That way Rails can guarantee that your rules run before any of the rules that may already have been loaded.
This API reference lists the inflections methods themselves in the modules where they are actually used: Numeric::Inflections
and String::Inflections
.
Specifies a new irregular that applies to both pluralization and singularization at the same time. The singular
and plural
arguments must be strings, not regular expressions. Simply pass the irregular word in singular and plural form.
irregular 'octopus', 'octopi' irregular 'person', 'people'
Specifies a new pluralization rule and its replacement. The rule
can either be a string or a regular expression. The replacement
should always be a string and may include references to the matched data from the rule by using backslash-number syntax, like this:
Inflector.inflections do |inflect| inflect.plural /^(ox)$/i, '1en' end
Specifies a new singularization rule and its replacement. The rule
can either be a string or a regular expression. The replacement
should always be a string and may include references to the matched data from the rule by using backslash-number syntax, like this:
Inflector.inflections do |inflect| inflect.singular /^(ox)en/i, '1' end
Methods to check whether an integer is even, odd, or a multiple of another number.
JSON stands for “JavaScript Object Notation,” and can be used to serialize data. It is more lightweight than XML and can be easily parsed by JavaScript interpreters, since it is JavaScript’s object literal format.
{ drink: "too much", smoke: "too much" }
Ruby might get better built-in support for JSON in versions 1.9 and above, since literal hash notation that looks exactly like JavaScript’s is being added to the language.
{ :drink: "too much", :smoke: "too much" } # valid hash in Ruby 1.9
Lately JSON has become a popular data transport for Ajax applications. Chapter 12, “Ajax on Rails,” has a section specifically about JSON.
The following words will cause problems if you try to use them as identifiers in your JSON-encoded data, because they are reserved words in JavaScript.
RESERVED_WORDS = %w( abstract delete goto private transient boolean do if protected try break double implements public typeof byte else import return var case enum in short void catch export instanceof static volatile char extends int super while class final interface switch with const finally long synchronized continue float native this debugger for new throw default function package throws )
When this attribute is set to true
, the to_json
method on Hash
will omit quoting string or symbol keys, provided that the resulting keys are valid JavaScript identifiers. Note that this is technically improper JSON (all object keys are supposed to be quoted), so if you need strict JSON compliance, set this option to false
.
ActiveSupport::JSON.unquote_hash_key_identifiers = false
Converts a JSON string into a Ruby object. Decoding is accomplished via intermediate conversion to YAML, which is very close to JSON, syntactically speaking.
Raises ParseError
if invalid JSON is provided.
Converts a Ruby object into a string of JSON.
>> print ActiveSupport::JSON.encode(:drink => "too much") {drink: "too much" }
In practice, it can be quite difficult to encode ActiveRecord
models as JSON because associations lead to circular dependencies:
ActiveSupport::JSON::CircularReferenceError: object references itself
A probable solution is to write custom Ruby classes that contain only the data that you need to serialize.
Returns true
if the word
is a reserved word in JavaScript and will cause problems if used in JSON-encoded data.
Methods added to Ruby’s Kernel
class are available in all contexts.
Turns the current script into a daemon process that detaches from the console. It can be shut down with a TERM
signal.
The source provides pretty much all the explanation you need:
def daemonize exit if fork # Parent exits, child continues Process.setsid # Become session leader exit if fork # Zap session leader Dir.chdir "/" # Release old working directory File.umask 0000 # Ensure sensible umask STDIN.reopen "/dev/null" # Free file descriptors and... STDOUT.reopen "/dev/null", "a" # point them somewhere sensible. STDERR.reopen STDOUT # TODO: better to go to a logfile trap("TERM") { exit } end
Starts a debugging session if ruby-debug
has been loaded. Calls script/server —debugger
to start Mongrel with the debugger (Rails 2.0 only).
Sets $VERBOSE
to true for the duration of the block and back to its original value afterward.
Requires a library with fallback to RubyGems. Warnings during library loading are silenced to increase signal/noise for application warnings.
Silences any stream for the duration of the block.
silence_stream(STDOUT) do puts 'This will never be seen' end puts 'But this will'
Sets $VERBOSE
to false for the duration of the block and back to its original value afterward.
Extensions to the built-in Ruby logger, accessible via the logger
property in various Rails contexts such as ActiveRecord
models and controller classes. Always accessible via the constant RAILS_DEFAULT_LOGGER
. Use of the logger is explained in Chapter 1.
To use the default log formatter as defined in the Ruby core, you need to set a formatter for the logger as in the following example:
logger.formatter = Formatter.new
You can then specify properties such as the datetime format, for example:
logger.datetime_format = "%Y-%m-%d"
Streamlines the all-too-common pattern of wrapping a few lines of code in comments that indicate the beginning and end of a routine, as follows:
logger.debug "Start rendering component (#{options.inspect}): " result = render_component_stuff(...) logger.debug " End of component rendering" result
The same code would be written with around_debug
like this:
around_debug "Start rendering component (#{options.inspect}):", "End of component rendering" do render_component_stuff(...) end
Gets the current logging datetime format. Returns nil
if the formatter does not support datetime formatting.
Sets the format string passed to strftime
to generate the log’s timestamp string.
Gets the current formatter. The Rails default formatter is a SimpleFormatter
, which only displays the log message.
Extensions to Ruby’s Module
class, available in all contexts.
This super-useful method allows you to easily make aliases for attributes, including their reader, writer, and query methods.
In the following example, the Content
class is serving as the base class for Email
using STI, but e-mails should have a subject, not a title:
class Content < ActiveRecord::Base # has column named 'title' end class Email < Content alias_attribute :subject, :title end
As a result of the alias_attribute
, you can see in the following example that the title
and subject
attributes become interchangeable:
>> e = Email.find(:first) >> e.title => "Superstars" >> e.subject => "Superstars" >> e.subject? => true >> e.subject = "Megastars" => "Megastars" >> e.title => "Megastars"
Encapsulates the following common pattern:
alias_method :foo_without_feature, :foo alias_method :foo, :foo_with_feature
With alias_method_chain
, you simply do one line of code and both aliases are set up for you:
alias_method_chain :foo, :feature
Query and bang methods keep the same punctuation. The following syntax
alias_method_chain :foo?, :feature
is equivalent to
alias_method :foo_without_feature?, :foo? alias_method :foo?, :foo_with_feature?
so you can safely chain foo
, foo?
, and foo!
.
Declares an attribute accessor with an initial default return value.
To give attribute :age
the initial value 25
, you would write the following:
class Person attr_accessor_with_default :age, 25 end
To give attribute :element_name
a dynamic default value, evaluated in scope of self, you would write
attr_accessor_with_default(:element_name) { name.underscore }
Declares attributes backed by internal instance variables names (using an @_
naming convention). Basically just a mechanism to enhance controlled access to sensitive attributes.
For instance, Object
’s copy_instance_variables_from
will not copy internal instance variables.
Declares an attribute reader backed by an internally named instance variable.
Declares an attribute writer backed by an internally named instance variable.
The const_missing
callback is invoked when Ruby can’t find a specified constant in the current scope, which is what makes Rails autoclassloading possible. See the Dependencies
module for more detail.
Provides a delegate class method to easily expose contained objects’ methods as your own. Pass one or more methods (specified as symbols or strings) and the name of the target object as the final :to
option (also a symbol or string). At least one method and the :to
option are required.
Delegation is particularly useful in conjunction with ActiveRecord
associations:
class Greeter < ActiveRecord::Base def hello "hello" end def goodbye "goodbye" end end class LazyFoo < ActiveRecord::Base belongs_to :greeter delegate :hello, :to => :greeter end
Multiple delegates to the same target are allowed:
class Foo < ActiveRecord::Base belongs_to :greeter delegate :hello, :goodbye, :to => :greeter end
Declares that a method has been deprecated. See Deprecation
for more information and usage instructions.
Returns a list of classes in which this module is included, using Ruby’s ObjectSpace
.
Returns the constants that have been defined locally by this object and not in an ancestor. This method may miss some constants if their definition in the ancestor is identical to their definition in the receiver.
Defines one or more module attribute reader and writer methods in the style of the native attr*
accessors for instance attributes.
Returns the module that contains this one; if this is a root module, such as ::MyModule
, then Object
is returned.
Returns all the parents of this module, ordered from nested outward. The receiver is not contained within the result.
The LoadError
raised by Rails when its name-based classloading mechanism fails to find a class. An explanation of how Rails looks for and loads classes is in Chapter 1, in the “Rails, Modules, and Auto-Loading Code” section.
The chars
proxy enables you to work transparently with multibyte encodings in the Ruby String
class without having extensive knowledge about encoding.
A Chars
object accepts a string upon initialization and proxies String
methods in an encoding-safe manner. All the normal String
methods are proxied through the Chars
object, and can be accessed through the chars
method. Methods that would normally return a String
object now return a Chars
object so that methods can be chained together safely.
>> "The Perfect String".chars.downcase.strip.normalize => "the perfect string"
Chars
objects are perfectly interchangeable with String
objects as long as no explicit class checks are made. If certain methods do explicitly check the class, call to_s
before you pass Chars
objects to them, to go back to a normal String
object:
bad.explicit_checking_method("T".chars.downcase.to_s)
The actual operations on the string are delegated to handlers. Theoretically handlers can be implemented for any encoding, but the default handler handles UTF-8. This handler is set during initialization.
Note that a few methods are defined on Chars
instead of the handler because they are defined on Object
or Kernel
and method_missing
(the method used for delegation) can’t catch them.
If you want to implement your own handler or use a third-party one, you can set it on the Chars
class manually:
ActiveSupport::Multibyte::Chars.handler = MyHandler
Look at the UTF8Handler
source for an example of how to implement your own handler. If you implement your own handler to work on anything but UTF-8, you probably also want to override the handler
on Chars
.
Returns -1, 0, or +1 depending on whether the Chars
object is to be sorted before, equal to, or after the object on the right side of the operation. In other words, it works exactly as you would expect it to.
Like String
’s version, only this method returns the character offset (in codepoints) instead of a byte offset.
Returns the proper handler for the contained string depending on $KCODE
and the encoding of the string. This method is used internally by Rails to always redirect messages to the proper classes depending on the context.
Tries to forward all undefined methods to the designated handler. When a method is not defined on the handler, it sends it to the contained string instead. Also responsible for making the bang (!
) methods destructive, since a handler doesn’t have access to change an enclosed string instance.
Remember that everything in Ruby is an object, even nil
, which is a special reference to a singleton instance of the NilClass
.
Besides blank?
, the extensions to nil
try to raise more descriptive error messages, to help Rails newbies. The aim is to ensure that when developers pass nil
to methods unintentionally, instead of NoMethodError
and the name of some method used by the framework, they’ll see a message explaining what type of object was expected. The behavior was named whiny nil as an inside joke.
Method missing magic is used to capture the method that was erroneously invoked on nil
. The method name is looked up in a hash containing method names indexed to Rails classes, so that a helpful suggestion can be attempted.
If you’ve done any amount of Rails programming, you’re probably familiar with the output of this error-helping process, as the description of a NoMethodError
:
You have a nil object when you didn’t expect it! You might have expected an instance of class_name. The error occurred while evaluating nil.method_name.
The whiny nil
behavior can be controlled in the individual environment configurations with the following line:
config.whiny_nils = true
Rails has it set to true
by default in development and test modes, and false
in production mode.
As with Hash
, ActiveSupport only adds the blank?
method directly to the Numeric
class.
Enables the use of byte calculations and declarations, like 45.bytes + 2.6.megabytes
.
exabyte
and exabytes
[2]Returns self * 1024.petabytes
.
Syntax sugar that enables the use of seconds-based time calculations and declarations directly on numbers, like this:
1.minute + 45.seconds == 105.seconds #=> true
The methods in this module use Time
’s advance
method for precise date calculations as well as adding or subtracting their results from a Time
object:
# equivalent to Time.now.advance(:months => 1) 1.month.from_now # equivalent to Time.now.advance(:years => 2) 2.years.from_now # equivalent to Time.now.advance(:months => 4, :years => 5) (4.months + 5.years).from_now
While these methods provide precise calculation when used as in the example, care should be taken concerning loss of precision when typecasting them to integral values. Ruby’s core Date
and Time
classes should be used for high-precision date and time arithmetic.
An amount of time in the future, from a specified time (which defaults to Time.now
).
Rails mixes quite a few methods into the Object
class, meaning they are available via every other object at runtime.
Makes backticks behave (somewhat more) similarly on all platforms. On win32 `nonexistent_command`
raises Errno::ENOENT
; on UNIX, the spawned shell prints a message to STDERR
and sets $?
. Emulates UNIX on the former but not the latter, by making win32
print a message to STDERR
.
A duck-type assistant method, with a really simple implementation:
def acts_like?(duck) respond_to? "acts_like_#{duck}?" end
ActiveSupport
extends Date
to define an acts_like_date?
method, and extends Time
to define acts_like_time?
. As a result, we can do x.acts_like?(:time)
and y.acts_like?(:date)
to do duck-type-safe comparisons, since classes that we want to act like Time
simply need to define an acts_like_time?
method that returns true
.
An empty string (""
), a string with only whitespace (" "
), nil
, an empty array ([])
, and an empty hash ({}
) are all considered blank.
Works by calling strip
(to remove whitespace) if that method is available, and then calling empty?
. If no empty?
method is available, simply returns the negation of self.
Useful to copy instance variables from one object to another.
Returns an array of modules that are in the ancestors
of a given object.
To illustrate, here’s a list of modules included in a Person
class belonging to one of my real projects. Is the list bigger than you might expect?
>> Person.find(:first).extended_by.sort_by(&:name) => [ActiveRecord::Acts::List, ActiveRecord::Acts::NestedSet, ActiveRecord::Acts::Tree, ActiveRecord::Aggregations, ActiveRecord::Associations, ActiveRecord::AttributeMethods, ActiveRecord::Calculations, ActiveRecord::Callbacks, ActiveRecord::Locking::Optimistic, ActiveRecord::Locking::Pessimistic, ActiveRecord::Observing, ActiveRecord::Reflection, ActiveRecord::Timestamp, ActiveRecord::Transactions, ActiveRecord::Validations, ActiveRecord::XmlSerialization, Base64, Base64::Deprecated, ERB::Util, GeoKit::ActsAsMappable, LatLongZoom, PP::ObjectMixin, PhotosMixin, Reloadable::Deprecated, ScottBarron::Acts::StateMachine, UJS::BehaviourHelper, UJS::Helpers, UJS::JavascriptProxies, WhiteListHelper, WillPaginate::Finder]
Invokes extend
on an object with each module included by the object
argument, with a really simple implementation:
def extend_with_included_modules_from(object) object.extended_by.each { |mod| extend mod } end
The instance_exec
method allows you to (somewhat efficiently) take a block of Ruby code and execute it in the context of another object.
>> t = Tag.find(:first) => #<Tag id: 1, name: "politics"> >> t.instance_exec { name } => "politics"
Returns instance variables of an object as a hash.
>> Tag.find(:first).instance_values => {"attributes" => {"name" => "politics", "id" => "1"}}
Rails overrides Ruby’s built-in load
method to tie it into the Dependencies
subsystem.
Rails overrides Ruby’s built-in require
method to tie it into the Dependencies
subsystem.
Used internally by Rails. Invokes Dependencies.associate_with (file_name)
.
Used internally by Rails. Invokes Dependencies.require_or_load(file_name)
.
A Ruby-ized realization of the K combinator, courtesy of Mikael Brockman. Simplifies the idiom where you know you will want to return a certain object; you just want to do a couple of things to it first, like this:
def foo returning values = [] do values << 'bar' values << 'baz' end end foo # => ['bar', 'baz']
A slightly more elegant way to access the returning value is via block variable. Here is the same example again, but with a block variable for values
:
def foo returning [] do |values| values << 'bar' values << 'baz' end end foo # => ['bar', 'baz']
Marks the specified constant as unloadable. Unloadable constants are removed each time dependencies are cleared.
Note that marking a constant for unloading need only be done once. Setup or init scripts may list each unloadable constant that will need unloading; constants marked in this way will be removed on every subsequent Dependencies.clear
, as opposed to the first clear only.
The provided constant descriptor const_desc
may be a (nonanonymous) module or class, or a qualified constant name as a string or symbol.
Returns true
if the constant was not previously marked for unloading, false
otherwise.
An elegant way to refactor out common options.
with_options(:class_name => 'Comment', :order => 'id desc') do |post| post.has_many :approved, :conditions => ['approved = ?', true] post.has_many :unapproved, :conditions => ['approved = ?', false] post.has_many :all_comments end
Can also be used with an explicit receiver, which will be passed as a block parameter:
map.with_options :controller => "people" do |people| people.connect "/people", :action => "index" people.connect "/people/:id", :action => "show" end
A hash implementation as a subclass of Ruby Array
. Preserves ordering of its elements, in contrast to normal Ruby hashes. It’s namespaced to prevent conflicts with other implementations. You can assign it to a top-level namespace if you don’t want to constantly use the fully qualified name:
OrderedHash = ActiveSupport::OrderedHash
The normal square bracket operators are implemented, but otherwise, it’s an Array
.
>> oh = ActiveSupport::OrderedHash.new => [] >> oh[:one] = 1 => 1 >> oh[:two] = 2 => 2 >> oh[:three] = 3 => 3 >> oh => [[:one, 1], [:two, 2], [:three, 3]]
A subclass of OrderedHash
that adds a method-missing implementation so that hash elements can be accessed and modified using normal attribute semantics, dot-notation:
def method_missing(name, *args) if name.to_s =~ /(.*)=$/ self[$1.to_sym] = args.first else self[name] end end
Rails trivia: The initializer.rb
file contains an exact duplicate of this class, except in the Rails
namespace. The reason? It’s needed before ActiveSupport
is loaded, as part of the startup process.
Extensions to Ruby’s Proc
class that make instance_exec
magic possible.
Facilitates binding of a proc to an arbitrary object, so that it executes in that object’s context when it is called. This technique makes the instance_exec
method of Object
possible.
To demonstrate in the following example, we first verify that name
is not defined in the current context. Then we create a Proc
object that invokes name
, and show that it still generates a NameError
when we call
it.
>> name NameError: undefined local variable or method `name' ... >> p = Proc.new { name } => #<Proc:0x031bf5b4@(irb):15> >> p.call NameError: undefined local variable or method `name' ...
Now, we use the bind
method to easily call our proc in the context of two separate objects that do define name
:
>> p.bind(Person.find(:first)).call => "Admin" >> p.bind(Tag.find(:first)).call => "politics"
The clever implementation works by first defining a new method on the target object using a generated unique name and the body of the proc. Then a reference to the new Method
instance is saved, and it is removed from the target object using remove_method
. Finally, the target object is bound to the new method and returned, so that call
executes the proc in the context of the target object.
Extensions to Ruby’s Range
class.
The DATE_FORMATS
constant holds a single proc used to convert a range into a SQL expression:
DATE_FORMATS = { :db => Proc.new {|start, stop| "BETWEEN '#{start.to_s(:db)}' AND '#{stop.to_s(:db)}'" } }
Generates a formatted string representation of the range.
>> (20.days.ago..10.days.ago).to_formatted_s => "Fri Aug 10 22:12:33 -0400 2007..Mon Aug 20 22:12:33 -0400 2007" >> (20.days.ago..10.days.ago).to_formatted_s(:db) => "BETWEEN '2007-08-10 22:12:36' AND '2007-08-20 22:12:36'"
Extensions to Ruby’s String
class.
Returns the character at position
, treating the string as an array (where 0 is the first character). Returns nil
if the position exceeds the length of the string.
"hello".at(0) # => "h" "hello".at(4) # => "o" "hello".at(10) # => nil
Returns the first number
of characters in a string.
"hello".first # => "h" "hello".first(2) # => "he" "hello".first(10) # => "hello"
Returns the remaining characters of a string from the position
, treating the string as an array (where 0 is the first character). Returns nil
if the position exceeds the length of the string.
"hello".at(0) # => "hello" "hello".at(2) # => "llo" "hello".at(10) # => nil
Returns the last number
of characters in a string.
"hello".last # => "o" "hello".last(2) # => "lo" "hello".last(10) # => "hello"
Returns the beginning of the string up to the position
treating the string as an array (where 0 is the first character). Doesn’t produce an error when the position
exceeds the length of the string.
"hello".at(0) # => "h" "hello".at(2) # => "hel" "hello".at(10) # => "hello"
String inflections define new methods on the String
class to transform names for different purposes.
For instance, you can figure out the name of a database from the name of a class:
"ScaleScore".tableize => "scale_scores"
If you get frustrated by the limitations of Rails inflections, try the most excellent Linguistics library by Michael Granger at http://www.deveiate.org/projects/Linguistics. It doesn’t do all of the same inflections as Rails, but the ones that it does do, it does better. (See titleize
for an example.)
By default, camelize
converts strings to UpperCamelCase. If the argument to camelize
is set to :lower
, then camelize
produces lowerCamelCase. The camelize
method will also convert “/” to “::”, which is useful for converting paths to namespaces.
"active_record".camelize #=> "ActiveRecord" "active_record".camelize(:lower) #=> "activeRecord" "active_record/errors".camelize #=> "ActiveRecord::Errors" "active_record/errors".camelize(:lower) #=> "activeRecord::Errors"
Creates a class name from a table name; used by ActiveRecord
to turn table names to model classes. Note that the classify
method returns a string and not a Class
. (To convert to an actual class, follow classify
with constantize
.)
"egg_and_hams".classify #=> "EggAndHam" "post".classify #=> "Post"
The constantize
method tries to find a declared constant with the name specified in the string. It raises a NameError
if a matching constant is not located.
"Module".constantize #=> Module "Class".constantize #=> Class
Removes the module prefixes from a fully qualified module or class name.
>> "ActiveRecord::CoreExtensions::String::Inflections".demodulize => "Inflections" "Inflections".demodulize #=> "Inflections"
Creates a foreign key name from a class name.
"Message".foreign_key #=> "message_id" "Message".foreign_key(false) #=> "messageid" "Admin::Post".foreign_key #=> "post_id"
Capitalizes the first word of a string, turns underscores into spaces, and strips _id
. Similar to the titleize
method in that it is intended for creating pretty output.
"employee_salary" #=> "Employee salary" "author_id" #=> "Author"
Returns the plural form of the word in the string.
"post".pluralize #=> "posts" "octopus".pluralize #=> "octopi" "sheep".pluralize #=> "sheep" "words".pluralize #=> "words" "the blue mailman".pluralize #=> "the blue mailmen" "CamelOctopus".pluralize #=> "CamelOctopi"
The reverse of pluralize
; returns the singular form of a word in a string.
"posts".singularize #=> "post" "octopi".singularize #=> "octopus" "sheep".singluarize #=> "sheep" "word".singluarize #=> "word" "the blue mailmen".singularize #=> "the blue mailman" "CamelOctopi".singularize #=> "CamelOctopus"
Creates a plural and underscored database table name based on Rails conventions. Used by ActiveRecord
to determine the proper table name for a model class. This method uses the pluralize
method on the last word in the string.
"RawScaledScorer".tableize #=> "raw_scaled_scorers" "egg_and_ham".tableize #=> "egg_and_hams" "fancyCategory".tableize #=> "fancy_categories"
Capitalizes all the words and replaces some characters in the string to create a nicer-looking title. The titleize
method is meant for creating pretty output and is not used in the Rails internals.
>> "The light on the beach was like a sinus headache".titleize => "The Light On The Beach Was Like A Sinus Headache"
It’s also not perfect. Among other things, it capitalizes words inside the sentence that it probably shouldn’t, like “a” and “the.” It also has a hard time with apostrophes:
>> "Her uncle's cousin's record albums".titleize => "Her Uncle'S Cousin'S Record Albums"
The Linguistics
gem mentioned in the beginning of this section has an excellent proper_noun
method that in my experience works much better than titleize
:
>> "Her uncle's cousin's record albums".en.proper_noun => "Her Uncle's Cousin's Record Albums"
Contains a custom string iterator that can be used to operate on each character of a string sequentially, in a Unicode-safe fashion.
Provides String
with additional condition methods.
Defines methods for handling Unicode strings.
The chars
method returns an instance of the ActiveSupport::Multibyte::Chars
class, a Unicode-safe proxy encapsulating the original string. Unicode versions of all the String
methods are defined on the chars
proxy, which gives you assurance that you won’t end up with garbled or ruined string data.
Undefined methods are forwarded to String
, so all of the string overrides can also be called through the chars
proxy with confidence.
Here are some examples:
name = 'Claus Müller' name.reverse #=> "rell??M sualC" # garbled!! name.length #=> 13 # wrong!! name.chars.reverse.to_s #=> "rellüM sualC" name.chars.length #=> 12
All the methods on the chars
proxy that normally return a string will return a chars
proxy object instead. This allows method chaining on the result of any of these methods without a problem.
name.chars.reverse.length #=> 12
The Char
proxy class tries to be as interchangeable with String
as possible: sorting and comparing between String
and Chars
objects work as expected. The bang (!
) methods change the internal string representation in the Chars
object. Interoperability problems should be resolved easily with a to_s
call.
For more information about the methods defined on the Chars
proxy, see Multibyte::Chars
and Multibyte::Handlers::UTF8Handler
.
Extensions to Ruby’s built-in Symbol
class.
Rails adds a number of assertions to the basic ones provided with Test::Unit
.
Tests whether a numeric difference in the return value of an expression is a result of what is evaluated in the yielded block. (Easier to demonstrate than to explain!)
The following example eval’s the expression Article.count
and saves the result. Then it yields to the block, which will execute the post :create
and return control to the assert_difference
method. At that point, Article.count
is eval’d again, and the difference is asserted to be 1
(the default difference).
assert_difference 'Article.count' do post :create, :article => {...} end
Any arbitrary expression can be passed in and evaluated:
assert_difference 'assigns(:article).comments(:reload).size' do post :create, :comment => {...} end
Arbitrary difference values may be specified. The default is +1, but negative numbers are okay too:
assert_difference 'Article.count', -1 do post :delete, :id => ... end
An array of expressions can also be passed in—each will be evaluated:
assert_difference [ 'Article.count', 'Post.count' ], +2 do post :create, :article => {...} end
A error message can be specified:
assert_difference 'Article.count', -1, "Article should be destroyed" do post :delete, :id => ... end
Extensions to Ruby’s built-in Time
class.
Returns the number of days in the given month. If a year is given, February will return the correct number of days for leap years. Otherwise, this method will always report February as having 28 days.
Wraps the class method time_with_datetime_fallback
with utc_or_local
argument set to :local
.
Returns a new Time
if the requested year can be accommodated by Ruby’s Time
class. The range of the Time
class is either 1970..2038 or 1902..2038, depending on the host system’s architecture. Years outside the supported range will return a DateTime
object.
Implemented by the plus_with_duration
method. It allows addition of times like this:
expiration_time = Time.now + 3.days
Implemented by the minus_with_duration
method. It allows addition of times like this:
two_weeks_ago = Time.now - 2.weeks
Provides precise Time
calculations. The options
parameter takes a hash with any of the keys :months
, :days
, :years
, :hour
, :min
, :sec
, and :usec
.
Returns a new Time
representing the time a number of seconds into the past; this is basically a wrapper around the Numeric
extension of the same name. For the best accuracy, do not use this method in combination with x.months
; use months_ago
instead!
Returns a new Time
representing the “start” of the current instance’s day, hard-coded to 00:00 hours.
Returns a new Time
representing the start of the month (1st of the month, 00:00 hours).
Returns a new Time
representing the start of the calendar quarter (1st of January, April, July, October, 00:00 hours).
Returns a new Time
representing the “start” of the current instance’s week, hard-coded to Monday at 00:00 hours.
Returns a new Time
representing the start of the year (1st of January, 00:00 hours).
Returns a new Time
where one or more of the elements have been changed according to the options
parameter. The valid date options are :year
, :month
, :day
. The valid time options are :hour
, :min
, :sec
, :offset
, and :start
.
Returns a new Time
representing the end of the month (last day of the month, 00:00 hours).
Returns a new Time
representing the time a number of specified months
into the past.
The opposite of months_ago
. Returns a new Time
representing the time a number of specified months
into the future.
Returns a new Time
representing the time a number of seconds
into the future starting from the instance time. This method is basically a wrapper around the Numeric
extension of the same name. For best accuracy, do not use this method in combination with x.months
; use months_since
instead!
The opposite of years_ago
. Returns a new Time
representing the time a number of specified years
into the future.
Extensions to Ruby’s Time
class to convert time objects into different convenient string representations and other objects.
The DATE_FORMATS
hash holds formatting patterns used by the to_formatted_s
method to convert a Time
object into a string representation:
DATE_FORMATS = { :db => "%Y-%m-%d %H:%M:%S", :time => "%H:%M", :short => "%d %b %H:%M", :long => "%B %d, %Y %H:%M", :long_ordinal => lambda { |time| time.strftime("%B #{time.day.ordinalize}, %Y %H:%M") }, :rfc822 => "%a, %d %b %Y %H:%M:%S %z" }
Returns a new DateTime
object based on a Time
, preserving the utc
offset. Basically a wrapper around the DateTime.civil
factory method:
DateTime.civil(year, month, day, hour, min, sec, Rational(utc_offset, 86400), 0)
A value object representing a timezone. A timezone is simply a named offset (in seconds) from GMT. Note that two timezone objects are only equivalent if they have both the same offset and the same name.
When you have users spread out across the world, you generally want to store times on the server as UTC time, and store the user’s timezone offset in association with their user accounts. That way, whenever you display a time for a user, you can adjust the time stored on the server to their local timezone.
Peter Marklund has a concise tutorial on the technique that you’ll want to read at http://www.marklunds.com/articles/one/311. Pay attention to his advice to use the TZInfo
Ruby library—it understands how to deal with Daylight Savings Time, whereas the Rails version does not.
Peter’s tutorial covers everything from setting up TZInfo
to adding timezone data to your User
class with composed_of
, and UI issues such as collecting the user’s time zone setting using a Rails time_zone_select
helper method.
US_ZONES
is a regular expression that matches the names of all timezones in the USA.
US_ZONES = /US|Arizona|Indiana|Hawaii|Alaska/
Locates a specific timezone object. If the argument is a string, it is interpreted to mean the name of the timezone to locate.
>> TimeZone['Dublin'] => #<TimeZone:0x3208390 @name="Dublin", @utc_offset=0>
If it is a numeric value it is either the hour offset, or the second offset, of the timezone to find. (The first one with that offset will be returned.)
Returns nil
if no such timezone is known to the system.
Returns an array of all TimeZone
objects. There are multiple TimeZone
objects per timezone (in many cases) to make it easier for users to find their own timezone.
This is the full array of timezone data included in the TimeZone
class:
[[-43_200, "International Date Line West" ], [-39_600, "Midway Island", "Samoa" ], [-36_000, "Hawaii" ], [-32_400, "Alaska" ], [-28_800, "Pacific Time (US & Canada)", "Tijuana" ], [-25_200, "Mountain Time (US & Canada)", "Chihuahua", "La Paz", "Mazatlan", "Arizona" ], [-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara", "Mexico City", "Monterrey", "Central America" ], [-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota", "Lima", "Quito" ], [-14_400, "Atlantic Time (Canada)", "Caracas", "La Paz", "Santiago" ], [-12_600, "Newfoundland" ], [-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ], [ -7_200, "Mid-Atlantic" ], [ -3_600, "Azores", "Cape Verde Is." ], [ 0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca", "Monrovia" ], [ 3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague", "Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels", "Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin", "Bern", "Rome", "Stockholm", "Vienna", "West Central Africa" ], [ 7_200, "Bucharest", "Cairo", "Helsinki", "Kyev", "Riga", "Sofia", "Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk", "Jerusalem", "Harare", "Pretoria" ], [ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh", "Nairobi", "Baghdad" ], [ 12_600, "Tehran" ], [ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ], [ 16_200, "Kabul" ], [ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ], [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi" ], [ 20_700, "Kathmandu" ], [ 21_600, "Astana", "Dhaka", "Sri Jayawardenepura", "Almaty", "Novosibirsk" ], [ 23_400, "Rangoon" ], [ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ], [ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi", "Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk", "Ulaan Bataar" ], [ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ], [ 34_200, "Darwin", "Adelaide" ], [ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart", "Vladivostok", "Guam", "Port Moresby" ], [ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ], [ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland", "Wellington" ], [ 46_800, "Nuku'alofa" ]]
Creates a new TimeZone
instance with the given name and offset.
>> TimeZone.create("Atlanta", -5.hours) => #<TimeZone:0x31e6d44 @name="Atlanta", @utc_offset=-18000 seconds>
Returns a TimeZone
instance with the given name, or nil
if no such TimeZone
instance exists. This method exists to support the use of this class with the composed_of
macro-style method on ActiveRecord
models, like this:
class Person < ActiveRecord::Base composed_of :tz, :class_name => 'TimeZone', :mapping => %w(time_zone name) end
A convenience method for returning a collection of TimeZone
objects for timezones in the USA.
>> TimeZone.us_zones.map(&:name) => ["Hawaii", "Alaska", "Pacific Time (US & Canada)", "Arizona", "Mountain Time (US & Canada)", "Central Time (US & Canada)", "Eastern Time (US & Canada)", "Indiana (East)"]
Compares this timezone to the parameter. The two are compared first based on their offsets, and then by name.
Adjusts the given time to this timezone.
>> TimeZone['Fiji'].adjust(Time.now) => Sat Sep 01 10:42:42 UTC 2007
Returns the offset of this timezone as a formatted string, in the format HH:MM
. If the offset is zero, this method will return an empty string. If colon
is false
, a colon will not be inserted into the output.
This constructor is used via TimeZone.create
. Instantiates a new TimeZone
object with the given name and offset. The offset is the number of seconds that this timezone is offset from UTC (GMT). Seconds were chosen as the offset unit because that is the unit that Ruby uses to represent timezone offsets (see Time
’s utc_offset
method).
Returns Time.now
adjusted to this timezone.
>> Time.now => Fri Aug 31 22:39:58 -0400 2007 >> TimeZone['Fiji'].now => Sat Sep 01 14:40:00 UTC 2007
Remember that everything in Ruby is an object, even true
, which is a special reference to a singleton instance of the TrueClass
.
1. | For an interesting summary of why zero is considered by many to be an even number, read http://ask.yahoo.com/20020909.html. |
2. | Bytes Trivia: According to an IDC study commissioned by storage vendor EMC, 161 exabytes of digital information were created and copied in 2006. One exabyte equals a billion gigabytes. By 2010, IDC expects the volume of annual data created and copied to rise sixfold to 988 exabytes. |
3.146.34.146