aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib
diff options
context:
space:
mode:
Diffstat (limited to 'activesupport/lib')
-rw-r--r--activesupport/lib/active_support.rb2
-rw-r--r--activesupport/lib/active_support/buffered_logger.rb16
-rw-r--r--activesupport/lib/active_support/cache/strategy/local_cache.rb5
-rw-r--r--activesupport/lib/active_support/callbacks.rb2
-rw-r--r--activesupport/lib/active_support/concurrent_hash.rb27
-rw-r--r--activesupport/lib/active_support/core_ext/class/attribute_accessors.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/class/delegating_attributes.rb10
-rw-r--r--activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb101
-rw-r--r--activesupport/lib/active_support/core_ext/hash/conversions.rb3
-rw-r--r--activesupport/lib/active_support/core_ext/module.rb1
-rw-r--r--activesupport/lib/active_support/core_ext/module/attribute_accessors.rb4
-rw-r--r--activesupport/lib/active_support/core_ext/module/setup.rb26
-rw-r--r--activesupport/lib/active_support/core_ext/proc.rb6
-rw-r--r--activesupport/lib/active_support/core_ext/string/access.rb34
-rw-r--r--activesupport/lib/active_support/core_ext/time/calculations.rb14
-rw-r--r--activesupport/lib/active_support/deprecation/method_wrappers.rb2
-rw-r--r--activesupport/lib/active_support/memoizable.rb19
-rw-r--r--activesupport/lib/active_support/mini.rb9
-rw-r--r--activesupport/lib/active_support/multibyte/unicode_database.rb10
-rw-r--r--activesupport/lib/active_support/new_callbacks.rb486
-rw-r--r--activesupport/lib/active_support/test_case.rb2
-rw-r--r--activesupport/lib/active_support/testing/declarative.rb49
-rw-r--r--activesupport/lib/active_support/testing/pending.rb43
-rw-r--r--activesupport/lib/active_support/testing/setup_and_teardown.rb4
-rw-r--r--activesupport/lib/active_support/time_with_zone.rb13
25 files changed, 816 insertions, 76 deletions
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index e4fa3b40e5..21b730fa0c 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -32,6 +32,8 @@ module ActiveSupport
autoload :BufferedLogger, 'active_support/buffered_logger'
autoload :Cache, 'active_support/cache'
autoload :Callbacks, 'active_support/callbacks'
+ autoload :NewCallbacks, 'active_support/new_callbacks'
+ autoload :ConcurrentHash, 'active_support/concurrent_hash'
autoload :Deprecation, 'active_support/deprecation'
autoload :Gzip, 'active_support/gzip'
autoload :Inflector, 'active_support/inflector'
diff --git a/activesupport/lib/active_support/buffered_logger.rb b/activesupport/lib/active_support/buffered_logger.rb
index 9bf63a90b1..ee66479dde 100644
--- a/activesupport/lib/active_support/buffered_logger.rb
+++ b/activesupport/lib/active_support/buffered_logger.rb
@@ -69,14 +69,14 @@ module ActiveSupport
end
for severity in Severity.constants
- class_eval <<-EOT, __FILE__, __LINE__
- def #{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block)
- add(#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block)
- end # end
- #
- def #{severity.downcase}? # def debug?
- #{severity} >= @level # DEBUG >= @level
- end # end
+ class_eval <<-EOT, __FILE__, __LINE__ + 1
+ def #{severity.downcase}(message = nil, progname = nil, &block) # def debug(message = nil, progname = nil, &block)
+ add(#{severity}, message, progname, &block) # add(DEBUG, message, progname, &block)
+ end # end
+
+ def #{severity.downcase}? # def debug?
+ #{severity} >= @level # DEBUG >= @level
+ end # end
EOT
end
diff --git a/activesupport/lib/active_support/cache/strategy/local_cache.rb b/activesupport/lib/active_support/cache/strategy/local_cache.rb
index d83e259a2a..84d9a0e6d8 100644
--- a/activesupport/lib/active_support/cache/strategy/local_cache.rb
+++ b/activesupport/lib/active_support/cache/strategy/local_cache.rb
@@ -27,6 +27,11 @@ module ActiveSupport
Thread.current[:#{thread_local_key}] = nil
end
EOS
+
+ def klass.to_s
+ "ActiveSupport::Cache::Strategy::LocalCache"
+ end
+
klass
end
end
diff --git a/activesupport/lib/active_support/callbacks.rb b/activesupport/lib/active_support/callbacks.rb
index 86e66e0588..4bac8292e2 100644
--- a/activesupport/lib/active_support/callbacks.rb
+++ b/activesupport/lib/active_support/callbacks.rb
@@ -204,7 +204,7 @@ module ActiveSupport
module ClassMethods
def define_callbacks(*callbacks)
callbacks.each do |callback|
- class_eval <<-"end_eval"
+ class_eval <<-"end_eval", __FILE__, __LINE__ + 1
def self.#{callback}(*methods, &block) # def self.before_save(*methods, &block)
callbacks = CallbackChain.build(:#{callback}, *methods, &block) # callbacks = CallbackChain.build(:before_save, *methods, &block)
@#{callback}_callbacks ||= CallbackChain.new # @before_save_callbacks ||= CallbackChain.new
diff --git a/activesupport/lib/active_support/concurrent_hash.rb b/activesupport/lib/active_support/concurrent_hash.rb
new file mode 100644
index 0000000000..40224765a7
--- /dev/null
+++ b/activesupport/lib/active_support/concurrent_hash.rb
@@ -0,0 +1,27 @@
+module ActiveSupport
+ class ConcurrentHash
+ def initialize(hash = {})
+ @backup_cache = hash.dup
+ @frozen_cache = hash.dup.freeze
+ @mutex = Mutex.new
+ end
+
+ def []=(k,v)
+ @mutex.synchronize { @backup_cache[k] = v }
+ @frozen_cache = @backup_cache.dup.freeze
+ v
+ end
+
+ def [](k)
+ if @frozen_cache.key?(k)
+ @frozen_cache[k]
+ else
+ @mutex.synchronize { @backup_cache[k] }
+ end
+ end
+
+ def empty?
+ @backup_cache.empty?
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
index c795871474..75e481fc54 100644
--- a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
+++ b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb
@@ -10,7 +10,7 @@ class Class
def cattr_reader(*syms)
syms.flatten.each do |sym|
next if sym.is_a?(Hash)
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
unless defined? @@#{sym} # unless defined? @@hair_colors
@@#{sym} = nil # @@hair_colors = nil
end # end
@@ -29,7 +29,7 @@ class Class
def cattr_writer(*syms)
options = syms.extract_options!
syms.flatten.each do |sym|
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
unless defined? @@#{sym} # unless defined? @@hair_colors
@@#{sym} = nil # @@hair_colors = nil
end # end
diff --git a/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb b/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
index c81af68034..da798c67e7 100644
--- a/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
+++ b/activesupport/lib/active_support/core_ext/class/delegating_attributes.rb
@@ -2,7 +2,7 @@ class Class
def superclass_delegating_reader(*names)
class_name_to_stop_searching_on = superclass.name.blank? ? "Object" : superclass.name
names.each do |name|
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{name} # def self.only_reader
if defined?(@#{name}) # if defined?(@only_reader)
@#{name} # @only_reader
@@ -26,10 +26,10 @@ class Class
def superclass_delegating_writer(*names)
names.each do |name|
- class_eval <<-EOS
- def self.#{name}=(value) # def self.only_writer=(value)
- @#{name} = value # @only_writer = value
- end # end
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def self.#{name}=(value) # def self.property=(value)
+ @#{name} = value # @property = value
+ end # end
EOS
end
end
diff --git a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
index 1794afe77c..2f18666ab9 100644
--- a/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
+++ b/activesupport/lib/active_support/core_ext/class/inheritable_attributes.rb
@@ -10,14 +10,14 @@ class Class # :nodoc:
def class_inheritable_reader(*syms)
syms.each do |sym|
next if sym.is_a?(Hash)
- class_eval <<-EOS
- def self.#{sym} # def self.before_add_for_comments
- read_inheritable_attribute(:#{sym}) # read_inheritable_attribute(:before_add_for_comments)
- end # end
- #
- def #{sym} # def before_add_for_comments
- self.class.#{sym} # self.class.before_add_for_comments
- end # end
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def self.#{sym} # def self.after_add
+ read_inheritable_attribute(:#{sym}) # read_inheritable_attribute(:after_add)
+ end # end
+
+ def #{sym} # def after_add
+ self.class.#{sym} # self.class.after_add
+ end # end
EOS
end
end
@@ -25,7 +25,7 @@ class Class # :nodoc:
def class_inheritable_writer(*syms)
options = syms.extract_options!
syms.each do |sym|
- class_eval <<-EOS
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{sym}=(obj) # def self.color=(obj)
write_inheritable_attribute(:#{sym}, obj) # write_inheritable_attribute(:color, obj)
end # end
@@ -42,7 +42,7 @@ class Class # :nodoc:
def class_inheritable_array_writer(*syms)
options = syms.extract_options!
syms.each do |sym|
- class_eval <<-EOS
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{sym}=(obj) # def self.levels=(obj)
write_inheritable_array(:#{sym}, obj) # write_inheritable_array(:levels, obj)
end # end
@@ -59,7 +59,7 @@ class Class # :nodoc:
def class_inheritable_hash_writer(*syms)
options = syms.extract_options!
syms.each do |sym|
- class_eval <<-EOS
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
def self.#{sym}=(obj) # def self.nicknames=(obj)
write_inheritable_hash(:#{sym}, obj) # write_inheritable_hash(:nicknames, obj)
end # end
@@ -138,3 +138,82 @@ class Class # :nodoc:
alias inherited_without_inheritable_attributes inherited
alias inherited inherited_with_inheritable_attributes
end
+
+class Class
+ # Defines class-level inheritable attribute reader. Attributes are available to subclasses,
+ # each subclass has a copy of parent's attribute.
+ #
+ # @param *syms<Array[#to_s]> Array of attributes to define inheritable reader for.
+ # @return <Array[#to_s]> Array of attributes converted into inheritable_readers.
+ #
+ # @api public
+ #
+ # @todo Do we want to block instance_reader via :instance_reader => false
+ # @todo It would be preferable that we do something with a Hash passed in
+ # (error out or do the same as other methods above) instead of silently
+ # moving on). In particular, this makes the return value of this function
+ # less useful.
+ def extlib_inheritable_reader(*ivars)
+ instance_reader = ivars.pop[:reader] if ivars.last.is_a?(Hash)
+
+ ivars.each do |ivar|
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def self.#{ivar}
+ return @#{ivar} if self.object_id == #{self.object_id} || defined?(@#{ivar})
+ ivar = superclass.#{ivar}
+ return nil if ivar.nil? && !#{self}.instance_variable_defined?("@#{ivar}")
+ @#{ivar} = ivar && !ivar.is_a?(Module) && !ivar.is_a?(Numeric) && !ivar.is_a?(TrueClass) && !ivar.is_a?(FalseClass) ? ivar.dup : ivar
+ end
+ RUBY
+ unless instance_reader == false
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{ivar}
+ self.class.#{ivar}
+ end
+ RUBY
+ end
+ end
+ end
+
+ # Defines class-level inheritable attribute writer. Attributes are available to subclasses,
+ # each subclass has a copy of parent's attribute.
+ #
+ # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
+ # define inheritable writer for.
+ # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
+ # @return <Array[#to_s]> An Array of the attributes that were made into inheritable writers.
+ #
+ # @api public
+ #
+ # @todo We need a style for class_eval <<-HEREDOC. I'd like to make it
+ # class_eval(<<-RUBY, __FILE__, __LINE__), but we should codify it somewhere.
+ def extlib_inheritable_writer(*ivars)
+ instance_writer = ivars.pop[:writer] if ivars.last.is_a?(Hash)
+ ivars.each do |ivar|
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def self.#{ivar}=(obj)
+ @#{ivar} = obj
+ end
+ RUBY
+ unless instance_writer == false
+ self.class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{ivar}=(obj) self.class.#{ivar} = obj end
+ RUBY
+ end
+ end
+ end
+
+ # Defines class-level inheritable attribute accessor. Attributes are available to subclasses,
+ # each subclass has a copy of parent's attribute.
+ #
+ # @param *syms<Array[*#to_s, Hash{:instance_writer => Boolean}]> Array of attributes to
+ # define inheritable accessor for.
+ # @option syms :instance_writer<Boolean> if true, instance-level inheritable attribute writer is defined.
+ # @return <Array[#to_s]> An Array of attributes turned into inheritable accessors.
+ #
+ # @api public
+ def extlib_inheritable_accessor(*syms)
+ extlib_inheritable_reader(*syms)
+ extlib_inheritable_writer(*syms)
+ end
+end \ No newline at end of file
diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb
index 45e56381a9..fa171720f9 100644
--- a/activesupport/lib/active_support/core_ext/hash/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -27,8 +27,7 @@ class Hash
"FalseClass" => "boolean",
"Date" => "date",
"DateTime" => "datetime",
- "Time" => "datetime",
- "ActiveSupport::TimeWithZone" => "datetime"
+ "Time" => "datetime"
} unless defined?(XML_TYPE_NAMES)
XML_FORMATTING = {
diff --git a/activesupport/lib/active_support/core_ext/module.rb b/activesupport/lib/active_support/core_ext/module.rb
index f35a554364..c37c9badca 100644
--- a/activesupport/lib/active_support/core_ext/module.rb
+++ b/activesupport/lib/active_support/core_ext/module.rb
@@ -9,6 +9,7 @@ require 'active_support/core_ext/module/delegation'
require 'active_support/core_ext/module/loading'
require 'active_support/core_ext/module/model_naming'
require 'active_support/core_ext/module/synchronization'
+require 'active_support/core_ext/module/setup'
module ActiveSupport
module CoreExtensions
diff --git a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
index 62bc64d137..131b512944 100644
--- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
+++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb
@@ -4,7 +4,7 @@ class Module
def mattr_reader(*syms)
syms.extract_options!
syms.each do |sym|
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
unless defined? @@#{sym} # unless defined? @@pagination_options
@@#{sym} = nil # @@pagination_options = nil
end # end
@@ -23,7 +23,7 @@ class Module
def mattr_writer(*syms)
options = syms.extract_options!
syms.each do |sym|
- class_eval(<<-EOS, __FILE__, __LINE__)
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
unless defined? @@#{sym} # unless defined? @@pagination_options
@@#{sym} = nil # @@pagination_options = nil
end # end
diff --git a/activesupport/lib/active_support/core_ext/module/setup.rb b/activesupport/lib/active_support/core_ext/module/setup.rb
new file mode 100644
index 0000000000..e6dfd0cf56
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/module/setup.rb
@@ -0,0 +1,26 @@
+class Module
+ attr_accessor :_setup_block
+ attr_accessor :_dependencies
+
+ def setup(&blk)
+ @_setup_block = blk
+ end
+
+ def use(mod)
+ return if self < mod
+
+ (mod._dependencies || []).each do |dep|
+ use dep
+ end
+ # raise "Circular dependencies" if self < mod
+ include mod
+ extend mod.const_get("ClassMethods") if mod.const_defined?("ClassMethods")
+ class_eval(&mod._setup_block) if mod._setup_block
+ end
+
+ def depends_on(mod)
+ return if self < mod
+ @_dependencies ||= []
+ @_dependencies << mod
+ end
+end \ No newline at end of file
diff --git a/activesupport/lib/active_support/core_ext/proc.rb b/activesupport/lib/active_support/core_ext/proc.rb
index 2ca23f62ef..5c29cc32a2 100644
--- a/activesupport/lib/active_support/core_ext/proc.rb
+++ b/activesupport/lib/active_support/core_ext/proc.rb
@@ -3,9 +3,9 @@ class Proc #:nodoc:
block, time = self, Time.now
(class << object; self end).class_eval do
method_name = "__bind_#{time.to_i}_#{time.usec}"
- define_method(method_name, &block)
- method = instance_method(method_name)
- remove_method(method_name)
+ define_method(method_name, &block) # define_method("__bind_1230458026_720454", &block)
+ method = instance_method(method_name) # method = instance_method("__bind_1230458026_720454")
+ remove_method(method_name) # remove_method("__bind_1230458026_720454")
method
end.bind(object)
end
diff --git a/activesupport/lib/active_support/core_ext/string/access.rb b/activesupport/lib/active_support/core_ext/string/access.rb
index 7fb21fa4dd..e806b321f1 100644
--- a/activesupport/lib/active_support/core_ext/string/access.rb
+++ b/activesupport/lib/active_support/core_ext/string/access.rb
@@ -41,9 +41,15 @@ module ActiveSupport #:nodoc:
# "hello".first(2) # => "he"
# "hello".first(10) # => "hello"
def first(limit = 1)
- mb_chars[0..(limit - 1)].to_s
+ if limit == 0
+ ''
+ elsif limit >= size
+ self
+ else
+ mb_chars[0...limit].to_s
+ end
end
-
+
# Returns the last character of the string or the last +limit+ characters.
#
# Examples:
@@ -51,7 +57,13 @@ module ActiveSupport #:nodoc:
# "hello".last(2) # => "lo"
# "hello".last(10) # => "hello"
def last(limit = 1)
- (mb_chars[(-limit)..-1] || self).to_s
+ if limit == 0
+ ''
+ elsif limit >= size
+ self
+ else
+ mb_chars[(-limit)..-1].to_s
+ end
end
end
else
@@ -69,11 +81,23 @@ module ActiveSupport #:nodoc:
end
def first(limit = 1)
- self[0..(limit - 1)]
+ if limit == 0
+ ''
+ elsif limit >= size
+ self
+ else
+ to(limit - 1)
+ end
end
def last(limit = 1)
- from(-limit) || self
+ if limit == 0
+ ''
+ elsif limit >= size
+ self
+ else
+ from(-limit)
+ end
end
end
end
diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb
index 608e3ad29c..b73c3b2c9b 100644
--- a/activesupport/lib/active_support/core_ext/time/calculations.rb
+++ b/activesupport/lib/active_support/core_ext/time/calculations.rb
@@ -101,19 +101,11 @@ class Time
since(-seconds)
end
- # Returns a new Time representing the time a number of seconds since the instance time, this is basically a wrapper around
- # the Numeric extension.
+ # Returns a new Time representing the time a number of seconds since the instance time
def since(seconds)
- f = seconds.since(self)
- if ActiveSupport::Duration === seconds
- f
- else
- initial_dst = dst? ? 1 : 0
- final_dst = f.dst? ? 1 : 0
- (seconds.abs >= 86400 && initial_dst != final_dst) ? f + (initial_dst - final_dst).hours : f
- end
+ self + seconds
rescue
- self.to_datetime.since(seconds)
+ to_datetime.since(seconds)
end
alias :in :since
diff --git a/activesupport/lib/active_support/deprecation/method_wrappers.rb b/activesupport/lib/active_support/deprecation/method_wrappers.rb
index 845bef059f..b35d4daf9a 100644
--- a/activesupport/lib/active_support/deprecation/method_wrappers.rb
+++ b/activesupport/lib/active_support/deprecation/method_wrappers.rb
@@ -9,7 +9,7 @@ module ActiveSupport
method_names.each do |method_name|
target_module.alias_method_chain(method_name, :deprecation) do |target, punctuation|
- target_module.module_eval(<<-end_eval, __FILE__, __LINE__)
+ target_module.module_eval(<<-end_eval, __FILE__, __LINE__ + 1)
def #{target}_with_deprecation#{punctuation}(*args, &block) # def generate_secret_with_deprecation(*args, &block)
::ActiveSupport::Deprecation.warn( # ::ActiveSupport::Deprecation.warn(
::ActiveSupport::Deprecation.deprecated_method_warning( # ::ActiveSupport::Deprecation.deprecated_method_warning(
diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb
index 71cfe61739..2b85fd7be4 100644
--- a/activesupport/lib/active_support/memoizable.rb
+++ b/activesupport/lib/active_support/memoizable.rb
@@ -1,4 +1,17 @@
module ActiveSupport
+ module SafelyMemoizable
+ def safely_memoize(*symbols)
+ symbols.each do |symbol|
+ class_eval <<-RUBY, __FILE__, __LINE__ + 1
+ def #{symbol}(*args)
+ memoized = @_memoized_#{symbol} || ::ActiveSupport::ConcurrentHash.new
+ memoized[args] ||= memoized_#{symbol}(*args)
+ end
+ RUBY
+ end
+ end
+ end
+
module Memoizable
def self.memoized_ivar_for(symbol)
"@_memoized_#{symbol.to_s.sub(/\?\Z/, '_query').sub(/!\Z/, '_bang')}".to_sym
@@ -58,7 +71,7 @@ module ActiveSupport
original_method = :"_unmemoized_#{symbol}"
memoized_ivar = ActiveSupport::Memoizable.memoized_ivar_for(symbol)
- class_eval <<-EOS, __FILE__, __LINE__
+ class_eval <<-EOS, __FILE__, __LINE__ + 1
include InstanceMethods # include InstanceMethods
#
if method_defined?(:#{original_method}) # if method_defined?(:_unmemoized_mime_type)
@@ -69,7 +82,7 @@ module ActiveSupport
if instance_method(:#{symbol}).arity == 0 # if instance_method(:mime_type).arity == 0
def #{symbol}(reload = false) # def mime_type(reload = false)
if reload || !defined?(#{memoized_ivar}) || #{memoized_ivar}.empty? # if reload || !defined?(@_memoized_mime_type) || @_memoized_mime_type.empty?
- #{memoized_ivar} = [#{original_method}.freeze] # @_memoized_mime_type = [_unmemoized_mime_type.freeze]
+ #{memoized_ivar} = [#{original_method}] # @_memoized_mime_type = [_unmemoized_mime_type]
end # end
#{memoized_ivar}[0] # @_memoized_mime_type[0]
end # end
@@ -82,7 +95,7 @@ module ActiveSupport
if !reload && #{memoized_ivar}.has_key?(args) # if !reload && @_memoized_mime_type.has_key?(args)
#{memoized_ivar}[args] # @_memoized_mime_type[args]
elsif #{memoized_ivar} # elsif @_memoized_mime_type
- #{memoized_ivar}[args] = #{original_method}(*args).freeze # @_memoized_mime_type[args] = _unmemoized_mime_type(*args).freeze
+ #{memoized_ivar}[args] = #{original_method}(*args) # @_memoized_mime_type[args] = _unmemoized_mime_type(*args)
end # end
else # else
#{original_method}(*args) # _unmemoized_mime_type(*args)
diff --git a/activesupport/lib/active_support/mini.rb b/activesupport/lib/active_support/mini.rb
new file mode 100644
index 0000000000..fe7ba48e58
--- /dev/null
+++ b/activesupport/lib/active_support/mini.rb
@@ -0,0 +1,9 @@
+$LOAD_PATH.unshift File.dirname(__FILE__)
+
+require "core_ext/blank"
+# whole object.rb pulls up rarely used introspection extensions
+require "core_ext/object/metaclass"
+require 'core_ext/array'
+require 'core_ext/hash'
+require 'core_ext/module/attribute_accessors'
+require 'core_ext/string/inflections' \ No newline at end of file
diff --git a/activesupport/lib/active_support/multibyte/unicode_database.rb b/activesupport/lib/active_support/multibyte/unicode_database.rb
index a08f38cdbb..074ad8613a 100644
--- a/activesupport/lib/active_support/multibyte/unicode_database.rb
+++ b/activesupport/lib/active_support/multibyte/unicode_database.rb
@@ -23,11 +23,11 @@ module ActiveSupport #:nodoc:
# Lazy load the Unicode database so it's only loaded when it's actually used
ATTRIBUTES.each do |attr_name|
- class_eval(<<-EOS, __FILE__, __LINE__)
- def #{attr_name} # def codepoints
- load # load
- @#{attr_name} # @codepoints
- end # end
+ class_eval(<<-EOS, __FILE__, __LINE__ + 1)
+ def #{attr_name} # def codepoints
+ load # load
+ @#{attr_name} # @codepoints
+ end # end
EOS
end
diff --git a/activesupport/lib/active_support/new_callbacks.rb b/activesupport/lib/active_support/new_callbacks.rb
new file mode 100644
index 0000000000..356d70b650
--- /dev/null
+++ b/activesupport/lib/active_support/new_callbacks.rb
@@ -0,0 +1,486 @@
+module ActiveSupport
+ # Callbacks are hooks into the lifecycle of an object that allow you to trigger logic
+ # before or after an alteration of the object state.
+ #
+ # Mixing in this module allows you to define callbacks in your class.
+ #
+ # Example:
+ # class Storage
+ # include ActiveSupport::Callbacks
+ #
+ # define_callbacks :save
+ # end
+ #
+ # class ConfigStorage < Storage
+ # save_callback :before, :saving_message
+ # def saving_message
+ # puts "saving..."
+ # end
+ #
+ # save_callback :after do |object|
+ # puts "saved"
+ # end
+ #
+ # def save
+ # _run_save_callbacks do
+ # puts "- save"
+ # end
+ # end
+ # end
+ #
+ # config = ConfigStorage.new
+ # config.save
+ #
+ # Output:
+ # saving...
+ # - save
+ # saved
+ #
+ # Callbacks from parent classes are inherited.
+ #
+ # Example:
+ # class Storage
+ # include ActiveSupport::Callbacks
+ #
+ # define_callbacks :save
+ #
+ # save_callback :before, :prepare
+ # def prepare
+ # puts "preparing save"
+ # end
+ # end
+ #
+ # class ConfigStorage < Storage
+ # save_callback :before, :saving_message
+ # def saving_message
+ # puts "saving..."
+ # end
+ #
+ # save_callback :after do |object|
+ # puts "saved"
+ # end
+ #
+ # def save
+ # _run_save_callbacks do
+ # puts "- save"
+ # end
+ # end
+ # end
+ #
+ # config = ConfigStorage.new
+ # config.save
+ #
+ # Output:
+ # preparing save
+ # saving...
+ # - save
+ # saved
+ module NewCallbacks
+ def self.included(klass)
+ klass.extend ClassMethods
+ end
+
+ def run_callbacks(kind, options = {}, &blk)
+ send("_run_#{kind}_callbacks", &blk)
+ end
+
+ class Callback
+ @@_callback_sequence = 0
+
+ attr_accessor :filter, :kind, :name, :options, :per_key, :klass
+ def initialize(filter, kind, options, klass, name)
+ @kind, @klass = kind, klass
+ @name = name
+
+ normalize_options!(options)
+
+ @per_key = options.delete(:per_key)
+ @raw_filter, @options = filter, options
+ @filter = _compile_filter(filter)
+ @compiled_options = _compile_options(options)
+ @callback_id = next_id
+
+ _compile_per_key_options
+ end
+
+ def clone(klass)
+ obj = super()
+ obj.klass = klass
+ obj.per_key = @per_key.dup
+ obj.options = @options.dup
+ obj.per_key[:if] = @per_key[:if].dup
+ obj.per_key[:unless] = @per_key[:unless].dup
+ obj.options[:if] = @options[:if].dup
+ obj.options[:unless] = @options[:unless].dup
+ obj
+ end
+
+ def normalize_options!(options)
+ options[:if] = Array.wrap(options[:if])
+ options[:unless] = Array.wrap(options[:unless])
+
+ options[:per_key] ||= {}
+ options[:per_key][:if] = Array.wrap(options[:per_key][:if])
+ options[:per_key][:unless] = Array.wrap(options[:per_key][:unless])
+ end
+
+ def next_id
+ @@_callback_sequence += 1
+ end
+
+ def matches?(_kind, _name, _filter)
+ @kind == _kind &&
+ @name == _name &&
+ @filter == _filter
+ end
+
+ def _update_filter(filter_options, new_options)
+ filter_options[:if].push(new_options[:unless]) if new_options.key?(:unless)
+ filter_options[:unless].push(new_options[:if]) if new_options.key?(:if)
+ end
+
+ def recompile!(_options, _per_key)
+ _update_filter(self.options, _options)
+ _update_filter(self.per_key, _per_key)
+
+ @callback_id = next_id
+ @filter = _compile_filter(@raw_filter)
+ @compiled_options = _compile_options(@options)
+ _compile_per_key_options
+ end
+
+ def _compile_per_key_options
+ key_options = _compile_options(@per_key)
+
+ @klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ def _one_time_conditions_valid_#{@callback_id}?
+ true #{key_options[0]}
+ end
+ RUBY_EVAL
+ end
+
+ # This will supply contents for before and around filters, and no
+ # contents for after filters (for the forward pass).
+ def start(key = nil, options = {})
+ object, terminator = (options || {}).values_at(:object, :terminator)
+
+ return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
+
+ terminator ||= false
+
+ # options[0] is the compiled form of supplied conditions
+ # options[1] is the "end" for the conditional
+
+ if @kind == :before || @kind == :around
+ if @kind == :before
+ # if condition # before_save :filter_name, :if => :condition
+ # filter_name
+ # end
+ filter = <<-RUBY_EVAL
+ unless halted
+ result = #{@filter}
+ halted ||= (#{terminator})
+ end
+ RUBY_EVAL
+ [@compiled_options[0], filter, @compiled_options[1]].compact.join("\n")
+ else
+ # Compile around filters with conditions into proxy methods
+ # that contain the conditions.
+ #
+ # For `around_save :filter_name, :if => :condition':
+ #
+ # def _conditional_callback_save_17
+ # if condition
+ # filter_name do
+ # yield self
+ # end
+ # else
+ # yield self
+ # end
+ # end
+
+ name = "_conditional_callback_#{@kind}_#{next_id}"
+ txt = <<-RUBY_EVAL
+ def #{name}(halted)
+ #{@compiled_options[0] || "if true"} && !halted
+ #{@filter} do
+ yield self
+ end
+ else
+ yield self
+ end
+ end
+ RUBY_EVAL
+ @klass.class_eval(txt)
+ "#{name}(halted) do"
+ end
+ end
+ end
+
+ # This will supply contents for around and after filters, but not
+ # before filters (for the backward pass).
+ def end(key = nil, options = {})
+ object = (options || {})[:object]
+
+ return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
+
+ if @kind == :around || @kind == :after
+ # if condition # after_save :filter_name, :if => :condition
+ # filter_name
+ # end
+ if @kind == :after
+ [@compiled_options[0], @filter, @compiled_options[1]].compact.join("\n")
+ else
+ "end"
+ end
+ end
+ end
+
+ private
+ # Options support the same options as filters themselves (and support
+ # symbols, string, procs, and objects), so compile a conditional
+ # expression based on the options
+ def _compile_options(options)
+ return [] if options[:if].empty? && options[:unless].empty?
+
+ conditions = []
+
+ unless options[:if].empty?
+ conditions << Array.wrap(_compile_filter(options[:if]))
+ end
+
+ unless options[:unless].empty?
+ conditions << Array.wrap(_compile_filter(options[:unless])).map {|f| "!#{f}"}
+ end
+
+ ["if #{conditions.flatten.join(" && ")}", "end"]
+ end
+
+ # Filters support:
+ # Arrays:: Used in conditions. This is used to specify
+ # multiple conditions. Used internally to
+ # merge conditions from skip_* filters
+ # Symbols:: A method to call
+ # Strings:: Some content to evaluate
+ # Procs:: A proc to call with the object
+ # Objects:: An object with a before_foo method on it to call
+ #
+ # All of these objects are compiled into methods and handled
+ # the same after this point:
+ # Arrays:: Merged together into a single filter
+ # Symbols:: Already methods
+ # Strings:: class_eval'ed into methods
+ # Procs:: define_method'ed into methods
+ # Objects::
+ # a method is created that calls the before_foo method
+ # on the object.
+ def _compile_filter(filter)
+ method_name = "_callback_#{@kind}_#{next_id}"
+ case filter
+ when Array
+ filter.map {|f| _compile_filter(f)}
+ when Symbol
+ filter
+ when Proc
+ @klass.send(:define_method, method_name, &filter)
+ method_name << (filter.arity == 1 ? "(self)" : "")
+ when String
+ @klass.class_eval <<-RUBY_EVAL
+ def #{method_name}
+ #{filter}
+ end
+ RUBY_EVAL
+ method_name
+ else
+ kind, name = @kind, @name
+ @klass.send(:define_method, method_name) do
+ filter.send("#{kind}_#{name}", self)
+ end
+ method_name
+ end
+ end
+ end
+
+ # This method_missing is supplied to catch callbacks with keys and create
+ # the appropriate callback for future use.
+ def method_missing(meth, *args, &blk)
+ if meth.to_s =~ /_run__([\w:]+)__(\w+)__(\w+)__callbacks/
+ return self.class._create_and_run_keyed_callback($1, $2.to_sym, $3.to_sym, self, &blk)
+ end
+ super
+ end
+
+ # An Array with a compile method
+ class CallbackChain < Array
+ def initialize(symbol)
+ @symbol = symbol
+ end
+
+ def compile(key = nil, options = {})
+ method = []
+ method << "halted = false"
+ each do |callback|
+ method << callback.start(key, options)
+ end
+ method << "yield self if block_given?"
+ reverse_each do |callback|
+ method << callback.end(key, options)
+ end
+ method.compact.join("\n")
+ end
+
+ def clone(klass)
+ chain = CallbackChain.new(@symbol)
+ chain.push(*map {|c| c.clone(klass)})
+ end
+ end
+
+ module ClassMethods
+ CHAINS = {:before => :before, :around => :before, :after => :after}
+
+ # Make the _run_save_callbacks method. The generated method takes
+ # a block that it'll yield to. It'll call the before and around filters
+ # in order, yield the block, and then run the after filters.
+ #
+ # _run_save_callbacks do
+ # save
+ # end
+ #
+ # The _run_save_callbacks method can optionally take a key, which
+ # will be used to compile an optimized callback method for each
+ # key. See #define_callbacks for more information.
+ def _define_runner(symbol, str, options)
+ str = <<-RUBY_EVAL
+ def _run_#{symbol}_callbacks(key = nil)
+ if key
+ name = "_run__\#{self.class.name.split("::").last}__#{symbol}__\#{key}__callbacks"
+
+ if respond_to?(name)
+ send(name) { yield if block_given? }
+ else
+ self.class._create_and_run_keyed_callback(
+ self.class.name.split("::").last,
+ :#{symbol}, key, self) { yield if block_given? }
+ end
+ else
+ #{str}
+ end
+ end
+ RUBY_EVAL
+
+ undef_method "_run_#{symbol}_callbacks" if method_defined?("_run_#{symbol}_callbacks")
+ class_eval str, __FILE__, __LINE__
+
+ before_name, around_name, after_name =
+ options.values_at(:before, :after, :around)
+ end
+
+ # This is called the first time a callback is called with a particular
+ # key. It creates a new callback method for the key, calculating
+ # which callbacks can be omitted because of per_key conditions.
+ def _create_and_run_keyed_callback(klass, kind, key, obj, &blk)
+ @_keyed_callbacks ||= {}
+ @_keyed_callbacks[[kind, key]] ||= begin
+ str = self.send("_#{kind}_callbacks").compile(key, :object => obj, :terminator => self.send("_#{kind}_terminator"))
+
+ self.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ def _run__#{klass.split("::").last}__#{kind}__#{key}__callbacks
+ #{str}
+ end
+ RUBY_EVAL
+
+ true
+ end
+
+ obj.send("_run__#{klass.split("::").last}__#{kind}__#{key}__callbacks", &blk)
+ end
+
+ # Define callbacks.
+ #
+ # Creates a <name>_callback method that you can use to add callbacks.
+ #
+ # Syntax:
+ # save_callback :before, :before_meth
+ # save_callback :after, :after_meth, :if => :condition
+ # save_callback :around {|r| stuff; yield; stuff }
+ #
+ # The <name>_callback method also updates the _run_<name>_callbacks
+ # method, which is the public API to run the callbacks.
+ #
+ # Also creates a skip_<name>_callback method that you can use to skip
+ # callbacks.
+ #
+ # When creating or skipping callbacks, you can specify conditions that
+ # are always the same for a given key. For instance, in ActionPack,
+ # we convert :only and :except conditions into per-key conditions.
+ #
+ # before_filter :authenticate, :except => "index"
+ # becomes
+ # dispatch_callback :before, :authenticate, :per_key => {:unless => proc {|c| c.action_name == "index"}}
+ #
+ # Per-Key conditions are evaluated only once per use of a given key.
+ # In the case of the above example, you would do:
+ #
+ # run_dispatch_callbacks(action_name) { ... dispatch stuff ... }
+ #
+ # In that case, each action_name would get its own compiled callback
+ # method that took into consideration the per_key conditions. This
+ # is a speed improvement for ActionPack.
+ def define_callbacks(*symbols)
+ terminator = symbols.pop if symbols.last.is_a?(String)
+ symbols.each do |symbol|
+ self.extlib_inheritable_accessor("_#{symbol}_terminator")
+ self.send("_#{symbol}_terminator=", terminator)
+ self.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
+ extlib_inheritable_accessor :_#{symbol}_callbacks
+ self._#{symbol}_callbacks = CallbackChain.new(:#{symbol})
+
+ def self.#{symbol}_callback(*filters, &blk)
+ type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
+ options = filters.last.is_a?(Hash) ? filters.pop : {}
+ filters.unshift(blk) if block_given?
+
+ filters.map! do |filter|
+ # overrides parent class
+ self._#{symbol}_callbacks.delete_if {|c| c.matches?(type, :#{symbol}, filter)}
+ Callback.new(filter, type, options.dup, self, :#{symbol})
+ end
+ self._#{symbol}_callbacks.push(*filters)
+ _define_runner(:#{symbol},
+ self._#{symbol}_callbacks.compile(nil, :terminator => _#{symbol}_terminator),
+ options)
+ end
+
+ def self.skip_#{symbol}_callback(*filters, &blk)
+ type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
+ options = filters.last.is_a?(Hash) ? filters.pop : {}
+ filters.unshift(blk) if block_given?
+ filters.each do |filter|
+ self._#{symbol}_callbacks = self._#{symbol}_callbacks.clone(self)
+
+ filter = self._#{symbol}_callbacks.find {|c| c.matches?(type, :#{symbol}, filter) }
+ per_key = options[:per_key] || {}
+ if filter
+ filter.recompile!(options, per_key)
+ else
+ self._#{symbol}_callbacks.delete(filter)
+ end
+ _define_runner(:#{symbol},
+ self._#{symbol}_callbacks.compile(nil, :terminator => _#{symbol}_terminator),
+ options)
+ end
+
+ end
+
+ def self.reset_#{symbol}_callbacks
+ self._#{symbol}_callbacks = CallbackChain.new(:#{symbol})
+ _define_runner(:#{symbol}, self._#{symbol}_callbacks.compile, {})
+ end
+
+ self.#{symbol}_callback(:before)
+ RUBY_EVAL
+ end
+ end
+ end
+ end
+end
diff --git a/activesupport/lib/active_support/test_case.rb b/activesupport/lib/active_support/test_case.rb
index f05d4098fc..50e25ef740 100644
--- a/activesupport/lib/active_support/test_case.rb
+++ b/activesupport/lib/active_support/test_case.rb
@@ -12,6 +12,7 @@ require 'active_support/testing/setup_and_teardown'
require 'active_support/testing/assertions'
require 'active_support/testing/deprecation'
require 'active_support/testing/declarative'
+require 'active_support/testing/pending'
module ActiveSupport
class TestCase < ::Test::Unit::TestCase
@@ -34,6 +35,7 @@ module ActiveSupport
include ActiveSupport::Testing::SetupAndTeardown
include ActiveSupport::Testing::Assertions
include ActiveSupport::Testing::Deprecation
+ include ActiveSupport::Testing::Pending
extend ActiveSupport::Testing::Declarative
end
end
diff --git a/activesupport/lib/active_support/testing/declarative.rb b/activesupport/lib/active_support/testing/declarative.rb
index cb6a5844eb..a7af7f4224 100644
--- a/activesupport/lib/active_support/testing/declarative.rb
+++ b/activesupport/lib/active_support/testing/declarative.rb
@@ -1,18 +1,43 @@
module ActiveSupport
module Testing
module Declarative
- # test "verify something" do
- # ...
- # end
- def test(name, &block)
- test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
- defined = instance_method(test_name) rescue false
- 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}"
+
+ def self.extended(klass)
+ klass.class_eval do
+
+ unless method_defined?(:describe)
+ def self.describe(text)
+ class_eval <<-RUBY_EVAL
+ def self.name
+ "#{text}"
+ end
+ RUBY_EVAL
+ end
+ end
+
+ if defined?(Spec)
+ class << self
+ alias_method :test, :it
+ end
+ end
+
+ end
+ end
+
+ unless defined?(Spec)
+ # test "verify something" do
+ # ...
+ # end
+ def test(name, &block)
+ test_name = "test_#{name.gsub(/\s+/,'_')}".to_sym
+ defined = instance_method(test_name) rescue false
+ 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
diff --git a/activesupport/lib/active_support/testing/pending.rb b/activesupport/lib/active_support/testing/pending.rb
new file mode 100644
index 0000000000..d945c7e476
--- /dev/null
+++ b/activesupport/lib/active_support/testing/pending.rb
@@ -0,0 +1,43 @@
+# Some code from jeremymcanally's "pending"
+# http://github.com/jeremymcanally/pending/tree/master
+
+module ActiveSupport
+ module Testing
+ module Pending
+
+ unless defined?(Spec)
+
+ @@pending_cases = []
+ @@at_exit = false
+
+ def pending(description = "", &block)
+ if block_given?
+ failed = false
+
+ begin
+ block.call
+ rescue Exception
+ failed = true
+ end
+
+ flunk("<#{description}> did not fail.") unless failed
+ end
+
+ caller[0] =~ (/(.*):(.*):in `(.*)'/)
+ @@pending_cases << "#{$3} at #{$1}, line #{$2}"
+ print "P"
+
+ @@at_exit ||= begin
+ at_exit do
+ puts "\nPending Cases:"
+ @@pending_cases.each do |test_case|
+ puts test_case
+ end
+ end
+ end
+ end
+ end
+
+ end
+ end
+end \ No newline at end of file
diff --git a/activesupport/lib/active_support/testing/setup_and_teardown.rb b/activesupport/lib/active_support/testing/setup_and_teardown.rb
index aaf9f8f42c..4537c30e9c 100644
--- a/activesupport/lib/active_support/testing/setup_and_teardown.rb
+++ b/activesupport/lib/active_support/testing/setup_and_teardown.rb
@@ -10,6 +10,8 @@ module ActiveSupport
if defined?(MiniTest::Assertions) && TestCase < MiniTest::Assertions
include ForMiniTest
+ elsif defined? Spec
+ include ForRspec
else
include ForClassicTestUnit
end
@@ -34,7 +36,7 @@ module ActiveSupport
result
end
end
-
+
module ForClassicTestUnit
# For compatibility with Ruby < 1.8.6
PASSTHROUGH_EXCEPTIONS = Test::Unit::TestCase::PASSTHROUGH_EXCEPTIONS rescue [NoMemoryError, SignalException, Interrupt, SystemExit]
diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb
index 9dcf75ff96..69abb80721 100644
--- a/activesupport/lib/active_support/time_with_zone.rb
+++ b/activesupport/lib/active_support/time_with_zone.rb
@@ -36,6 +36,11 @@ module ActiveSupport
# t.is_a?(Time) # => true
# t.is_a?(ActiveSupport::TimeWithZone) # => true
class TimeWithZone
+
+ def self.name
+ 'Time' # Report class name as 'Time' to thwart type checking
+ end
+
include Comparable
attr_reader :time_zone
@@ -244,10 +249,10 @@ module ActiveSupport
end
%w(year mon month day mday wday yday hour min sec to_date).each do |method_name|
- class_eval <<-EOV
- def #{method_name} # def year
- time.#{method_name} # time.year
- end # end
+ class_eval <<-EOV, __FILE__, __LINE__ + 1
+ def #{method_name} # def month
+ time.#{method_name} # time.month
+ end # end
EOV
end