aboutsummaryrefslogtreecommitdiffstats
path: root/activesupport/lib
diff options
context:
space:
mode:
authorPratik Naik <pratiknaik@gmail.com>2009-09-30 22:27:02 +0100
committerPratik Naik <pratiknaik@gmail.com>2009-09-30 22:27:02 +0100
commitdd2779e1b83b4d867d47dd286ec0c919f5df12a9 (patch)
tree6e52ea0a329c24429f4d1d41b065e082f0ed6baa /activesupport/lib
parent329b14aa8fdd291a00d17ba12c2e0ab4c3a157cc (diff)
parent420004e030e96f2ace6e27fd622c90ee9e986677 (diff)
downloadrails-dd2779e1b83b4d867d47dd286ec0c919f5df12a9.tar.gz
rails-dd2779e1b83b4d867d47dd286ec0c919f5df12a9.tar.bz2
rails-dd2779e1b83b4d867d47dd286ec0c919f5df12a9.zip
Merge commit 'mainstream/master'
Diffstat (limited to 'activesupport/lib')
-rw-r--r--activesupport/lib/active_support.rb2
-rw-r--r--activesupport/lib/active_support/cache/mem_cache_store.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/array/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/hash/conversions.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/string/xchar.rb2
-rw-r--r--activesupport/lib/active_support/memoizable.rb4
-rw-r--r--activesupport/lib/active_support/message_verifier.rb4
-rw-r--r--activesupport/lib/active_support/new_callbacks.rb155
-rw-r--r--activesupport/lib/active_support/testing/isolation.rb13
-rw-r--r--activesupport/lib/active_support/values/time_zone.rb2
-rw-r--r--activesupport/lib/active_support/vendor.rb33
-rw-r--r--activesupport/lib/active_support/vendor/builder.rb6
-rw-r--r--activesupport/lib/active_support/vendor/i18n.rb6
-rw-r--r--activesupport/lib/active_support/vendor/memcache.rb6
-rw-r--r--activesupport/lib/active_support/vendor/tzinfo.rb6
15 files changed, 142 insertions, 103 deletions
diff --git a/activesupport/lib/active_support.rb b/activesupport/lib/active_support.rb
index 3372fb853a..0478ae4ebc 100644
--- a/activesupport/lib/active_support.rb
+++ b/activesupport/lib/active_support.rb
@@ -37,5 +37,5 @@ end
require 'active_support/autoload'
require 'active_support/vendor'
-require 'active_support/vendor/i18n'
+require 'i18n'
I18n.load_path << "#{File.dirname(__FILE__)}/active_support/locale/en.yml"
diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb
index ea38baa9ad..516af99ce9 100644
--- a/activesupport/lib/active_support/cache/mem_cache_store.rb
+++ b/activesupport/lib/active_support/cache/mem_cache_store.rb
@@ -1,4 +1,4 @@
-require 'active_support/vendor/memcache'
+require 'memcache'
module ActiveSupport
module Cache
diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb
index 0743ab181e..c53cf3f530 100644
--- a/activesupport/lib/active_support/core_ext/array/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/array/conversions.rb
@@ -157,7 +157,7 @@ class Array
#
def to_xml(options = {})
raise "Not all elements respond to to_xml" unless all? { |e| e.respond_to? :to_xml }
- require 'active_support/vendor/builder' unless defined?(Builder)
+ require 'builder' unless defined?(Builder)
options = options.dup
options[:root] ||= all? { |e| e.is_a?(first.class) && first.class.to_s != "Hash" } ? ActiveSupport::Inflector.pluralize(ActiveSupport::Inflector.underscore(first.class.name)) : "records"
diff --git a/activesupport/lib/active_support/core_ext/hash/conversions.rb b/activesupport/lib/active_support/core_ext/hash/conversions.rb
index ffe9e3d1b1..aa686ec2eb 100644
--- a/activesupport/lib/active_support/core_ext/hash/conversions.rb
+++ b/activesupport/lib/active_support/core_ext/hash/conversions.rb
@@ -132,7 +132,7 @@ class Hash
# configure your own builder with the <tt>:builder</tt> option. The method also accepts
# options like <tt>:dasherize</tt> and friends, they are forwarded to the builder.
def to_xml(options = {})
- require 'active_support/vendor/builder' unless defined?(Builder)
+ require 'builder' unless defined?(Builder)
options = options.dup
options[:indent] ||= 2
diff --git a/activesupport/lib/active_support/core_ext/string/xchar.rb b/activesupport/lib/active_support/core_ext/string/xchar.rb
index 26857c8b0d..7183218634 100644
--- a/activesupport/lib/active_support/core_ext/string/xchar.rb
+++ b/activesupport/lib/active_support/core_ext/string/xchar.rb
@@ -6,7 +6,7 @@ rescue LoadError
# fast_xs extension unavailable
else
begin
- require 'active_support/vendor/builder'
+ require 'builder'
rescue LoadError
# builder demands the first shot at defining String#to_xs
end
diff --git a/activesupport/lib/active_support/memoizable.rb b/activesupport/lib/active_support/memoizable.rb
index 7724b9d88b..b197fbc9bf 100644
--- a/activesupport/lib/active_support/memoizable.rb
+++ b/activesupport/lib/active_support/memoizable.rb
@@ -57,10 +57,10 @@ module ActiveSupport
end
end
- def flush_cache(*syms, &block)
+ def flush_cache(*syms)
syms.each do |sym|
(methods + private_methods + protected_methods).each do |m|
- if m.to_s =~ /^_unmemoized_(#{sym})/
+ if m.to_s =~ /^_unmemoized_(#{sym.to_s.gsub(/\?\Z/, '\?')})/
ivar = ActiveSupport::Memoizable.memoized_ivar_for($1)
instance_variable_get(ivar).clear if instance_variable_defined?(ivar)
end
diff --git a/activesupport/lib/active_support/message_verifier.rb b/activesupport/lib/active_support/message_verifier.rb
index 0474b476df..74e080a23d 100644
--- a/activesupport/lib/active_support/message_verifier.rb
+++ b/activesupport/lib/active_support/message_verifier.rb
@@ -1,3 +1,5 @@
+require 'active_support/core_ext/string/bytesize'
+
module ActiveSupport
# MessageVerifier makes it easy to generate and verify messages which are signed
# to prevent tampering.
@@ -51,7 +53,7 @@ module ActiveSupport
def generate_digest(data)
require 'openssl' unless defined?(OpenSSL)
- OpenSSL::HMAC.hexdigest(OpenSSL::Digest::Digest.new(@digest), @secret, data)
+ OpenSSL::HMAC.hexdigest(OpenSSL::Digest.const_get(@digest).new, @secret, data)
end
end
end
diff --git a/activesupport/lib/active_support/new_callbacks.rb b/activesupport/lib/active_support/new_callbacks.rb
index c56b9ad1ac..2f0853d84a 100644
--- a/activesupport/lib/active_support/new_callbacks.rb
+++ b/activesupport/lib/active_support/new_callbacks.rb
@@ -92,10 +92,10 @@ module ActiveSupport
class Callback
@@_callback_sequence = 0
- attr_accessor :name, :filter, :kind, :options, :per_key, :klass
+ attr_accessor :chain, :filter, :kind, :options, :per_key, :klass
- def initialize(name, filter, kind, options, klass)
- @name, @kind, @klass = name, kind, klass
+ def initialize(chain, filter, kind, options, klass)
+ @chain, @kind, @klass = chain, kind, klass
normalize_options!(options)
@per_key = options.delete(:per_key)
@@ -107,9 +107,9 @@ module ActiveSupport
_compile_per_key_options
end
- def clone(klass)
+ def clone(chain, klass)
obj = super()
- obj.name = name
+ obj.chain = chain
obj.klass = klass
obj.per_key = @per_key.dup
obj.options = @options.dup
@@ -117,7 +117,6 @@ module ActiveSupport
obj.per_key[:unless] = @per_key[:unless].dup
obj.options[:if] = @options[:if].dup
obj.options[:unless] = @options[:unless].dup
- obj.options[:scope] = @options[:scope].dup
obj
end
@@ -125,14 +124,15 @@ module ActiveSupport
options[:if] = Array.wrap(options[:if])
options[:unless] = Array.wrap(options[:unless])
- options[:scope] ||= [:kind]
- options[:scope] = Array.wrap(options[:scope])
-
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 name
+ chain.name
+ end
+
def next_id
@@_callback_sequence += 1
end
@@ -168,15 +168,12 @@ module ActiveSupport
# 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)
+ def start(key=nil, object=nil)
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
@@ -185,7 +182,7 @@ module ActiveSupport
filter = <<-RUBY_EVAL
unless halted
result = #{@filter}
- halted = (#{terminator})
+ halted = (#{chain.config[:terminator]})
end
RUBY_EVAL
@@ -226,8 +223,7 @@ module ActiveSupport
# 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]
+ def end(key=nil, object=nil)
return if key && !object.send("_one_time_conditions_valid_#{@callback_id}?")
if @kind == :around || @kind == :after
@@ -302,7 +298,8 @@ module ActiveSupport
@klass.send(:define_method, "#{method_name}_object") { filter }
_normalize_legacy_filter(kind, filter)
- method_to_call = @options[:scope].map{ |s| s.is_a?(Symbol) ? send(s) : s }.join("_")
+ scopes = Array.wrap(chain.config[:scope])
+ method_to_call = scopes.map{ |s| s.is_a?(Symbol) ? send(s) : s }.join("_")
@klass.class_eval <<-RUBY_EVAL, __FILE__, __LINE__ + 1
def #{method_name}(&blk)
@@ -331,37 +328,52 @@ module ActiveSupport
# An Array with a compile method
class CallbackChain < Array
- attr_reader :symbol, :config
-
- def initialize(symbol, config)
- @symbol = symbol
- @config = config
+ attr_reader :name, :config
+
+ def initialize(name, config)
+ @name = name
+ @config = {
+ :terminator => "false",
+ :rescuable => false,
+ :scope => [ :kind ]
+ }.merge(config)
end
- def compile(key=nil, options={})
- options = config.merge(options)
-
+ def compile(key=nil, object=nil)
method = []
method << "value = nil"
method << "halted = false"
each do |callback|
- method << callback.start(key, options)
+ method << callback.start(key, object)
+ end
+
+ if config[:rescuable]
+ method << "rescued_error = nil"
+ method << "begin"
end
method << "value = yield if block_given? && !halted"
+ if config[:rescuable]
+ method << "rescue Exception => e"
+ method << "rescued_error = e"
+ method << "end"
+ end
+
reverse_each do |callback|
- method << callback.end(key, options)
+ method << callback.end(key, object)
end
+ method << "raise rescued_error if rescued_error" if config[:rescuable]
method << "halted ? false : (block_given? ? value : true)"
method.compact.join("\n")
end
def clone(klass)
- chain = CallbackChain.new(@symbol, @config.dup)
- chain.push(*map {|c| c.clone(klass)})
+ chain = CallbackChain.new(@name, @config.dup)
+ callbacks = map { |c| c.clone(chain, klass) }
+ chain.push(*callbacks)
end
end
@@ -407,32 +419,35 @@ module ActiveSupport
# key. It creates a new callback method for the key, calculating
# which callbacks can be omitted because of per_key conditions.
#
- def __create_keyed_callback(name, kind, obj, &blk) #:nodoc:
+ def __create_keyed_callback(name, kind, object, &blk) #:nodoc:
@_keyed_callbacks ||= {}
@_keyed_callbacks[name] ||= begin
- str = send("_#{kind}_callbacks").compile(name, :object => obj)
+ str = send("_#{kind}_callbacks").compile(name, object)
class_eval "def #{name}() #{str} end", __FILE__, __LINE__
true
end
end
- def __update_callbacks(name, filters = CallbackChain.new(name, {}), block = nil)
+ # This is used internally to append, prepend and skip callbacks to the
+ # CallbackChain.
+ #
+ def __update_callbacks(name, filters = [], block = nil) #:nodoc:
type = [:before, :after, :around].include?(filters.first) ? filters.shift : :before
options = filters.last.is_a?(Hash) ? filters.pop : {}
filters.unshift(block) if block
- callbacks = send("_#{name}_callbacks")
- yield callbacks, type, filters, options if block_given?
+ chain = send("_#{name}_callbacks")
+ yield chain, type, filters, options if block_given?
__define_runner(name)
end
- # Define callbacks.
+ # Set callbacks for a previously defined callback.
#
# Syntax:
# set_callback :save, :before, :before_meth
# set_callback :save, :after, :after_meth, :if => :condition
- # set_callback :save, :around {|r| stuff; yield; stuff }
+ # set_callback :save, :around, lambda { |r| stuff; yield; stuff }
#
# It also updates the _run_<name>_callbacks method, which is the public
# API to run the callbacks. Use skip_callback to skip any defined one.
@@ -448,43 +463,91 @@ module ActiveSupport
# 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 ... }
+ # _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 set_callback(name, *filters, &block)
- __update_callbacks(name, filters, block) do |callbacks, type, filters, options|
+ __update_callbacks(name, filters, block) do |chain, type, filters, options|
filters.map! do |filter|
- callbacks.delete_if {|c| c.matches?(type, filter) }
- Callback.new(name, filter, type, options.merge(callbacks.config), self)
+ chain.delete_if {|c| c.matches?(type, filter) }
+ Callback.new(chain, filter, type, options.dup, self)
end
- options[:prepend] ? callbacks.unshift(*filters) : callbacks.push(*filters)
+ options[:prepend] ? chain.unshift(*filters) : chain.push(*filters)
end
end
+ # Skip a previously defined callback for a given type.
+ #
def skip_callback(name, *filters, &block)
- __update_callbacks(name, filters, block) do |callbacks, type, filters, options|
+ __update_callbacks(name, filters, block) do |chain, type, filters, options|
+ chain = send("_#{name}_callbacks=", chain.clone(self))
+
filters.each do |filter|
- callbacks = send("_#{name}_callbacks=", callbacks.clone(self))
- filter = callbacks.find {|c| c.matches?(type, filter) }
+ filter = chain.find {|c| c.matches?(type, filter) }
if filter && options.any?
filter.recompile!(options, options[:per_key] || {})
else
- callbacks.delete(filter)
+ chain.delete(filter)
end
end
end
end
+ # Reset callbacks for a given type.
+ #
def reset_callbacks(symbol)
send("_#{symbol}_callbacks").clear
__define_runner(symbol)
end
+ # Define callbacks types.
+ #
+ # ==== Example
+ #
+ # define_callbacks :validate
+ #
+ # ==== Options
+ #
+ # * <tt>:terminator</tt> - Indicates when a before filter is considered
+ # to be halted.
+ #
+ # define_callbacks :validate, :terminator => "result == false"
+ #
+ # In the example above, if any before validate callbacks returns false,
+ # other callbacks are not executed. Defaults to "false".
+ #
+ # * <tt>:rescuable</tt> - By default, after filters are not executed if
+ # the given block or an before_filter raises an error. Supply :rescuable => true
+ # to change this behavior.
+ #
+ # * <tt>:scope</tt> - Show which methods should be executed when a class
+ # is giben as callback:
+ #
+ # define_callbacks :filters, :scope => [ :kind ]
+ #
+ # When a class is given:
+ #
+ # before_filter MyFilter
+ #
+ # It will call the type of the filter in the given class, which in this
+ # case, is "before".
+ #
+ # If, for instance, you supply the given scope:
+ #
+ # define_callbacks :validate, :scope => [ :kind, :name ]
+ #
+ # It will call "#{kind}_#{name}" in the given class. So "before_validate"
+ # will be called in the class below:
+ #
+ # before_validate MyValidation
+ #
+ # Defaults to :kind.
+ #
def define_callbacks(*symbols)
config = symbols.last.is_a?(Hash) ? symbols.pop : {}
symbols.each do |symbol|
diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb
index 30e194536b..cdd6d5f49b 100644
--- a/activesupport/lib/active_support/testing/isolation.rb
+++ b/activesupport/lib/active_support/testing/isolation.rb
@@ -31,10 +31,15 @@ module ActiveSupport
@_result = result
- proxy = run_in_isolation do |proxy|
- super(proxy) { }
+ serialized = run_in_isolation do |proxy|
+ begin
+ super(proxy) { }
+ rescue Exception => e
+ proxy.add_error(Test::Unit::Error.new(name, e))
+ end
end
+ proxy = Marshal.load(serialized)
proxy.__replay__(@_result)
yield(Test::Unit::TestCase::FINISHED, name)
@@ -55,7 +60,7 @@ module ActiveSupport
write.close
result = read.read
Process.wait2(pid)
- Marshal.load(result.unpack("m")[0])
+ return result.unpack("m")[0]
end
end
@@ -83,7 +88,7 @@ module ActiveSupport
ENV.delete("ISOLATION_TEST")
ENV.delete("ISOLATION_OUTPUT")
- return Marshal.load(tmpfile.read.unpack("m")[0])
+ return tmpfile.read.unpack("m")[0]
end
end
end
diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb
index 4eb268ac7d..564528bfe2 100644
--- a/activesupport/lib/active_support/values/time_zone.rb
+++ b/activesupport/lib/active_support/values/time_zone.rb
@@ -306,7 +306,7 @@ module ActiveSupport
# TODO: Preload instead of lazy load for thread safety
def tzinfo
- require 'active_support/vendor/tzinfo' unless defined?(TZInfo)
+ require 'tzinfo' unless defined?(TZInfo)
@tzinfo ||= TZInfo::Timezone.get(MAPPING[name])
end
diff --git a/activesupport/lib/active_support/vendor.rb b/activesupport/lib/active_support/vendor.rb
index 10dbfd9a77..9f464c8246 100644
--- a/activesupport/lib/active_support/vendor.rb
+++ b/activesupport/lib/active_support/vendor.rb
@@ -1,23 +1,16 @@
-# Fakes out gem optional dependencies until they are fully supported by gemspec.
-# Activate any optional dependencies that are available.
-if defined? Gem
- begin
- gem 'builder', '~> 2.1.2'
- rescue Gem::LoadError
- end
-
- begin
- gem 'memcache-client', '>= 1.6.5'
- rescue Gem::LoadError
- end
-
- begin
- gem 'tzinfo', '~> 0.3.13'
- rescue Gem::LoadError
- end
+def ActiveSupport.requirable?(file)
+ $LOAD_PATH.any? { |p| Dir.glob("#{p}/#{file}.*").any? }
+end
- begin
- gem 'i18n', '~> 0.1.3'
- rescue Gem::LoadError
+[%w(builder 2.1.2), %w(i18n 0.1.3), %w(memcache-client 1.7.5), %w(tzinfo 0.3.13)].each do |lib, version|
+ # If the lib is not already requirable
+ unless ActiveSupport.requirable? lib
+ # Try to activate a gem ~> satisfying the requested version first.
+ begin
+ gem lib, "~> #{version}"
+ # Use the vendored lib if the gem's missing or we aren't using RubyGems.
+ rescue LoadError, NoMethodError
+ $LOAD_PATH.unshift File.expand_path("#{File.dirname(__FILE__)}/vendor/#{lib}-#{version}/lib")
+ end
end
end
diff --git a/activesupport/lib/active_support/vendor/builder.rb b/activesupport/lib/active_support/vendor/builder.rb
deleted file mode 100644
index ad89e6635d..0000000000
--- a/activesupport/lib/active_support/vendor/builder.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-begin
- require 'builder'
-rescue LoadError
- $:.unshift File.expand_path(File.join(File.dirname(__FILE__), 'builder-2.1.2', 'lib'))
- retry
-end
diff --git a/activesupport/lib/active_support/vendor/i18n.rb b/activesupport/lib/active_support/vendor/i18n.rb
deleted file mode 100644
index 6011253035..0000000000
--- a/activesupport/lib/active_support/vendor/i18n.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-begin
- require 'i18n'
-rescue LoadError
- $:.unshift File.expand_path(File.join(File.dirname(__FILE__), 'i18n-0.1.3', 'lib'))
- retry
-end
diff --git a/activesupport/lib/active_support/vendor/memcache.rb b/activesupport/lib/active_support/vendor/memcache.rb
deleted file mode 100644
index 442f50a817..0000000000
--- a/activesupport/lib/active_support/vendor/memcache.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-begin
- require 'memcache'
-rescue LoadError
- $:.unshift File.expand_path(File.join(File.dirname(__FILE__), 'memcache-client-1.7.5', 'lib'))
- retry
-end
diff --git a/activesupport/lib/active_support/vendor/tzinfo.rb b/activesupport/lib/active_support/vendor/tzinfo.rb
deleted file mode 100644
index 01fba6d632..0000000000
--- a/activesupport/lib/active_support/vendor/tzinfo.rb
+++ /dev/null
@@ -1,6 +0,0 @@
-begin
- require 'tzinfo'
-rescue LoadError
- $:.unshift File.expand_path(File.join(File.dirname(__FILE__), 'tzinfo-0.3.13', 'lib'))
- retry
-end