diff options
author | Pratik Naik <pratiknaik@gmail.com> | 2009-09-30 22:27:02 +0100 |
---|---|---|
committer | Pratik Naik <pratiknaik@gmail.com> | 2009-09-30 22:27:02 +0100 |
commit | dd2779e1b83b4d867d47dd286ec0c919f5df12a9 (patch) | |
tree | 6e52ea0a329c24429f4d1d41b065e082f0ed6baa /activesupport/lib/active_support | |
parent | 329b14aa8fdd291a00d17ba12c2e0ab4c3a157cc (diff) | |
parent | 420004e030e96f2ace6e27fd622c90ee9e986677 (diff) | |
download | rails-dd2779e1b83b4d867d47dd286ec0c919f5df12a9.tar.gz rails-dd2779e1b83b4d867d47dd286ec0c919f5df12a9.tar.bz2 rails-dd2779e1b83b4d867d47dd286ec0c919f5df12a9.zip |
Merge commit 'mainstream/master'
Diffstat (limited to 'activesupport/lib/active_support')
14 files changed, 141 insertions, 102 deletions
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 |