update AS docs [ci skip]

This commit is contained in:
Francesco Rodriguez 2012-09-17 00:22:18 -05:00
parent c1c9f1c7b9
commit d71d5ba71f
23 changed files with 376 additions and 327 deletions

View File

@ -1,22 +1,29 @@
module ActiveSupport
# Backtraces often include many lines that are not relevant for the context under review. This makes it hard to find the
# signal amongst the backtrace noise, and adds debugging time. With a BacktraceCleaner, filters and silencers are used to
# remove the noisy lines, so that only the most relevant lines remain.
# Backtraces often include many lines that are not relevant for the context
# under review. This makes it hard to find the signal amongst the backtrace
# noise, and adds debugging time. With a BacktraceCleaner, filters and
# silencers are used to remove the noisy lines, so that only the most relevant
# lines remain.
#
# Filters are used to modify lines of data, while silencers are used to remove lines entirely. The typical filter use case
# is to remove lengthy path information from the start of each line, and view file paths relevant to the app directory
# instead of the file system root. The typical silencer use case is to exclude the output of a noisy library from the
# backtrace, so that you can focus on the rest.
# Filters are used to modify lines of data, while silencers are used to remove
# lines entirely. The typical filter use case is to remove lengthy path
# information from the start of each line, and view file paths relevant to the
# app directory instead of the file system root. The typical silencer use case
# is to exclude the output of a noisy library from the backtrace, so that you
# can focus on the rest.
#
# bc = BacktraceCleaner.new
# bc.add_filter { |line| line.gsub(Rails.root, '') }
# bc.add_silencer { |line| line =~ /mongrel|rubygems/ }
# bc.clean(exception.backtrace) # will strip the Rails.root prefix and skip any lines from mongrel or rubygems
#
# To reconfigure an existing BacktraceCleaner (like the default one in Rails) and show as much data as possible, you can
# always call <tt>BacktraceCleaner#remove_silencers!</tt>, which will restore the backtrace to a pristine state. If you
# need to reconfigure an existing BacktraceCleaner so that it does not filter or modify the paths of any lines of the
# backtrace, you can call BacktraceCleaner#remove_filters! These two methods will give you a completely untouched backtrace.
# To reconfigure an existing BacktraceCleaner (like the default one in Rails)
# and show as much data as possible, you can always call
# <tt>BacktraceCleaner#remove_silencers!</tt>, which will restore the
# backtrace to a pristine state. If you need to reconfigure an existing
# BacktraceCleaner so that it does not filter or modify the paths of any lines
# of the backtrace, you can call BacktraceCleaner#remove_filters! These two
# methods will give you a completely untouched backtrace.
#
# Inspired by the Quiet Backtrace gem by Thoughtbot.
class BacktraceCleaner
@ -24,7 +31,8 @@ module ActiveSupport
@filters, @silencers = [], []
end
# Returns the backtrace after all filters and silencers have been run against it. Filters run first, then silencers.
# Returns the backtrace after all filters and silencers have been run
# against it. Filters run first, then silencers.
def clean(backtrace, kind = :silent)
filtered = filter(backtrace)
@ -38,7 +46,8 @@ module ActiveSupport
end
end
# Adds a filter from the block provided. Each line in the backtrace will be mapped against this filter.
# Adds a filter from the block provided. Each line in the backtrace will be
# mapped against this filter.
#
# # Will turn "/my/rails/root/app/models/person.rb" into "/app/models/person.rb"
# backtrace_cleaner.add_filter { |line| line.gsub(Rails.root, '') }
@ -46,8 +55,8 @@ module ActiveSupport
@filters << block
end
# Adds a silencer from the block provided. If the silencer returns true for a given line, it will be excluded from
# the clean backtrace.
# Adds a silencer from the block provided. If the silencer returns +true+
# for a given line, it will be excluded from the clean backtrace.
#
# # Will reject all lines that include the word "mongrel", like "/gems/mongrel/server.rb" or "/app/my_mongrel_server/rb"
# backtrace_cleaner.add_silencer { |line| line =~ /mongrel/ }
@ -55,8 +64,9 @@ module ActiveSupport
@silencers << block
end
# Will remove all silencers, but leave in the filters. This is useful if your context of debugging suddenly expands as
# you suspect a bug in one of the libraries you use.
# Will remove all silencers, but leave in the filters. This is useful if
# your context of debugging suddenly expands as you suspect a bug in one of
# the libraries you use.
def remove_silencers!
@silencers = []
end

View File

@ -3,30 +3,33 @@ require 'active_support/core_ext/hash/keys'
module ActiveSupport
module Benchmarkable
# Allows you to measure the execution time of a block in a template and records the result to
# the log. Wrap this block around expensive operations or possible bottlenecks to get a time
# reading for the operation. For example, let's say you thought your file processing method
# was taking too long; you could wrap it in a benchmark block.
# Allows you to measure the execution time of a block in a template and
# records the result to the log. Wrap this block around expensive operations
# or possible bottlenecks to get a time reading for the operation. For
# example, let's say you thought your file processing method was taking too
# long; you could wrap it in a benchmark block.
#
# <% benchmark "Process data files" do %>
# <% benchmark 'Process data files' do %>
# <%= expensive_files_operation %>
# <% end %>
#
# That would add something like "Process data files (345.2ms)" to the log, which you can then
# use to compare timings when optimizing your code.
# That would add something like "Process data files (345.2ms)" to the log,
# which you can then use to compare timings when optimizing your code.
#
# You may give an optional logger level (:debug, :info, :warn, :error) as the :level option.
# The default logger level value is :info.
# You may give an optional logger level (<tt>:debug</tt>, <tt>:info</tt>,
# <tt>:warn</tt>, <tt>:error</tt>) as the <tt>:level</tt> option. The
# default logger level value is <tt>:info</tt>.
#
# <% benchmark "Low-level files", :level => :debug do %>
# <% benchmark 'Low-level files', level: :debug do %>
# <%= lowlevel_files_operation %>
# <% end %>
#
# Finally, you can pass true as the third argument to silence all log activity (other than the
# timing information) from inside the block. This is great for boiling down a noisy block to
# just a single statement that produces one log line:
# Finally, you can pass true as the third argument to silence all log
# activity (other than the timing information) from inside the block. This
# is great for boiling down a noisy block to just a single statement that
# produces one log line:
#
# <% benchmark "Process data files", :level => :info, :silence => true do %>
# <% benchmark 'Process data files', level: :info, silence: true do %>
# <%= expensive_and_chatty_files_operation %>
# <% end %>
def benchmark(message = "Benchmarking", options = {})
@ -44,7 +47,6 @@ module ActiveSupport
end
# Silence the logger during the execution of the block.
#
def silence
old_logger_level, logger.level = logger.level, ::Logger::ERROR if logger
yield

View File

@ -45,8 +45,8 @@ module ActiveSupport
# Any additional arguments will be passed to the corresponding cache store
# class's constructor:
#
# ActiveSupport::Cache.lookup_store(:file_store, "/tmp/cache")
# # => same as: ActiveSupport::Cache::FileStore.new("/tmp/cache")
# ActiveSupport::Cache.lookup_store(:file_store, '/tmp/cache')
# # => same as: ActiveSupport::Cache::FileStore.new('/tmp/cache')
#
# If the first argument is not a Symbol, then it will simply be returned:
#
@ -110,9 +110,9 @@ module ActiveSupport
#
# cache = ActiveSupport::Cache::MemoryStore.new
#
# cache.read("city") # => nil
# cache.write("city", "Duckburgh")
# cache.read("city") # => "Duckburgh"
# cache.read('city') # => nil
# cache.write('city', "Duckburgh")
# cache.read('city') # => "Duckburgh"
#
# Keys are always translated into Strings and are case sensitive. When an
# object is specified as a key and has a +cache_key+ method defined, this
@ -121,7 +121,7 @@ module ActiveSupport
# elements will be delimited by slashes, and the elements within a Hash
# will be sorted by key so they are consistent.
#
# cache.read("city") == cache.read(:city) # => true
# cache.read('city') == cache.read(:city) # => true
#
# Nil values can be cached.
#
@ -131,14 +131,13 @@ module ActiveSupport
# is a Proc, it will be invoked when each key is evaluated so that you can
# use application logic to invalidate keys.
#
# cache.namespace = lambda { @last_mod_time } # Set the namespace to a variable
# cache.namespace = -> { @last_mod_time } # Set the namespace to a variable
# @last_mod_time = Time.now # Invalidate the entire cache by changing namespace
#
#
# Caches can also store values in a compressed format to save space and
# reduce time spent sending data. Since there is overhead, values must be
# large enough to warrant compression. To turn on compression either pass
# <tt>:compress => true</tt> in the initializer or as an option to +fetch+
# <tt>compress: true</tt> in the initializer or as an option to +fetch+
# or +write+. To specify the threshold at which to compress values, set the
# <tt>:compress_threshold</tt> option. The default threshold is 16K.
class Store
@ -148,8 +147,9 @@ module ActiveSupport
attr_reader :silence, :options
alias :silence? :silence
# Create a new cache. The options will be passed to any write method calls except
# for :namespace which can be used to set the global namespace for the cache.
# Create a new cache. The options will be passed to any write method calls
# except for <tt>:namespace</tt> which can be used to set the global
# namespace for the cache.
def initialize(options = nil)
@options = options ? options.dup : {}
end
@ -168,7 +168,8 @@ module ActiveSupport
@silence = previous_silence
end
# Set to true if cache stores should be instrumented. Default is false.
# Set to +true+ if cache stores should be instrumented.
# Default is +false+.
def self.instrument=(boolean)
Thread.current[:instrument_cache_store] = boolean
end
@ -180,95 +181,97 @@ module ActiveSupport
# Fetches data from the cache, using the given key. If there is data in
# the cache with the given key, then that data is returned.
#
# If there is no such data in the cache (a cache miss), then nil will be
# If there is no such data in the cache (a cache miss), then +nil+ will be
# returned. However, if a block has been passed, that block will be run
# in the event of a cache miss. The return value of the block will be
# written to the cache under the given cache key, and that return value
# will be returned.
#
# cache.write("today", "Monday")
# cache.fetch("today") # => "Monday"
# cache.write('today', 'Monday')
# cache.fetch('today') # => "Monday"
#
# cache.fetch("city") # => nil
# cache.fetch("city") do
# "Duckburgh"
# cache.fetch('city') # => nil
# cache.fetch('city') do
# 'Duckburgh'
# end
# cache.fetch("city") # => "Duckburgh"
# cache.fetch('city') # => "Duckburgh"
#
# You may also specify additional options via the +options+ argument.
# Setting <tt>:force => true</tt> will force a cache miss:
# Setting <tt>force: true</tt> will force a cache miss:
#
# cache.write("today", "Monday")
# cache.fetch("today", :force => true) # => nil
# cache.write('today', 'Monday')
# cache.fetch('today', force: true) # => nil
#
# Setting <tt>:compress</tt> will store a large cache entry set by the call
# in a compressed format.
#
#
# Setting <tt>:expires_in</tt> will set an expiration time on the cache.
# All caches support auto-expiring content after a specified number of
# seconds. This value can be specified as an option to the constructor
# (in which case all entries will be affected), or it can be supplied to
# the +fetch+ or +write+ method to effect just one entry.
#
# cache = ActiveSupport::Cache::MemoryStore.new(:expires_in => 5.minutes)
# cache.write(key, value, :expires_in => 1.minute) # Set a lower value for one entry
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 5.minutes)
# cache.write(key, value, expires_in: 1.minute) # Set a lower value for one entry
#
# Setting <tt>:race_condition_ttl</tt> is very useful in situations where a cache entry
# is used very frequently and is under heavy load. If a cache expires and due to heavy load
# seven different processes will try to read data natively and then they all will try to
# write to cache. To avoid that case the first process to find an expired cache entry will
# bump the cache expiration time by the value set in <tt>:race_condition_ttl</tt>. Yes
# this process is extending the time for a stale value by another few seconds. Because
# of extended life of the previous cache, other processes will continue to use slightly
# stale data for a just a big longer. In the meantime that first process will go ahead
# and will write into cache the new value. After that all the processes will start
# getting new value. The key is to keep <tt>:race_condition_ttl</tt> small.
# Setting <tt>:race_condition_ttl</tt> is very useful in situations where
# a cache entry is used very frequently and is under heavy load. If a
# cache expires and due to heavy load seven different processes will try
# to read data natively and then they all will try to write to cache. To
# avoid that case the first process to find an expired cache entry will
# bump the cache expiration time by the value set in <tt>:race_condition_ttl</tt>.
# Yes, this process is extending the time for a stale value by another few
# seconds. Because of extended life of the previous cache, other processes
# will continue to use slightly stale data for a just a big longer. In the
# meantime that first process will go ahead and will write into cache the
# new value. After that all the processes will start getting new value.
# The key is to keep <tt>:race_condition_ttl</tt> small.
#
# If the process regenerating the entry errors out, the entry will be regenerated
# after the specified number of seconds. Also note that the life of stale cache is
# extended only if it expired recently. Otherwise a new value is generated and
# <tt>:race_condition_ttl</tt> does not play any role.
# If the process regenerating the entry errors out, the entry will be
# regenerated after the specified number of seconds. Also note that the
# life of stale cache is extended only if it expired recently. Otherwise
# a new value is generated and <tt>:race_condition_ttl</tt> does not play
# any role.
#
# # Set all values to expire after one minute.
# cache = ActiveSupport::Cache::MemoryStore.new(:expires_in => 1.minute)
# cache = ActiveSupport::Cache::MemoryStore.new(expires_in: 1.minute)
#
# cache.write("foo", "original value")
# cache.write('foo', 'original value')
# val_1 = nil
# val_2 = nil
# sleep 60
#
# Thread.new do
# val_1 = cache.fetch("foo", :race_condition_ttl => 10) do
# val_1 = cache.fetch('foo', race_condition_ttl: 10) do
# sleep 1
# "new value 1"
# 'new value 1'
# end
# end
#
# Thread.new do
# val_2 = cache.fetch("foo", :race_condition_ttl => 10) do
# "new value 2"
# val_2 = cache.fetch('foo', race_condition_ttl: 10) do
# 'new value 2'
# end
# end
#
# # val_1 => "new value 1"
# # val_2 => "original value"
# # sleep 10 # First thread extend the life of cache by another 10 seconds
# # cache.fetch("foo") => "new value 1"
# # cache.fetch('foo') => "new value 1"
#
# Other options will be handled by the specific cache store implementation.
# Internally, #fetch calls #read_entry, and calls #write_entry on a cache miss.
# +options+ will be passed to the #read and #write calls.
# Internally, #fetch calls #read_entry, and calls #write_entry on a cache
# miss. +options+ will be passed to the #read and #write calls.
#
# For example, MemCacheStore's #write method supports the +:raw+
# option, which tells the memcached server to store all values as strings.
# We can use this option with #fetch too:
#
# cache = ActiveSupport::Cache::MemCacheStore.new
# cache.fetch("foo", :force => true, :raw => true) do
# cache.fetch("foo", force: true, raw: true) do
# :bar
# end
# cache.fetch("foo") # => "bar"
# cache.fetch('foo') # => "bar"
def fetch(name, options = nil)
if block_given?
options = merged_options(options)
@ -307,7 +310,7 @@ module ActiveSupport
# Fetches data from the cache, using the given key. If there is data in
# the cache with the given key, then that data is returned. Otherwise,
# nil is returned.
# +nil+ is returned.
#
# Options are passed to the underlying cache implementation.
def read(name, options = nil)
@ -376,7 +379,7 @@ module ActiveSupport
end
end
# Return true if the cache contains an entry for the given key.
# Return +true+ if the cache contains an entry for the given key.
#
# Options are passed to the underlying cache implementation.
def exist?(name, options = nil)
@ -434,9 +437,10 @@ module ActiveSupport
end
protected
# Add the namespace defined in the options to a pattern designed to match keys.
# Implementations that support delete_matched should call this method to translate
# a pattern that matches names into one that matches namespaced keys.
# Add the namespace defined in the options to a pattern designed to
# match keys. Implementations that support delete_matched should call
# this method to translate a pattern that matches names into one that
# matches namespaced keys.
def key_matcher(pattern, options)
prefix = options[:namespace].is_a?(Proc) ? options[:namespace].call : options[:namespace]
if prefix
@ -452,17 +456,20 @@ module ActiveSupport
end
end
# Read an entry from the cache implementation. Subclasses must implement this method.
# Read an entry from the cache implementation. Subclasses must implement
# this method.
def read_entry(key, options) # :nodoc:
raise NotImplementedError.new
end
# Write an entry to the cache implementation. Subclasses must implement this method.
# Write an entry to the cache implementation. Subclasses must implement
# this method.
def write_entry(key, entry, options) # :nodoc:
raise NotImplementedError.new
end
# Delete an entry from the cache implementation. Subclasses must implement this method.
# Delete an entry from the cache implementation. Subclasses must
# implement this method.
def delete_entry(key, options) # :nodoc:
raise NotImplementedError.new
end
@ -478,7 +485,7 @@ module ActiveSupport
end
# Expand key to be a consistent string value. Invoke +cache_key+ if
# object responds to +cache_key+. Otherwise, to_param method will be
# object responds to +cache_key+. Otherwise, +to_param+ method will be
# called. If the key is a Hash, then keys will be sorted alphabetically.
def expanded_key(key) # :nodoc:
return key.cache_key.to_s if key.respond_to?(:cache_key)
@ -497,7 +504,8 @@ module ActiveSupport
key.to_param
end
# Prefix a key with the namespace. Namespace and key will be delimited with a colon.
# Prefix a key with the namespace. Namespace and key will be delimited
# with a colon.
def namespaced_key(key, options)
key = expanded_key(key)
namespace = options[:namespace] if options
@ -524,17 +532,17 @@ module ActiveSupport
end
end
# Entry that is put into caches. It supports expiration time on entries and can compress values
# to save space in the cache.
# Entry that is put into caches. It supports expiration time on entries and
# can compress values to save space in the cache.
class Entry
attr_reader :created_at, :expires_in
DEFAULT_COMPRESS_LIMIT = 16.kilobytes
class << self
# Create an entry with internal attributes set. This method is intended to be
# used by implementations that store cache entries in a native format instead
# of as serialized Ruby objects.
# Create an entry with internal attributes set. This method is intended
# to be used by implementations that store cache entries in a native
# format instead of as serialized Ruby objects.
def create(raw_value, created_at, options = {})
entry = new(nil)
entry.instance_variable_set(:@value, raw_value)
@ -582,8 +590,8 @@ module ActiveSupport
@compressed
end
# Check if the entry is expired. The +expires_in+ parameter can override the
# value set when the entry was created.
# Check if the entry is expired. The +expires_in+ parameter can override
# the value set when the entry was created.
def expired?
@expires_in && @created_at + @expires_in <= Time.now.to_f
end
@ -602,8 +610,8 @@ module ActiveSupport
@expires_in ? @created_at + @expires_in : nil
end
# Returns the size of the cached value. This could be less than value.size
# if the data is compressed.
# Returns the size of the cached value. This could be less than
# <tt>value.size</tt> if the data is compressed.
def size
if @value.nil?
0

View File

@ -5,22 +5,24 @@ require 'active_support/core_ext/kernel/reporting'
require 'active_support/core_ext/kernel/singleton_class'
module ActiveSupport
# \Callbacks are code hooks that are run at key points in an object's lifecycle.
# The typical use case is to have a base class define a set of callbacks relevant
# to the other functionality it supplies, so that subclasses can install callbacks
# that enhance or modify the base functionality without needing to override
# or redefine methods of the base class.
# Callbacks are code hooks that are run at key points in an object's lifecycle.
# The typical use case is to have a base class define a set of callbacks
# relevant to the other functionality it supplies, so that subclasses can
# install callbacks that enhance or modify the base functionality without
# needing to override or redefine methods of the base class.
#
# Mixing in this module allows you to define the events in the object's lifecycle
# that will support callbacks (via +ClassMethods.define_callbacks+), set the instance
# methods, procs, or callback objects to be called (via +ClassMethods.set_callback+),
# and run the installed callbacks at the appropriate times (via +run_callbacks+).
# Mixing in this module allows you to define the events in the object's
# lifecycle that will support callbacks (via +ClassMethods.define_callbacks+),
# set the instance methods, procs, or callback objects to be called (via
# +ClassMethods.set_callback+), and run the installed callbacks at the
# appropriate times (via +run_callbacks+).
#
# Three kinds of callbacks are supported: before callbacks, run before a certain event;
# after callbacks, run after the event; and around callbacks, blocks that surround the
# event, triggering it when they yield. Callback code can be contained in instance
# methods, procs or lambdas, or callback objects that respond to certain predetermined
# methods. See +ClassMethods.set_callback+ for details.
# Three kinds of callbacks are supported: before callbacks, run before a
# certain event; after callbacks, run after the event; and around callbacks,
# blocks that surround the event, triggering it when they yield. Callback code
# can be contained in instance methods, procs or lambdas, or callback objects
# that respond to certain predetermined methods. See +ClassMethods.set_callback+
# for details.
#
# class Record
# include ActiveSupport::Callbacks
@ -61,10 +63,11 @@ module ActiveSupport
# Runs the callbacks for the given event.
#
# Calls the before and around callbacks in the order they were set, yields
# the block (if given one), and then runs the after callbacks in reverse order.
# the block (if given one), and then runs the after callbacks in reverse
# order.
#
# If the callback chain was halted, returns +false+. Otherwise returns the result
# of the block, or +true+ if no block is given.
# If the callback chain was halted, returns +false+. Otherwise returns the
# result of the block, or +true+ if no block is given.
#
# run_callbacks :save do
# save
@ -182,17 +185,17 @@ module ActiveSupport
# Compile around filters with conditions into proxy methods
# that contain the conditions.
#
# For `set_callback :save, :around, :filter_name, :if => :condition':
# For `set_callback :save, :around, :filter_name, if: :condition':
#
# def _conditional_callback_save_17
# if condition
# filter_name do
# def _conditional_callback_save_17
# if condition
# filter_name do
# yield self
# end
# else
# yield self
# end
# else
# yield self
# end
# end
def define_conditional_callback
name = "_conditional_callback_#{@kind}_#{next_id}"
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
@ -211,7 +214,7 @@ module ActiveSupport
# Options support the same options as filters themselves (and support
# symbols, string, procs, and objects), so compile a conditional
# expression based on the options
# expression based on the options.
def recompile_options!
conditions = ["true"]
@ -230,19 +233,19 @@ module ActiveSupport
#
# Arrays:: Used in conditions. This is used to specify
# multiple conditions. Used internally to
# merge conditions from skip_* filters
# Symbols:: A method to call
# Strings:: Some content to evaluate
# Procs:: A proc to call with the object
# Objects:: An object with a before_foo method on it to call
# merge conditions from skip_* filters.
# Symbols:: A method to call.
# Strings:: Some content to evaluate.
# Procs:: A proc to call with the object.
# Objects:: An object with a <tt>before_foo</tt> method on it to call.
#
# All of these objects are compiled into methods and handled
# the same after this point:
#
# Arrays:: Merged together into a single filter
# Symbols:: Already methods
# Strings:: class_eval'ed into methods
# Procs:: define_method'ed into methods
# Arrays:: Merged together into a single filter.
# Symbols:: Already methods.
# Strings:: class_eval'ed into methods.
# Procs:: define_method'ed into methods.
# Objects::
# a method is created that calls the before_foo method
# on the object.
@ -294,7 +297,7 @@ module ActiveSupport
end
end
# An Array with a compile method
# An Array with a compile method.
class CallbackChain < Array #:nodoc:#
attr_reader :name, :config
@ -351,7 +354,6 @@ module ActiveSupport
# This is used internally to append, prepend and skip callbacks to the
# CallbackChain.
#
def __update_callbacks(name, filters = [], block = nil) #:nodoc:
type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
options = filters.last.is_a?(Hash) ? filters.pop : {}
@ -367,8 +369,8 @@ module ActiveSupport
# Install a callback for the given event.
#
# set_callback :save, :before, :before_meth
# set_callback :save, :after, :after_meth, :if => :condition
# set_callback :save, :around, lambda { |r, &block| stuff; result = block.call; stuff }
# set_callback :save, :after, :after_meth, if: :condition
# set_callback :save, :around, ->(r, &block) { stuff; result = block.call; stuff }
#
# The second arguments indicates whether the callback is to be run +:before+,
# +:after+, or +:around+ the event. If omitted, +:before+ is assumed. This
@ -376,29 +378,29 @@ module ActiveSupport
#
# set_callback :save, :before_meth
#
# The callback can specified as a symbol naming an instance method; as a proc,
# lambda, or block; as a string to be instance evaluated; or as an object that
# responds to a certain method determined by the <tt>:scope</tt> argument to
# +define_callback+.
# The callback can specified as a symbol naming an instance method; as a
# proc, lambda, or block; as a string to be instance evaluated; or as an
# object that responds to a certain method determined by the <tt>:scope</tt>
# argument to +define_callback+.
#
# If a proc, lambda, or block is given, its body is evaluated in the context
# of the current object. It can also optionally accept the current object as
# an argument.
#
# Before and around callbacks are called in the order that they are set; after
# callbacks are called in the reverse order.
#
# Before and around callbacks are called in the order that they are set;
# after callbacks are called in the reverse order.
#
# Around callbacks can access the return value from the event, if it
# wasn't halted, from the +yield+ call.
#
# ===== Options
#
# * <tt>:if</tt> - A symbol naming an instance method or a proc; the callback
# will be called only when it returns a true value.
# * <tt>:unless</tt> - A symbol naming an instance method or a proc; the callback
# will be called only when it returns a false value.
# * <tt>:prepend</tt> - If true, the callback will be prepended to the existing
# chain rather than appended.
# * <tt>:if</tt> - A symbol naming an instance method or a proc; the
# callback will be called only when it returns a +true+ value.
# * <tt>:unless</tt> - A symbol naming an instance method or a proc; the
# callback will be called only when it returns a +false+ value.
# * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
# existing chain rather than appended.
def set_callback(name, *filter_list, &block)
mapped = nil
@ -417,11 +419,12 @@ module ActiveSupport
end
end
# Skip a previously set callback. Like +set_callback+, <tt>:if</tt> or <tt>:unless</tt>
# options may be passed in order to control when the callback is skipped.
# Skip a previously set callback. Like +set_callback+, <tt>:if</tt> or
# <tt>:unless</tt> options may be passed in order to control when the
# callback is skipped.
#
# class Writer < Person
# skip_callback :validate, :before, :check_membership, :if => lambda { self.age > 18 }
# skip_callback :validate, :before, :check_membership, if: -> { self.age > 18 }
# end
def skip_callback(name, *filter_list, &block)
__update_callbacks(name, filter_list, block) do |target, chain, type, filters, options|
@ -463,24 +466,25 @@ module ActiveSupport
#
# ===== Options
#
# * <tt>:terminator</tt> - Determines when a before filter will halt the callback
# chain, preventing following callbacks from being called and the event from being
# triggered. This is a string to be eval'ed. The result of the callback is available
# in the <tt>result</tt> variable.
# * <tt>:terminator</tt> - Determines when a before filter will halt the
# callback chain, preventing following callbacks from being called and
# the event from being triggered. This is a string to be eval'ed. The
# result of the callback is available in the +result+ variable.
#
# define_callbacks :validate, :terminator => "result == false"
# define_callbacks :validate, terminator: 'result == false'
#
# In this example, if any before validate callbacks returns +false+,
# other callbacks are not executed. Defaults to "false", meaning no value
# other callbacks are not executed. Defaults to +false+, meaning no value
# halts the chain.
#
# * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after callbacks should be terminated
# by the <tt>:terminator</tt> option. By default after callbacks executed no matter
# if callback chain was terminated or not.
# Option makes sence only when <tt>:terminator</tt> option is specified.
# * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after
# callbacks should be terminated by the <tt>:terminator</tt> option. By
# default after callbacks executed no matter if callback chain was
# terminated or not. Option makes sense only when <tt>:terminator</tt>
# option is specified.
#
# * <tt>:scope</tt> - Indicates which methods should be executed when an object
# is used as a callback.
# * <tt>:scope</tt> - Indicates which methods should be executed when an
# object is used as a callback.
#
# class Audit
# def before(caller)
@ -505,20 +509,21 @@ module ActiveSupport
# end
# end
#
# In the above case whenever you save an account the method <tt>Audit#before</tt> will
# be called. On the other hand
# In the above case whenever you save an account the method
# <tt>Audit#before</tt> will be called. On the other hand
#
# define_callbacks :save, :scope => [:kind, :name]
# define_callbacks :save, scope: [:kind, :name]
#
# would trigger <tt>Audit#before_save</tt> instead. That's constructed by calling
# <tt>#{kind}_#{name}</tt> on the given instance. In this case "kind" is "before" and
# "name" is "save". In this context +:kind+ and +:name+ have special meanings: +:kind+
# refers to the kind of callback (before/after/around) and +:name+ refers to the
# method on which callbacks are being defined.
# would trigger <tt>Audit#before_save</tt> instead. That's constructed
# by calling <tt>#{kind}_#{name}</tt> on the given instance. In this
# case "kind" is "before" and "name" is "save". In this context +:kind+
# and +:name+ have special meanings: +:kind+ refers to the kind of
# callback (before/after/around) and +:name+ refers to the method on
# which callbacks are being defined.
#
# A declaration like
#
# define_callbacks :save, :scope => [:name]
# define_callbacks :save, scope: [:name]
#
# would call <tt>Audit#save</tt>.
def define_callbacks(*callbacks)

View File

@ -4,7 +4,7 @@ module ActiveSupport
# module M
# def self.included(base)
# base.extend ClassMethods
# scope :disabled, where(:disabled => true)
# scope :disabled, where(disabled: true)
# end
#
# module ClassMethods
@ -12,7 +12,8 @@ module ActiveSupport
# end
# end
#
# By using <tt>ActiveSupport::Concern</tt> the above module could instead be written as:
# By using <tt>ActiveSupport::Concern</tt> the above module could instead be
# written as:
#
# require 'active_support/concern'
#
@ -20,7 +21,7 @@ module ActiveSupport
# extend ActiveSupport::Concern
#
# included do
# scope :disabled, where(:disabled => true)
# scope :disabled, where(disabled: true)
# end
#
# module ClassMethods
@ -28,8 +29,9 @@ module ActiveSupport
# end
# end
#
# Moreover, it gracefully handles module dependencies. Given a +Foo+ module and a +Bar+
# module which depends on the former, we would typically write the following:
# Moreover, it gracefully handles module dependencies. Given a +Foo+ module
# and a +Bar+ module which depends on the former, we would typically write the
# following:
#
# module Foo
# def self.included(base)
@ -52,8 +54,8 @@ module ActiveSupport
# include Bar # Bar is the module that Host really needs
# end
#
# But why should +Host+ care about +Bar+'s dependencies, namely +Foo+? We could try to hide
# these from +Host+ directly including +Foo+ in +Bar+:
# But why should +Host+ care about +Bar+'s dependencies, namely +Foo+? We
# could try to hide these from +Host+ directly including +Foo+ in +Bar+:
#
# module Bar
# include Foo
@ -66,8 +68,9 @@ module ActiveSupport
# include Bar
# end
#
# Unfortunately this won't work, since when +Foo+ is included, its <tt>base</tt> is the +Bar+ module,
# not the +Host+ class. With <tt>ActiveSupport::Concern</tt>, module dependencies are properly resolved:
# Unfortunately this won't work, since when +Foo+ is included, its <tt>base</tt>
# is the +Bar+ module, not the +Host+ class. With <tt>ActiveSupport::Concern</tt>,
# module dependencies are properly resolved:
#
# require 'active_support/concern'
#

View File

@ -13,7 +13,7 @@ module ActiveSupport
self.class.compile_methods!(keys)
end
# compiles reader methods so we don't have to go through method_missing
# Compiles reader methods so we don't have to go through method_missing.
def self.compile_methods!(keys)
keys.reject { |m| method_defined?(m) }.each do |key|
class_eval <<-RUBY, __FILE__, __LINE__ + 1
@ -39,7 +39,7 @@ module ActiveSupport
# Allows you to add shortcut so that you don't have to refer to attribute
# through config. Also look at the example for config to contrast.
#
#
# Defines both class and instance config accessors.
#
# class User
@ -47,16 +47,16 @@ module ActiveSupport
# config_accessor :allowed_access
# end
#
# User.allowed_access # => nil
# User.allowed_access # => nil
# User.allowed_access = false
# User.allowed_access # => false
#
# User.allowed_access # => false
#
# user = User.new
# user.allowed_access # => false
# user.allowed_access = true
# user.allowed_access # => true
#
# User.allowed_access # => false
# User.allowed_access # => false
#
# The attribute name must be a valid method name in Ruby.
#
@ -91,7 +91,7 @@ module ActiveSupport
#  User.allowed_access # => false
#
# User.new.allowed_access = true # => NoMethodError
# User.new.allowed_access # => NoMethodError
# User.new.allowed_access # => NoMethodError
def config_accessor(*names)
options = names.extract_options!

View File

@ -43,8 +43,9 @@ module ActiveSupport #:nodoc:
mattr_accessor :autoload_once_paths
self.autoload_once_paths = []
# 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 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.
mattr_accessor :autoloaded_constants
self.autoloaded_constants = []
@ -53,30 +54,32 @@ module ActiveSupport #:nodoc:
mattr_accessor :explicitly_unloadable_constants
self.explicitly_unloadable_constants = []
# The logger is used for generating information on the action run-time (including benchmarking) if available.
# Can be set to nil for no logging. Compatible with both Ruby's own Logger and Log4r loggers.
# The logger is used for generating information on the action run-time
# (including benchmarking) if available. Can be set to nil for no logging.
# Compatible with both Ruby's own Logger and Log4r loggers.
mattr_accessor :logger
# Set to true to enable logging of const_missing and file loads
# Set to +true+ to enable logging of const_missing and file loads.
mattr_accessor :log_activity
self.log_activity = false
# The WatchStack keeps a stack of the modules being watched as files are loaded.
# If a file in the process of being loaded (parent.rb) triggers the load of
# another file (child.rb) the stack will ensure that child.rb handles the new
# constants.
# The WatchStack keeps a stack of the modules being watched as files are
# loaded. If a file in the process of being loaded (parent.rb) triggers the
# load of another file (child.rb) the stack will ensure that child.rb
# handles the new constants.
#
# If child.rb is being autoloaded, its constants will be added to
# autoloaded_constants. If it was being `require`d, they will be discarded.
#
# This is handled by walking back up the watch stack and adding the constants
# found by child.rb to the list of original constants in parent.rb
# found by child.rb to the list of original constants in parent.rb.
class WatchStack
include Enumerable
# @watching is a stack of lists of constants being watched. For instance,
# if parent.rb is autoloaded, the stack will look like [[Object]]. If parent.rb
# then requires namespace/child.rb, the stack will look like [[Object], [Namespace]].
# if parent.rb is autoloaded, the stack will look like [[Object]]. If
# parent.rb then requires namespace/child.rb, the stack will look like
# [[Object], [Namespace]].
def initialize
@watching = []
@ -91,7 +94,8 @@ module ActiveSupport #:nodoc:
!@watching.empty?
end
# return a list of new constants found since the last call to watch_namespaces
# Returns a list of new constants found since the last call to
# <tt>watch_namespaces</tt>.
def new_constants
constants = []
@ -127,7 +131,8 @@ module ActiveSupport #:nodoc:
pop_modules(@watching.pop)
end
# Add a set of modules to the watch stack, remembering the initial constants
# Add a set of modules to the watch stack, remembering the initial
# constants.
def watch_namespaces(namespaces)
@watching << namespaces.map do |namespace|
module_name = Dependencies.to_constant_name(namespace)
@ -149,7 +154,7 @@ module ActiveSupport #:nodoc:
mattr_accessor :constant_watch_stack
self.constant_watch_stack = WatchStack.new
# Module includes this module
# Module includes this module.
module ModuleConstMissing #:nodoc:
def self.append_features(base)
base.class_eval do
@ -182,7 +187,7 @@ module ActiveSupport #:nodoc:
end
end
# Object includes this module
# Object includes this module.
module Loadable #:nodoc:
def self.exclude_from(base)
base.class_eval { define_method(:load, Kernel.instance_method(:load)) }
@ -223,25 +228,25 @@ module ActiveSupport #:nodoc:
result
end
# Mark the given constant as unloadable. Unloadable constants are removed each
# time dependencies are cleared.
# Mark the given 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 may need unloading;
# each constant will be removed for every subsequent clear, as opposed to for
# the first clear.
# each constant will be removed for every subsequent clear, as opposed to
# for the first clear.
#
# The provided constant descriptor may be a (non-anonymous) 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.
# Returns +true+ if the constant was not previously marked for unloading,
# +false+ otherwise.
def unloadable(const_desc)
Dependencies.mark_for_unload const_desc
end
end
# Exception file-blaming
# Exception file-blaming.
module Blamable #:nodoc:
def blame_file!(file)
(@blamed_files ||= []).unshift file
@ -337,8 +342,9 @@ module ActiveSupport #:nodoc:
Object.qualified_const_defined?(path.sub(/^::/, ''), false)
end
# Given +path+, a filesystem path to a ruby file, return an array of constant
# paths which would cause Dependencies to attempt to load this file.
# Given +path+, a filesystem path to a ruby file, return an array of
# constant paths which would cause Dependencies to attempt to load this
# file.
def loadable_constants_for_path(path, bases = autoload_paths)
path = $` if path =~ /\.rb\z/
expanded_path = File.expand_path(path)
@ -371,7 +377,8 @@ module ActiveSupport #:nodoc:
end
# Does the provided path_suffix correspond to an autoloadable module?
# Instead of returning a boolean, the autoload base for this module is returned.
# Instead of returning a boolean, the autoload base for this module is
# returned.
def autoloadable_module?(path_suffix)
autoload_paths.each do |load_path|
return load_path if File.directory? File.join(load_path, path_suffix)
@ -385,10 +392,10 @@ module ActiveSupport #:nodoc:
end
# Attempt 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.
# 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.
def autoload_module!(into, const_name, qualified_name, path_suffix)
return nil unless base_path = autoloadable_module?(path_suffix)
mod = Module.new
@ -402,8 +409,8 @@ module ActiveSupport #:nodoc:
# addition of these constants. Each 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, then Dependencies will construct a set
# of names that the file at +path+ may define. See
# If the second parameter is left off, then Dependencies will construct a
# set of names that the file at +path+ may define. See
# +loadable_constants_for_path+ for more details.
def load_file(path, const_paths = loadable_constants_for_path(path))
log_call path, const_paths
@ -421,15 +428,15 @@ module ActiveSupport #:nodoc:
result
end
# Return the constant path for the provided parent and constant name.
# Returns the constant path for the provided parent and constant name.
def qualified_name_for(mod, name)
mod_name = to_constant_name mod
mod_name == "Object" ? name.to_s : "#{mod_name}::#{name}"
end
# Load the constant named +const_name+ which is missing from +from_mod+. If
# it is not possible to load the constant into from_mod, try its parent module
# using const_missing.
# it is not possible to load the constant into from_mod, try its parent
# module using +const_missing+.
def load_missing_constant(from_mod, const_name)
log_call from_mod, const_name
@ -558,7 +565,7 @@ module ActiveSupport #:nodoc:
end
# Get the reference for class named +name+ if one exists.
# Otherwise returns nil.
# Otherwise returns +nil+.
def safe_constantize(name)
Reference.safe_get(name)
end

View File

@ -6,7 +6,7 @@ module ActiveSupport
# Provides accurate date and time measurements using Date#advance and
# Time#advance, respectively. It mainly supports the methods on Numeric.
#
# 1.month.ago # equivalent to Time.now.advance(:months => -1)
# 1.month.ago # equivalent to Time.now.advance(months: -1)
class Duration < BasicObject
attr_accessor :value, :parts
@ -39,8 +39,8 @@ module ActiveSupport
end
alias :kind_of? :is_a?
# Returns true if <tt>other</tt> is also a Duration instance with the
# same <tt>value</tt>, or if <tt>other == value</tt>.
# Returns +true+ if +other+ is also a Duration instance with the
# same +value+, or if <tt>other == value</tt>.
def ==(other)
if Duration === other
other.value == value

View File

@ -1,23 +1,21 @@
module ActiveSupport
# \FileUpdateChecker specifies the API used by Rails to watch files
# FileUpdateChecker specifies the API used by Rails to watch files
# and control reloading. The API depends on four methods:
#
# * +initialize+ which expects two parameters and one block as
# described below;
# described below.
#
# * +updated?+ which returns a boolean if there were updates in
# the filesystem or not;
# the filesystem or not.
#
# * +execute+ which executes the given block on initialization
# and updates the latest watched files and timestamp;
# and updates the latest watched files and timestamp.
#
# * +execute_if_updated+ which just executes the block if it was updated;
# * +execute_if_updated+ which just executes the block if it was updated.
#
# After initialization, a call to +execute_if_updated+ must execute
# the block only if there was really a change in the filesystem.
#
# == Examples
#
# This class is used by Rails to reload the I18n framework whenever
# they are changed upon a new request.
#
@ -28,7 +26,6 @@ module ActiveSupport
# ActionDispatch::Reloader.to_prepare do
# i18n_reloader.execute_if_updated
# end
#
class FileUpdateChecker
# It accepts two parameters on initialization. The first is an array
# of files and the second is an optional hash of directories. The hash must
@ -52,7 +49,7 @@ module ActiveSupport
# Check if any of the entries were updated. If so, the watched and/or
# updated_at values are cached until the block is executed via +execute+
# or +execute_if_updated+
# or +execute_if_updated+.
def updated?
current_watched = watched
if @last_watched.size != current_watched.size
@ -70,7 +67,8 @@ module ActiveSupport
end
end
# Executes the given block and updates the latest watched files and timestamp.
# Executes the given block and updates the latest watched files and
# timestamp.
def execute
@last_watched = watched
@last_update_at = updated_at(@last_watched)

View File

@ -1,7 +1,8 @@
require 'active_support/core_ext/hash/keys'
module ActiveSupport
# Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered to be the same.
# Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
# to be the same.
#
# rgb = ActiveSupport::HashWithIndifferentAccess.new
#
@ -15,11 +16,11 @@ module ActiveSupport
#
# Internally symbols are mapped to strings when used as keys in the entire
# writing interface (calling <tt>[]=</tt>, <tt>merge</tt>, etc). This
# mapping belongs to the public interface. For example, given
# mapping belongs to the public interface. For example, given:
#
# hash = ActiveSupport::HashWithIndifferentAccess.new(a: 1)
#
# you are guaranteed that the key is returned as a string:
# You are guaranteed that the key is returned as a string:
#
# hash.keys # => ["a"]
#
@ -39,7 +40,7 @@ module ActiveSupport
#
# which may be handy.
class HashWithIndifferentAccess < Hash
# Returns true so that <tt>Array#extract_options!</tt> finds members of
# Returns +true+ so that <tt>Array#extract_options!</tt> finds members of
# this class.
def extractable_options?
true

View File

@ -16,7 +16,7 @@ module I18n
end
# Trigger i18n config before any eager loading has happened
# so it's ready if any classes require it when eager loaded
# so it's ready if any classes require it when eager loaded.
config.before_eager_load do |app|
I18n::Railtie.initialize_i18n(app)
end
@ -25,7 +25,7 @@ module I18n
@i18n_inited = false
# Setup i18n configuration
# Setup i18n configuration.
def self.initialize_i18n(app)
return if @i18n_inited

View File

@ -1,23 +1,25 @@
module ActiveSupport
# lazy_load_hooks allows rails to lazily load a lot of components and thus making the app boot faster. Because of
# this feature now there is no need to require <tt>ActiveRecord::Base</tt> at boot time purely to apply configuration. Instead
# a hook is registered that applies configuration once <tt>ActiveRecord::Base</tt> is loaded. Here <tt>ActiveRecord::Base</tt> is used
# as example but this feature can be applied elsewhere too.
# lazy_load_hooks allows rails to lazily load a lot of components and thus
# making the app boot faster. Because of this feature now there is no need to
# require <tt>ActiveRecord::Base</tt> at boot time purely to apply
# configuration. Instead a hook is registered that applies configuration once
# <tt>ActiveRecord::Base</tt> is loaded. Here <tt>ActiveRecord::Base</tt> is
# used as example but this feature can be applied elsewhere too.
#
# Here is an example where +on_load+ method is called to register a hook.
#
# initializer "active_record.initialize_timezone" do
# initializer 'active_record.initialize_timezone' do
# ActiveSupport.on_load(:active_record) do
# self.time_zone_aware_attributes = true
# self.default_timezone = :utc
# end
# end
#
# When the entirety of +activerecord/lib/active_record/base.rb+ has been evaluated then +run_load_hooks+ is invoked.
# The very last line of +activerecord/lib/active_record/base.rb+ is:
# When the entirety of +activerecord/lib/active_record/base.rb+ has been
# evaluated then +run_load_hooks+ is invoked. The very last line of
# +activerecord/lib/active_record/base.rb+ is:
#
# ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
#
@load_hooks = Hash.new { |h,k| h[k] = [] }
@loaded = Hash.new { |h,k| h[k] = [] }

View File

@ -2,11 +2,13 @@ require 'active_support/core_ext/module/attribute_accessors'
require 'active_support/core_ext/class/attribute'
module ActiveSupport
# ActiveSupport::LogSubscriber is an object set to consume ActiveSupport::Notifications
# with the sole purpose of logging them. The log subscriber dispatches notifications to
# a registered object based on its given namespace.
# ActiveSupport::LogSubscriber is an object set to consume
# ActiveSupport::Notifications with the sole purpose of logging them.
# The log subscriber dispatches notifications to a registered object based
# on its given namespace.
#
# An example would be Active Record log subscriber responsible for logging queries:
# An example would be Active Record log subscriber responsible for logging
# queries:
#
# module ActiveRecord
# class LogSubscriber < ActiveSupport::LogSubscriber
@ -20,16 +22,17 @@ module ActiveSupport
#
# ActiveRecord::LogSubscriber.attach_to :active_record
#
# Since we need to know all instance methods before attaching the log subscriber,
# the line above should be called after your <tt>ActiveRecord::LogSubscriber</tt> definition.
# Since we need to know all instance methods before attaching the log
# subscriber, the line above should be called after your
# <tt>ActiveRecord::LogSubscriber</tt> definition.
#
# After configured, whenever a "sql.active_record" notification is published,
# it will properly dispatch the event (ActiveSupport::Notifications::Event) to
# the sql method.
#
# Log subscriber also has some helpers to deal with logging and automatically flushes
# all logs when the request finishes (via action_dispatch.callback notification) in
# a Rails environment.
# Log subscriber also has some helpers to deal with logging and automatically
# flushes all logs when the request finishes (via action_dispatch.callback
# notification) in a Rails environment.
class LogSubscriber
# Embed in a String to clear all previous ANSI sequences.
CLEAR = "\e[0m"
@ -122,10 +125,9 @@ module ActiveSupport
end
# Set color by using a string or one of the defined constants. If a third
# option is set to true, it also adds bold to the string. This is based
# option is set to +true+, it also adds bold to the string. This is based
# on the Highline implementation and will automatically append CLEAR to the
# end of the returned String.
#
def color(text, color, bold=false)
return text unless colorize_logging
color = self.class.const_get(color.upcase) if color.is_a?(Symbol)

View File

@ -2,7 +2,7 @@ require 'logger'
module ActiveSupport
class Logger < ::Logger
# Broadcasts logs to multiple loggers
# Broadcasts logs to multiple loggers.
def self.broadcast(logger) # :nodoc:
Module.new do
define_method(:add) do |*args, &block|

View File

@ -2,18 +2,19 @@ require 'openssl'
require 'base64'
module ActiveSupport
# MessageEncryptor is a simple way to encrypt values which get stored somewhere
# you don't trust.
# MessageEncryptor is a simple way to encrypt values which get stored
# somewhere you don't trust.
#
# The cipher text and initialization vector are base64 encoded and returned to you.
# The cipher text and initialization vector are base64 encoded and returned
# to you.
#
# This can be used in situations similar to the <tt>MessageVerifier</tt>, but where you don't
# want users to be able to determine the value of the payload.
# This can be used in situations similar to the <tt>MessageVerifier</tt>, but
# where you don't want users to be able to determine the value of the payload.
#
# key = OpenSSL::Digest::SHA256.new('password').digest # => "\x89\xE0\x156\xAC..."
# crypt = ActiveSupport::MessageEncryptor.new(key) # => #<ActiveSupport::MessageEncryptor ...>
# encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..."
# crypt.decrypt_and_verify(encrypted_data) # => "my secret data"
# key = OpenSSL::Digest::SHA256.new('password').digest # => "\x89\xE0\x156\xAC..."
# crypt = ActiveSupport::MessageEncryptor.new(key) # => #<ActiveSupport::MessageEncryptor ...>
# encrypted_data = crypt.encrypt_and_sign('my secret data') # => "NlFBTTMwOUV5UlA1QlNEN2xkY2d6eThYWWh..."
# crypt.decrypt_and_verify(encrypted_data) # => "my secret data"
class MessageEncryptor
module NullSerializer #:nodoc:
def self.load(value)
@ -28,15 +29,16 @@ module ActiveSupport
class InvalidMessage < StandardError; end
OpenSSLCipherError = OpenSSL::Cipher.const_defined?(:CipherError) ? OpenSSL::Cipher::CipherError : OpenSSL::CipherError
# Initialize a new MessageEncryptor.
# +secret+ must be at least as long as the cipher key size. For the default 'aes-256-cbc' cipher,
# this is 256 bits. If you are using a user-entered secret, you can generate a suitable key with
# <tt>OpenSSL::Digest::SHA256.new(user_secret).digest</tt> or similar.
# Initialize a new MessageEncryptor. +secret+ must be at least as long as
# the cipher key size. For the default 'aes-256-cbc' cipher, this is 256
# bits. If you are using a user-entered secret, you can generate a suitable
# key with <tt>OpenSSL::Digest::SHA256.new(user_secret).digest</tt> or
# similar.
#
# Options:
# * <tt>:cipher</tt> - Cipher to use. Can be any cipher returned by <tt>OpenSSL::Cipher.ciphers</tt>. Default is 'aes-256-cbc'
# * <tt>:serializer</tt> - Object serializer to use. Default is +Marshal+.
#
# * <tt>:cipher</tt> - Cipher to use. Can be any cipher returned by
# <tt>OpenSSL::Cipher.ciphers</tt>. Default is 'aes-256-cbc'.
# * <tt>:serializer</tt> - Object serializer to use. Default is +Marshal+.
def initialize(secret, options = {})
@secret = secret
@cipher = options[:cipher] || 'aes-256-cbc'
@ -44,14 +46,14 @@ module ActiveSupport
@serializer = options[:serializer] || Marshal
end
# Encrypt and sign a message. We need to sign the message in order to avoid padding attacks.
# Reference: http://www.limited-entropy.com/padding-oracle-attacks
# Encrypt and sign a message. We need to sign the message in order to avoid
# padding attacks. Reference: http://www.limited-entropy.com/padding-oracle-attacks.
def encrypt_and_sign(value)
verifier.generate(_encrypt(value))
end
# Decrypt and verify a message. We need to verify the message in order to avoid padding attacks.
# Reference: http://www.limited-entropy.com/padding-oracle-attacks
# Decrypt and verify a message. We need to verify the message in order to
# avoid padding attacks. Reference: http://www.limited-entropy.com/padding-oracle-attacks.
def decrypt_and_verify(value)
_decrypt(verifier.verify(value))
end

View File

@ -2,11 +2,11 @@ require 'base64'
require 'active_support/core_ext/object/blank'
module ActiveSupport
# +MessageVerifier+ makes it easy to generate and verify messages which are signed
# to prevent tampering.
# +MessageVerifier+ makes it easy to generate and verify messages which are
# signed to prevent tampering.
#
# This is useful for cases like remember-me tokens and auto-unsubscribe links where the
# session store isn't suitable or available.
# This is useful for cases like remember-me tokens and auto-unsubscribe links
# where the session store isn't suitable or available.
#
# Remember Me:
# cookies[:remember_me] = @verifier.generate([@user.id, 2.weeks.from_now])
@ -18,9 +18,9 @@ module ActiveSupport
# self.current_user = User.find(id)
# end
#
# By default it uses Marshal to serialize the message. If you want to use another
# serialization method, you can set the serializer attribute to something that responds
# to dump and load, e.g.:
# By default it uses Marshal to serialize the message. If you want to use
# another serialization method, you can set the serializer attribute to
# something that responds to dump and load, e.g.:
#
# @verifier.serializer = YAML
class MessageVerifier

View File

@ -3,16 +3,17 @@ module ActiveSupport #:nodoc:
autoload :Chars, 'active_support/multibyte/chars'
autoload :Unicode, 'active_support/multibyte/unicode'
# The proxy class returned when calling mb_chars. You can use this accessor to configure your own proxy
# class so you can support other encodings. See the ActiveSupport::Multibyte::Chars implementation for
# an example how to do this.
# The proxy class returned when calling mb_chars. You can use this accessor
# to configure your own proxy class so you can support other encodings. See
# the ActiveSupport::Multibyte::Chars implementation for an example how to
# do this.
#
# ActiveSupport::Multibyte.proxy_class = CharsForUTF32
def self.proxy_class=(klass)
@proxy_class = klass
end
# Returns the current proxy class
# Returns the current proxy class.
def self.proxy_class
@proxy_class ||= ActiveSupport::Multibyte::Chars
end

View File

@ -4,7 +4,8 @@ require 'active_support/notifications/fanout'
module ActiveSupport
# = Notifications
#
# <tt>ActiveSupport::Notifications</tt> provides an instrumentation API for Ruby.
# <tt>ActiveSupport::Notifications</tt> provides an instrumentation API for
# Ruby.
#
# == Instrumenters
#

View File

@ -1,4 +1,4 @@
module ActiveSupport #:nodoc:
module ActiveSupport
# Usually key value pairs are handled something like this:
#
# h = {}
@ -7,7 +7,7 @@ module ActiveSupport #:nodoc:
# h[:boy] # => 'John'
# h[:girl] # => 'Mary'
#
# Using <tt>OrderedOptions</tt>, the above code could be reduced to:
# Using +OrderedOptions+, the above code could be reduced to:
#
# h = ActiveSupport::OrderedOptions.new
# h.boy = 'John'

View File

@ -2,7 +2,7 @@ require "active_support"
require "active_support/i18n_railtie"
module ActiveSupport
class Railtie < Rails::Railtie
class Railtie < Rails::Railtie # :nodoc:
config.active_support = ActiveSupport::OrderedOptions.new
config.eager_load_namespaces << ActiveSupport

View File

@ -3,12 +3,11 @@ module ActiveSupport
# for equality. The value returned by <tt>Rails.env</tt> is wrapped
# in a StringInquirer object so instead of calling this:
#
# Rails.env == "production"
# Rails.env == 'production'
#
# you can call this:
#
# Rails.env.production?
#
class StringInquirer < String
private

View File

@ -6,15 +6,16 @@ module ActiveSupport
# Wraps any standard Logger object to provide tagging capabilities.
#
# logger = ActiveSupport::TaggedLogging.new(Logger.new(STDOUT))
# logger.tagged("BCX") { logger.info "Stuff" } # Logs "[BCX] Stuff"
# logger.tagged("BCX", "Jason") { logger.info "Stuff" } # Logs "[BCX] [Jason] Stuff"
# logger.tagged("BCX") { logger.tagged("Jason") { logger.info "Stuff" } } # Logs "[BCX] [Jason] Stuff"
# logger.tagged('BCX') { logger.info 'Stuff' } # Logs "[BCX] Stuff"
# logger.tagged('BCX', "Jason") { logger.info 'Stuff' } # Logs "[BCX] [Jason] Stuff"
# logger.tagged('BCX') { logger.tagged('Jason') { logger.info 'Stuff' } } # Logs "[BCX] [Jason] Stuff"
#
# This is used by the default Rails.logger as configured by Railties to make it easy to stamp log lines
# with subdomains, request ids, and anything else to aid debugging of multi-user production applications.
# This is used by the default Rails.logger as configured by Railties to make
# it easy to stamp log lines with subdomains, request ids, and anything else
# to aid debugging of multi-user production applications.
module TaggedLogging
module Formatter # :nodoc:
# This method is invoked when a log event occurs
# This method is invoked when a log event occurs.
def call(severity, timestamp, progname, msg)
super(severity, timestamp, progname, "#{tags_text}#{msg}")
end

View File

@ -2,11 +2,13 @@ require 'active_support/values/time_zone'
require 'active_support/core_ext/object/acts_like'
module ActiveSupport
# A Time-like class that can represent a time in any time zone. Necessary because standard Ruby Time instances are
# limited to UTC and the system's <tt>ENV['TZ']</tt> zone.
# A Time-like class that can represent a time in any time zone. Necessary
# because standard Ruby Time instances are limited to UTC and the
# system's <tt>ENV['TZ']</tt> zone.
#
# You shouldn't ever need to create a TimeWithZone instance directly via <tt>new</tt> . Instead use methods
# +local+, +parse+, +at+ and +now+ on TimeZone instances, and +in_time_zone+ on Time and DateTime instances.
# You shouldn't ever need to create a TimeWithZone instance directly via +new+.
# Instead use methods +local+, +parse+, +at+ and +now+ on TimeZone instances,
# and +in_time_zone+ on Time and DateTime instances.
#
# Time.zone = 'Eastern Time (US & Canada)' # => 'Eastern Time (US & Canada)'
# Time.zone.local(2007, 2, 10, 15, 30, 45) # => Sat, 10 Feb 2007 15:30:45 EST -05:00
@ -17,7 +19,8 @@ module ActiveSupport
#
# See Time and TimeZone for further documentation of these methods.
#
# TimeWithZone instances implement the same API as Ruby Time instances, so that Time and TimeWithZone instances are interchangeable.
# TimeWithZone instances implement the same API as Ruby Time instances, so
# that Time and TimeWithZone instances are interchangeable.
#
# t = Time.zone.now # => Sun, 18 May 2008 13:27:25 EDT -04:00
# t.hour # => 13
@ -30,10 +33,9 @@ module ActiveSupport
# t > Time.utc(1999) # => true
# t.is_a?(Time) # => true
# t.is_a?(ActiveSupport::TimeWithZone) # => true
#
class TimeWithZone
# Report class name as 'Time' to thwart type checking
# Report class name as 'Time' to thwart type checking.
def self.name
'Time'
end
@ -71,7 +73,8 @@ module ActiveSupport
utc.in_time_zone(new_zone)
end
# Returns a <tt>Time.local()</tt> instance of the simultaneous time in your system's <tt>ENV['TZ']</tt> zone
# Returns a <tt>Time.local()</tt> instance of the simultaneous time in your
# system's <tt>ENV['TZ']</tt> zone.
def localtime
utc.respond_to?(:getlocal) ? utc.getlocal : utc.to_time.getlocal
end
@ -97,7 +100,8 @@ module ActiveSupport
utc? && alternate_utc_string || TimeZone.seconds_to_utc_offset(utc_offset, colon)
end
# Time uses +zone+ to display the time zone abbreviation, so we're duck-typing it.
# Time uses +zone+ to display the time zone abbreviation, so we're
# duck-typing it.
def zone
period.zone_identifier.to_s
end
@ -115,9 +119,10 @@ module ActiveSupport
end
alias_method :iso8601, :xmlschema
# Coerces time to a string for JSON encoding. The default format is ISO 8601. You can get
# %Y/%m/%d %H:%M:%S +offset style by setting <tt>ActiveSupport::JSON::Encoding.use_standard_json_time_format</tt>
# to false.
# Coerces time to a string for JSON encoding. The default format is ISO 8601.
# You can get %Y/%m/%d %H:%M:%S +offset style by setting
# <tt>ActiveSupport::JSON::Encoding.use_standard_json_time_format</tt>
# to +false+.
#
# # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = true
# Time.utc(2005,2,1,15,15,10).in_time_zone.to_json
@ -126,7 +131,6 @@ module ActiveSupport
# # With ActiveSupport::JSON::Encoding.use_standard_json_time_format = false
# Time.utc(2005,2,1,15,15,10).in_time_zone.to_json
# # => "2005/02/01 15:15:10 +0000"
#
def as_json(options = nil)
if ActiveSupport::JSON::Encoding.use_standard_json_time_format
xmlschema
@ -165,8 +169,9 @@ module ActiveSupport
end
alias_method :to_formatted_s, :to_s
# Replaces <tt>%Z</tt> and <tt>%z</tt> directives with +zone+ and +formatted_offset+, respectively, before passing to
# Time#strftime, so that zone information is correct
# Replaces <tt>%Z</tt> and <tt>%z</tt> directives with +zone+ and
# +formatted_offset+, respectively, before passing to Time#strftime, so
# that zone information is correct
def strftime(format)
format = format.gsub('%Z', zone).gsub('%z', formatted_offset(false))
time.strftime(format)
@ -307,14 +312,16 @@ module ActiveSupport
initialize(variables[0].utc, ::Time.find_zone(variables[1]), variables[2].utc)
end
# Ensure proxy class responds to all methods that underlying time instance responds to.
# Ensure proxy class responds to all methods that underlying time instance
# responds to.
def respond_to_missing?(sym, include_priv)
# consistently respond false to acts_like?(:date), regardless of whether #time is a Time or DateTime
return false if sym.to_sym == :acts_like_date?
time.respond_to?(sym, include_priv)
end
# Send the missing method to +time+ instance, and wrap result in a new TimeWithZone with the existing +time_zone+.
# Send the missing method to +time+ instance, and wrap result in a new
# TimeWithZone with the existing +time_zone+.
def method_missing(sym, *args, &block)
wrap_with_time_zone time.__send__(sym, *args, &block)
end