All Files (53.43% covered at 537.76 hits/line)
62 files in total.
2098 relevant lines.
1121 lines covered and
977 lines missed
-
#--
-
# Copyright (c) 2005-2017 David Heinemeier Hansson
-
#
-
# Permission is hereby granted, free of charge, to any person obtaining
-
# a copy of this software and associated documentation files (the
-
# "Software"), to deal in the Software without restriction, including
-
# without limitation the rights to use, copy, modify, merge, publish,
-
# distribute, sublicense, and/or sell copies of the Software, and to
-
# permit persons to whom the Software is furnished to do so, subject to
-
# the following conditions:
-
#
-
# The above copyright notice and this permission notice shall be
-
# included in all copies or substantial portions of the Software.
-
#
-
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
-
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
-
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
-
# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
-
# LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
-
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
-
# WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
-
#++
-
-
1
require "securerandom"
-
1
require "active_support/dependencies/autoload"
-
1
require "active_support/version"
-
1
require "active_support/logger"
-
1
require "active_support/lazy_load_hooks"
-
1
require "active_support/core_ext/date_and_time/compatibility"
-
-
1
module ActiveSupport
-
1
extend ActiveSupport::Autoload
-
-
1
autoload :Concern
-
1
autoload :Dependencies
-
1
autoload :DescendantsTracker
-
1
autoload :ExecutionWrapper
-
1
autoload :Executor
-
1
autoload :FileUpdateChecker
-
1
autoload :EventedFileUpdateChecker
-
1
autoload :LogSubscriber
-
1
autoload :Notifications
-
1
autoload :Reloader
-
-
1
eager_autoload do
-
1
autoload :BacktraceCleaner
-
1
autoload :ProxyObject
-
1
autoload :Benchmarkable
-
1
autoload :Cache
-
1
autoload :Callbacks
-
1
autoload :Configurable
-
1
autoload :Deprecation
-
1
autoload :Gzip
-
1
autoload :Inflector
-
1
autoload :JSON
-
1
autoload :KeyGenerator
-
1
autoload :MessageEncryptor
-
1
autoload :MessageVerifier
-
1
autoload :Multibyte
-
1
autoload :NumberHelper
-
1
autoload :OptionMerger
-
1
autoload :OrderedHash
-
1
autoload :OrderedOptions
-
1
autoload :StringInquirer
-
1
autoload :TaggedLogging
-
1
autoload :XmlMini
-
1
autoload :ArrayInquirer
-
end
-
-
1
autoload :Rescuable
-
1
autoload :SafeBuffer, "active_support/core_ext/string/output_safety"
-
1
autoload :TestCase
-
-
1
def self.eager_load!
-
super
-
-
NumberHelper.eager_load!
-
end
-
-
1
cattr_accessor :test_order # :nodoc:
-
-
1
def self.halt_callback_chains_on_return_false
-
Callbacks.halt_and_display_warning_on_return_false
-
end
-
-
1
def self.halt_callback_chains_on_return_false=(value)
-
Callbacks.halt_and_display_warning_on_return_false = value
-
end
-
-
1
def self.to_time_preserves_timezone
-
DateAndTime::Compatibility.preserve_timezone
-
end
-
-
1
def self.to_time_preserves_timezone=(value)
-
1
DateAndTime::Compatibility.preserve_timezone = value
-
end
-
end
-
-
1
autoload :I18n, "active_support/i18n"
-
1
require "active_support/concern"
-
1
require "active_support/descendants_tracker"
-
1
require "active_support/core_ext/array/extract_options"
-
1
require "active_support/core_ext/class/attribute"
-
1
require "active_support/core_ext/kernel/reporting"
-
1
require "active_support/core_ext/kernel/singleton_class"
-
1
require "active_support/core_ext/module/attribute_accessors"
-
1
require "active_support/core_ext/string/filters"
-
1
require "active_support/deprecation"
-
1
require "thread"
-
-
1
module ActiveSupport
-
# Callbacks are code hooks that are run at key points in an object's life cycle.
-
# 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
-
# life cycle 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.
-
#
-
# class Record
-
# include ActiveSupport::Callbacks
-
# define_callbacks :save
-
#
-
# def save
-
# run_callbacks :save do
-
# puts "- save"
-
# end
-
# end
-
# end
-
#
-
# class PersonRecord < Record
-
# set_callback :save, :before, :saving_message
-
# def saving_message
-
# puts "saving..."
-
# end
-
#
-
# set_callback :save, :after do |object|
-
# puts "saved"
-
# end
-
# end
-
#
-
# person = PersonRecord.new
-
# person.save
-
#
-
# Output:
-
# saving...
-
# - save
-
# saved
-
1
module Callbacks
-
1
extend Concern
-
-
1
included do
-
1
extend ActiveSupport::DescendantsTracker
-
1
class_attribute :__callbacks, instance_writer: false
-
1
self.__callbacks ||= {}
-
end
-
-
1
CALLBACK_FILTER_TYPES = [:before, :after, :around]
-
-
# If true, Active Record and Active Model callbacks returning +false+ will
-
# halt the entire callback chain and display a deprecation message.
-
# If false, callback chains will only be halted by calling +throw :abort+.
-
# Defaults to +true+.
-
2
mattr_accessor(:halt_and_display_warning_on_return_false, instance_writer: false) { true }
-
-
# 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.
-
#
-
# If the callback chain was halted, returns +false+. Otherwise returns the
-
# result of the block, +nil+ if no callbacks have been set, or +true+
-
# if callbacks have been set but no block is given.
-
#
-
# run_callbacks :save do
-
# save
-
# end
-
#
-
#--
-
#
-
# As this method is used in many places, and often wraps large portions of
-
# user code, it has an additional design goal of minimizing its impact on
-
# the visible call stack. An exception from inside a :before or :after
-
# callback can be as noisy as it likes -- but when control has passed
-
# smoothly through and into the supplied block, we want as little evidence
-
# as possible that we were here.
-
1
def run_callbacks(kind)
-
2
callbacks = __callbacks[kind.to_sym]
-
-
2
if callbacks.empty?
-
2
yield if block_given?
-
else
-
env = Filters::Environment.new(self, false, nil)
-
next_sequence = callbacks.compile
-
-
invoke_sequence = Proc.new do
-
skipped = nil
-
while true
-
current = next_sequence
-
current.invoke_before(env)
-
if current.final?
-
env.value = !env.halted && (!block_given? || yield)
-
elsif current.skip?(env)
-
(skipped ||= []) << current
-
next_sequence = next_sequence.nested
-
next
-
else
-
next_sequence = next_sequence.nested
-
begin
-
target, block, method, *arguments = current.expand_call_template(env, invoke_sequence)
-
target.send(method, *arguments, &block)
-
ensure
-
next_sequence = current
-
end
-
end
-
current.invoke_after(env)
-
skipped.pop.invoke_after(env) while skipped && skipped.first
-
break env.value
-
end
-
end
-
-
# Common case: no 'around' callbacks defined
-
if next_sequence.final?
-
next_sequence.invoke_before(env)
-
env.value = !env.halted && (!block_given? || yield)
-
next_sequence.invoke_after(env)
-
env.value
-
else
-
invoke_sequence.call
-
end
-
end
-
end
-
-
1
private
-
-
# A hook invoked every time a before callback is halted.
-
# This can be overridden in ActiveSupport::Callbacks implementors in order
-
# to provide better debugging/logging.
-
1
def halted_callback_hook(filter)
-
end
-
-
1
module Conditionals # :nodoc:
-
1
class Value
-
1
def initialize(&block)
-
@block = block
-
end
-
1
def call(target, value); @block.call(value); end
-
end
-
end
-
-
1
module Filters
-
1
Environment = Struct.new(:target, :halted, :value)
-
-
1
class Before
-
1
def self.build(callback_sequence, user_callback, user_conditions, chain_config, filter)
-
halted_lambda = chain_config[:terminator]
-
-
if user_conditions.any?
-
halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
-
else
-
halting(callback_sequence, user_callback, halted_lambda, filter)
-
end
-
end
-
-
1
def self.halting_and_conditional(callback_sequence, user_callback, user_conditions, halted_lambda, filter)
-
callback_sequence.before do |env|
-
target = env.target
-
value = env.value
-
halted = env.halted
-
-
if !halted && user_conditions.all? { |c| c.call(target, value) }
-
result_lambda = -> { user_callback.call target, value }
-
env.halted = halted_lambda.call(target, result_lambda)
-
if env.halted
-
target.send :halted_callback_hook, filter
-
end
-
end
-
-
env
-
end
-
end
-
1
private_class_method :halting_and_conditional
-
-
1
def self.halting(callback_sequence, user_callback, halted_lambda, filter)
-
callback_sequence.before do |env|
-
target = env.target
-
value = env.value
-
halted = env.halted
-
-
unless halted
-
result_lambda = -> { user_callback.call target, value }
-
env.halted = halted_lambda.call(target, result_lambda)
-
-
if env.halted
-
target.send :halted_callback_hook, filter
-
end
-
end
-
-
env
-
end
-
end
-
1
private_class_method :halting
-
end
-
-
1
class After
-
1
def self.build(callback_sequence, user_callback, user_conditions, chain_config)
-
if chain_config[:skip_after_callbacks_if_terminated]
-
if user_conditions.any?
-
halting_and_conditional(callback_sequence, user_callback, user_conditions)
-
else
-
halting(callback_sequence, user_callback)
-
end
-
else
-
if user_conditions.any?
-
conditional callback_sequence, user_callback, user_conditions
-
else
-
simple callback_sequence, user_callback
-
end
-
end
-
end
-
-
1
def self.halting_and_conditional(callback_sequence, user_callback, user_conditions)
-
callback_sequence.after do |env|
-
target = env.target
-
value = env.value
-
halted = env.halted
-
-
if !halted && user_conditions.all? { |c| c.call(target, value) }
-
user_callback.call target, value
-
end
-
-
env
-
end
-
end
-
1
private_class_method :halting_and_conditional
-
-
1
def self.halting(callback_sequence, user_callback)
-
callback_sequence.after do |env|
-
unless env.halted
-
user_callback.call env.target, env.value
-
end
-
-
env
-
end
-
end
-
1
private_class_method :halting
-
-
1
def self.conditional(callback_sequence, user_callback, user_conditions)
-
callback_sequence.after do |env|
-
target = env.target
-
value = env.value
-
-
if user_conditions.all? { |c| c.call(target, value) }
-
user_callback.call target, value
-
end
-
-
env
-
end
-
end
-
1
private_class_method :conditional
-
-
1
def self.simple(callback_sequence, user_callback)
-
callback_sequence.after do |env|
-
user_callback.call env.target, env.value
-
-
env
-
end
-
end
-
1
private_class_method :simple
-
end
-
end
-
-
1
class Callback #:nodoc:#
-
1
def self.build(chain, filter, kind, options)
-
if filter.is_a?(String)
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
-
Passing string to define callback is deprecated and will be removed
-
in Rails 5.1 without replacement.
-
MSG
-
end
-
-
new chain.name, filter, kind, options, chain.config
-
end
-
-
1
attr_accessor :kind, :name
-
1
attr_reader :chain_config
-
-
1
def initialize(name, filter, kind, options, chain_config)
-
@chain_config = chain_config
-
@name = name
-
@kind = kind
-
@filter = filter
-
@key = compute_identifier filter
-
@if = Array(options[:if])
-
@unless = Array(options[:unless])
-
end
-
-
1
def filter; @key; end
-
1
def raw_filter; @filter; end
-
-
1
def merge_conditional_options(chain, if_option:, unless_option:)
-
options = {
-
if: @if.dup,
-
unless: @unless.dup
-
}
-
-
options[:if].concat Array(unless_option)
-
options[:unless].concat Array(if_option)
-
-
self.class.build chain, @filter, @kind, options
-
end
-
-
1
def matches?(_kind, _filter)
-
@kind == _kind && filter == _filter
-
end
-
-
1
def duplicates?(other)
-
case @filter
-
when Symbol, String
-
matches?(other.kind, other.filter)
-
else
-
false
-
end
-
end
-
-
# Wraps code with filter
-
1
def apply(callback_sequence)
-
user_conditions = conditions_lambdas
-
user_callback = CallTemplate.build(@filter, self)
-
-
case kind
-
when :before
-
Filters::Before.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config, @filter)
-
when :after
-
Filters::After.build(callback_sequence, user_callback.make_lambda, user_conditions, chain_config)
-
when :around
-
callback_sequence.around(user_callback, user_conditions)
-
end
-
end
-
-
1
def current_scopes
-
Array(chain_config[:scope]).map { |s| public_send(s) }
-
end
-
-
1
private
-
1
def compute_identifier(filter)
-
case filter
-
when String, ::Proc
-
filter.object_id
-
else
-
filter
-
end
-
end
-
-
1
def conditions_lambdas
-
@if.map { |c| CallTemplate.build(c, self).make_lambda } +
-
@unless.map { |c| CallTemplate.build(c, self).inverted_lambda }
-
end
-
end
-
-
# A future invocation of user-supplied code (either as a callback,
-
# or a condition filter).
-
1
class CallTemplate # :nodoc:
-
1
def initialize(target, method, arguments, block)
-
@override_target = target
-
@method_name = method
-
@arguments = arguments
-
@override_block = block
-
end
-
-
# Return the parts needed to make this call, with the given
-
# input values.
-
#
-
# Returns an array of the form:
-
#
-
# [target, block, method, *arguments]
-
#
-
# This array can be used as such:
-
#
-
# target.send(method, *arguments, &block)
-
#
-
# The actual invocation is left up to the caller to minimize
-
# call stack pollution.
-
1
def expand(target, value, block)
-
result = @arguments.map { |arg|
-
case arg
-
when :value; value
-
when :target; target
-
when :block; block || raise(ArgumentError)
-
end
-
}
-
-
result.unshift @method_name
-
result.unshift @override_block || block
-
result.unshift @override_target || target
-
-
# target, block, method, *arguments = result
-
# target.send(method, *arguments, &block)
-
result
-
end
-
-
# Return a lambda that will make this call when given the input
-
# values.
-
1
def make_lambda
-
lambda do |target, value, &block|
-
target, block, method, *arguments = expand(target, value, block)
-
target.send(method, *arguments, &block)
-
end
-
end
-
-
# Return a lambda that will make this call when given the input
-
# values, but then return the boolean inverse of that result.
-
1
def inverted_lambda
-
lambda do |target, value, &block|
-
target, block, method, *arguments = expand(target, value, block)
-
! target.send(method, *arguments, &block)
-
end
-
end
-
-
# Filters support:
-
#
-
# 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 converted into a CallTemplate and handled
-
# the same after this point.
-
1
def self.build(filter, callback)
-
case filter
-
when Symbol
-
new(nil, filter, [], nil)
-
when String
-
new(nil, :instance_exec, [:value], compile_lambda(filter))
-
when Conditionals::Value
-
new(filter, :call, [:target, :value], nil)
-
when ::Proc
-
if filter.arity > 1
-
new(nil, :instance_exec, [:target, :block], filter)
-
elsif filter.arity > 0
-
new(nil, :instance_exec, [:target], filter)
-
else
-
new(nil, :instance_exec, [], filter)
-
end
-
else
-
method_to_call = callback.current_scopes.join("_")
-
-
new(filter, method_to_call, [:target], nil)
-
end
-
end
-
-
1
def self.compile_lambda(filter)
-
eval("lambda { |value| #{filter} }")
-
end
-
end
-
-
# Execute before and after filters in a sequence instead of
-
# chaining them with nested lambda calls, see:
-
# https://github.com/rails/rails/issues/18011
-
1
class CallbackSequence # :nodoc:
-
1
def initialize(nested = nil, call_template = nil, user_conditions = nil)
-
@nested = nested
-
@call_template = call_template
-
@user_conditions = user_conditions
-
-
@before = []
-
@after = []
-
end
-
-
1
def before(&before)
-
@before.unshift(before)
-
self
-
end
-
-
1
def after(&after)
-
@after.push(after)
-
self
-
end
-
-
1
def around(call_template, user_conditions)
-
CallbackSequence.new(self, call_template, user_conditions)
-
end
-
-
1
def skip?(arg)
-
arg.halted || !@user_conditions.all? { |c| c.call(arg.target, arg.value) }
-
end
-
-
1
def nested
-
@nested
-
end
-
-
1
def final?
-
!@call_template
-
end
-
-
1
def expand_call_template(arg, block)
-
@call_template.expand(arg.target, arg.value, block)
-
end
-
-
1
def invoke_before(arg)
-
@before.each { |b| b.call(arg) }
-
end
-
-
1
def invoke_after(arg)
-
@after.each { |a| a.call(arg) }
-
end
-
end
-
-
# An Array with a compile method.
-
1
class CallbackChain #:nodoc:#
-
1
include Enumerable
-
-
1
attr_reader :name, :config
-
-
1
def initialize(name, config)
-
2
@name = name
-
2
@config = {
-
scope: [:kind],
-
terminator: default_terminator
-
}.merge!(config)
-
2
@chain = []
-
2
@callbacks = nil
-
2
@mutex = Mutex.new
-
end
-
-
1
def each(&block); @chain.each(&block); end
-
1
def index(o); @chain.index(o); end
-
3
def empty?; @chain.empty?; end
-
-
1
def insert(index, o)
-
@callbacks = nil
-
@chain.insert(index, o)
-
end
-
-
1
def delete(o)
-
@callbacks = nil
-
@chain.delete(o)
-
end
-
-
1
def clear
-
@callbacks = nil
-
@chain.clear
-
self
-
end
-
-
1
def initialize_copy(other)
-
@callbacks = nil
-
@chain = other.chain.dup
-
@mutex = Mutex.new
-
end
-
-
1
def compile
-
@callbacks || @mutex.synchronize do
-
final_sequence = CallbackSequence.new
-
@callbacks ||= @chain.reverse.inject(final_sequence) do |callback_sequence, callback|
-
callback.apply callback_sequence
-
end
-
end
-
end
-
-
1
def append(*callbacks)
-
callbacks.each { |c| append_one(c) }
-
end
-
-
1
def prepend(*callbacks)
-
callbacks.each { |c| prepend_one(c) }
-
end
-
-
1
protected
-
1
def chain; @chain; end
-
-
1
private
-
-
1
def append_one(callback)
-
@callbacks = nil
-
remove_duplicates(callback)
-
@chain.push(callback)
-
end
-
-
1
def prepend_one(callback)
-
@callbacks = nil
-
remove_duplicates(callback)
-
@chain.unshift(callback)
-
end
-
-
1
def remove_duplicates(callback)
-
@callbacks = nil
-
@chain.delete_if { |c| callback.duplicates?(c) }
-
end
-
-
1
def default_terminator
-
2
Proc.new do |target, result_lambda|
-
terminate = true
-
catch(:abort) do
-
result_lambda.call if result_lambda.is_a?(Proc)
-
terminate = false
-
end
-
terminate
-
end
-
end
-
end
-
-
1
module ClassMethods
-
1
def normalize_callback_params(filters, block) # :nodoc:
-
type = CALLBACK_FILTER_TYPES.include?(filters.first) ? filters.shift : :before
-
options = filters.extract_options!
-
filters.unshift(block) if block
-
[type, filters, options.dup]
-
end
-
-
# This is used internally to append, prepend and skip callbacks to the
-
# CallbackChain.
-
1
def __update_callbacks(name) #:nodoc:
-
([self] + ActiveSupport::DescendantsTracker.descendants(self)).reverse_each do |target|
-
chain = target.get_callbacks name
-
yield target, chain.dup
-
end
-
end
-
-
# Install a callback for the given event.
-
#
-
# set_callback :save, :before, :before_method
-
# set_callback :save, :after, :after_method, if: :condition
-
# set_callback :save, :around, ->(r, block) { stuff; result = block.call; stuff }
-
#
-
# The second argument indicates whether the callback is to be run +:before+,
-
# +:after+, or +:around+ the event. If omitted, +:before+ is assumed. This
-
# means the first example above can also be written as:
-
#
-
# set_callback :save, :before_method
-
#
-
# The callback can be specified as a symbol naming an instance method; as a
-
# proc, lambda, or block; as a string to be instance evaluated(deprecated); or as an
-
# object that responds to a certain method determined by the <tt>:scope</tt>
-
# argument to +define_callbacks+.
-
#
-
# 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.
-
#
-
# 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, a string or an array of symbols and strings,
-
# each naming an instance method or a proc; the callback will be called
-
# only when they all return a true value.
-
# * <tt>:unless</tt> - A symbol, a string or an array of symbols and
-
# strings, each naming an instance method or a proc; the callback will
-
# be called only when they all return a false value.
-
# * <tt>:prepend</tt> - If +true+, the callback will be prepended to the
-
# existing chain rather than appended.
-
1
def set_callback(name, *filter_list, &block)
-
type, filters, options = normalize_callback_params(filter_list, block)
-
self_chain = get_callbacks name
-
mapped = filters.map do |filter|
-
Callback.build(self_chain, filter, type, options)
-
end
-
-
__update_callbacks(name) do |target, chain|
-
options[:prepend] ? chain.prepend(*mapped) : chain.append(*mapped)
-
target.set_callbacks name, chain
-
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.
-
#
-
# class Writer < Person
-
# skip_callback :validate, :before, :check_membership, if: -> { age > 18 }
-
# end
-
#
-
# An <tt>ArgumentError</tt> will be raised if the callback has not
-
# already been set (unless the <tt>:raise</tt> option is set to <tt>false</tt>).
-
1
def skip_callback(name, *filter_list, &block)
-
type, filters, options = normalize_callback_params(filter_list, block)
-
options[:raise] = true unless options.key?(:raise)
-
-
__update_callbacks(name) do |target, chain|
-
filters.each do |filter|
-
callback = chain.find { |c| c.matches?(type, filter) }
-
-
if !callback && options[:raise]
-
raise ArgumentError, "#{type.to_s.capitalize} #{name} callback #{filter.inspect} has not been defined"
-
end
-
-
if callback && (options.key?(:if) || options.key?(:unless))
-
new_callback = callback.merge_conditional_options(chain, if_option: options[:if], unless_option: options[:unless])
-
chain.insert(chain.index(callback), new_callback)
-
end
-
-
chain.delete(callback)
-
end
-
target.set_callbacks name, chain
-
end
-
end
-
-
# Remove all set callbacks for the given event.
-
1
def reset_callbacks(name)
-
callbacks = get_callbacks name
-
-
ActiveSupport::DescendantsTracker.descendants(self).each do |target|
-
chain = target.get_callbacks(name).dup
-
callbacks.each { |c| chain.delete(c) }
-
target.set_callbacks name, chain
-
end
-
-
set_callbacks(name, callbacks.dup.clear)
-
end
-
-
# Define sets of events in the object life cycle that support callbacks.
-
#
-
# define_callbacks :validate
-
# define_callbacks :initialize, :save, :destroy
-
#
-
# ===== Options
-
#
-
# * <tt>:terminator</tt> - Determines when a before filter will halt the
-
# callback chain, preventing following before and around callbacks from
-
# being called and the event from being triggered.
-
# This should be a lambda to be executed.
-
# The current object and the result lambda of the callback will be provided
-
# to the terminator lambda.
-
#
-
# define_callbacks :validate, terminator: ->(target, result_lambda) { result_lambda.call == false }
-
#
-
# In this example, if any before validate callbacks returns +false+,
-
# any successive before and around callback is not executed.
-
#
-
# The default terminator halts the chain when a callback throws +:abort+.
-
#
-
# * <tt>:skip_after_callbacks_if_terminated</tt> - Determines if after
-
# callbacks should be terminated by the <tt>:terminator</tt> option. By
-
# default after callbacks are executed no matter if callback chain was
-
# terminated or not. This 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.
-
#
-
# class Audit
-
# def before(caller)
-
# puts 'Audit: before is called'
-
# end
-
#
-
# def before_save(caller)
-
# puts 'Audit: before_save is called'
-
# end
-
# end
-
#
-
# class Account
-
# include ActiveSupport::Callbacks
-
#
-
# define_callbacks :save
-
# set_callback :save, :before, Audit.new
-
#
-
# def save
-
# run_callbacks :save do
-
# puts 'save in main'
-
# end
-
# end
-
# end
-
#
-
# 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]
-
#
-
# 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]
-
#
-
# would call <tt>Audit#save</tt>.
-
#
-
# ===== Notes
-
#
-
# +names+ passed to +define_callbacks+ must not end with
-
# <tt>!</tt>, <tt>?</tt> or <tt>=</tt>.
-
#
-
# Calling +define_callbacks+ multiple times with the same +names+ will
-
# overwrite previous callbacks registered with +set_callback+.
-
1
def define_callbacks(*names)
-
1
options = names.extract_options!
-
-
1
names.each do |name|
-
2
name = name.to_sym
-
-
2
set_callbacks name, CallbackChain.new(name, options)
-
-
2
module_eval <<-RUBY, __FILE__, __LINE__ + 1
-
1
def _run_#{name}_callbacks(&block)
-
run_callbacks #{name.inspect}, &block
-
end
-
-
1
def self._#{name}_callbacks
-
get_callbacks(#{name.inspect})
-
end
-
-
1
def self._#{name}_callbacks=(value)
-
set_callbacks(#{name.inspect}, value)
-
end
-
-
1
def _#{name}_callbacks
-
__callbacks[#{name.inspect}]
-
end
-
RUBY
-
end
-
end
-
-
1
protected
-
-
1
def get_callbacks(name) # :nodoc:
-
__callbacks[name.to_sym]
-
end
-
-
1
def set_callbacks(name, callbacks) # :nodoc:
-
2
self.__callbacks = __callbacks.merge(name.to_sym => callbacks)
-
end
-
-
1
def deprecated_false_terminator # :nodoc:
-
Proc.new do |target, result_lambda|
-
terminate = true
-
catch(:abort) do
-
result = result_lambda.call if result_lambda.is_a?(Proc)
-
if Callbacks.halt_and_display_warning_on_return_false && result == false
-
display_deprecation_warning_for_false_terminator
-
else
-
terminate = false
-
end
-
end
-
terminate
-
end
-
end
-
-
1
private
-
-
1
def display_deprecation_warning_for_false_terminator
-
ActiveSupport::Deprecation.warn(<<-MSG.squish)
-
Returning `false` in Active Record and Active Model callbacks will not implicitly halt a callback chain in Rails 5.1.
-
To explicitly halt the callback chain, please use `throw :abort` instead.
-
MSG
-
end
-
end
-
end
-
end
-
1
module ActiveSupport
-
# A typical module looks like this:
-
#
-
# module M
-
# def self.included(base)
-
# base.extend ClassMethods
-
# base.class_eval do
-
# scope :disabled, -> { where(disabled: true) }
-
# end
-
# end
-
#
-
# module ClassMethods
-
# ...
-
# end
-
# end
-
#
-
# By using <tt>ActiveSupport::Concern</tt> the above module could instead be
-
# written as:
-
#
-
# require 'active_support/concern'
-
#
-
# module M
-
# extend ActiveSupport::Concern
-
#
-
# included do
-
# scope :disabled, -> { where(disabled: true) }
-
# end
-
#
-
# class_methods do
-
# ...
-
# 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:
-
#
-
# module Foo
-
# def self.included(base)
-
# base.class_eval do
-
# def self.method_injected_by_foo
-
# ...
-
# end
-
# end
-
# end
-
# end
-
#
-
# module Bar
-
# def self.included(base)
-
# base.method_injected_by_foo
-
# end
-
# end
-
#
-
# class Host
-
# include Foo # We need to include this dependency for Bar
-
# 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+:
-
#
-
# module Bar
-
# include Foo
-
# def self.included(base)
-
# base.method_injected_by_foo
-
# end
-
# end
-
#
-
# class Host
-
# 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:
-
#
-
# require 'active_support/concern'
-
#
-
# module Foo
-
# extend ActiveSupport::Concern
-
# included do
-
# def self.method_injected_by_foo
-
# ...
-
# end
-
# end
-
# end
-
#
-
# module Bar
-
# extend ActiveSupport::Concern
-
# include Foo
-
#
-
# included do
-
# self.method_injected_by_foo
-
# end
-
# end
-
#
-
# class Host
-
# include Bar # It works, now Bar takes care of its dependencies
-
# end
-
1
module Concern
-
1
class MultipleIncludedBlocks < StandardError #:nodoc:
-
1
def initialize
-
super "Cannot define multiple 'included' blocks for a Concern"
-
end
-
end
-
-
1
def self.extended(base) #:nodoc:
-
6
base.instance_variable_set(:@_dependencies, [])
-
end
-
-
1
def append_features(base)
-
5
if base.instance_variable_defined?(:@_dependencies)
-
base.instance_variable_get(:@_dependencies) << self
-
return false
-
else
-
5
return false if base < self
-
5
@_dependencies.each { |dep| base.include(dep) }
-
5
super
-
5
base.extend const_get(:ClassMethods) if const_defined?(:ClassMethods)
-
5
base.class_eval(&@_included_block) if instance_variable_defined?(:@_included_block)
-
end
-
end
-
-
1
def included(base = nil, &block)
-
9
if base.nil?
-
4
raise MultipleIncludedBlocks if instance_variable_defined?(:@_included_block)
-
-
4
@_included_block = block
-
else
-
5
super
-
end
-
end
-
-
1
def class_methods(&class_methods_module_definition)
-
mod = const_defined?(:ClassMethods, false) ?
-
const_get(:ClassMethods) :
-
const_set(:ClassMethods, Module.new)
-
-
mod.module_eval(&class_methods_module_definition)
-
end
-
end
-
end
-
1
class Hash
-
# By default, only instances of Hash itself are extractable.
-
# Subclasses of Hash may implement this method and return
-
# true to declare themselves as extractable. If a Hash
-
# is extractable, Array#extract_options! pops it from
-
# the Array when it is the last element of the Array.
-
1
def extractable_options?
-
6
instance_of?(Hash)
-
end
-
end
-
-
1
class Array
-
# Extracts options from a set of arguments. Removes and returns the last
-
# element in the array if it's a hash, otherwise returns a blank hash.
-
#
-
# def options(*args)
-
# args.extract_options!
-
# end
-
#
-
# options(1, 2) # => {}
-
# options(1, 2, a: :b) # => {:a=>:b}
-
1
def extract_options!
-
11
if last.is_a?(Hash) && last.extractable_options?
-
6
pop
-
else
-
5
{}
-
end
-
end
-
end
-
1
class Array
-
# The human way of thinking about adding stuff to the end of a list is with append.
-
1
alias_method :append, :<<
-
-
# The human way of thinking about adding stuff to the beginning of a list is with prepend.
-
1
alias_method :prepend, :unshift
-
end
-
1
require "active_support/core_ext/kernel/singleton_class"
-
1
require "active_support/core_ext/module/remove_method"
-
1
require "active_support/core_ext/array/extract_options"
-
-
1
class Class
-
# Declare a class-level attribute whose value is inheritable by subclasses.
-
# Subclasses can change their own value and it will not impact parent class.
-
#
-
# class Base
-
# class_attribute :setting
-
# end
-
#
-
# class Subclass < Base
-
# end
-
#
-
# Base.setting = true
-
# Subclass.setting # => true
-
# Subclass.setting = false
-
# Subclass.setting # => false
-
# Base.setting # => true
-
#
-
# In the above case as long as Subclass does not assign a value to setting
-
# by performing <tt>Subclass.setting = _something_</tt>, <tt>Subclass.setting</tt>
-
# would read value assigned to parent class. Once Subclass assigns a value then
-
# the value assigned by Subclass would be returned.
-
#
-
# This matches normal Ruby method inheritance: think of writing an attribute
-
# on a subclass as overriding the reader method. However, you need to be aware
-
# when using +class_attribute+ with mutable structures as +Array+ or +Hash+.
-
# In such cases, you don't want to do changes in place. Instead use setters:
-
#
-
# Base.setting = []
-
# Base.setting # => []
-
# Subclass.setting # => []
-
#
-
# # Appending in child changes both parent and child because it is the same object:
-
# Subclass.setting << :foo
-
# Base.setting # => [:foo]
-
# Subclass.setting # => [:foo]
-
#
-
# # Use setters to not propagate changes:
-
# Base.setting = []
-
# Subclass.setting += [:foo]
-
# Base.setting # => []
-
# Subclass.setting # => [:foo]
-
#
-
# For convenience, an instance predicate method is defined as well.
-
# To skip it, pass <tt>instance_predicate: false</tt>.
-
#
-
# Subclass.setting? # => false
-
#
-
# Instances may overwrite the class value in the same way:
-
#
-
# Base.setting = true
-
# object = Base.new
-
# object.setting # => true
-
# object.setting = false
-
# object.setting # => false
-
# Base.setting # => true
-
#
-
# To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
-
#
-
# object.setting # => NoMethodError
-
# object.setting? # => NoMethodError
-
#
-
# To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
-
#
-
# object.setting = false # => NoMethodError
-
#
-
# To opt out of both instance methods, pass <tt>instance_accessor: false</tt>.
-
1
def class_attribute(*attrs)
-
2
options = attrs.extract_options!
-
2
instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
-
2
instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
-
2
instance_predicate = options.fetch(:instance_predicate, true)
-
-
2
attrs.each do |name|
-
2
remove_possible_singleton_method(name)
-
3
define_singleton_method(name) { nil }
-
-
2
remove_possible_singleton_method("#{name}?")
-
2
define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
-
-
2
ivar = "@#{name}"
-
-
2
remove_possible_singleton_method("#{name}=")
-
2
define_singleton_method("#{name}=") do |val|
-
3
singleton_class.class_eval do
-
3
remove_possible_method(name)
-
7
define_method(name) { val }
-
end
-
-
3
if singleton_class?
-
class_eval do
-
remove_possible_method(name)
-
define_method(name) do
-
if instance_variable_defined? ivar
-
instance_variable_get ivar
-
else
-
singleton_class.send name
-
end
-
end
-
end
-
end
-
3
val
-
end
-
-
2
if instance_reader
-
2
remove_possible_method name
-
2
define_method(name) do
-
2
if instance_variable_defined?(ivar)
-
instance_variable_get ivar
-
else
-
2
self.class.public_send name
-
end
-
end
-
-
2
remove_possible_method "#{name}?"
-
2
define_method("#{name}?") { !!public_send(name) } if instance_predicate
-
end
-
-
2
if instance_writer
-
remove_possible_method "#{name}="
-
attr_writer name
-
end
-
end
-
end
-
end
-
1
require "active_support/core_ext/module/attribute_accessors"
-
-
1
module DateAndTime
-
1
module Compatibility
-
# If true, +to_time+ preserves the timezone offset of receiver.
-
#
-
# NOTE: With Ruby 2.4+ the default for +to_time+ changed from
-
# converting to the local system time, to preserving the offset
-
# of the receiver. For backwards compatibility we're overriding
-
# this behavior, but new apps will have an initializer that sets
-
# this to true, because the new behavior is preferred.
-
2
mattr_accessor(:preserve_timezone, instance_writer: false) { false }
-
-
1
def to_time
-
if preserve_timezone
-
@_to_time_with_instance_offset ||= getlocal(utc_offset)
-
else
-
@_to_time_with_system_offset ||= getlocal
-
end
-
end
-
end
-
end
-
1
class Hash
-
# Returns a new hash with +self+ and +other_hash+ merged recursively.
-
#
-
# h1 = { a: true, b: { c: [1, 2, 3] } }
-
# h2 = { a: false, b: { x: [3, 4, 5] } }
-
#
-
# h1.deep_merge(h2) # => { a: false, b: { c: [1, 2, 3], x: [3, 4, 5] } }
-
#
-
# Like with Hash#merge in the standard library, a block can be provided
-
# to merge values:
-
#
-
# h1 = { a: 100, b: 200, c: { c1: 100 } }
-
# h2 = { b: 250, c: { c1: 200 } }
-
# h1.deep_merge(h2) { |key, this_val, other_val| this_val + other_val }
-
# # => { a: 100, b: 450, c: { c1: 300 } }
-
1
def deep_merge(other_hash, &block)
-
dup.deep_merge!(other_hash, &block)
-
end
-
-
# Same as +deep_merge+, but modifies +self+.
-
1
def deep_merge!(other_hash, &block)
-
other_hash.each_pair do |current_key, other_value|
-
this_value = self[current_key]
-
-
self[current_key] = if this_value.is_a?(Hash) && other_value.is_a?(Hash)
-
this_value.deep_merge(other_value, &block)
-
else
-
if block_given? && key?(current_key)
-
block.call(current_key, this_value, other_value)
-
else
-
other_value
-
end
-
end
-
end
-
-
self
-
end
-
end
-
1
class Hash
-
# Returns a hash that includes everything except given keys.
-
# hash = { a: true, b: false, c: nil }
-
# hash.except(:c) # => { a: true, b: false }
-
# hash.except(:a, :b) # => { c: nil }
-
# hash # => { a: true, b: false, c: nil }
-
#
-
# This is useful for limiting a set of parameters to everything but a few known toggles:
-
# @person.update(params[:person].except(:admin))
-
1
def except(*keys)
-
dup.except!(*keys)
-
end
-
-
# Removes the given keys from hash and returns it.
-
# hash = { a: true, b: false, c: nil }
-
# hash.except!(:c) # => { a: true, b: false }
-
# hash # => { a: true, b: false }
-
1
def except!(*keys)
-
keys.each { |key| delete(key) }
-
self
-
end
-
end
-
1
class Hash
-
# Slices a hash to include only the given keys. Returns a hash containing
-
# the given keys.
-
#
-
# { a: 1, b: 2, c: 3, d: 4 }.slice(:a, :b)
-
# # => {:a=>1, :b=>2}
-
#
-
# This is useful for limiting an options hash to valid keys before
-
# passing to a method:
-
#
-
# def search(criteria = {})
-
# criteria.assert_valid_keys(:mass, :velocity, :time)
-
# end
-
#
-
# search(options.slice(:mass, :velocity, :time))
-
#
-
# If you have an array of keys you want to limit to, you should splat them:
-
#
-
# valid_keys = [:mass, :velocity, :time]
-
# search(options.slice(*valid_keys))
-
1
def slice(*keys)
-
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
-
keys.each_with_object(self.class.new) { |k, hash| hash[k] = self[k] if has_key?(k) }
-
end
-
-
# Replaces the hash with only the given keys.
-
# Returns a hash containing the removed key/value pairs.
-
#
-
# { a: 1, b: 2, c: 3, d: 4 }.slice!(:a, :b)
-
# # => {:c=>3, :d=>4}
-
1
def slice!(*keys)
-
keys.map! { |key| convert_key(key) } if respond_to?(:convert_key, true)
-
omit = slice(*self.keys - keys)
-
hash = slice(*keys)
-
hash.default = default
-
hash.default_proc = default_proc if default_proc
-
replace(hash)
-
omit
-
end
-
-
# Removes and returns the key/value pairs matching the given keys.
-
#
-
# { a: 1, b: 2, c: 3, d: 4 }.extract!(:a, :b) # => {:a=>1, :b=>2}
-
# { a: 1, b: 2 }.extract!(:a, :x) # => {:a=>1}
-
1
def extract!(*keys)
-
keys.each_with_object(self.class.new) { |key, result| result[key] = delete(key) if has_key?(key) }
-
end
-
end
-
1
module Kernel
-
1
module_function
-
-
# Sets $VERBOSE to +nil+ for the duration of the block and back to its original
-
# value afterwards.
-
#
-
# silence_warnings do
-
# value = noisy_call # no warning voiced
-
# end
-
#
-
# noisy_call # warning voiced
-
1
def silence_warnings
-
2
with_warnings(nil) { yield }
-
end
-
-
# Sets $VERBOSE to +true+ for the duration of the block and back to its
-
# original value afterwards.
-
1
def enable_warnings
-
with_warnings(true) { yield }
-
end
-
-
# Sets $VERBOSE for the duration of the block and back to its original
-
# value afterwards.
-
1
def with_warnings(flag)
-
1
old_verbose, $VERBOSE = $VERBOSE, flag
-
1
yield
-
ensure
-
1
$VERBOSE = old_verbose
-
end
-
-
# Blocks and ignores any exception passed as argument if raised within the block.
-
#
-
# suppress(ZeroDivisionError) do
-
# 1/0
-
# puts 'This code is NOT reached'
-
# end
-
#
-
# puts 'This code gets executed and nothing related to ZeroDivisionError was seen'
-
1
def suppress(*exception_classes)
-
yield
-
rescue *exception_classes
-
end
-
end
-
1
module Kernel
-
# class_eval on an object acts like singleton_class.class_eval.
-
1
def class_eval(*args, &block)
-
singleton_class.class_eval(*args, &block)
-
end
-
end
-
1
class Module
-
# Allows you to make aliases for attributes, which includes
-
# getter, setter, and a predicate.
-
#
-
# class Content < ActiveRecord::Base
-
# # has a title attribute
-
# end
-
#
-
# class Email < Content
-
# alias_attribute :subject, :title
-
# end
-
#
-
# e = Email.find(1)
-
# e.title # => "Superstars"
-
# e.subject # => "Superstars"
-
# e.subject? # => true
-
# e.subject = "Megastars"
-
# e.title # => "Megastars"
-
1
def alias_attribute(new_name, old_name)
-
# The following reader methods use an explicit `self` receiver in order to
-
# support aliases that start with an uppercase letter. Otherwise, they would
-
# be resolved as constants instead.
-
module_eval <<-STR, __FILE__, __LINE__ + 1
-
def #{new_name}; self.#{old_name}; end # def subject; self.title; end
-
def #{new_name}?; self.#{old_name}?; end # def subject?; self.title?; end
-
def #{new_name}=(v); self.#{old_name} = v; end # def subject=(v); self.title = v; end
-
STR
-
end
-
end
-
1
require "active_support/core_ext/array/extract_options"
-
1
require "active_support/core_ext/regexp"
-
-
# Extends the module object with class/module and instance accessors for
-
# class/module attributes, just like the native attr* accessors for instance
-
# attributes.
-
1
class Module
-
# Defines a class attribute and creates a class and instance reader methods.
-
# The underlying class variable is set to +nil+, if it is not previously
-
# defined. All class and instance methods created will be public, even if
-
# this method is called with a private or protected access modifier.
-
#
-
# module HairColors
-
# mattr_reader :hair_colors
-
# end
-
#
-
# HairColors.hair_colors # => nil
-
# HairColors.class_variable_set("@@hair_colors", [:brown, :black])
-
# HairColors.hair_colors # => [:brown, :black]
-
#
-
# The attribute name must be a valid method name in Ruby.
-
#
-
# module Foo
-
# mattr_reader :"1_Badname"
-
# end
-
# # => NameError: invalid attribute name: 1_Badname
-
#
-
# If you want to opt out the creation on the instance reader method, pass
-
# <tt>instance_reader: false</tt> or <tt>instance_accessor: false</tt>.
-
#
-
# module HairColors
-
# mattr_reader :hair_colors, instance_reader: false
-
# end
-
#
-
# class Person
-
# include HairColors
-
# end
-
#
-
# Person.new.hair_colors # => NoMethodError
-
#
-
#
-
# Also, you can pass a block to set up the attribute with a default value.
-
#
-
# module HairColors
-
# mattr_reader :hair_colors do
-
# [:brown, :black, :blonde, :red]
-
# end
-
# end
-
#
-
# class Person
-
# include HairColors
-
# end
-
#
-
# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
-
1
def mattr_reader(*syms)
-
4
options = syms.extract_options!
-
4
syms.each do |sym|
-
4
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
-
4
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
-
1
@@#{sym} = nil unless defined? @@#{sym}
-
-
1
def self.#{sym}
-
@@#{sym}
-
end
-
EOS
-
-
4
unless options[:instance_reader] == false || options[:instance_accessor] == false
-
4
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
-
1
def #{sym}
-
@@#{sym}
-
end
-
EOS
-
end
-
4
class_variable_set("@@#{sym}", yield) if block_given?
-
end
-
end
-
1
alias :cattr_reader :mattr_reader
-
-
# Defines a class attribute and creates a class and instance writer methods to
-
# allow assignment to the attribute. All class and instance methods created
-
# will be public, even if this method is called with a private or protected
-
# access modifier.
-
#
-
# module HairColors
-
# mattr_writer :hair_colors
-
# end
-
#
-
# class Person
-
# include HairColors
-
# end
-
#
-
# HairColors.hair_colors = [:brown, :black]
-
# Person.class_variable_get("@@hair_colors") # => [:brown, :black]
-
# Person.new.hair_colors = [:blonde, :red]
-
# HairColors.class_variable_get("@@hair_colors") # => [:blonde, :red]
-
#
-
# If you want to opt out the instance writer method, pass
-
# <tt>instance_writer: false</tt> or <tt>instance_accessor: false</tt>.
-
#
-
# module HairColors
-
# mattr_writer :hair_colors, instance_writer: false
-
# end
-
#
-
# class Person
-
# include HairColors
-
# end
-
#
-
# Person.new.hair_colors = [:blonde, :red] # => NoMethodError
-
#
-
# Also, you can pass a block to set up the attribute with a default value.
-
#
-
# module HairColors
-
# mattr_writer :hair_colors do
-
# [:brown, :black, :blonde, :red]
-
# end
-
# end
-
#
-
# class Person
-
# include HairColors
-
# end
-
#
-
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
-
1
def mattr_writer(*syms)
-
4
options = syms.extract_options!
-
4
syms.each do |sym|
-
4
raise NameError.new("invalid attribute name: #{sym}") unless /\A[_A-Za-z]\w*\z/.match?(sym)
-
4
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
-
1
@@#{sym} = nil unless defined? @@#{sym}
-
-
1
def self.#{sym}=(obj)
-
@@#{sym} = obj
-
end
-
EOS
-
-
4
unless options[:instance_writer] == false || options[:instance_accessor] == false
-
2
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
-
1
def #{sym}=(obj)
-
@@#{sym} = obj
-
end
-
EOS
-
end
-
4
send("#{sym}=", yield) if block_given?
-
end
-
end
-
1
alias :cattr_writer :mattr_writer
-
-
# Defines both class and instance accessors for class attributes.
-
# All class and instance methods created will be public, even if
-
# this method is called with a private or protected access modifier.
-
#
-
# module HairColors
-
# mattr_accessor :hair_colors
-
# end
-
#
-
# class Person
-
# include HairColors
-
# end
-
#
-
# HairColors.hair_colors = [:brown, :black, :blonde, :red]
-
# HairColors.hair_colors # => [:brown, :black, :blonde, :red]
-
# Person.new.hair_colors # => [:brown, :black, :blonde, :red]
-
#
-
# If a subclass changes the value then that would also change the value for
-
# parent class. Similarly if parent class changes the value then that would
-
# change the value of subclasses too.
-
#
-
# class Male < Person
-
# end
-
#
-
# Male.new.hair_colors << :blue
-
# Person.new.hair_colors # => [:brown, :black, :blonde, :red, :blue]
-
#
-
# To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
-
# To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
-
#
-
# module HairColors
-
# mattr_accessor :hair_colors, instance_writer: false, instance_reader: false
-
# end
-
#
-
# class Person
-
# include HairColors
-
# end
-
#
-
# Person.new.hair_colors = [:brown] # => NoMethodError
-
# Person.new.hair_colors # => NoMethodError
-
#
-
# Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
-
#
-
# module HairColors
-
# mattr_accessor :hair_colors, instance_accessor: false
-
# end
-
#
-
# class Person
-
# include HairColors
-
# end
-
#
-
# Person.new.hair_colors = [:brown] # => NoMethodError
-
# Person.new.hair_colors # => NoMethodError
-
#
-
# Also you can pass a block to set up the attribute with a default value.
-
#
-
# module HairColors
-
# mattr_accessor :hair_colors do
-
# [:brown, :black, :blonde, :red]
-
# end
-
# end
-
#
-
# class Person
-
# include HairColors
-
# end
-
#
-
# Person.class_variable_get("@@hair_colors") # => [:brown, :black, :blonde, :red]
-
1
def mattr_accessor(*syms, &blk)
-
4
mattr_reader(*syms, &blk)
-
4
mattr_writer(*syms)
-
end
-
1
alias :cattr_accessor :mattr_accessor
-
end
-
1
require "set"
-
1
require "active_support/core_ext/regexp"
-
-
1
class Module
-
# Error generated by +delegate+ when a method is called on +nil+ and +allow_nil+
-
# option is not used.
-
1
class DelegationError < NoMethodError; end
-
-
1
RUBY_RESERVED_KEYWORDS = %w(alias and BEGIN begin break case class def defined? do
-
else elsif END end ensure false for if in module next nil not or redo rescue retry
-
return self super then true undef unless until when while yield)
-
1
DELEGATION_RESERVED_KEYWORDS = %w(_ arg args block)
-
1
DELEGATION_RESERVED_METHOD_NAMES = Set.new(
-
RUBY_RESERVED_KEYWORDS + DELEGATION_RESERVED_KEYWORDS
-
).freeze
-
-
# Provides a +delegate+ class method to easily expose contained objects'
-
# public methods as your own.
-
#
-
# ==== Options
-
# * <tt>:to</tt> - Specifies the target object
-
# * <tt>:prefix</tt> - Prefixes the new method with the target name or a custom prefix
-
# * <tt>:allow_nil</tt> - if set to true, prevents a +NoMethodError+ from being raised
-
#
-
# The macro receives one or more method names (specified as symbols or
-
# strings) and the name of the target object via the <tt>:to</tt> option
-
# (also a symbol or string).
-
#
-
# Delegation is particularly useful with Active Record associations:
-
#
-
# class Greeter < ActiveRecord::Base
-
# def hello
-
# 'hello'
-
# end
-
#
-
# def goodbye
-
# 'goodbye'
-
# end
-
# end
-
#
-
# class Foo < ActiveRecord::Base
-
# belongs_to :greeter
-
# delegate :hello, to: :greeter
-
# end
-
#
-
# Foo.new.hello # => "hello"
-
# Foo.new.goodbye # => NoMethodError: undefined method `goodbye' for #<Foo:0x1af30c>
-
#
-
# Multiple delegates to the same target are allowed:
-
#
-
# class Foo < ActiveRecord::Base
-
# belongs_to :greeter
-
# delegate :hello, :goodbye, to: :greeter
-
# end
-
#
-
# Foo.new.goodbye # => "goodbye"
-
#
-
# Methods can be delegated to instance variables, class variables, or constants
-
# by providing them as a symbols:
-
#
-
# class Foo
-
# CONSTANT_ARRAY = [0,1,2,3]
-
# @@class_array = [4,5,6,7]
-
#
-
# def initialize
-
# @instance_array = [8,9,10,11]
-
# end
-
# delegate :sum, to: :CONSTANT_ARRAY
-
# delegate :min, to: :@@class_array
-
# delegate :max, to: :@instance_array
-
# end
-
#
-
# Foo.new.sum # => 6
-
# Foo.new.min # => 4
-
# Foo.new.max # => 11
-
#
-
# It's also possible to delegate a method to the class by using +:class+:
-
#
-
# class Foo
-
# def self.hello
-
# "world"
-
# end
-
#
-
# delegate :hello, to: :class
-
# end
-
#
-
# Foo.new.hello # => "world"
-
#
-
# Delegates can optionally be prefixed using the <tt>:prefix</tt> option. If the value
-
# is <tt>true</tt>, the delegate methods are prefixed with the name of the object being
-
# delegated to.
-
#
-
# Person = Struct.new(:name, :address)
-
#
-
# class Invoice < Struct.new(:client)
-
# delegate :name, :address, to: :client, prefix: true
-
# end
-
#
-
# john_doe = Person.new('John Doe', 'Vimmersvej 13')
-
# invoice = Invoice.new(john_doe)
-
# invoice.client_name # => "John Doe"
-
# invoice.client_address # => "Vimmersvej 13"
-
#
-
# It is also possible to supply a custom prefix.
-
#
-
# class Invoice < Struct.new(:client)
-
# delegate :name, :address, to: :client, prefix: :customer
-
# end
-
#
-
# invoice = Invoice.new(john_doe)
-
# invoice.customer_name # => 'John Doe'
-
# invoice.customer_address # => 'Vimmersvej 13'
-
#
-
# If the target is +nil+ and does not respond to the delegated method a
-
# +NoMethodError+ is raised, as with any other value. Sometimes, however, it
-
# makes sense to be robust to that situation and that is the purpose of the
-
# <tt>:allow_nil</tt> option: If the target is not +nil+, or it is and
-
# responds to the method, everything works as usual. But if it is +nil+ and
-
# does not respond to the delegated method, +nil+ is returned.
-
#
-
# class User < ActiveRecord::Base
-
# has_one :profile
-
# delegate :age, to: :profile
-
# end
-
#
-
# User.new.age # raises NoMethodError: undefined method `age'
-
#
-
# But if not having a profile yet is fine and should not be an error
-
# condition:
-
#
-
# class User < ActiveRecord::Base
-
# has_one :profile
-
# delegate :age, to: :profile, allow_nil: true
-
# end
-
#
-
# User.new.age # nil
-
#
-
# Note that if the target is not +nil+ then the call is attempted regardless of the
-
# <tt>:allow_nil</tt> option, and thus an exception is still raised if said object
-
# does not respond to the method:
-
#
-
# class Foo
-
# def initialize(bar)
-
# @bar = bar
-
# end
-
#
-
# delegate :name, to: :@bar, allow_nil: true
-
# end
-
#
-
# Foo.new("Bar").name # raises NoMethodError: undefined method `name'
-
#
-
# The target method must be public, otherwise it will raise +NoMethodError+.
-
1
def delegate(*methods, to: nil, prefix: nil, allow_nil: nil)
-
15
unless to
-
raise ArgumentError, "Delegation needs a target. Supply an options hash with a :to key as the last argument (e.g. delegate :hello, to: :greeter)."
-
end
-
-
15
if prefix == true && /^[^a-z_]/.match?(to)
-
raise ArgumentError, "Can only automatically set the delegation prefix when delegating to a method."
-
end
-
-
15
method_prefix = \
-
15
if prefix
-
"#{prefix == true ? to : prefix}_"
-
else
-
15
""
-
end
-
-
15
location = caller_locations(1, 1).first
-
15
file, line = location.path, location.lineno
-
-
15
to = to.to_s
-
15
to = "self.#{to}" if DELEGATION_RESERVED_METHOD_NAMES.include?(to)
-
-
15
methods.each do |method|
-
# Attribute writer methods only accept one argument. Makes sure []=
-
# methods still accept two arguments.
-
15
definition = /[^\]]=$/.match?(method) ? "arg" : "*args, &block"
-
-
# The following generated method calls the target exactly once, storing
-
# the returned value in a dummy variable.
-
#
-
# Reason is twofold: On one hand doing less calls is in general better.
-
# On the other hand it could be that the target has side-effects,
-
# whereas conceptually, from the user point of view, the delegator should
-
# be doing one call.
-
15
if allow_nil
-
method_def = [
-
"def #{method_prefix}#{method}(#{definition})",
-
"_ = #{to}",
-
"if !_.nil? || nil.respond_to?(:#{method})",
-
" _.#{method}(#{definition})",
-
"end",
-
"end"
-
].join ";"
-
else
-
15
exception = %(raise DelegationError, "#{self}##{method_prefix}#{method} delegated to #{to}.#{method}, but #{to} is nil: \#{self.inspect}")
-
-
15
method_def = [
-
"def #{method_prefix}#{method}(#{definition})",
-
" _ = #{to}",
-
" _.#{method}(#{definition})",
-
"rescue NoMethodError => e",
-
" if _.nil? && e.name == :#{method}",
-
" #{exception}",
-
" else",
-
" raise",
-
" end",
-
"end"
-
].join ";"
-
end
-
-
15
module_eval(method_def, file, line)
-
end
-
end
-
-
# When building decorators, a common pattern may emerge:
-
#
-
# class Partition
-
# def initialize(first_event)
-
# @events = [ first_event ]
-
# end
-
#
-
# def people
-
# if @events.first.detail.people.any?
-
# @events.collect { |e| Array(e.detail.people) }.flatten.uniq
-
# else
-
# @events.collect(&:creator).uniq
-
# end
-
# end
-
#
-
# private
-
# def respond_to_missing?(name, include_private = false)
-
# @events.respond_to?(name, include_private)
-
# end
-
#
-
# def method_missing(method, *args, &block)
-
# @events.send(method, *args, &block)
-
# end
-
# end
-
#
-
# With `Module#delegate_missing_to`, the above is condensed to:
-
#
-
# class Partition
-
# delegate_missing_to :@events
-
#
-
# def initialize(first_event)
-
# @events = [ first_event ]
-
# end
-
#
-
# def people
-
# if @events.first.detail.people.any?
-
# @events.collect { |e| Array(e.detail.people) }.flatten.uniq
-
# else
-
# @events.collect(&:creator).uniq
-
# end
-
# end
-
# end
-
#
-
# The target can be anything callable within the object. E.g. instance
-
# variables, methods, constants ant the likes.
-
1
def delegate_missing_to(target)
-
target = target.to_s
-
target = "self.#{target}" if DELEGATION_RESERVED_METHOD_NAMES.include?(target)
-
-
module_eval <<-RUBY, __FILE__, __LINE__ + 1
-
def respond_to_missing?(name, include_private = false)
-
#{target}.respond_to?(name, include_private)
-
end
-
-
def method_missing(method, *args, &block)
-
if #{target}.respond_to?(method)
-
#{target}.public_send(method, *args, &block)
-
else
-
super
-
end
-
end
-
RUBY
-
end
-
end
-
1
class Module
-
# deprecate :foo
-
# deprecate bar: 'message'
-
# deprecate :foo, :bar, baz: 'warning!', qux: 'gone!'
-
#
-
# You can also use custom deprecator instance:
-
#
-
# deprecate :foo, deprecator: MyLib::Deprecator.new
-
# deprecate :foo, bar: "warning!", deprecator: MyLib::Deprecator.new
-
#
-
# \Custom deprecators must respond to <tt>deprecation_warning(deprecated_method_name, message, caller_backtrace)</tt>
-
# method where you can implement your custom warning behavior.
-
#
-
# class MyLib::Deprecator
-
# def deprecation_warning(deprecated_method_name, message, caller_backtrace = nil)
-
# message = "#{deprecated_method_name} is deprecated and will be removed from MyLibrary | #{message}"
-
# Kernel.warn message
-
# end
-
# end
-
1
def deprecate(*method_names)
-
ActiveSupport::Deprecation.deprecate_methods(self, *method_names)
-
end
-
end
-
1
class Module
-
# Removes the named method, if it exists.
-
1
def remove_possible_method(method)
-
13
if method_defined?(method) || private_method_defined?(method)
-
3
undef_method(method)
-
end
-
end
-
-
# Removes the named singleton method, if it exists.
-
1
def remove_possible_singleton_method(method)
-
6
singleton_class.instance_eval do
-
6
remove_possible_method(method)
-
end
-
end
-
-
# Replaces the existing method definition, if there is one, with the passed
-
# block as its body.
-
1
def redefine_method(method, &block)
-
visibility = method_visibility(method)
-
remove_possible_method(method)
-
define_method(method, &block)
-
send(visibility, method)
-
end
-
-
1
def method_visibility(method) # :nodoc:
-
case
-
when private_method_defined?(method)
-
:private
-
when protected_method_defined?(method)
-
:protected
-
else
-
:public
-
end
-
end
-
end
-
1
class Regexp #:nodoc:
-
1
def multiline?
-
options & MULTILINE == MULTILINE
-
end
-
-
def match?(string, pos = 0)
-
!!match(string, pos)
-
1
end unless //.respond_to?(:match?)
-
end
-
1
class String
-
# Returns the string, first removing all whitespace on both ends of
-
# the string, and then changing remaining consecutive whitespace
-
# groups into one space each.
-
#
-
# Note that it handles both ASCII and Unicode whitespace.
-
#
-
# %{ Multi-line
-
# string }.squish # => "Multi-line string"
-
# " foo bar \n \t boo".squish # => "foo bar boo"
-
1
def squish
-
dup.squish!
-
end
-
-
# Performs a destructive squish. See String#squish.
-
# str = " foo bar \n \t boo"
-
# str.squish! # => "foo bar boo"
-
# str # => "foo bar boo"
-
1
def squish!
-
gsub!(/[[:space:]]+/, " ")
-
strip!
-
self
-
end
-
-
# Returns a new string with all occurrences of the patterns removed.
-
# str = "foo bar test"
-
# str.remove(" test") # => "foo bar"
-
# str.remove(" test", /bar/) # => "foo "
-
# str # => "foo bar test"
-
1
def remove(*patterns)
-
dup.remove!(*patterns)
-
end
-
-
# Alters the string by removing all occurrences of the patterns.
-
# str = "foo bar test"
-
# str.remove!(" test", /bar/) # => "foo "
-
# str # => "foo "
-
1
def remove!(*patterns)
-
patterns.each do |pattern|
-
gsub! pattern, ""
-
end
-
-
self
-
end
-
-
# Truncates a given +text+ after a given <tt>length</tt> if +text+ is longer than <tt>length</tt>:
-
#
-
# 'Once upon a time in a world far far away'.truncate(27)
-
# # => "Once upon a time in a wo..."
-
#
-
# Pass a string or regexp <tt>:separator</tt> to truncate +text+ at a natural break:
-
#
-
# 'Once upon a time in a world far far away'.truncate(27, separator: ' ')
-
# # => "Once upon a time in a..."
-
#
-
# 'Once upon a time in a world far far away'.truncate(27, separator: /\s/)
-
# # => "Once upon a time in a..."
-
#
-
# The last characters will be replaced with the <tt>:omission</tt> string (defaults to "...")
-
# for a total length not exceeding <tt>length</tt>:
-
#
-
# 'And they found that many people were sleeping better.'.truncate(25, omission: '... (continued)')
-
# # => "And they f... (continued)"
-
1
def truncate(truncate_at, options = {})
-
return dup unless length > truncate_at
-
-
omission = options[:omission] || "..."
-
length_with_room_for_omission = truncate_at - omission.length
-
stop = \
-
if options[:separator]
-
rindex(options[:separator], length_with_room_for_omission) || length_with_room_for_omission
-
else
-
length_with_room_for_omission
-
end
-
-
"#{self[0, stop]}#{omission}"
-
end
-
-
# Truncates a given +text+ after a given number of words (<tt>words_count</tt>):
-
#
-
# 'Once upon a time in a world far far away'.truncate_words(4)
-
# # => "Once upon a time..."
-
#
-
# Pass a string or regexp <tt>:separator</tt> to specify a different separator of words:
-
#
-
# 'Once<br>upon<br>a<br>time<br>in<br>a<br>world'.truncate_words(5, separator: '<br>')
-
# # => "Once<br>upon<br>a<br>time<br>in..."
-
#
-
# The last characters will be replaced with the <tt>:omission</tt> string (defaults to "..."):
-
#
-
# 'And they found that many people were sleeping better.'.truncate_words(5, omission: '... (continued)')
-
# # => "And they found that many... (continued)"
-
1
def truncate_words(words_count, options = {})
-
sep = options[:separator] || /\s+/
-
sep = Regexp.escape(sep.to_s) unless Regexp === sep
-
if self =~ /\A((?>.+?#{sep}){#{words_count - 1}}.+?)#{sep}.*/m
-
$1 + (options[:omission] || "...")
-
else
-
dup
-
end
-
end
-
end
-
1
require "active_support/inflector/methods"
-
1
require "active_support/inflector/transliterate"
-
-
# 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 table from the name of a class.
-
#
-
# 'ScaleScore'.tableize # => "scale_scores"
-
#
-
1
class String
-
# Returns the plural form of the word in the string.
-
#
-
# If the optional parameter +count+ is specified,
-
# the singular form will be returned if <tt>count == 1</tt>.
-
# For any other value of +count+ the plural will be returned.
-
#
-
# If the optional parameter +locale+ is specified,
-
# the word will be pluralized as a word of that language.
-
# By default, this parameter is set to <tt>:en</tt>.
-
# You must define your own inflection rules for languages other than English.
-
#
-
# 'post'.pluralize # => "posts"
-
# 'octopus'.pluralize # => "octopi"
-
# 'sheep'.pluralize # => "sheep"
-
# 'words'.pluralize # => "words"
-
# 'the blue mailman'.pluralize # => "the blue mailmen"
-
# 'CamelOctopus'.pluralize # => "CamelOctopi"
-
# 'apple'.pluralize(1) # => "apple"
-
# 'apple'.pluralize(2) # => "apples"
-
# 'ley'.pluralize(:es) # => "leyes"
-
# 'ley'.pluralize(1, :es) # => "ley"
-
1
def pluralize(count = nil, locale = :en)
-
locale = count if count.is_a?(Symbol)
-
if count == 1
-
dup
-
else
-
ActiveSupport::Inflector.pluralize(self, locale)
-
end
-
end
-
-
# The reverse of +pluralize+, returns the singular form of a word in a string.
-
#
-
# If the optional parameter +locale+ is specified,
-
# the word will be singularized as a word of that language.
-
# By default, this parameter is set to <tt>:en</tt>.
-
# You must define your own inflection rules for languages other than English.
-
#
-
# 'posts'.singularize # => "post"
-
# 'octopi'.singularize # => "octopus"
-
# 'sheep'.singularize # => "sheep"
-
# 'word'.singularize # => "word"
-
# 'the blue mailmen'.singularize # => "the blue mailman"
-
# 'CamelOctopi'.singularize # => "CamelOctopus"
-
# 'leyes'.singularize(:es) # => "ley"
-
1
def singularize(locale = :en)
-
ActiveSupport::Inflector.singularize(self, locale)
-
end
-
-
# +constantize+ tries to find a declared constant with the name specified
-
# in the string. It raises a NameError when the name is not in CamelCase
-
# or is not initialized. See ActiveSupport::Inflector.constantize
-
#
-
# 'Module'.constantize # => Module
-
# 'Class'.constantize # => Class
-
# 'blargle'.constantize # => NameError: wrong constant name blargle
-
1
def constantize
-
ActiveSupport::Inflector.constantize(self)
-
end
-
-
# +safe_constantize+ tries to find a declared constant with the name specified
-
# in the string. It returns +nil+ when the name is not in CamelCase
-
# or is not initialized. See ActiveSupport::Inflector.safe_constantize
-
#
-
# 'Module'.safe_constantize # => Module
-
# 'Class'.safe_constantize # => Class
-
# 'blargle'.safe_constantize # => nil
-
1
def safe_constantize
-
ActiveSupport::Inflector.safe_constantize(self)
-
end
-
-
# By default, +camelize+ converts strings to UpperCamelCase. If the argument to camelize
-
# is set to <tt>:lower</tt> then camelize produces lowerCamelCase.
-
#
-
# +camelize+ 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"
-
1
def camelize(first_letter = :upper)
-
case first_letter
-
when :upper
-
ActiveSupport::Inflector.camelize(self, true)
-
when :lower
-
ActiveSupport::Inflector.camelize(self, false)
-
end
-
end
-
1
alias_method :camelcase, :camelize
-
-
# Capitalizes all the words and replaces some characters in the string to create
-
# a nicer looking title. +titleize+ is meant for creating pretty output. It is not
-
# used in the Rails internals.
-
#
-
# +titleize+ is also aliased as +titlecase+.
-
#
-
# 'man from the boondocks'.titleize # => "Man From The Boondocks"
-
# 'x-men: the last stand'.titleize # => "X Men: The Last Stand"
-
1
def titleize
-
ActiveSupport::Inflector.titleize(self)
-
end
-
1
alias_method :titlecase, :titleize
-
-
# The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
-
#
-
# +underscore+ will also change '::' to '/' to convert namespaces to paths.
-
#
-
# 'ActiveModel'.underscore # => "active_model"
-
# 'ActiveModel::Errors'.underscore # => "active_model/errors"
-
1
def underscore
-
ActiveSupport::Inflector.underscore(self)
-
end
-
-
# Replaces underscores with dashes in the string.
-
#
-
# 'puni_puni'.dasherize # => "puni-puni"
-
1
def dasherize
-
ActiveSupport::Inflector.dasherize(self)
-
end
-
-
# Removes the module part from the constant expression in the string.
-
#
-
# 'ActiveSupport::Inflector::Inflections'.demodulize # => "Inflections"
-
# 'Inflections'.demodulize # => "Inflections"
-
# '::Inflections'.demodulize # => "Inflections"
-
# ''.demodulize # => ''
-
#
-
# See also +deconstantize+.
-
1
def demodulize
-
ActiveSupport::Inflector.demodulize(self)
-
end
-
-
# Removes the rightmost segment from the constant expression in the string.
-
#
-
# 'Net::HTTP'.deconstantize # => "Net"
-
# '::Net::HTTP'.deconstantize # => "::Net"
-
# 'String'.deconstantize # => ""
-
# '::String'.deconstantize # => ""
-
# ''.deconstantize # => ""
-
#
-
# See also +demodulize+.
-
1
def deconstantize
-
ActiveSupport::Inflector.deconstantize(self)
-
end
-
-
# Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
-
#
-
# class Person
-
# def to_param
-
# "#{id}-#{name.parameterize}"
-
# end
-
# end
-
#
-
# @person = Person.find(1)
-
# # => #<Person id: 1, name: "Donald E. Knuth">
-
#
-
# <%= link_to(@person.name, person_path) %>
-
# # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
-
#
-
# To preserve the case of the characters in a string, use the `preserve_case` argument.
-
#
-
# class Person
-
# def to_param
-
# "#{id}-#{name.parameterize(preserve_case: true)}"
-
# end
-
# end
-
#
-
# @person = Person.find(1)
-
# # => #<Person id: 1, name: "Donald E. Knuth">
-
#
-
# <%= link_to(@person.name, person_path) %>
-
# # => <a href="/person/1-Donald-E-Knuth">Donald E. Knuth</a>
-
1
def parameterize(separator: "-", preserve_case: false)
-
ActiveSupport::Inflector.parameterize(self, separator: separator, preserve_case: preserve_case)
-
end
-
-
# Creates the name of a table like Rails does for models to table names. This method
-
# uses the +pluralize+ method on the last word in the string.
-
#
-
# 'RawScaledScorer'.tableize # => "raw_scaled_scorers"
-
# 'ham_and_egg'.tableize # => "ham_and_eggs"
-
# 'fancyCategory'.tableize # => "fancy_categories"
-
1
def tableize
-
ActiveSupport::Inflector.tableize(self)
-
end
-
-
# Creates a class name from a plural table name like Rails does for table names to models.
-
# Note that this returns a string and not a class. (To convert to an actual class
-
# follow +classify+ with +constantize+.)
-
#
-
# 'ham_and_eggs'.classify # => "HamAndEgg"
-
# 'posts'.classify # => "Post"
-
1
def classify
-
ActiveSupport::Inflector.classify(self)
-
end
-
-
# Capitalizes the first word, turns underscores into spaces, and strips a
-
# trailing '_id' if present.
-
# Like +titleize+, this is meant for creating pretty output.
-
#
-
# The capitalization of the first word can be turned off by setting the
-
# optional parameter +capitalize+ to false.
-
# By default, this parameter is true.
-
#
-
# 'employee_salary'.humanize # => "Employee salary"
-
# 'author_id'.humanize # => "Author"
-
# 'author_id'.humanize(capitalize: false) # => "author"
-
# '_id'.humanize # => "Id"
-
1
def humanize(options = {})
-
ActiveSupport::Inflector.humanize(self, options)
-
end
-
-
# Converts just the first character to uppercase.
-
#
-
# 'what a Lovely Day'.upcase_first # => "What a Lovely Day"
-
# 'w'.upcase_first # => "W"
-
# ''.upcase_first # => ""
-
1
def upcase_first
-
ActiveSupport::Inflector.upcase_first(self)
-
end
-
-
# Creates a foreign key name from a class name.
-
# +separate_class_name_and_id_with_underscore+ sets whether
-
# the method should put '_' between the name and 'id'.
-
#
-
# 'Message'.foreign_key # => "message_id"
-
# 'Message'.foreign_key(false) # => "messageid"
-
# 'Admin::Post'.foreign_key # => "post_id"
-
1
def foreign_key(separate_class_name_and_id_with_underscore = true)
-
ActiveSupport::Inflector.foreign_key(self, separate_class_name_and_id_with_underscore)
-
end
-
end
-
1
require "active_support/multibyte"
-
-
1
class String
-
# == Multibyte proxy
-
#
-
# +mb_chars+ is a multibyte safe proxy for string methods.
-
#
-
# It creates and returns an instance of the ActiveSupport::Multibyte::Chars class which
-
# encapsulates the original string. A Unicode safe version of all the String methods are defined on this proxy
-
# class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsulated string.
-
#
-
# >> "lj".upcase
-
# => "lj"
-
# >> "lj".mb_chars.upcase.to_s
-
# => "LJ"
-
#
-
# == Method chaining
-
#
-
# All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
-
# method chaining on the result of any of these methods.
-
#
-
# name.mb_chars.reverse.length # => 12
-
#
-
# == Interoperability and configuration
-
#
-
# The Chars object tries to be as interchangeable with String objects as possible: sorting and comparing between
-
# String and Char work like expected. The bang! methods change the internal string representation in the Chars
-
# object. Interoperability problems can be resolved easily with a +to_s+ call.
-
#
-
# For more information about the methods defined on the Chars proxy see ActiveSupport::Multibyte::Chars. For
-
# information about how to change the default Multibyte behavior see ActiveSupport::Multibyte.
-
1
def mb_chars
-
ActiveSupport::Multibyte.proxy_class.new(self)
-
end
-
-
# Returns +true+ if string has utf_8 encoding.
-
#
-
# utf_8_str = "some string".encode "UTF-8"
-
# iso_str = "some string".encode "ISO-8859-1"
-
#
-
# utf_8_str.is_utf8? # => true
-
# iso_str.is_utf8? # => false
-
1
def is_utf8?
-
case encoding
-
when Encoding::UTF_8
-
valid_encoding?
-
when Encoding::ASCII_8BIT, Encoding::US_ASCII
-
dup.force_encoding(Encoding::UTF_8).valid_encoding?
-
else
-
false
-
end
-
end
-
end
-
1
class String
-
# Strips indentation in heredocs.
-
#
-
# For example in
-
#
-
# if options[:usage]
-
# puts <<-USAGE.strip_heredoc
-
# This command does such and such.
-
#
-
# Supported options are:
-
# -h This message
-
# ...
-
# USAGE
-
# end
-
#
-
# the user would see the usage message aligned against the left margin.
-
#
-
# Technically, it looks for the least indented non-empty line
-
# in the whole string, and removes that amount of leading whitespace.
-
1
def strip_heredoc
-
gsub(/^#{scan(/^[ \t]*(?=\S)/).min}/, "".freeze)
-
end
-
end
-
1
require "active_support/inflector/methods"
-
-
1
module ActiveSupport
-
# Autoload and eager load conveniences for your library.
-
#
-
# This module allows you to define autoloads based on
-
# Rails conventions (i.e. no need to define the path
-
# it is automatically guessed based on the filename)
-
# and also define a set of constants that needs to be
-
# eager loaded:
-
#
-
# module MyLib
-
# extend ActiveSupport::Autoload
-
#
-
# autoload :Model
-
#
-
# eager_autoload do
-
# autoload :Cache
-
# end
-
# end
-
#
-
# Then your library can be eager loaded by simply calling:
-
#
-
# MyLib.eager_load!
-
1
module Autoload
-
1
def self.extended(base) # :nodoc:
-
1
base.class_eval do
-
1
@_autoloads = {}
-
1
@_under_path = nil
-
1
@_at_path = nil
-
1
@_eager_autoload = false
-
end
-
end
-
-
1
def autoload(const_name, path = @_at_path)
-
35
unless path
-
34
full = [name, @_under_path, const_name.to_s].compact.join("::")
-
34
path = Inflector.underscore(full)
-
end
-
-
35
if @_eager_autoload
-
22
@_autoloads[const_name] = path
-
end
-
-
35
super const_name, path
-
end
-
-
1
def autoload_under(path)
-
@_under_path, old_path = path, @_under_path
-
yield
-
ensure
-
@_under_path = old_path
-
end
-
-
1
def autoload_at(path)
-
@_at_path, old_path = path, @_at_path
-
yield
-
ensure
-
@_at_path = old_path
-
end
-
-
1
def eager_autoload
-
1
old_eager, @_eager_autoload = @_eager_autoload, true
-
1
yield
-
ensure
-
1
@_eager_autoload = old_eager
-
end
-
-
1
def eager_load!
-
@_autoloads.each_value { |file| require file }
-
end
-
-
1
def autoloads
-
@_autoloads
-
end
-
end
-
end
-
1
require "singleton"
-
-
1
module ActiveSupport
-
# \Deprecation specifies the API used by Rails to deprecate methods, instance
-
# variables, objects and constants.
-
1
class Deprecation
-
# active_support.rb sets an autoload for ActiveSupport::Deprecation.
-
#
-
# If these requires were at the top of the file the constant would not be
-
# defined by the time their files were loaded. Since some of them reopen
-
# ActiveSupport::Deprecation its autoload would be triggered, resulting in
-
# a circular require warning for active_support/deprecation.rb.
-
#
-
# So, we define the constant first, and load dependencies later.
-
1
require "active_support/deprecation/instance_delegator"
-
1
require "active_support/deprecation/behaviors"
-
1
require "active_support/deprecation/reporting"
-
1
require "active_support/deprecation/method_wrappers"
-
1
require "active_support/deprecation/proxy_wrappers"
-
1
require "active_support/core_ext/module/deprecation"
-
-
1
include Singleton
-
1
include InstanceDelegator
-
1
include Behavior
-
1
include Reporting
-
1
include MethodWrapper
-
-
# The version number in which the deprecated behavior will be removed, by default.
-
1
attr_accessor :deprecation_horizon
-
-
# It accepts two parameters on initialization. The first is a version of library
-
# and the second is a library name
-
#
-
# ActiveSupport::Deprecation.new('2.0', 'MyLibrary')
-
1
def initialize(deprecation_horizon = "5.2", gem_name = "Rails")
-
1
self.gem_name = gem_name
-
1
self.deprecation_horizon = deprecation_horizon
-
# By default, warnings are not silenced and debugging is off.
-
1
self.silenced = false
-
1
self.debug = false
-
end
-
end
-
end
-
1
require "active_support/notifications"
-
-
1
module ActiveSupport
-
# Raised when <tt>ActiveSupport::Deprecation::Behavior#behavior</tt> is set with <tt>:raise</tt>.
-
# You would set <tt>:raise</tt>, as a behavior to raise errors and proactively report exceptions from deprecations.
-
1
class DeprecationException < StandardError
-
end
-
-
1
class Deprecation
-
# Default warning behaviors per Rails.env.
-
1
DEFAULT_BEHAVIORS = {
-
raise: ->(message, callstack) {
-
e = DeprecationException.new(message)
-
e.set_backtrace(callstack.map(&:to_s))
-
raise e
-
},
-
-
stderr: ->(message, callstack) {
-
$stderr.puts(message)
-
$stderr.puts callstack.join("\n ") if debug
-
},
-
-
log: ->(message, callstack) {
-
logger =
-
if defined?(Rails.logger) && Rails.logger
-
Rails.logger
-
else
-
require "active_support/logger"
-
ActiveSupport::Logger.new($stderr)
-
end
-
logger.warn message
-
logger.debug callstack.join("\n ") if debug
-
},
-
-
notify: ->(message, callstack) {
-
ActiveSupport::Notifications.instrument("deprecation.rails",
-
message: message, callstack: callstack)
-
},
-
-
silence: ->(message, callstack) {},
-
}
-
-
# Behavior module allows to determine how to display deprecation messages.
-
# You can create a custom behavior or set any from the +DEFAULT_BEHAVIORS+
-
# constant. Available behaviors are:
-
#
-
# [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>.
-
# [+stderr+] Log all deprecation warnings to +$stderr+.
-
# [+log+] Log all deprecation warnings to +Rails.logger+.
-
# [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
-
# [+silence+] Do nothing.
-
#
-
# Setting behaviors only affects deprecations that happen after boot time.
-
# For more information you can read the documentation of the +behavior=+ method.
-
1
module Behavior
-
# Whether to print a backtrace along with the warning.
-
1
attr_accessor :debug
-
-
# Returns the current behavior or if one isn't set, defaults to +:stderr+.
-
1
def behavior
-
@behavior ||= [DEFAULT_BEHAVIORS[:stderr]]
-
end
-
-
# Sets the behavior to the specified value. Can be a single value, array,
-
# or an object that responds to +call+.
-
#
-
# Available behaviors:
-
#
-
# [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>.
-
# [+stderr+] Log all deprecation warnings to +$stderr+.
-
# [+log+] Log all deprecation warnings to +Rails.logger+.
-
# [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
-
# [+silence+] Do nothing.
-
#
-
# Setting behaviors only affects deprecations that happen after boot time.
-
# Deprecation warnings raised by gems are not affected by this setting
-
# because they happen before Rails boots up.
-
#
-
# ActiveSupport::Deprecation.behavior = :stderr
-
# ActiveSupport::Deprecation.behavior = [:stderr, :log]
-
# ActiveSupport::Deprecation.behavior = MyCustomHandler
-
# ActiveSupport::Deprecation.behavior = ->(message, callstack) {
-
# # custom stuff
-
# }
-
1
def behavior=(behavior)
-
@behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || b }
-
end
-
end
-
end
-
end
-
1
require "active_support/core_ext/kernel/singleton_class"
-
1
require "active_support/core_ext/module/delegation"
-
-
1
module ActiveSupport
-
1
class Deprecation
-
1
module InstanceDelegator # :nodoc:
-
1
def self.included(base)
-
1
base.extend(ClassMethods)
-
1
base.singleton_class.prepend(OverrideDelegators)
-
1
base.public_class_method :new
-
end
-
-
1
module ClassMethods # :nodoc:
-
1
def include(included_module)
-
15
included_module.instance_methods.each { |m| method_added(m) }
-
3
super
-
end
-
-
1
def method_added(method_name)
-
1
singleton_class.delegate(method_name, to: :instance)
-
end
-
end
-
-
1
module OverrideDelegators # :nodoc:
-
1
def warn(message = nil, callstack = nil)
-
callstack ||= caller_locations(2)
-
super
-
end
-
-
1
def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil)
-
caller_backtrace ||= caller_locations(2)
-
super
-
end
-
end
-
end
-
end
-
end
-
1
require "active_support/core_ext/module/aliasing"
-
1
require "active_support/core_ext/array/extract_options"
-
-
1
module ActiveSupport
-
1
class Deprecation
-
1
module MethodWrapper
-
# Declare that a method has been deprecated.
-
#
-
# module Fred
-
# extend self
-
#
-
# def aaa; end
-
# def bbb; end
-
# def ccc; end
-
# def ddd; end
-
# def eee; end
-
# end
-
#
-
# Using the default deprecator:
-
# ActiveSupport::Deprecation.deprecate_methods(Fred, :aaa, bbb: :zzz, ccc: 'use Bar#ccc instead')
-
# # => [:aaa, :bbb, :ccc]
-
#
-
# Fred.aaa
-
# # DEPRECATION WARNING: aaa is deprecated and will be removed from Rails 5.1. (called from irb_binding at (irb):10)
-
# # => nil
-
#
-
# Fred.bbb
-
# # DEPRECATION WARNING: bbb is deprecated and will be removed from Rails 5.1 (use zzz instead). (called from irb_binding at (irb):11)
-
# # => nil
-
#
-
# Fred.ccc
-
# # DEPRECATION WARNING: ccc is deprecated and will be removed from Rails 5.1 (use Bar#ccc instead). (called from irb_binding at (irb):12)
-
# # => nil
-
#
-
# Passing in a custom deprecator:
-
# custom_deprecator = ActiveSupport::Deprecation.new('next-release', 'MyGem')
-
# ActiveSupport::Deprecation.deprecate_methods(Fred, ddd: :zzz, deprecator: custom_deprecator)
-
# # => [:ddd]
-
#
-
# Fred.ddd
-
# DEPRECATION WARNING: ddd is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):15)
-
# # => nil
-
#
-
# Using a custom deprecator directly:
-
# custom_deprecator = ActiveSupport::Deprecation.new('next-release', 'MyGem')
-
# custom_deprecator.deprecate_methods(Fred, eee: :zzz)
-
# # => [:eee]
-
#
-
# Fred.eee
-
# DEPRECATION WARNING: eee is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):18)
-
# # => nil
-
1
def deprecate_methods(target_module, *method_names)
-
options = method_names.extract_options!
-
deprecator = options.delete(:deprecator) || self
-
method_names += options.keys
-
-
mod = Module.new do
-
method_names.each do |method_name|
-
define_method(method_name) do |*args, &block|
-
deprecator.deprecation_warning(method_name, options[method_name])
-
super(*args, &block)
-
end
-
end
-
end
-
-
target_module.prepend(mod)
-
end
-
end
-
end
-
end
-
1
require "active_support/inflector/methods"
-
1
require "active_support/core_ext/regexp"
-
-
1
module ActiveSupport
-
1
class Deprecation
-
1
class DeprecationProxy #:nodoc:
-
1
def self.new(*args, &block)
-
object = args.first
-
-
return object unless object
-
super
-
end
-
-
61
instance_methods.each { |m| undef_method m unless /^__|^object_id$/.match?(m) }
-
-
# Don't give a deprecation warning on inspect since test/unit and error
-
# logs rely on it for diagnostics.
-
1
def inspect
-
target.inspect
-
end
-
-
1
private
-
1
def method_missing(called, *args, &block)
-
warn caller_locations, called, args
-
target.__send__(called, *args, &block)
-
end
-
end
-
-
# DeprecatedObjectProxy transforms an object into a deprecated one. It
-
# takes an object, a deprecation message and optionally a deprecator. The
-
# deprecator defaults to +ActiveSupport::Deprecator+ if none is specified.
-
#
-
# deprecated_object = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(Object.new, "This object is now deprecated")
-
# # => #<Object:0x007fb9b34c34b0>
-
#
-
# deprecated_object.to_s
-
# DEPRECATION WARNING: This object is now deprecated.
-
# (Backtrace)
-
# # => "#<Object:0x007fb9b34c34b0>"
-
1
class DeprecatedObjectProxy < DeprecationProxy
-
1
def initialize(object, message, deprecator = ActiveSupport::Deprecation.instance)
-
@object = object
-
@message = message
-
@deprecator = deprecator
-
end
-
-
1
private
-
1
def target
-
@object
-
end
-
-
1
def warn(callstack, called, args)
-
@deprecator.warn(@message, callstack)
-
end
-
end
-
-
# DeprecatedInstanceVariableProxy transforms an instance variable into a
-
# deprecated one. It takes an instance of a class, a method on that class
-
# and an instance variable. It optionally takes a deprecator as the last
-
# argument. The deprecator defaults to +ActiveSupport::Deprecator+ if none
-
# is specified.
-
#
-
# class Example
-
# def initialize
-
# @request = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :request, :@request)
-
# @_request = :special_request
-
# end
-
#
-
# def request
-
# @_request
-
# end
-
#
-
# def old_request
-
# @request
-
# end
-
# end
-
#
-
# example = Example.new
-
# # => #<Example:0x007fb9b31090b8 @_request=:special_request, @request=:special_request>
-
#
-
# example.old_request.to_s
-
# # => DEPRECATION WARNING: @request is deprecated! Call request.to_s instead of
-
# @request.to_s
-
# (Backtrace information…)
-
# "special_request"
-
#
-
# example.request.to_s
-
# # => "special_request"
-
1
class DeprecatedInstanceVariableProxy < DeprecationProxy
-
1
def initialize(instance, method, var = "@#{method}", deprecator = ActiveSupport::Deprecation.instance)
-
@instance = instance
-
@method = method
-
@var = var
-
@deprecator = deprecator
-
end
-
-
1
private
-
1
def target
-
@instance.__send__(@method)
-
end
-
-
1
def warn(callstack, called, args)
-
@deprecator.warn("#{@var} is deprecated! Call #{@method}.#{called} instead of #{@var}.#{called}. Args: #{args.inspect}", callstack)
-
end
-
end
-
-
# DeprecatedConstantProxy transforms a constant into a deprecated one. It
-
# takes the names of an old (deprecated) constant and of a new constant
-
# (both in string form) and optionally a deprecator. The deprecator defaults
-
# to +ActiveSupport::Deprecator+ if none is specified. The deprecated constant
-
# now returns the value of the new one.
-
#
-
# PLANETS = %w(mercury venus earth mars jupiter saturn uranus neptune pluto)
-
#
-
# (In a later update, the original implementation of `PLANETS` has been removed.)
-
#
-
# PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
-
# PLANETS = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('PLANETS', 'PLANETS_POST_2006')
-
#
-
# PLANETS.map { |planet| planet.capitalize }
-
# # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead.
-
# (Backtrace information…)
-
# ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
-
1
class DeprecatedConstantProxy < DeprecationProxy
-
1
def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance, message: "#{old_const} is deprecated! Use #{new_const} instead.")
-
@old_const = old_const
-
@new_const = new_const
-
@deprecator = deprecator
-
@message = message
-
end
-
-
# Returns the class of the new constant.
-
#
-
# PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
-
# PLANETS = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('PLANETS', 'PLANETS_POST_2006')
-
# PLANETS.class # => Array
-
1
def class
-
target.class
-
end
-
-
1
private
-
1
def target
-
ActiveSupport::Inflector.constantize(@new_const.to_s)
-
end
-
-
1
def warn(callstack, called, args)
-
@deprecator.warn(@message, callstack)
-
end
-
end
-
end
-
end
-
1
require "rbconfig"
-
-
1
module ActiveSupport
-
1
class Deprecation
-
1
module Reporting
-
# Whether to print a message (silent mode)
-
1
attr_accessor :silenced
-
# Name of gem where method is deprecated
-
1
attr_accessor :gem_name
-
-
# Outputs a deprecation warning to the output configured by
-
# <tt>ActiveSupport::Deprecation.behavior</tt>.
-
#
-
# ActiveSupport::Deprecation.warn('something broke!')
-
# # => "DEPRECATION WARNING: something broke! (called from your_code.rb:1)"
-
1
def warn(message = nil, callstack = nil)
-
return if silenced
-
-
callstack ||= caller_locations(2)
-
deprecation_message(callstack, message).tap do |m|
-
behavior.each { |b| b.call(m, callstack) }
-
end
-
end
-
-
# Silence deprecation warnings within the block.
-
#
-
# ActiveSupport::Deprecation.warn('something broke!')
-
# # => "DEPRECATION WARNING: something broke! (called from your_code.rb:1)"
-
#
-
# ActiveSupport::Deprecation.silence do
-
# ActiveSupport::Deprecation.warn('something broke!')
-
# end
-
# # => nil
-
1
def silence
-
old_silenced, @silenced = @silenced, true
-
yield
-
ensure
-
@silenced = old_silenced
-
end
-
-
1
def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil)
-
caller_backtrace ||= caller_locations(2)
-
deprecated_method_warning(deprecated_method_name, message).tap do |msg|
-
warn(msg, caller_backtrace)
-
end
-
end
-
-
1
private
-
# Outputs a deprecation warning message
-
#
-
# ActiveSupport::Deprecation.deprecated_method_warning(:method_name)
-
# # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon}"
-
# ActiveSupport::Deprecation.deprecated_method_warning(:method_name, :another_method)
-
# # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon} (use another_method instead)"
-
# ActiveSupport::Deprecation.deprecated_method_warning(:method_name, "Optional message")
-
# # => "method_name is deprecated and will be removed from Rails #{deprecation_horizon} (Optional message)"
-
1
def deprecated_method_warning(method_name, message = nil)
-
warning = "#{method_name} is deprecated and will be removed from #{gem_name} #{deprecation_horizon}"
-
case message
-
when Symbol then "#{warning} (use #{message} instead)"
-
when String then "#{warning} (#{message})"
-
else warning
-
end
-
end
-
-
1
def deprecation_message(callstack, message = nil)
-
message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
-
"DEPRECATION WARNING: #{message} #{deprecation_caller_message(callstack)}"
-
end
-
-
1
def deprecation_caller_message(callstack)
-
file, line, method = extract_callstack(callstack)
-
if file
-
if line && method
-
"(called from #{method} at #{file}:#{line})"
-
else
-
"(called from #{file}:#{line})"
-
end
-
end
-
end
-
-
1
def extract_callstack(callstack)
-
return _extract_callstack(callstack) if callstack.first.is_a? String
-
-
offending_line = callstack.find { |frame|
-
frame.absolute_path && !ignored_callstack(frame.absolute_path)
-
} || callstack.first
-
-
[offending_line.path, offending_line.lineno, offending_line.label]
-
end
-
-
1
def _extract_callstack(callstack)
-
warn "Please pass `caller_locations` to the deprecation API" if $VERBOSE
-
offending_line = callstack.find { |line| !ignored_callstack(line) } || callstack.first
-
-
if offending_line
-
if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
-
md.captures
-
else
-
offending_line
-
end
-
end
-
end
-
-
1
RAILS_GEM_ROOT = File.expand_path("../../../../..", __FILE__) + "/"
-
-
1
def ignored_callstack(path)
-
path.start_with?(RAILS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG["rubylibdir"])
-
end
-
end
-
end
-
end
-
1
module ActiveSupport
-
# This module provides an internal implementation to track descendants
-
# which is faster than iterating through ObjectSpace.
-
1
module DescendantsTracker
-
1
@@direct_descendants = {}
-
-
1
class << self
-
1
def direct_descendants(klass)
-
@@direct_descendants[klass] || []
-
end
-
-
1
def descendants(klass)
-
arr = []
-
accumulate_descendants(klass, arr)
-
arr
-
end
-
-
1
def clear
-
if defined? ActiveSupport::Dependencies
-
@@direct_descendants.each do |klass, descendants|
-
if ActiveSupport::Dependencies.autoloaded?(klass)
-
@@direct_descendants.delete(klass)
-
else
-
descendants.reject! { |v| ActiveSupport::Dependencies.autoloaded?(v) }
-
end
-
end
-
else
-
@@direct_descendants.clear
-
end
-
end
-
-
# This is the only method that is not thread safe, but is only ever called
-
# during the eager loading phase.
-
1
def store_inherited(klass, descendant)
-
1
(@@direct_descendants[klass] ||= []) << descendant
-
end
-
-
1
private
-
1
def accumulate_descendants(klass, acc)
-
if direct_descendants = @@direct_descendants[klass]
-
acc.concat(direct_descendants)
-
direct_descendants.each { |direct_descendant| accumulate_descendants(direct_descendant, acc) }
-
end
-
end
-
end
-
-
1
def inherited(base)
-
1
DescendantsTracker.store_inherited(self, base)
-
1
super
-
end
-
-
1
def direct_descendants
-
DescendantsTracker.direct_descendants(self)
-
end
-
-
1
def descendants
-
DescendantsTracker.descendants(self)
-
end
-
end
-
end
-
1
module ActiveSupport
-
# Returns the version of the currently loaded Active Support as a <tt>Gem::Version</tt>.
-
1
def self.gem_version
-
Gem::Version.new VERSION::STRING
-
end
-
-
1
module VERSION
-
1
MAJOR = 5
-
1
MINOR = 1
-
1
TINY = 0
-
1
PRE = "alpha"
-
-
1
STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
-
end
-
end
-
1
require "active_support/core_ext/hash/deep_merge"
-
1
require "active_support/core_ext/hash/except"
-
1
require "active_support/core_ext/hash/slice"
-
1
begin
-
1
require "i18n"
-
rescue LoadError => e
-
$stderr.puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
-
raise e
-
end
-
1
require "active_support/lazy_load_hooks"
-
-
1
ActiveSupport.run_load_hooks(:i18n)
-
1
I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml"
-
1
require "active_support/inflector/inflections"
-
-
#--
-
# Defines the standard inflection rules. These are the starting point for
-
# new projects and are not considered complete. The current set of inflection
-
# rules is frozen. This means, we do not change them to become more complete.
-
# This is a safety measure to keep existing applications from breaking.
-
#++
-
1
module ActiveSupport
-
1
Inflector.inflections(:en) do |inflect|
-
1
inflect.plural(/$/, "s")
-
1
inflect.plural(/s$/i, "s")
-
1
inflect.plural(/^(ax|test)is$/i, '\1es')
-
1
inflect.plural(/(octop|vir)us$/i, '\1i')
-
1
inflect.plural(/(octop|vir)i$/i, '\1i')
-
1
inflect.plural(/(alias|status)$/i, '\1es')
-
1
inflect.plural(/(bu)s$/i, '\1ses')
-
1
inflect.plural(/(buffal|tomat)o$/i, '\1oes')
-
1
inflect.plural(/([ti])um$/i, '\1a')
-
1
inflect.plural(/([ti])a$/i, '\1a')
-
1
inflect.plural(/sis$/i, "ses")
-
1
inflect.plural(/(?:([^f])fe|([lr])f)$/i, '\1\2ves')
-
1
inflect.plural(/(hive)$/i, '\1s')
-
1
inflect.plural(/([^aeiouy]|qu)y$/i, '\1ies')
-
1
inflect.plural(/(x|ch|ss|sh)$/i, '\1es')
-
1
inflect.plural(/(matr|vert|ind)(?:ix|ex)$/i, '\1ices')
-
1
inflect.plural(/^(m|l)ouse$/i, '\1ice')
-
1
inflect.plural(/^(m|l)ice$/i, '\1ice')
-
1
inflect.plural(/^(ox)$/i, '\1en')
-
1
inflect.plural(/^(oxen)$/i, '\1')
-
1
inflect.plural(/(quiz)$/i, '\1zes')
-
-
1
inflect.singular(/s$/i, "")
-
1
inflect.singular(/(ss)$/i, '\1')
-
1
inflect.singular(/(n)ews$/i, '\1ews')
-
1
inflect.singular(/([ti])a$/i, '\1um')
-
1
inflect.singular(/((a)naly|(b)a|(d)iagno|(p)arenthe|(p)rogno|(s)ynop|(t)he)(sis|ses)$/i, '\1sis')
-
1
inflect.singular(/(^analy)(sis|ses)$/i, '\1sis')
-
1
inflect.singular(/([^f])ves$/i, '\1fe')
-
1
inflect.singular(/(hive)s$/i, '\1')
-
1
inflect.singular(/(tive)s$/i, '\1')
-
1
inflect.singular(/([lr])ves$/i, '\1f')
-
1
inflect.singular(/([^aeiouy]|qu)ies$/i, '\1y')
-
1
inflect.singular(/(s)eries$/i, '\1eries')
-
1
inflect.singular(/(m)ovies$/i, '\1ovie')
-
1
inflect.singular(/(x|ch|ss|sh)es$/i, '\1')
-
1
inflect.singular(/^(m|l)ice$/i, '\1ouse')
-
1
inflect.singular(/(bus)(es)?$/i, '\1')
-
1
inflect.singular(/(o)es$/i, '\1')
-
1
inflect.singular(/(shoe)s$/i, '\1')
-
1
inflect.singular(/(cris|test)(is|es)$/i, '\1is')
-
1
inflect.singular(/^(a)x[ie]s$/i, '\1xis')
-
1
inflect.singular(/(octop|vir)(us|i)$/i, '\1us')
-
1
inflect.singular(/(alias|status)(es)?$/i, '\1')
-
1
inflect.singular(/^(ox)en/i, '\1')
-
1
inflect.singular(/(vert|ind)ices$/i, '\1ex')
-
1
inflect.singular(/(matr)ices$/i, '\1ix')
-
1
inflect.singular(/(quiz)zes$/i, '\1')
-
1
inflect.singular(/(database)s$/i, '\1')
-
-
1
inflect.irregular("person", "people")
-
1
inflect.irregular("man", "men")
-
1
inflect.irregular("child", "children")
-
1
inflect.irregular("sex", "sexes")
-
1
inflect.irregular("move", "moves")
-
1
inflect.irregular("zombie", "zombies")
-
-
1
inflect.uncountable(%w(equipment information rice money species series fish sheep jeans police))
-
end
-
end
-
# in case active_support/inflector is required without the rest of active_support
-
1
require "active_support/inflector/inflections"
-
1
require "active_support/inflector/transliterate"
-
1
require "active_support/inflector/methods"
-
-
1
require "active_support/inflections"
-
1
require "active_support/core_ext/string/inflections"
-
1
require "concurrent/map"
-
1
require "active_support/core_ext/array/prepend_and_append"
-
1
require "active_support/core_ext/regexp"
-
1
require "active_support/i18n"
-
-
1
module ActiveSupport
-
1
module Inflector
-
1
extend self
-
-
# A singleton instance of this class is yielded by Inflector.inflections,
-
# which can then be used to specify additional inflection rules. If passed
-
# an optional locale, rules for other languages can be specified. The
-
# default locale is <tt>:en</tt>. Only rules for English are provided.
-
#
-
# ActiveSupport::Inflector.inflections(:en) do |inflect|
-
# inflect.plural /^(ox)$/i, '\1\2en'
-
# 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 above, the irregular
-
# rule for octopus will now be the first of the pluralization and
-
# singularization rules that is runs. This guarantees that your rules run
-
# before any of the rules that may already have been loaded.
-
1
class Inflections
-
1
@__instance__ = Concurrent::Map.new
-
-
1
class Uncountables < Array
-
1
def initialize
-
1
@regex_array = []
-
1
super
-
end
-
-
1
def delete(entry)
-
84
super entry
-
84
@regex_array.delete(to_regex(entry))
-
end
-
-
1
def <<(*word)
-
add(word)
-
end
-
-
1
def add(words)
-
1
words = words.flatten.map(&:downcase)
-
1
concat(words)
-
11
@regex_array += words.map { |word| to_regex(word) }
-
1
self
-
end
-
-
1
def uncountable?(str)
-
@regex_array.any? { |regex| regex.match? str }
-
end
-
-
1
private
-
1
def to_regex(string)
-
94
/\b#{::Regexp.escape(string)}\Z/i
-
end
-
end
-
-
1
def self.instance(locale = :en)
-
35
@__instance__[locale] ||= new
-
end
-
-
1
attr_reader :plurals, :singulars, :uncountables, :humans, :acronyms, :acronym_regex
-
-
1
def initialize
-
1
@plurals, @singulars, @uncountables, @humans, @acronyms, @acronym_regex = [], [], Uncountables.new, [], {}, /(?=a)b/
-
end
-
-
# Private, for the test suite.
-
1
def initialize_dup(orig) # :nodoc:
-
%w(plurals singulars uncountables humans acronyms acronym_regex).each do |scope|
-
instance_variable_set("@#{scope}", orig.send(scope).dup)
-
end
-
end
-
-
# Specifies a new acronym. An acronym must be specified as it will appear
-
# in a camelized string. An underscore string that contains the acronym
-
# will retain the acronym when passed to +camelize+, +humanize+, or
-
# +titleize+. A camelized string that contains the acronym will maintain
-
# the acronym when titleized or humanized, and will convert the acronym
-
# into a non-delimited single lowercase word when passed to +underscore+.
-
#
-
# acronym 'HTML'
-
# titleize 'html' # => 'HTML'
-
# camelize 'html' # => 'HTML'
-
# underscore 'MyHTML' # => 'my_html'
-
#
-
# The acronym, however, must occur as a delimited unit and not be part of
-
# another word for conversions to recognize it:
-
#
-
# acronym 'HTTP'
-
# camelize 'my_http_delimited' # => 'MyHTTPDelimited'
-
# camelize 'https' # => 'Https', not 'HTTPs'
-
# underscore 'HTTPS' # => 'http_s', not 'https'
-
#
-
# acronym 'HTTPS'
-
# camelize 'https' # => 'HTTPS'
-
# underscore 'HTTPS' # => 'https'
-
#
-
# Note: Acronyms that are passed to +pluralize+ will no longer be
-
# recognized, since the acronym will not occur as a delimited unit in the
-
# pluralized result. To work around this, you must specify the pluralized
-
# form as an acronym as well:
-
#
-
# acronym 'API'
-
# camelize(pluralize('api')) # => 'Apis'
-
#
-
# acronym 'APIs'
-
# camelize(pluralize('api')) # => 'APIs'
-
#
-
# +acronym+ may be used to specify any word that contains an acronym or
-
# otherwise needs to maintain a non-standard capitalization. The only
-
# restriction is that the word must begin with a capital letter.
-
#
-
# acronym 'RESTful'
-
# underscore 'RESTful' # => 'restful'
-
# underscore 'RESTfulController' # => 'restful_controller'
-
# titleize 'RESTfulController' # => 'RESTful Controller'
-
# camelize 'restful' # => 'RESTful'
-
# camelize 'restful_controller' # => 'RESTfulController'
-
#
-
# acronym 'McDonald'
-
# underscore 'McDonald' # => 'mcdonald'
-
# camelize 'mcdonald' # => 'McDonald'
-
1
def acronym(word)
-
@acronyms[word.downcase] = word
-
@acronym_regex = /#{@acronyms.values.join("|")}/
-
end
-
-
# 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 that may include references to the matched data from
-
# the rule.
-
1
def plural(rule, replacement)
-
33
@uncountables.delete(rule) if rule.is_a?(String)
-
33
@uncountables.delete(replacement)
-
33
@plurals.prepend([rule, replacement])
-
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 that may include references to the matched data from
-
# the rule.
-
1
def singular(rule, replacement)
-
39
@uncountables.delete(rule) if rule.is_a?(String)
-
39
@uncountables.delete(replacement)
-
39
@singulars.prepend([rule, replacement])
-
end
-
-
# Specifies a new irregular that applies to both pluralization and
-
# singularization at the same time. This can only be used for strings, not
-
# regular expressions. You simply pass the irregular in singular and
-
# plural form.
-
#
-
# irregular 'octopus', 'octopi'
-
# irregular 'person', 'people'
-
1
def irregular(singular, plural)
-
6
@uncountables.delete(singular)
-
6
@uncountables.delete(plural)
-
-
6
s0 = singular[0]
-
6
srest = singular[1..-1]
-
-
6
p0 = plural[0]
-
6
prest = plural[1..-1]
-
-
6
if s0.upcase == p0.upcase
-
6
plural(/(#{s0})#{srest}$/i, '\1' + prest)
-
6
plural(/(#{p0})#{prest}$/i, '\1' + prest)
-
-
6
singular(/(#{s0})#{srest}$/i, '\1' + srest)
-
6
singular(/(#{p0})#{prest}$/i, '\1' + srest)
-
else
-
plural(/#{s0.upcase}(?i)#{srest}$/, p0.upcase + prest)
-
plural(/#{s0.downcase}(?i)#{srest}$/, p0.downcase + prest)
-
plural(/#{p0.upcase}(?i)#{prest}$/, p0.upcase + prest)
-
plural(/#{p0.downcase}(?i)#{prest}$/, p0.downcase + prest)
-
-
singular(/#{s0.upcase}(?i)#{srest}$/, s0.upcase + srest)
-
singular(/#{s0.downcase}(?i)#{srest}$/, s0.downcase + srest)
-
singular(/#{p0.upcase}(?i)#{prest}$/, s0.upcase + srest)
-
singular(/#{p0.downcase}(?i)#{prest}$/, s0.downcase + srest)
-
end
-
end
-
-
# Specifies words that are uncountable and should not be inflected.
-
#
-
# uncountable 'money'
-
# uncountable 'money', 'information'
-
# uncountable %w( money information rice )
-
1
def uncountable(*words)
-
1
@uncountables.add(words)
-
end
-
-
# Specifies a humanized form of a string by a regular expression rule or
-
# by a string mapping. When using a regular expression based replacement,
-
# the normal humanize formatting is called after the replacement. When a
-
# string is used, the human form should be specified as desired (example:
-
# 'The name', not 'the_name').
-
#
-
# human /_cnt$/i, '\1_count'
-
# human 'legacy_col_person_name', 'Name'
-
1
def human(rule, replacement)
-
@humans.prepend([rule, replacement])
-
end
-
-
# Clears the loaded inflections within a given scope (default is
-
# <tt>:all</tt>). Give the scope as a symbol of the inflection type, the
-
# options are: <tt>:plurals</tt>, <tt>:singulars</tt>, <tt>:uncountables</tt>,
-
# <tt>:humans</tt>.
-
#
-
# clear :all
-
# clear :plurals
-
1
def clear(scope = :all)
-
case scope
-
when :all
-
@plurals, @singulars, @uncountables, @humans = [], [], Uncountables.new, []
-
else
-
instance_variable_set "@#{scope}", []
-
end
-
end
-
end
-
-
# Yields a singleton instance of Inflector::Inflections so you can specify
-
# additional inflector rules. If passed an optional locale, rules for other
-
# languages can be specified. If not specified, defaults to <tt>:en</tt>.
-
# Only rules for English are provided.
-
#
-
# ActiveSupport::Inflector.inflections(:en) do |inflect|
-
# inflect.uncountable 'rails'
-
# end
-
1
def inflections(locale = :en)
-
35
if block_given?
-
1
yield Inflections.instance(locale)
-
else
-
34
Inflections.instance(locale)
-
end
-
end
-
end
-
end
-
1
require "active_support/inflections"
-
1
require "active_support/core_ext/regexp"
-
-
1
module ActiveSupport
-
# The Inflector 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 inflections.rb.
-
#
-
# The Rails core team has stated patches for the inflections library will not
-
# be accepted in order to avoid breaking legacy applications which may be
-
# relying on errant inflections. If you discover an incorrect inflection and
-
# require it for your application or wish to define rules for languages other
-
# than English, please correct or add them yourself (explained below).
-
1
module Inflector
-
1
extend self
-
-
# Returns the plural form of the word in the string.
-
#
-
# If passed an optional +locale+ parameter, the word will be
-
# pluralized using rules defined for that language. By default,
-
# this parameter is set to <tt>:en</tt>.
-
#
-
# pluralize('post') # => "posts"
-
# pluralize('octopus') # => "octopi"
-
# pluralize('sheep') # => "sheep"
-
# pluralize('words') # => "words"
-
# pluralize('CamelOctopus') # => "CamelOctopi"
-
# pluralize('ley', :es) # => "leyes"
-
1
def pluralize(word, locale = :en)
-
apply_inflections(word, inflections(locale).plurals)
-
end
-
-
# The reverse of #pluralize, returns the singular form of a word in a
-
# string.
-
#
-
# If passed an optional +locale+ parameter, the word will be
-
# singularized using rules defined for that language. By default,
-
# this parameter is set to <tt>:en</tt>.
-
#
-
# singularize('posts') # => "post"
-
# singularize('octopi') # => "octopus"
-
# singularize('sheep') # => "sheep"
-
# singularize('word') # => "word"
-
# singularize('CamelOctopi') # => "CamelOctopus"
-
# singularize('leyes', :es) # => "ley"
-
1
def singularize(word, locale = :en)
-
apply_inflections(word, inflections(locale).singulars)
-
end
-
-
# Converts strings to UpperCamelCase.
-
# If the +uppercase_first_letter+ parameter is set to false, then produces
-
# lowerCamelCase.
-
#
-
# Also converts '/' to '::' which is useful for converting
-
# paths to namespaces.
-
#
-
# camelize('active_model') # => "ActiveModel"
-
# camelize('active_model', false) # => "activeModel"
-
# camelize('active_model/errors') # => "ActiveModel::Errors"
-
# camelize('active_model/errors', false) # => "activeModel::Errors"
-
#
-
# As a rule of thumb you can think of +camelize+ as the inverse of
-
# #underscore, though there are cases where that does not hold:
-
#
-
# camelize(underscore('SSLError')) # => "SslError"
-
1
def camelize(term, uppercase_first_letter = true)
-
string = term.to_s
-
if uppercase_first_letter
-
string = string.sub(/^[a-z\d]*/) { |match| inflections.acronyms[match] || match.capitalize }
-
else
-
string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { |match| match.downcase }
-
end
-
string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
-
string.gsub!("/".freeze, "::".freeze)
-
string
-
end
-
-
# Makes an underscored, lowercase form from the expression in the string.
-
#
-
# Changes '::' to '/' to convert namespaces to paths.
-
#
-
# underscore('ActiveModel') # => "active_model"
-
# underscore('ActiveModel::Errors') # => "active_model/errors"
-
#
-
# As a rule of thumb you can think of +underscore+ as the inverse of
-
# #camelize, though there are cases where that does not hold:
-
#
-
# camelize(underscore('SSLError')) # => "SslError"
-
1
def underscore(camel_cased_word)
-
34
return camel_cased_word unless /[A-Z-]|::/.match?(camel_cased_word)
-
34
word = camel_cased_word.to_s.gsub("::".freeze, "/".freeze)
-
34
word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1 && '_'.freeze }#{$2.downcase}" }
-
34
word.gsub!(/([A-Z\d]+)([A-Z][a-z])/, '\1_\2'.freeze)
-
34
word.gsub!(/([a-z\d])([A-Z])/, '\1_\2'.freeze)
-
34
word.tr!("-".freeze, "_".freeze)
-
34
word.downcase!
-
34
word
-
end
-
-
# Tweaks an attribute name for display to end users.
-
#
-
# Specifically, performs these transformations:
-
#
-
# * Applies human inflection rules to the argument.
-
# * Deletes leading underscores, if any.
-
# * Removes a "_id" suffix if present.
-
# * Replaces underscores with spaces, if any.
-
# * Downcases all words except acronyms.
-
# * Capitalizes the first word.
-
#
-
# The capitalization of the first word can be turned off by setting the
-
# +:capitalize+ option to false (default is true).
-
#
-
# humanize('employee_salary') # => "Employee salary"
-
# humanize('author_id') # => "Author"
-
# humanize('author_id', capitalize: false) # => "author"
-
# humanize('_id') # => "Id"
-
#
-
# If "SSL" was defined to be an acronym:
-
#
-
# humanize('ssl_error') # => "SSL error"
-
#
-
1
def humanize(lower_case_and_underscored_word, options = {})
-
result = lower_case_and_underscored_word.to_s.dup
-
-
inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
-
-
result.sub!(/\A_+/, "".freeze)
-
result.sub!(/_id\z/, "".freeze)
-
result.tr!("_".freeze, " ".freeze)
-
-
result.gsub!(/([a-z\d]*)/i) do |match|
-
"#{inflections.acronyms[match] || match.downcase}"
-
end
-
-
if options.fetch(:capitalize, true)
-
result.sub!(/\A\w/) { |match| match.upcase }
-
end
-
-
result
-
end
-
-
# Converts just the first character to uppercase.
-
#
-
# upcase_first('what a Lovely Day') # => "What a Lovely Day"
-
# upcase_first('w') # => "W"
-
# upcase_first('') # => ""
-
1
def upcase_first(string)
-
string.length > 0 ? string[0].upcase.concat(string[1..-1]) : ""
-
end
-
-
# Capitalizes all the words and replaces some characters in the string to
-
# create a nicer looking title. +titleize+ is meant for creating pretty
-
# output. It is not used in the Rails internals.
-
#
-
# +titleize+ is also aliased as +titlecase+.
-
#
-
# titleize('man from the boondocks') # => "Man From The Boondocks"
-
# titleize('x-men: the last stand') # => "X Men: The Last Stand"
-
# titleize('TheManWithoutAPast') # => "The Man Without A Past"
-
# titleize('raiders_of_the_lost_ark') # => "Raiders Of The Lost Ark"
-
1
def titleize(word)
-
humanize(underscore(word)).gsub(/\b(?<!['’`])[a-z]/) { |match| match.capitalize }
-
end
-
-
# Creates the name of a table like Rails does for models to table names.
-
# This method uses the #pluralize method on the last word in the string.
-
#
-
# tableize('RawScaledScorer') # => "raw_scaled_scorers"
-
# tableize('ham_and_egg') # => "ham_and_eggs"
-
# tableize('fancyCategory') # => "fancy_categories"
-
1
def tableize(class_name)
-
pluralize(underscore(class_name))
-
end
-
-
# Creates a class name from a plural table name like Rails does for table
-
# names to models. Note that this returns a string and not a Class (To
-
# convert to an actual class follow +classify+ with #constantize).
-
#
-
# classify('ham_and_eggs') # => "HamAndEgg"
-
# classify('posts') # => "Post"
-
#
-
# Singular names are not handled correctly:
-
#
-
# classify('calculus') # => "Calculus"
-
1
def classify(table_name)
-
# strip out any leading schema name
-
camelize(singularize(table_name.to_s.sub(/.*\./, "".freeze)))
-
end
-
-
# Replaces underscores with dashes in the string.
-
#
-
# dasherize('puni_puni') # => "puni-puni"
-
1
def dasherize(underscored_word)
-
underscored_word.tr("_".freeze, "-".freeze)
-
end
-
-
# Removes the module part from the expression in the string.
-
#
-
# demodulize('ActiveSupport::Inflector::Inflections') # => "Inflections"
-
# demodulize('Inflections') # => "Inflections"
-
# demodulize('::Inflections') # => "Inflections"
-
# demodulize('') # => ""
-
#
-
# See also #deconstantize.
-
1
def demodulize(path)
-
path = path.to_s
-
if i = path.rindex("::")
-
path[(i + 2)..-1]
-
else
-
path
-
end
-
end
-
-
# Removes the rightmost segment from the constant expression in the string.
-
#
-
# deconstantize('Net::HTTP') # => "Net"
-
# deconstantize('::Net::HTTP') # => "::Net"
-
# deconstantize('String') # => ""
-
# deconstantize('::String') # => ""
-
# deconstantize('') # => ""
-
#
-
# See also #demodulize.
-
1
def deconstantize(path)
-
path.to_s[0, path.rindex("::") || 0] # implementation based on the one in facets' Module#spacename
-
end
-
-
# Creates a foreign key name from a class name.
-
# +separate_class_name_and_id_with_underscore+ sets whether
-
# the method should put '_' between the name and 'id'.
-
#
-
# foreign_key('Message') # => "message_id"
-
# foreign_key('Message', false) # => "messageid"
-
# foreign_key('Admin::Post') # => "post_id"
-
1
def foreign_key(class_name, separate_class_name_and_id_with_underscore = true)
-
underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id")
-
end
-
-
# Tries to find a constant with the name specified in the argument string.
-
#
-
# constantize('Module') # => Module
-
# constantize('Foo::Bar') # => Foo::Bar
-
#
-
# The name is assumed to be the one of a top-level constant, no matter
-
# whether it starts with "::" or not. No lexical context is taken into
-
# account:
-
#
-
# C = 'outside'
-
# module M
-
# C = 'inside'
-
# C # => 'inside'
-
# constantize('C') # => 'outside', same as ::C
-
# end
-
#
-
# NameError is raised when the name is not in CamelCase or the constant is
-
# unknown.
-
1
def constantize(camel_cased_word)
-
names = camel_cased_word.split("::".freeze)
-
-
# Trigger a built-in NameError exception including the ill-formed constant in the message.
-
Object.const_get(camel_cased_word) if names.empty?
-
-
# Remove the first blank element in case of '::ClassName' notation.
-
names.shift if names.size > 1 && names.first.empty?
-
-
names.inject(Object) do |constant, name|
-
if constant == Object
-
constant.const_get(name)
-
else
-
candidate = constant.const_get(name)
-
next candidate if constant.const_defined?(name, false)
-
next candidate unless Object.const_defined?(name)
-
-
# Go down the ancestors to check if it is owned directly. The check
-
# stops when we reach Object or the end of ancestors tree.
-
constant = constant.ancestors.inject(constant) do |const, ancestor|
-
break const if ancestor == Object
-
break ancestor if ancestor.const_defined?(name, false)
-
const
-
end
-
-
# owner is in Object, so raise
-
constant.const_get(name, false)
-
end
-
end
-
end
-
-
# Tries to find a constant with the name specified in the argument string.
-
#
-
# safe_constantize('Module') # => Module
-
# safe_constantize('Foo::Bar') # => Foo::Bar
-
#
-
# The name is assumed to be the one of a top-level constant, no matter
-
# whether it starts with "::" or not. No lexical context is taken into
-
# account:
-
#
-
# C = 'outside'
-
# module M
-
# C = 'inside'
-
# C # => 'inside'
-
# safe_constantize('C') # => 'outside', same as ::C
-
# end
-
#
-
# +nil+ is returned when the name is not in CamelCase or the constant (or
-
# part of it) is unknown.
-
#
-
# safe_constantize('blargle') # => nil
-
# safe_constantize('UnknownModule') # => nil
-
# safe_constantize('UnknownModule::Foo::Bar') # => nil
-
1
def safe_constantize(camel_cased_word)
-
constantize(camel_cased_word)
-
rescue NameError => e
-
raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) ||
-
e.name.to_s == camel_cased_word.to_s)
-
rescue ArgumentError => e
-
raise unless /not missing constant #{const_regexp(camel_cased_word)}!$/.match?(e.message)
-
end
-
-
# Returns the suffix that should be added to a number to denote the position
-
# in an ordered sequence such as 1st, 2nd, 3rd, 4th.
-
#
-
# ordinal(1) # => "st"
-
# ordinal(2) # => "nd"
-
# ordinal(1002) # => "nd"
-
# ordinal(1003) # => "rd"
-
# ordinal(-11) # => "th"
-
# ordinal(-1021) # => "st"
-
1
def ordinal(number)
-
abs_number = number.to_i.abs
-
-
if (11..13).include?(abs_number % 100)
-
"th"
-
else
-
case abs_number % 10
-
when 1; "st"
-
when 2; "nd"
-
when 3; "rd"
-
else "th"
-
end
-
end
-
end
-
-
# Turns a number into an ordinal string used to denote the position in an
-
# ordered sequence such as 1st, 2nd, 3rd, 4th.
-
#
-
# ordinalize(1) # => "1st"
-
# ordinalize(2) # => "2nd"
-
# ordinalize(1002) # => "1002nd"
-
# ordinalize(1003) # => "1003rd"
-
# ordinalize(-11) # => "-11th"
-
# ordinalize(-1021) # => "-1021st"
-
1
def ordinalize(number)
-
"#{number}#{ordinal(number)}"
-
end
-
-
1
private
-
-
# Mounts a regular expression, returned as a string to ease interpolation,
-
# that will match part by part the given constant.
-
#
-
# const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?"
-
# const_regexp("::") # => "::"
-
1
def const_regexp(camel_cased_word)
-
parts = camel_cased_word.split("::".freeze)
-
-
return Regexp.escape(camel_cased_word) if parts.blank?
-
-
last = parts.pop
-
-
parts.reverse.inject(last) do |acc, part|
-
part.empty? ? acc : "#{part}(::#{acc})?"
-
end
-
end
-
-
# Applies inflection rules for +singularize+ and +pluralize+.
-
#
-
# apply_inflections('post', inflections.plurals) # => "posts"
-
# apply_inflections('posts', inflections.singulars) # => "post"
-
1
def apply_inflections(word, rules)
-
result = word.to_s.dup
-
-
if word.empty? || inflections.uncountables.uncountable?(result)
-
result
-
else
-
rules.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
-
result
-
end
-
end
-
end
-
end
-
1
require "active_support/core_ext/string/multibyte"
-
1
require "active_support/i18n"
-
-
1
module ActiveSupport
-
1
module Inflector
-
# Replaces non-ASCII characters with an ASCII approximation, or if none
-
# exists, a replacement character which defaults to "?".
-
#
-
# transliterate('Ærøskøbing')
-
# # => "AEroskobing"
-
#
-
# Default approximations are provided for Western/Latin characters,
-
# e.g, "ø", "ñ", "é", "ß", etc.
-
#
-
# This method is I18n aware, so you can set up custom approximations for a
-
# locale. This can be useful, for example, to transliterate German's "ü"
-
# and "ö" to "ue" and "oe", or to add support for transliterating Russian
-
# to ASCII.
-
#
-
# In order to make your custom transliterations available, you must set
-
# them as the <tt>i18n.transliterate.rule</tt> i18n key:
-
#
-
# # Store the transliterations in locales/de.yml
-
# i18n:
-
# transliterate:
-
# rule:
-
# ü: "ue"
-
# ö: "oe"
-
#
-
# # Or set them using Ruby
-
# I18n.backend.store_translations(:de, i18n: {
-
# transliterate: {
-
# rule: {
-
# 'ü' => 'ue',
-
# 'ö' => 'oe'
-
# }
-
# }
-
# })
-
#
-
# The value for <tt>i18n.transliterate.rule</tt> can be a simple Hash that
-
# maps characters to ASCII approximations as shown above, or, for more
-
# complex requirements, a Proc:
-
#
-
# I18n.backend.store_translations(:de, i18n: {
-
# transliterate: {
-
# rule: ->(string) { MyTransliterator.transliterate(string) }
-
# }
-
# })
-
#
-
# Now you can have different transliterations for each locale:
-
#
-
# I18n.locale = :en
-
# transliterate('Jürgen')
-
# # => "Jurgen"
-
#
-
# I18n.locale = :de
-
# transliterate('Jürgen')
-
# # => "Juergen"
-
1
def transliterate(string, replacement = "?".freeze)
-
raise ArgumentError, "Can only transliterate strings. Received #{string.class.name}" unless string.is_a?(String)
-
-
I18n.transliterate(ActiveSupport::Multibyte::Unicode.normalize(
-
ActiveSupport::Multibyte::Unicode.tidy_bytes(string), :c),
-
replacement: replacement)
-
end
-
-
# Replaces special characters in a string so that it may be used as part of
-
# a 'pretty' URL.
-
#
-
# parameterize("Donald E. Knuth") # => "donald-e-knuth"
-
# parameterize("^trés|Jolie-- ") # => "tres-jolie"
-
#
-
# To use a custom separator, override the `separator` argument.
-
#
-
# parameterize("Donald E. Knuth", separator: '_') # => "donald_e_knuth"
-
# parameterize("^trés|Jolie-- ", separator: '_') # => "tres_jolie"
-
#
-
# To preserve the case of the characters in a string, use the `preserve_case` argument.
-
#
-
# parameterize("Donald E. Knuth", preserve_case: true) # => "Donald-E-Knuth"
-
# parameterize("^trés|Jolie-- ", preserve_case: true) # => "tres-Jolie"
-
#
-
1
def parameterize(string, separator: "-", preserve_case: false)
-
# Replace accented chars with their ASCII equivalents.
-
parameterized_string = transliterate(string)
-
-
# Turn unwanted chars into the separator.
-
parameterized_string.gsub!(/[^a-z0-9\-_]+/i, separator)
-
-
unless separator.nil? || separator.empty?
-
if separator == "-".freeze
-
re_duplicate_separator = /-{2,}/
-
re_leading_trailing_separator = /^-|-$/i
-
else
-
re_sep = Regexp.escape(separator)
-
re_duplicate_separator = /#{re_sep}{2,}/
-
re_leading_trailing_separator = /^#{re_sep}|#{re_sep}$/i
-
end
-
# No more than one of the separator in a row.
-
parameterized_string.gsub!(re_duplicate_separator, separator)
-
# Remove leading/trailing separator.
-
parameterized_string.gsub!(re_leading_trailing_separator, "".freeze)
-
end
-
-
parameterized_string.downcase! unless preserve_case
-
parameterized_string
-
end
-
end
-
end
-
1
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.
-
#
-
# Here is an example where +on_load+ method is called to register a hook.
-
#
-
# 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::Base+ has been
-
# evaluated then +run_load_hooks+ is invoked. The very last line of
-
# +ActiveRecord::Base+ is:
-
#
-
# ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
-
1
module LazyLoadHooks
-
1
def self.extended(base) # :nodoc:
-
1
base.class_eval do
-
3
@load_hooks = Hash.new { |h, k| h[k] = [] }
-
3
@loaded = Hash.new { |h, k| h[k] = [] }
-
end
-
end
-
-
# Declares a block that will be executed when a Rails component is fully
-
# loaded.
-
1
def on_load(name, options = {}, &block)
-
@loaded[name].each do |base|
-
execute_hook(base, options, block)
-
end
-
-
@load_hooks[name] << [block, options]
-
end
-
-
1
def execute_hook(base, options, block)
-
if options[:yield]
-
block.call(base)
-
else
-
base.instance_eval(&block)
-
end
-
end
-
-
1
def run_load_hooks(name, base = Object)
-
2
@loaded[name] << base
-
2
@load_hooks[name].each do |hook, options|
-
execute_hook(base, options, hook)
-
end
-
end
-
end
-
-
1
extend LazyLoadHooks
-
end
-
1
require "active_support/logger_silence"
-
1
require "active_support/logger_thread_safe_level"
-
1
require "logger"
-
-
1
module ActiveSupport
-
1
class Logger < ::Logger
-
1
include ActiveSupport::LoggerThreadSafeLevel
-
1
include LoggerSilence
-
-
# Returns true if the logger destination matches one of the sources
-
#
-
# logger = Logger.new(STDOUT)
-
# ActiveSupport::Logger.logger_outputs_to?(logger, STDOUT)
-
# # => true
-
1
def self.logger_outputs_to?(logger, *sources)
-
logdev = logger.instance_variable_get("@logdev")
-
logger_source = logdev.dev if logdev.respond_to?(:dev)
-
sources.any? { |source| source == logger_source }
-
end
-
-
# Broadcasts logs to multiple loggers.
-
1
def self.broadcast(logger) # :nodoc:
-
Module.new do
-
define_method(:add) do |*args, &block|
-
logger.add(*args, &block)
-
super(*args, &block)
-
end
-
-
define_method(:<<) do |x|
-
logger << x
-
super(x)
-
end
-
-
define_method(:close) do
-
logger.close
-
super()
-
end
-
-
define_method(:progname=) do |name|
-
logger.progname = name
-
super(name)
-
end
-
-
define_method(:formatter=) do |formatter|
-
logger.formatter = formatter
-
super(formatter)
-
end
-
-
define_method(:level=) do |level|
-
logger.level = level
-
super(level)
-
end
-
-
define_method(:local_level=) do |level|
-
logger.local_level = level if logger.respond_to?(:local_level=)
-
super(level) if respond_to?(:local_level=)
-
end
-
-
define_method(:silence) do |level = Logger::ERROR, &block|
-
if logger.respond_to?(:silence)
-
logger.silence(level) do
-
if defined?(super)
-
super(level, &block)
-
else
-
block.call(self)
-
end
-
end
-
else
-
if defined?(super)
-
super(level, &block)
-
else
-
block.call(self)
-
end
-
end
-
end
-
end
-
end
-
-
1
def initialize(*args)
-
super
-
@formatter = SimpleFormatter.new
-
after_initialize if respond_to? :after_initialize
-
end
-
-
1
def add(severity, message = nil, progname = nil, &block)
-
return true if @logdev.nil? || (severity || UNKNOWN) < level
-
super
-
end
-
-
1
Logger::Severity.constants.each do |severity|
-
6
class_eval(<<-EOT, __FILE__, __LINE__ + 1)
-
1
def #{severity.downcase}? # def debug?
-
Logger::#{severity} >= level # DEBUG >= level
-
end # end
-
EOT
-
end
-
-
# Simple formatter which only displays the message.
-
1
class SimpleFormatter < ::Logger::Formatter
-
# This method is invoked when a log event occurs
-
1
def call(severity, timestamp, progname, msg)
-
"#{String === msg ? msg : msg.inspect}\n"
-
end
-
end
-
end
-
end
-
1
require "active_support/concern"
-
1
require "active_support/core_ext/module/attribute_accessors"
-
1
require "concurrent"
-
-
1
module LoggerSilence
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
cattr_accessor :silencer
-
1
self.silencer = true
-
end
-
-
# Silences the logger for the duration of the block.
-
1
def silence(temporary_level = Logger::ERROR)
-
if silencer
-
begin
-
old_local_level = local_level
-
self.local_level = temporary_level
-
-
yield self
-
ensure
-
self.local_level = old_local_level
-
end
-
else
-
yield self
-
end
-
end
-
end
-
1
require "active_support/concern"
-
-
1
module ActiveSupport
-
1
module LoggerThreadSafeLevel # :nodoc:
-
1
extend ActiveSupport::Concern
-
-
1
def after_initialize
-
@local_levels = Concurrent::Map.new(initial_capacity: 2)
-
end
-
-
1
def local_log_id
-
Thread.current.__id__
-
end
-
-
1
def local_level
-
@local_levels[local_log_id]
-
end
-
-
1
def local_level=(level)
-
if level
-
@local_levels[local_log_id] = level
-
else
-
@local_levels.delete(local_log_id)
-
end
-
end
-
-
1
def level
-
local_level || super
-
end
-
end
-
end
-
1
module ActiveSupport #:nodoc:
-
1
module Multibyte
-
1
autoload :Chars, "active_support/multibyte/chars"
-
1
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.
-
#
-
# ActiveSupport::Multibyte.proxy_class = CharsForUTF32
-
1
def self.proxy_class=(klass)
-
@proxy_class = klass
-
end
-
-
# Returns the current proxy class.
-
1
def self.proxy_class
-
@proxy_class ||= ActiveSupport::Multibyte::Chars
-
end
-
end
-
end
-
1
module ActiveSupport
-
1
module Multibyte
-
1
module Unicode
-
1
extend self
-
-
# A list of all available normalization forms.
-
# See http://www.unicode.org/reports/tr15/tr15-29.html for more
-
# information about normalization.
-
1
NORMALIZATION_FORMS = [:c, :kc, :d, :kd]
-
-
# The Unicode version that is supported by the implementation
-
1
UNICODE_VERSION = "9.0.0"
-
-
# The default normalization used for operations that require
-
# normalization. It can be set to any of the normalizations
-
# in NORMALIZATION_FORMS.
-
#
-
# ActiveSupport::Multibyte::Unicode.default_normalization_form = :c
-
1
attr_accessor :default_normalization_form
-
1
@default_normalization_form = :kc
-
-
# Hangul character boundaries and properties
-
1
HANGUL_SBASE = 0xAC00
-
1
HANGUL_LBASE = 0x1100
-
1
HANGUL_VBASE = 0x1161
-
1
HANGUL_TBASE = 0x11A7
-
1
HANGUL_LCOUNT = 19
-
1
HANGUL_VCOUNT = 21
-
1
HANGUL_TCOUNT = 28
-
1
HANGUL_NCOUNT = HANGUL_VCOUNT * HANGUL_TCOUNT
-
1
HANGUL_SCOUNT = 11172
-
1
HANGUL_SLAST = HANGUL_SBASE + HANGUL_SCOUNT
-
-
# Detect whether the codepoint is in a certain character class. Returns
-
# +true+ when it's in the specified character class and +false+ otherwise.
-
# Valid character classes are: <tt>:cr</tt>, <tt>:lf</tt>, <tt>:l</tt>,
-
# <tt>:v</tt>, <tt>:lv</tt>, <tt>:lvt</tt> and <tt>:t</tt>.
-
#
-
# Primarily used by the grapheme cluster support.
-
1
def in_char_class?(codepoint, classes)
-
18487
classes.detect { |c| database.boundary[c] === codepoint } ? true : false
-
end
-
-
# Unpack the string at grapheme boundaries. Returns a list of character
-
# lists.
-
#
-
# Unicode.unpack_graphemes('क्षि') # => [[2325, 2381], [2359], [2367]]
-
# Unicode.unpack_graphemes('Café') # => [[67], [97], [102], [233]]
-
1
def unpack_graphemes(string)
-
744
codepoints = string.codepoints.to_a
-
744
unpacked = []
-
744
pos = 0
-
744
marker = 0
-
744
eoc = codepoints.length
-
3366
while (pos < eoc)
-
1878
pos += 1
-
1878
previous = codepoints[pos - 1]
-
1878
current = codepoints[pos]
-
-
# See http://unicode.org/reports/tr29/#Grapheme_Cluster_Boundary_Rules
-
1878
should_break =
-
1878
if pos == eoc
-
744
true
-
# GB3. CR X LF
-
1134
elsif previous == database.boundary[:cr] && current == database.boundary[:lf]
-
2
false
-
# GB4. (Control|CR|LF) ÷
-
1132
elsif previous && in_char_class?(previous, [:control, :cr, :lf])
-
115
true
-
# GB5. ÷ (Control|CR|LF)
-
1017
elsif in_char_class?(current, [:control, :cr, :lf])
-
106
true
-
# GB6. L X (L|V|LV|LVT)
-
911
elsif database.boundary[:l] === previous && in_char_class?(current, [:l, :v, :lv, :lvt])
-
5
false
-
# GB7. (LV|V) X (V|T)
-
906
elsif in_char_class?(previous, [:lv, :v]) && in_char_class?(current, [:v, :t])
-
5
false
-
# GB8. (LVT|T) X (T)
-
901
elsif in_char_class?(previous, [:lvt, :t]) && database.boundary[:t] === current
-
3
false
-
# GB9. X (Extend | ZWJ)
-
898
elsif in_char_class?(current, [:extend, :zwj])
-
381
false
-
# GB9a. X SpacingMark
-
517
elsif database.boundary[:spacingmark] === current
-
36
false
-
# GB9b. Prepend X
-
481
elsif database.boundary[:prepend] === previous
-
14
false
-
# GB10. (E_Base | EBG) Extend* X E_Modifier
-
1159
elsif (marker...pos).any? { |i| in_char_class?(codepoints[i], [:e_base, :e_base_gaz]) && codepoints[i + 1...pos].all? { |c| database.boundary[:extend] === c } } && database.boundary[:e_modifier] === current
-
7
false
-
# GB11. ZWJ X (Glue_After_Zwj | EBG)
-
460
elsif database.boundary[:zwj] === previous && in_char_class?(current, [:glue_after_zwj, :e_base_gaz])
-
5
false
-
# GB12. ^ (RI RI)* RI X RI
-
# GB13. [^RI] (RI RI)* RI X RI
-
981
elsif codepoints[marker..pos].all? { |c| database.boundary[:regional_indicator] === c } && codepoints[marker..pos].count { |c| database.boundary[:regional_indicator] === c }.even?
-
7
false
-
# GB999. Any ÷ Any
-
else
-
448
true
-
end
-
-
1878
if should_break
-
1413
unpacked << codepoints[marker..pos - 1]
-
1413
marker = pos
-
end
-
end
-
744
unpacked
-
end
-
-
# Reverse operation of unpack_graphemes.
-
#
-
# Unicode.pack_graphemes(Unicode.unpack_graphemes('क्षि')) # => 'क्षि'
-
1
def pack_graphemes(unpacked)
-
744
unpacked.flatten.pack("U*")
-
end
-
-
# Re-order codepoints so the string becomes canonical.
-
1
def reorder_characters(codepoints)
-
length = codepoints.length - 1
-
pos = 0
-
while pos < length do
-
cp1, cp2 = database.codepoints[codepoints[pos]], database.codepoints[codepoints[pos + 1]]
-
if (cp1.combining_class > cp2.combining_class) && (cp2.combining_class > 0)
-
codepoints[pos..pos + 1] = cp2.code, cp1.code
-
pos += (pos > 0 ? -1 : 1)
-
else
-
pos += 1
-
end
-
end
-
codepoints
-
end
-
-
# Decompose composed characters to the decomposed form.
-
1
def decompose(type, codepoints)
-
codepoints.inject([]) do |decomposed, cp|
-
# if it's a hangul syllable starter character
-
if HANGUL_SBASE <= cp && cp < HANGUL_SLAST
-
sindex = cp - HANGUL_SBASE
-
ncp = [] # new codepoints
-
ncp << HANGUL_LBASE + sindex / HANGUL_NCOUNT
-
ncp << HANGUL_VBASE + (sindex % HANGUL_NCOUNT) / HANGUL_TCOUNT
-
tindex = sindex % HANGUL_TCOUNT
-
ncp << (HANGUL_TBASE + tindex) unless tindex == 0
-
decomposed.concat ncp
-
# if the codepoint is decomposable in with the current decomposition type
-
elsif (ncp = database.codepoints[cp].decomp_mapping) && (!database.codepoints[cp].decomp_type || type == :compatibility)
-
decomposed.concat decompose(type, ncp.dup)
-
else
-
decomposed << cp
-
end
-
end
-
end
-
-
# Compose decomposed characters to the composed form.
-
1
def compose(codepoints)
-
pos = 0
-
eoa = codepoints.length - 1
-
starter_pos = 0
-
starter_char = codepoints[0]
-
previous_combining_class = -1
-
while pos < eoa
-
pos += 1
-
lindex = starter_char - HANGUL_LBASE
-
# -- Hangul
-
if 0 <= lindex && lindex < HANGUL_LCOUNT
-
vindex = codepoints[starter_pos + 1] - HANGUL_VBASE rescue vindex = -1
-
if 0 <= vindex && vindex < HANGUL_VCOUNT
-
tindex = codepoints[starter_pos + 2] - HANGUL_TBASE rescue tindex = -1
-
if 0 <= tindex && tindex < HANGUL_TCOUNT
-
j = starter_pos + 2
-
eoa -= 2
-
else
-
tindex = 0
-
j = starter_pos + 1
-
eoa -= 1
-
end
-
codepoints[starter_pos..j] = (lindex * HANGUL_VCOUNT + vindex) * HANGUL_TCOUNT + tindex + HANGUL_SBASE
-
end
-
starter_pos += 1
-
starter_char = codepoints[starter_pos]
-
# -- Other characters
-
else
-
current_char = codepoints[pos]
-
current = database.codepoints[current_char]
-
if current.combining_class > previous_combining_class
-
if ref = database.composition_map[starter_char]
-
composition = ref[current_char]
-
else
-
composition = nil
-
end
-
unless composition.nil?
-
codepoints[starter_pos] = composition
-
starter_char = composition
-
codepoints.delete_at pos
-
eoa -= 1
-
pos -= 1
-
previous_combining_class = -1
-
else
-
previous_combining_class = current.combining_class
-
end
-
else
-
previous_combining_class = current.combining_class
-
end
-
if current.combining_class == 0
-
starter_pos = pos
-
starter_char = codepoints[pos]
-
end
-
end
-
end
-
codepoints
-
end
-
-
# Rubinius' String#scrub, however, doesn't support ASCII-incompatible chars.
-
1
if !defined?(Rubinius)
-
# Replaces all ISO-8859-1 or CP1252 characters by their UTF-8 equivalent
-
# resulting in a valid UTF-8 string.
-
#
-
# Passing +true+ will forcibly tidy all bytes, assuming that the string's
-
# encoding is entirely CP1252 or ISO-8859-1.
-
1
def tidy_bytes(string, force = false)
-
return string if string.empty?
-
return recode_windows1252_chars(string) if force
-
string.scrub { |bad| recode_windows1252_chars(bad) }
-
end
-
else
-
def tidy_bytes(string, force = false)
-
return string if string.empty?
-
return recode_windows1252_chars(string) if force
-
-
# We can't transcode to the same format, so we choose a nearly-identical encoding.
-
# We're going to 'transcode' bytes from UTF-8 when possible, then fall back to
-
# CP1252 when we get errors. The final string will be 'converted' back to UTF-8
-
# before returning.
-
reader = Encoding::Converter.new(Encoding::UTF_8, Encoding::UTF_16LE)
-
-
source = string.dup
-
out = "".force_encoding(Encoding::UTF_16LE)
-
-
loop do
-
reader.primitive_convert(source, out)
-
_, _, _, error_bytes, _ = reader.primitive_errinfo
-
break if error_bytes.nil?
-
out << error_bytes.encode(Encoding::UTF_16LE, Encoding::Windows_1252, invalid: :replace, undef: :replace)
-
end
-
-
reader.finish
-
-
out.encode!(Encoding::UTF_8)
-
end
-
end
-
-
# Returns the KC normalization of the string by default. NFKC is
-
# considered the best normalization form for passing strings to databases
-
# and validations.
-
#
-
# * <tt>string</tt> - The string to perform normalization on.
-
# * <tt>form</tt> - The form you want to normalize in. Should be one of
-
# the following: <tt>:c</tt>, <tt>:kc</tt>, <tt>:d</tt>, or <tt>:kd</tt>.
-
# Default is ActiveSupport::Multibyte::Unicode.default_normalization_form.
-
1
def normalize(string, form = nil)
-
form ||= @default_normalization_form
-
# See http://www.unicode.org/reports/tr15, Table 1
-
codepoints = string.codepoints.to_a
-
case form
-
when :d
-
reorder_characters(decompose(:canonical, codepoints))
-
when :c
-
compose(reorder_characters(decompose(:canonical, codepoints)))
-
when :kd
-
reorder_characters(decompose(:compatibility, codepoints))
-
when :kc
-
compose(reorder_characters(decompose(:compatibility, codepoints)))
-
else
-
raise ArgumentError, "#{form} is not a valid normalization variant", caller
-
end.pack("U*".freeze)
-
end
-
-
1
def downcase(string)
-
apply_mapping string, :lowercase_mapping
-
end
-
-
1
def upcase(string)
-
apply_mapping string, :uppercase_mapping
-
end
-
-
1
def swapcase(string)
-
apply_mapping string, :swapcase_mapping
-
end
-
-
# Holds data about a codepoint in the Unicode database.
-
1
class Codepoint
-
1
attr_accessor :code, :combining_class, :decomp_type, :decomp_mapping, :uppercase_mapping, :lowercase_mapping
-
-
# Initializing Codepoint object with default values
-
1
def initialize
-
1
@combining_class = 0
-
1
@uppercase_mapping = 0
-
1
@lowercase_mapping = 0
-
end
-
-
1
def swapcase_mapping
-
uppercase_mapping > 0 ? uppercase_mapping : lowercase_mapping
-
end
-
end
-
-
# Holds static data from the Unicode database.
-
1
class UnicodeDatabase
-
1
ATTRIBUTES = :codepoints, :composition_exclusion, :composition_map, :boundary, :cp1252
-
-
1
attr_writer(*ATTRIBUTES)
-
-
1
def initialize
-
1
@codepoints = Hash.new(Codepoint.new)
-
1
@composition_exclusion = []
-
1
@composition_map = {}
-
1
@boundary = {}
-
1
@cp1252 = {}
-
end
-
-
# Lazy load the Unicode database so it's only loaded when it's actually used
-
1
ATTRIBUTES.each do |attr_name|
-
5
class_eval(<<-EOS, __FILE__, __LINE__ + 1)
-
1
def #{attr_name} # def codepoints
-
load # load
-
@#{attr_name} # @codepoints
-
end # end
-
EOS
-
end
-
-
# Loads the Unicode database and returns all the internal objects of
-
# UnicodeDatabase.
-
1
def load
-
1
begin
-
2
@codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, "rb") { |f| Marshal.load f.read }
-
rescue => e
-
raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), ActiveSupport::Multibyte is unusable")
-
end
-
-
# Redefine the === method so we can write shorter rules for grapheme cluster breaks
-
1
@boundary.each_key do |k|
-
@boundary[k].instance_eval do
-
15
def ===(other)
-
1054930
detect { |i| i === other } ? true : false
-
end
-
17
end if @boundary[k].kind_of?(Array)
-
end
-
-
# define attr_reader methods for the instance variables
-
1
class << self
-
1
attr_reader(*ATTRIBUTES)
-
end
-
end
-
-
# Returns the directory in which the data files are stored.
-
1
def self.dirname
-
1
File.dirname(__FILE__) + "/../values/"
-
end
-
-
# Returns the filename for the data file for this version.
-
1
def self.filename
-
1
File.expand_path File.join(dirname, "unicode_tables.dat")
-
end
-
end
-
-
1
private
-
-
1
def apply_mapping(string, mapping)
-
database.codepoints
-
string.each_codepoint.map do |codepoint|
-
cp = database.codepoints[codepoint]
-
if cp && (ncp = cp.send(mapping)) && ncp > 0
-
ncp
-
else
-
codepoint
-
end
-
end.pack("U*")
-
end
-
-
1
def recode_windows1252_chars(string)
-
string.encode(Encoding::UTF_8, Encoding::Windows_1252, invalid: :replace, undef: :replace)
-
end
-
-
1
def database
-
17065
@database ||= UnicodeDatabase.new
-
end
-
end
-
end
-
end
-
1
require "active_support/notifications/instrumenter"
-
1
require "active_support/notifications/fanout"
-
1
require "active_support/per_thread_registry"
-
-
1
module ActiveSupport
-
# = Notifications
-
#
-
# <tt>ActiveSupport::Notifications</tt> provides an instrumentation API for
-
# Ruby.
-
#
-
# == Instrumenters
-
#
-
# To instrument an event you just need to do:
-
#
-
# ActiveSupport::Notifications.instrument('render', extra: :information) do
-
# render plain: 'Foo'
-
# end
-
#
-
# That first executes the block and then notifies all subscribers once done.
-
#
-
# In the example above +render+ is the name of the event, and the rest is called
-
# the _payload_. The payload is a mechanism that allows instrumenters to pass
-
# extra information to subscribers. Payloads consist of a hash whose contents
-
# are arbitrary and generally depend on the event.
-
#
-
# == Subscribers
-
#
-
# You can consume those events and the information they provide by registering
-
# a subscriber.
-
#
-
# ActiveSupport::Notifications.subscribe('render') do |name, start, finish, id, payload|
-
# name # => String, name of the event (such as 'render' from above)
-
# start # => Time, when the instrumented block started execution
-
# finish # => Time, when the instrumented block ended execution
-
# id # => String, unique ID for this notification
-
# payload # => Hash, the payload
-
# end
-
#
-
# For instance, let's store all "render" events in an array:
-
#
-
# events = []
-
#
-
# ActiveSupport::Notifications.subscribe('render') do |*args|
-
# events << ActiveSupport::Notifications::Event.new(*args)
-
# end
-
#
-
# That code returns right away, you are just subscribing to "render" events.
-
# The block is saved and will be called whenever someone instruments "render":
-
#
-
# ActiveSupport::Notifications.instrument('render', extra: :information) do
-
# render plain: 'Foo'
-
# end
-
#
-
# event = events.first
-
# event.name # => "render"
-
# event.duration # => 10 (in milliseconds)
-
# event.payload # => { extra: :information }
-
#
-
# The block in the <tt>subscribe</tt> call gets the name of the event, start
-
# timestamp, end timestamp, a string with a unique identifier for that event
-
# (something like "535801666f04d0298cd6"), and a hash with the payload, in
-
# that order.
-
#
-
# If an exception happens during that particular instrumentation the payload will
-
# have a key <tt>:exception</tt> with an array of two elements as value: a string with
-
# the name of the exception class, and the exception message.
-
#
-
# As the previous example depicts, the class <tt>ActiveSupport::Notifications::Event</tt>
-
# is able to take the arguments as they come and provide an object-oriented
-
# interface to that data.
-
#
-
# It is also possible to pass an object which responds to <tt>call</tt> method
-
# as the second parameter to the <tt>subscribe</tt> method instead of a block:
-
#
-
# module ActionController
-
# class PageRequest
-
# def call(name, started, finished, unique_id, payload)
-
# Rails.logger.debug ['notification:', name, started, finished, unique_id, payload].join(' ')
-
# end
-
# end
-
# end
-
#
-
# ActiveSupport::Notifications.subscribe('process_action.action_controller', ActionController::PageRequest.new)
-
#
-
# resulting in the following output within the logs including a hash with the payload:
-
#
-
# notification: process_action.action_controller 2012-04-13 01:08:35 +0300 2012-04-13 01:08:35 +0300 af358ed7fab884532ec7 {
-
# controller: "Devise::SessionsController",
-
# action: "new",
-
# params: {"action"=>"new", "controller"=>"devise/sessions"},
-
# format: :html,
-
# method: "GET",
-
# path: "/login/sign_in",
-
# status: 200,
-
# view_runtime: 279.3080806732178,
-
# db_runtime: 40.053
-
# }
-
#
-
# You can also subscribe to all events whose name matches a certain regexp:
-
#
-
# ActiveSupport::Notifications.subscribe(/render/) do |*args|
-
# ...
-
# end
-
#
-
# and even pass no argument to <tt>subscribe</tt>, in which case you are subscribing
-
# to all events.
-
#
-
# == Temporary Subscriptions
-
#
-
# Sometimes you do not want to subscribe to an event for the entire life of
-
# the application. There are two ways to unsubscribe.
-
#
-
# WARNING: The instrumentation framework is designed for long-running subscribers,
-
# use this feature sparingly because it wipes some internal caches and that has
-
# a negative impact on performance.
-
#
-
# === Subscribe While a Block Runs
-
#
-
# You can subscribe to some event temporarily while some block runs. For
-
# example, in
-
#
-
# callback = lambda {|*args| ... }
-
# ActiveSupport::Notifications.subscribed(callback, "sql.active_record") do
-
# ...
-
# end
-
#
-
# the callback will be called for all "sql.active_record" events instrumented
-
# during the execution of the block. The callback is unsubscribed automatically
-
# after that.
-
#
-
# === Manual Unsubscription
-
#
-
# The +subscribe+ method returns a subscriber object:
-
#
-
# subscriber = ActiveSupport::Notifications.subscribe("render") do |*args|
-
# ...
-
# end
-
#
-
# To prevent that block from being called anymore, just unsubscribe passing
-
# that reference:
-
#
-
# ActiveSupport::Notifications.unsubscribe(subscriber)
-
#
-
# You can also unsubscribe by passing the name of the subscriber object. Note
-
# that this will unsubscribe all subscriptions with the given name:
-
#
-
# ActiveSupport::Notifications.unsubscribe("render")
-
#
-
# == Default Queue
-
#
-
# Notifications ships with a queue implementation that consumes and publishes events
-
# to all log subscribers. You can use any queue implementation you want.
-
#
-
1
module Notifications
-
1
class << self
-
1
attr_accessor :notifier
-
-
1
def publish(name, *args)
-
notifier.publish(name, *args)
-
end
-
-
1
def instrument(name, payload = {})
-
if notifier.listening?(name)
-
instrumenter.instrument(name, payload) { yield payload if block_given? }
-
else
-
yield payload if block_given?
-
end
-
end
-
-
1
def subscribe(*args, &block)
-
notifier.subscribe(*args, &block)
-
end
-
-
1
def subscribed(callback, *args, &block)
-
subscriber = subscribe(*args, &callback)
-
yield
-
ensure
-
unsubscribe(subscriber)
-
end
-
-
1
def unsubscribe(subscriber_or_name)
-
notifier.unsubscribe(subscriber_or_name)
-
end
-
-
1
def instrumenter
-
InstrumentationRegistry.instance.instrumenter_for(notifier)
-
end
-
end
-
-
# This class is a registry which holds all of the +Instrumenter+ objects
-
# in a particular thread local. To access the +Instrumenter+ object for a
-
# particular +notifier+, you can call the following method:
-
#
-
# InstrumentationRegistry.instrumenter_for(notifier)
-
#
-
# The instrumenters for multiple notifiers are held in a single instance of
-
# this class.
-
1
class InstrumentationRegistry # :nodoc:
-
1
extend ActiveSupport::PerThreadRegistry
-
-
1
def initialize
-
@registry = {}
-
end
-
-
1
def instrumenter_for(notifier)
-
@registry[notifier] ||= Instrumenter.new(notifier)
-
end
-
end
-
-
1
self.notifier = Fanout.new
-
end
-
end
-
1
require "mutex_m"
-
1
require "concurrent/map"
-
-
1
module ActiveSupport
-
1
module Notifications
-
# This is a default queue implementation that ships with Notifications.
-
# It just pushes events to all registered log subscribers.
-
#
-
# This class is thread safe. All methods are reentrant.
-
1
class Fanout
-
1
include Mutex_m
-
-
1
def initialize
-
1
@subscribers = []
-
1
@listeners_for = Concurrent::Map.new
-
1
super
-
end
-
-
1
def subscribe(pattern = nil, block = Proc.new)
-
subscriber = Subscribers.new pattern, block
-
synchronize do
-
@subscribers << subscriber
-
@listeners_for.clear
-
end
-
subscriber
-
end
-
-
1
def unsubscribe(subscriber_or_name)
-
synchronize do
-
case subscriber_or_name
-
when String
-
@subscribers.reject! { |s| s.matches?(subscriber_or_name) }
-
else
-
@subscribers.delete(subscriber_or_name)
-
end
-
-
@listeners_for.clear
-
end
-
end
-
-
1
def start(name, id, payload)
-
listeners_for(name).each { |s| s.start(name, id, payload) }
-
end
-
-
1
def finish(name, id, payload, listeners = listeners_for(name))
-
listeners.each { |s| s.finish(name, id, payload) }
-
end
-
-
1
def publish(name, *args)
-
listeners_for(name).each { |s| s.publish(name, *args) }
-
end
-
-
1
def listeners_for(name)
-
# this is correctly done double-checked locking (Concurrent::Map's lookups have volatile semantics)
-
@listeners_for[name] || synchronize do
-
# use synchronisation when accessing @subscribers
-
@listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) }
-
end
-
end
-
-
1
def listening?(name)
-
listeners_for(name).any?
-
end
-
-
# This is a sync queue, so there is no waiting.
-
1
def wait
-
end
-
-
1
module Subscribers # :nodoc:
-
1
def self.new(pattern, listener)
-
if listener.respond_to?(:start) && listener.respond_to?(:finish)
-
subscriber = Evented.new pattern, listener
-
else
-
subscriber = Timed.new pattern, listener
-
end
-
-
unless pattern
-
AllMessages.new(subscriber)
-
else
-
subscriber
-
end
-
end
-
-
1
class Evented #:nodoc:
-
1
def initialize(pattern, delegate)
-
@pattern = pattern
-
@delegate = delegate
-
@can_publish = delegate.respond_to?(:publish)
-
end
-
-
1
def publish(name, *args)
-
if @can_publish
-
@delegate.publish name, *args
-
end
-
end
-
-
1
def start(name, id, payload)
-
@delegate.start name, id, payload
-
end
-
-
1
def finish(name, id, payload)
-
@delegate.finish name, id, payload
-
end
-
-
1
def subscribed_to?(name)
-
@pattern === name
-
end
-
-
1
def matches?(name)
-
@pattern && @pattern === name
-
end
-
end
-
-
1
class Timed < Evented # :nodoc:
-
1
def publish(name, *args)
-
@delegate.call name, *args
-
end
-
-
1
def start(name, id, payload)
-
timestack = Thread.current[:_timestack] ||= []
-
timestack.push Time.now
-
end
-
-
1
def finish(name, id, payload)
-
timestack = Thread.current[:_timestack]
-
started = timestack.pop
-
@delegate.call(name, started, Time.now, id, payload)
-
end
-
end
-
-
1
class AllMessages # :nodoc:
-
1
def initialize(delegate)
-
@delegate = delegate
-
end
-
-
1
def start(name, id, payload)
-
@delegate.start name, id, payload
-
end
-
-
1
def finish(name, id, payload)
-
@delegate.finish name, id, payload
-
end
-
-
1
def publish(name, *args)
-
@delegate.publish name, *args
-
end
-
-
1
def subscribed_to?(name)
-
true
-
end
-
-
1
alias :matches? :===
-
end
-
end
-
end
-
end
-
end
-
1
require "securerandom"
-
-
1
module ActiveSupport
-
1
module Notifications
-
# Instrumenters are stored in a thread local.
-
1
class Instrumenter
-
1
attr_reader :id
-
-
1
def initialize(notifier)
-
@id = unique_id
-
@notifier = notifier
-
end
-
-
# Instrument the given block by measuring the time taken to execute it
-
# and publish it. Notice that events get sent even if an error occurs
-
# in the passed-in block.
-
1
def instrument(name, payload = {})
-
# some of the listeners might have state
-
listeners_state = start name, payload
-
begin
-
yield payload
-
rescue Exception => e
-
payload[:exception] = [e.class.name, e.message]
-
payload[:exception_object] = e
-
raise e
-
ensure
-
finish_with_state listeners_state, name, payload
-
end
-
end
-
-
# Send a start notification with +name+ and +payload+.
-
1
def start(name, payload)
-
@notifier.start name, @id, payload
-
end
-
-
# Send a finish notification with +name+ and +payload+.
-
1
def finish(name, payload)
-
@notifier.finish name, @id, payload
-
end
-
-
1
def finish_with_state(listeners_state, name, payload)
-
@notifier.finish name, @id, payload, listeners_state
-
end
-
-
1
private
-
-
1
def unique_id
-
SecureRandom.hex(10)
-
end
-
end
-
-
1
class Event
-
1
attr_reader :name, :time, :transaction_id, :payload, :children
-
1
attr_accessor :end
-
-
1
def initialize(name, start, ending, transaction_id, payload)
-
@name = name
-
@payload = payload.dup
-
@time = start
-
@transaction_id = transaction_id
-
@end = ending
-
@children = []
-
@duration = nil
-
end
-
-
# Returns the difference in milliseconds between when the execution of the
-
# event started and when it ended.
-
#
-
# ActiveSupport::Notifications.subscribe('wait') do |*args|
-
# @event = ActiveSupport::Notifications::Event.new(*args)
-
# end
-
#
-
# ActiveSupport::Notifications.instrument('wait') do
-
# sleep 1
-
# end
-
#
-
# @event.duration # => 1000.138
-
1
def duration
-
@duration ||= 1000.0 * (self.end - time)
-
end
-
-
1
def <<(event)
-
@children << event
-
end
-
-
1
def parent_of?(event)
-
@children.include? event
-
end
-
end
-
end
-
end
-
1
require "active_support/core_ext/module/delegation"
-
-
1
module ActiveSupport
-
# NOTE: This approach has been deprecated for end-user code in favor of {thread_mattr_accessor}[rdoc-ref:Module#thread_mattr_accessor] and friends.
-
# Please use that approach instead.
-
#
-
# This module is used to encapsulate access to thread local variables.
-
#
-
# Instead of polluting the thread locals namespace:
-
#
-
# Thread.current[:connection_handler]
-
#
-
# you define a class that extends this module:
-
#
-
# module ActiveRecord
-
# class RuntimeRegistry
-
# extend ActiveSupport::PerThreadRegistry
-
#
-
# attr_accessor :connection_handler
-
# end
-
# end
-
#
-
# and invoke the declared instance accessors as class methods. So
-
#
-
# ActiveRecord::RuntimeRegistry.connection_handler = connection_handler
-
#
-
# sets a connection handler local to the current thread, and
-
#
-
# ActiveRecord::RuntimeRegistry.connection_handler
-
#
-
# returns a connection handler local to the current thread.
-
#
-
# This feature is accomplished by instantiating the class and storing the
-
# instance as a thread local keyed by the class name. In the example above
-
# a key "ActiveRecord::RuntimeRegistry" is stored in <tt>Thread.current</tt>.
-
# The class methods proxy to said thread local instance.
-
#
-
# If the class has an initializer, it must accept no arguments.
-
1
module PerThreadRegistry
-
1
def self.extended(object)
-
1
object.instance_variable_set "@per_thread_registry_key", object.name.freeze
-
end
-
-
1
def instance
-
Thread.current[@per_thread_registry_key] ||= new
-
end
-
-
1
private
-
1
def method_missing(name, *args, &block)
-
# Caches the method definition as a singleton method of the receiver.
-
#
-
# By letting #delegate handle it, we avoid an enclosure that'll capture args.
-
singleton_class.delegate name, to: :instance
-
-
send(name, *args, &block)
-
end
-
end
-
end
-
1
gem "minitest" # make sure we get the gem, not stdlib
-
1
require "minitest"
-
1
require "active_support/testing/tagged_logging"
-
1
require "active_support/testing/setup_and_teardown"
-
1
require "active_support/testing/assertions"
-
1
require "active_support/testing/deprecation"
-
1
require "active_support/testing/declarative"
-
1
require "active_support/testing/isolation"
-
1
require "active_support/testing/constant_lookup"
-
1
require "active_support/testing/time_helpers"
-
1
require "active_support/testing/file_fixtures"
-
1
require "active_support/core_ext/kernel/reporting"
-
-
1
module ActiveSupport
-
1
class TestCase < ::Minitest::Test
-
1
Assertion = Minitest::Assertion
-
-
1
class << self
-
# Sets the order in which test cases are run.
-
#
-
# ActiveSupport::TestCase.test_order = :random # => :random
-
#
-
# Valid values are:
-
# * +:random+ (to run tests in random order)
-
# * +:parallel+ (to run tests in parallel)
-
# * +:sorted+ (to run tests alphabetically by method name)
-
# * +:alpha+ (equivalent to +:sorted+)
-
1
def test_order=(new_order)
-
ActiveSupport.test_order = new_order
-
end
-
-
# Returns the order in which test cases are run.
-
#
-
# ActiveSupport::TestCase.test_order # => :random
-
#
-
# Possible values are +:random+, +:parallel+, +:alpha+, +:sorted+.
-
# Defaults to +:random+.
-
1
def test_order
-
4
ActiveSupport.test_order ||= :random
-
end
-
end
-
-
1
alias_method :method_name, :name
-
-
1
include ActiveSupport::Testing::TaggedLogging
-
1
include ActiveSupport::Testing::SetupAndTeardown
-
1
include ActiveSupport::Testing::Assertions
-
1
include ActiveSupport::Testing::Deprecation
-
1
include ActiveSupport::Testing::TimeHelpers
-
1
include ActiveSupport::Testing::FileFixtures
-
1
extend ActiveSupport::Testing::Declarative
-
-
# test/unit backwards compatibility methods
-
1
alias :assert_raise :assert_raises
-
1
alias :assert_not_empty :refute_empty
-
1
alias :assert_not_equal :refute_equal
-
1
alias :assert_not_in_delta :refute_in_delta
-
1
alias :assert_not_in_epsilon :refute_in_epsilon
-
1
alias :assert_not_includes :refute_includes
-
1
alias :assert_not_instance_of :refute_instance_of
-
1
alias :assert_not_kind_of :refute_kind_of
-
1
alias :assert_no_match :refute_match
-
1
alias :assert_not_nil :refute_nil
-
1
alias :assert_not_operator :refute_operator
-
1
alias :assert_not_predicate :refute_predicate
-
1
alias :assert_not_respond_to :refute_respond_to
-
1
alias :assert_not_same :refute_same
-
-
1
ActiveSupport.run_load_hooks(:active_support_test_case, self)
-
end
-
end
-
1
module ActiveSupport
-
1
module Testing
-
1
module Assertions
-
1
UNTRACKED = Object.new # :nodoc:
-
-
# Asserts that an expression is not truthy. Passes if <tt>object</tt> is
-
# +nil+ or +false+. "Truthy" means "considered true in a conditional"
-
# like <tt>if foo</tt>.
-
#
-
# assert_not nil # => true
-
# assert_not false # => true
-
# assert_not 'foo' # => Expected "foo" to be nil or false
-
#
-
# An error message can be specified.
-
#
-
# assert_not foo, 'foo should be false'
-
1
def assert_not(object, message = nil)
-
message ||= "Expected #{mu_pp(object)} to be nil or false"
-
assert !object, message
-
end
-
-
# Assertion that the block should not raise an exception.
-
#
-
# Passes if evaluated code in the yielded block raises no exception.
-
#
-
# assert_nothing_raised do
-
# perform_service(param: 'no_exception')
-
# end
-
1
def assert_nothing_raised
-
yield
-
end
-
-
# Test numeric difference between the return value of an expression as a
-
# result of what is evaluated in the yielded block.
-
#
-
# assert_difference 'Article.count' do
-
# post :create, params: { article: {...} }
-
# end
-
#
-
# An arbitrary expression is passed in and evaluated.
-
#
-
# assert_difference 'Article.last.comments(:reload).size' do
-
# post :create, params: { comment: {...} }
-
# end
-
#
-
# An arbitrary positive or negative difference can be specified.
-
# The default is <tt>1</tt>.
-
#
-
# assert_difference 'Article.count', -1 do
-
# post :delete, params: { id: ... }
-
# end
-
#
-
# An array of expressions can also be passed in and evaluated.
-
#
-
# assert_difference [ 'Article.count', 'Post.count' ], 2 do
-
# post :create, params: { article: {...} }
-
# end
-
#
-
# A lambda or a list of lambdas can be passed in and evaluated:
-
#
-
# assert_difference ->{ Article.count }, 2 do
-
# post :create, params: { article: {...} }
-
# end
-
#
-
# assert_difference [->{ Article.count }, ->{ Post.count }], 2 do
-
# post :create, params: { article: {...} }
-
# end
-
#
-
# An error message can be specified.
-
#
-
# assert_difference 'Article.count', -1, 'An Article should be destroyed' do
-
# post :delete, params: { id: ... }
-
# end
-
1
def assert_difference(expression, difference = 1, message = nil, &block)
-
expressions = Array(expression)
-
-
exps = expressions.map { |e|
-
e.respond_to?(:call) ? e : lambda { eval(e, block.binding) }
-
}
-
before = exps.map(&:call)
-
-
retval = yield
-
-
expressions.zip(exps).each_with_index do |(code, e), i|
-
error = "#{code.inspect} didn't change by #{difference}"
-
error = "#{message}.\n#{error}" if message
-
assert_equal(before[i] + difference, e.call, error)
-
end
-
-
retval
-
end
-
-
# Assertion that the numeric result of evaluating an expression is not
-
# changed before and after invoking the passed in block.
-
#
-
# assert_no_difference 'Article.count' do
-
# post :create, params: { article: invalid_attributes }
-
# end
-
#
-
# An error message can be specified.
-
#
-
# assert_no_difference 'Article.count', 'An Article should not be created' do
-
# post :create, params: { article: invalid_attributes }
-
# end
-
1
def assert_no_difference(expression, message = nil, &block)
-
assert_difference expression, 0, message, &block
-
end
-
-
# Assertion that the result of evaluating an expression is changed before
-
# and after invoking the passed in block.
-
#
-
# assert_changes 'Status.all_good?' do
-
# post :create, params: { status: { ok: false } }
-
# end
-
#
-
# You can pass the block as a string to be evaluated in the context of
-
# the block. A lambda can be passed for the block as well.
-
#
-
# assert_changes -> { Status.all_good? } do
-
# post :create, params: { status: { ok: false } }
-
# end
-
#
-
# The assertion is useful to test side effects. The passed block can be
-
# anything that can be converted to string with #to_s.
-
#
-
# assert_changes :@object do
-
# @object = 42
-
# end
-
#
-
# The keyword arguments :from and :to can be given to specify the
-
# expected initial value and the expected value after the block was
-
# executed.
-
#
-
# assert_changes :@object, from: nil, to: :foo do
-
# @object = :foo
-
# end
-
#
-
# An error message can be specified.
-
#
-
# assert_changes -> { Status.all_good? }, 'Expected the status to be bad' do
-
# post :create, params: { status: { incident: true } }
-
# end
-
1
def assert_changes(expression, message = nil, from: UNTRACKED, to: UNTRACKED, &block)
-
exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
-
-
before = exp.call
-
retval = yield
-
-
unless from == UNTRACKED
-
error = "#{expression.inspect} isn't #{from.inspect}"
-
error = "#{message}.\n#{error}" if message
-
assert from === before, error
-
end
-
-
after = exp.call
-
-
if to == UNTRACKED
-
error = "#{expression.inspect} didn't changed"
-
error = "#{message}.\n#{error}" if message
-
assert_not_equal before, after, error
-
else
-
error = "#{expression.inspect} didn't change to #{to}"
-
error = "#{message}.\n#{error}" if message
-
assert to === after, error
-
end
-
-
retval
-
end
-
-
# Assertion that the result of evaluating an expression is changed before
-
# and after invoking the passed in block.
-
#
-
# assert_no_changes 'Status.all_good?' do
-
# post :create, params: { status: { ok: true } }
-
# end
-
#
-
# An error message can be specified.
-
#
-
# assert_no_changes -> { Status.all_good? }, 'Expected the status to be good' do
-
# post :create, params: { status: { ok: false } }
-
# end
-
1
def assert_no_changes(expression, message = nil, &block)
-
exp = expression.respond_to?(:call) ? expression : -> { eval(expression.to_s, block.binding) }
-
-
before = exp.call
-
retval = yield
-
after = exp.call
-
-
error = "#{expression.inspect} did change to #{after}"
-
error = "#{message}.\n#{error}" if message
-
assert_equal before, after, error
-
-
retval
-
end
-
end
-
end
-
end
-
1
gem "minitest"
-
-
1
require "minitest"
-
-
1
if Minitest.respond_to?(:run_via) && !Minitest.run_via[:rails]
-
Minitest.run_via[:ruby] = true
-
end
-
-
1
Minitest.autorun
-
1
require "active_support/concern"
-
1
require "active_support/inflector"
-
-
1
module ActiveSupport
-
1
module Testing
-
# Resolves a constant from a minitest spec name.
-
#
-
# Given the following spec-style test:
-
#
-
# describe WidgetsController, :index do
-
# describe "authenticated user" do
-
# describe "returns widgets" do
-
# it "has a controller that exists" do
-
# assert_kind_of WidgetsController, @controller
-
# end
-
# end
-
# end
-
# end
-
#
-
# The test will have the following name:
-
#
-
# "WidgetsController::index::authenticated user::returns widgets"
-
#
-
# The constant WidgetsController can be resolved from the name.
-
# The following code will resolve the constant:
-
#
-
# controller = determine_constant_from_test_name(name) do |constant|
-
# Class === constant && constant < ::ActionController::Metal
-
# end
-
1
module ConstantLookup
-
1
extend ::ActiveSupport::Concern
-
-
1
module ClassMethods # :nodoc:
-
1
def determine_constant_from_test_name(test_name)
-
names = test_name.split "::"
-
while names.size > 0 do
-
names.last.sub!(/Test$/, "")
-
begin
-
constant = names.join("::").safe_constantize
-
break(constant) if yield(constant)
-
ensure
-
names.pop
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveSupport
-
1
module Testing
-
1
module Declarative
-
1
unless defined?(Spec)
-
# Helper to define a test method using a String. Under the hood, it replaces
-
# spaces with underscores and defines the test method.
-
#
-
# test "verify something" do
-
# ...
-
# end
-
1
def test(name, &block)
-
test_name = "test_#{name.gsub(/\s+/, '_')}".to_sym
-
defined = method_defined? test_name
-
raise "#{test_name} is already defined in #{self}" if defined
-
if block_given?
-
define_method(test_name, &block)
-
else
-
define_method(test_name) do
-
flunk "No implementation provided for #{name}"
-
end
-
end
-
end
-
end
-
end
-
end
-
end
-
1
require "active_support/deprecation"
-
1
require "active_support/core_ext/regexp"
-
-
1
module ActiveSupport
-
1
module Testing
-
1
module Deprecation #:nodoc:
-
1
def assert_deprecated(match = nil, deprecator = nil, &block)
-
result, warnings = collect_deprecations(deprecator, &block)
-
assert !warnings.empty?, "Expected a deprecation warning within the block but received none"
-
if match
-
match = Regexp.new(Regexp.escape(match)) unless match.is_a?(Regexp)
-
assert warnings.any? { |w| match.match?(w) }, "No deprecation warning matched #{match}: #{warnings.join(', ')}"
-
end
-
result
-
end
-
-
1
def assert_not_deprecated(deprecator = nil, &block)
-
result, deprecations = collect_deprecations(deprecator, &block)
-
assert deprecations.empty?, "Expected no deprecation warning within the block but received #{deprecations.size}: \n #{deprecations * "\n "}"
-
result
-
end
-
-
1
def collect_deprecations(deprecator = nil)
-
deprecator ||= ActiveSupport::Deprecation
-
old_behavior = deprecator.behavior
-
deprecations = []
-
deprecator.behavior = Proc.new do |message, callstack|
-
deprecations << message
-
end
-
result = yield
-
[result, deprecations]
-
ensure
-
deprecator.behavior = old_behavior
-
end
-
end
-
end
-
end
-
1
module ActiveSupport
-
1
module Testing
-
# Adds simple access to sample files called file fixtures.
-
# File fixtures are normal files stored in
-
# <tt>ActiveSupport::TestCase.file_fixture_path</tt>.
-
#
-
# File fixtures are represented as +Pathname+ objects.
-
# This makes it easy to extract specific information:
-
#
-
# file_fixture("example.txt").read # get the file's content
-
# file_fixture("example.mp3").size # get the file size
-
1
module FileFixtures
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
class_attribute :file_fixture_path, instance_writer: false
-
end
-
-
# Returns a +Pathname+ to the fixture file named +fixture_name+.
-
#
-
# Raises +ArgumentError+ if +fixture_name+ can't be found.
-
1
def file_fixture(fixture_name)
-
path = Pathname.new(File.join(file_fixture_path, fixture_name))
-
-
if path.exist?
-
path
-
else
-
msg = "the directory '%s' does not contain a file named '%s'"
-
raise ArgumentError, msg % [file_fixture_path, fixture_name]
-
end
-
end
-
end
-
end
-
end
-
1
module ActiveSupport
-
1
module Testing
-
1
module Isolation
-
1
require "thread"
-
-
1
def self.included(klass) #:nodoc:
-
klass.class_eval do
-
parallelize_me!
-
end
-
end
-
-
1
def self.forking_env?
-
1
!ENV["NO_FORK"] && Process.respond_to?(:fork)
-
end
-
-
1
def run
-
serialized = run_in_isolation do
-
super
-
end
-
-
Marshal.load(serialized)
-
end
-
-
1
module Forking
-
1
def run_in_isolation(&blk)
-
read, write = IO.pipe
-
read.binmode
-
write.binmode
-
-
pid = fork do
-
read.close
-
yield
-
begin
-
if error?
-
failures.map! { |e|
-
begin
-
Marshal.dump e
-
e
-
rescue TypeError
-
ex = Exception.new e.message
-
ex.set_backtrace e.backtrace
-
Minitest::UnexpectedError.new ex
-
end
-
}
-
end
-
result = Marshal.dump(dup)
-
end
-
-
write.puts [result].pack("m")
-
exit!
-
end
-
-
write.close
-
result = read.read
-
Process.wait2(pid)
-
return result.unpack("m")[0]
-
end
-
end
-
-
1
module Subprocess
-
1
ORIG_ARGV = ARGV.dup unless defined?(ORIG_ARGV)
-
-
# Crazy H4X to get this working in windows / jruby with
-
# no forking.
-
1
def run_in_isolation(&blk)
-
require "tempfile"
-
-
if ENV["ISOLATION_TEST"]
-
yield
-
File.open(ENV["ISOLATION_OUTPUT"], "w") do |file|
-
file.puts [Marshal.dump(dup)].pack("m")
-
end
-
exit!
-
else
-
Tempfile.open("isolation") do |tmpfile|
-
env = {
-
"ISOLATION_TEST" => self.class.name,
-
"ISOLATION_OUTPUT" => tmpfile.path
-
}
-
-
test_opts = "-n#{self.class.name}##{name}"
-
-
load_path_args = []
-
$-I.each do |p|
-
load_path_args << "-I"
-
load_path_args << File.expand_path(p)
-
end
-
-
child = IO.popen([env, Gem.ruby, *load_path_args, $0, *ORIG_ARGV, test_opts])
-
-
begin
-
Process.wait(child.pid)
-
rescue Errno::ECHILD # The child process may exit before we wait
-
nil
-
end
-
-
return tmpfile.read.unpack("m")[0]
-
end
-
end
-
end
-
end
-
-
1
include forking_env? ? Forking : Subprocess
-
end
-
end
-
end
-
1
require "minitest/mock"
-
-
1
module ActiveSupport
-
1
module Testing
-
1
module MethodCallAssertions # :nodoc:
-
1
private
-
1
def assert_called(object, method_name, message = nil, times: 1, returns: nil)
-
times_called = 0
-
-
object.stub(method_name, proc { times_called += 1; returns }) { yield }
-
-
error = "Expected #{method_name} to be called #{times} times, " \
-
"but was called #{times_called} times"
-
error = "#{message}.\n#{error}" if message
-
assert_equal times, times_called, error
-
end
-
-
1
def assert_called_with(object, method_name, args = [], returns: nil)
-
mock = Minitest::Mock.new
-
-
if args.all? { |arg| arg.is_a?(Array) }
-
args.each { |arg| mock.expect(:call, returns, arg) }
-
else
-
mock.expect(:call, returns, args)
-
end
-
-
object.stub(method_name, mock) { yield }
-
-
mock.verify
-
end
-
-
1
def assert_not_called(object, method_name, message = nil, &block)
-
assert_called(object, method_name, message, times: 0, &block)
-
end
-
-
1
def stub_any_instance(klass, instance: klass.new)
-
klass.stub(:new, instance) { yield instance }
-
end
-
end
-
end
-
end
-
1
require "active_support/concern"
-
1
require "active_support/callbacks"
-
-
1
module ActiveSupport
-
1
module Testing
-
# Adds support for +setup+ and +teardown+ callbacks.
-
# These callbacks serve as a replacement to overwriting the
-
# <tt>#setup</tt> and <tt>#teardown</tt> methods of your TestCase.
-
#
-
# class ExampleTest < ActiveSupport::TestCase
-
# setup do
-
# # ...
-
# end
-
#
-
# teardown do
-
# # ...
-
# end
-
# end
-
1
module SetupAndTeardown
-
1
extend ActiveSupport::Concern
-
-
1
included do
-
1
include ActiveSupport::Callbacks
-
1
define_callbacks :setup, :teardown
-
end
-
-
1
module ClassMethods
-
# Add a callback, which runs before <tt>TestCase#setup</tt>.
-
1
def setup(*args, &block)
-
set_callback(:setup, :before, *args, &block)
-
end
-
-
# Add a callback, which runs after <tt>TestCase#teardown</tt>.
-
1
def teardown(*args, &block)
-
set_callback(:teardown, :after, *args, &block)
-
end
-
end
-
-
1
def before_setup # :nodoc:
-
1
super
-
1
run_callbacks :setup
-
end
-
-
1
def after_teardown # :nodoc:
-
1
run_callbacks :teardown
-
1
super
-
end
-
end
-
end
-
end
-
1
module ActiveSupport
-
1
module Testing
-
# Logs a "PostsControllerTest: test name" heading before each test to
-
# make test.log easier to search and follow along with.
-
1
module TaggedLogging #:nodoc:
-
1
attr_writer :tagged_logger
-
-
1
def before_setup
-
1
if tagged_logger && tagged_logger.info?
-
heading = "#{self.class}: #{name}"
-
divider = "-" * heading.size
-
tagged_logger.info divider
-
tagged_logger.info heading
-
tagged_logger.info divider
-
end
-
1
super
-
end
-
-
1
private
-
1
def tagged_logger
-
1
@tagged_logger ||= (defined?(Rails.logger) && Rails.logger)
-
end
-
end
-
end
-
end
-
1
require "active_support/core_ext/string/strip" # for strip_heredoc
-
1
require "concurrent/map"
-
-
1
module ActiveSupport
-
1
module Testing
-
1
class SimpleStubs # :nodoc:
-
1
Stub = Struct.new(:object, :method_name, :original_method)
-
-
1
def initialize
-
@stubs = Concurrent::Map.new { |h, k| h[k] = {} }
-
end
-
-
1
def stub_object(object, method_name, &block)
-
if stub = stubbing(object, method_name)
-
unstub_object(stub)
-
end
-
-
new_name = "__simple_stub__#{method_name}"
-
-
@stubs[object.object_id][method_name] = Stub.new(object, method_name, new_name)
-
-
object.singleton_class.send :alias_method, new_name, method_name
-
object.define_singleton_method(method_name, &block)
-
end
-
-
1
def unstub_all!
-
@stubs.each_value do |object_stubs|
-
object_stubs.each_value do |stub|
-
unstub_object(stub)
-
end
-
end
-
@stubs.clear
-
end
-
-
1
def stubbing(object, method_name)
-
@stubs[object.object_id][method_name]
-
end
-
-
1
private
-
-
1
def unstub_object(stub)
-
singleton_class = stub.object.singleton_class
-
singleton_class.send :undef_method, stub.method_name
-
singleton_class.send :alias_method, stub.method_name, stub.original_method
-
singleton_class.send :undef_method, stub.original_method
-
end
-
end
-
-
# Contains helpers that help you test passage of time.
-
1
module TimeHelpers
-
# Changes current time to the time in the future or in the past by a given time difference by
-
# stubbing +Time.now+, +Date.today+, and +DateTime.now+.
-
#
-
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
-
# travel 1.day
-
# Time.current # => Sun, 10 Nov 2013 15:34:49 EST -05:00
-
# Date.current # => Sun, 10 Nov 2013
-
# DateTime.current # => Sun, 10 Nov 2013 15:34:49 -0500
-
#
-
# This method also accepts a block, which will return the current time back to its original
-
# state at the end of the block:
-
#
-
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
-
# travel 1.day do
-
# User.create.created_at # => Sun, 10 Nov 2013 15:34:49 EST -05:00
-
# end
-
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
-
1
def travel(duration, &block)
-
travel_to Time.now + duration, &block
-
end
-
-
# Changes current time to the given time by stubbing +Time.now+,
-
# +Date.today+, and +DateTime.now+ to return the time or date passed into this method.
-
#
-
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
-
# travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
-
# Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
-
# Date.current # => Wed, 24 Nov 2004
-
# DateTime.current # => Wed, 24 Nov 2004 01:04:44 -0500
-
#
-
# Dates are taken as their timestamp at the beginning of the day in the
-
# application time zone. <tt>Time.current</tt> returns said timestamp,
-
# and <tt>Time.now</tt> its equivalent in the system time zone. Similarly,
-
# <tt>Date.current</tt> returns a date equal to the argument, and
-
# <tt>Date.today</tt> the date according to <tt>Time.now</tt>, which may
-
# be different. (Note that you rarely want to deal with <tt>Time.now</tt>,
-
# or <tt>Date.today</tt>, in order to honor the application time zone
-
# please always use <tt>Time.current</tt> and <tt>Date.current</tt>.)
-
#
-
# Note that the usec for the time passed will be set to 0 to prevent rounding
-
# errors with external services, like MySQL (which will round instead of floor,
-
# leading to off-by-one-second errors).
-
#
-
# This method also accepts a block, which will return the current time back to its original
-
# state at the end of the block:
-
#
-
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
-
# travel_to Time.zone.local(2004, 11, 24, 01, 04, 44) do
-
# Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
-
# end
-
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
-
1
def travel_to(date_or_time)
-
if block_given? && simple_stubs.stubbing(Time, :now)
-
travel_to_nested_block_call = <<-MSG.strip_heredoc
-
-
Calling `travel_to` with a block, when we have previously already made a call to `travel_to`, can lead to confusing time stubbing.
-
-
Instead of:
-
-
travel_to 2.days.from_now do
-
# 2 days from today
-
travel_to 3.days.from_now do
-
# 5 days from today
-
end
-
end
-
-
preferred way to achieve above is:
-
-
travel 2.days do
-
# 2 days from today
-
end
-
-
travel 5.days do
-
# 5 days from today
-
end
-
-
MSG
-
raise travel_to_nested_block_call
-
end
-
-
if date_or_time.is_a?(Date) && !date_or_time.is_a?(DateTime)
-
now = date_or_time.midnight.to_time
-
else
-
now = date_or_time.to_time.change(usec: 0)
-
end
-
-
simple_stubs.stub_object(Time, :now) { at(now.to_i) }
-
simple_stubs.stub_object(Date, :today) { jd(now.to_date.jd) }
-
simple_stubs.stub_object(DateTime, :now) { jd(now.to_date.jd, now.hour, now.min, now.sec, Rational(now.utc_offset, 86400)) }
-
-
if block_given?
-
begin
-
yield
-
ensure
-
travel_back
-
end
-
end
-
end
-
-
# Returns the current time back to its original state, by removing the stubs added by
-
# `travel` and `travel_to`.
-
#
-
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
-
# travel_to Time.zone.local(2004, 11, 24, 01, 04, 44)
-
# Time.current # => Wed, 24 Nov 2004 01:04:44 EST -05:00
-
# travel_back
-
# Time.current # => Sat, 09 Nov 2013 15:34:49 EST -05:00
-
1
def travel_back
-
simple_stubs.unstub_all!
-
end
-
-
1
private
-
-
1
def simple_stubs
-
@simple_stubs ||= SimpleStubs.new
-
end
-
end
-
end
-
end
-
1
require_relative "gem_version"
-
-
1
module ActiveSupport
-
# Returns the version of the currently loaded ActiveSupport as a <tt>Gem::Version</tt>
-
1
def self.version
-
gem_version
-
end
-
end
-
1
ORIG_ARGV = ARGV.dup
-
-
1
require "active_support/core_ext/kernel/reporting"
-
-
1
silence_warnings do
-
1
Encoding.default_internal = Encoding::UTF_8
-
1
Encoding.default_external = Encoding::UTF_8
-
end
-
-
1
require "active_support/testing/autorun"
-
1
require "active_support/testing/method_call_assertions"
-
-
1
ENV["NO_RELOAD"] = "1"
-
1
require "active_support"
-
-
1
Thread.abort_on_exception = true
-
-
# Show backtraces for deprecated behavior for quicker cleanup.
-
1
ActiveSupport::Deprecation.debug = true
-
-
# Default to old to_time behavior but allow running tests with new behavior
-
1
ActiveSupport.to_time_preserves_timezone = ENV["PRESERVE_TIMEZONES"] == "1"
-
-
# Disable available locale checks to avoid warnings running the test suite.
-
1
I18n.enforce_available_locales = false
-
-
1
class ActiveSupport::TestCase
-
1
include ActiveSupport::Testing::MethodCallAssertions
-
-
# Skips the current run on Rubinius using Minitest::Assertions#skip
-
1
private def rubinius_skip(message = "")
-
skip message if RUBY_ENGINE == "rbx"
-
end
-
-
# Skips the current run on JRuby using Minitest::Assertions#skip
-
1
private def jruby_skip(message = "")
-
skip message if defined?(JRUBY_VERSION)
-
end
-
end
-
1
module MultibyteTestHelpers
-
1
class Downloader
-
1
def self.download(from, to)
-
1
unless File.exist?(to)
-
unless File.exist?(File.dirname(to))
-
system "mkdir -p #{File.dirname(to)}"
-
end
-
open(from) do |source|
-
File.open(to, "w") do |target|
-
source.each_line do |l|
-
target.write l
-
end
-
end
-
end
-
end
-
1
true
-
end
-
end
-
-
1
UNIDATA_URL = "http://www.unicode.org/Public/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}/ucd"
-
1
CACHE_DIR = "#{Dir.tmpdir}/cache/unicode_conformance/#{ActiveSupport::Multibyte::Unicode::UNICODE_VERSION}"
-
1
FileUtils.mkdir_p(CACHE_DIR)
-
-
1
UNICODE_STRING = "こにちわ".freeze
-
1
ASCII_STRING = "ohayo".freeze
-
1
BYTE_STRING = "\270\236\010\210\245".force_encoding("ASCII-8BIT").freeze
-
-
1
def chars(str)
-
ActiveSupport::Multibyte::Chars.new(str)
-
end
-
-
1
def inspect_codepoints(str)
-
str.to_s.unpack("U*").map { |cp| cp.to_s(16) }.join(" ")
-
end
-
-
1
def assert_equal_codepoints(expected, actual, message = nil)
-
assert_equal(inspect_codepoints(expected), inspect_codepoints(actual), message)
-
end
-
end