diff options
Diffstat (limited to 'activesupport')
29 files changed, 482 insertions, 306 deletions
diff --git a/activesupport/CHANGELOG b/activesupport/CHANGELOG index a911361d3b..3ee9ed925c 100644 --- a/activesupport/CHANGELOG +++ b/activesupport/CHANGELOG @@ -1,5 +1,7 @@ *SVN* +* Added Ruby 1.8 implementation of Process.daemon + * Duration #since and #ago with no argument (e.g., 5.days.ago) return TimeWithZone when config.time_zone is set. Introducing Time.current, which returns Time.zone.now if config.time_zone is set, otherwise just returns Time.now [Geoff Buesing] * Time#since behaves correctly when passed a Duration. Closes #11527 [kemiller] diff --git a/activesupport/lib/active_support/cache.rb b/activesupport/lib/active_support/cache.rb index 64394afec4..b3c9c23d9f 100644 --- a/activesupport/lib/active_support/cache.rb +++ b/activesupport/lib/active_support/cache.rb @@ -49,7 +49,7 @@ module ActiveSupport self end - # Pass :force => true to force a cache miss. + # Pass <tt>:force => true</tt> to force a cache miss. def fetch(key, options = {}) @logger_off = true if !options[:force] && value = read(key, options) @@ -87,8 +87,25 @@ module ActiveSupport def delete_matched(matcher, options = nil) log("delete matched", matcher.inspect, options) + end + + def increment(key, amount = 1) + log("incrementing", key, amount) + if num = read(key) + write(key, num + amount) + else + nil + end end + def decrement(key, amount = 1) + log("decrementing", key, amount) + if num = read(key) + write(key, num - amount) + else + nil + end + end private def log(operation, key, options) diff --git a/activesupport/lib/active_support/cache/file_store.rb b/activesupport/lib/active_support/cache/file_store.rb index 88f9ac19db..16a2509ce2 100644 --- a/activesupport/lib/active_support/cache/file_store.rb +++ b/activesupport/lib/active_support/cache/file_store.rb @@ -20,14 +20,14 @@ module ActiveSupport RAILS_DEFAULT_LOGGER.error "Couldn't create cache directory: #{name} (#{e.message})" if RAILS_DEFAULT_LOGGER end - def delete(name, options) + def delete(name, options = nil) super File.delete(real_file_path(name)) rescue SystemCallError => e # If there's no cache, then there's nothing to complain about end - def delete_matched(matcher, options) + def delete_matched(matcher, options = nil) super search_dir(@cache_path) do |f| if f =~ matcher diff --git a/activesupport/lib/active_support/cache/mem_cache_store.rb b/activesupport/lib/active_support/cache/mem_cache_store.rb index 9b787702b2..bfe7e2ccf3 100644 --- a/activesupport/lib/active_support/cache/mem_cache_store.rb +++ b/activesupport/lib/active_support/cache/mem_cache_store.rb @@ -29,12 +29,11 @@ module ActiveSupport nil end - # Set key = value if key isn't already set. Pass :force => true - # to unconditionally set key = value. Returns a boolean indicating - # whether the key was set. + # Set key = value. Pass :unless_exist => true if you don't + # want to update the cache if the key is already set. def write(key, value, options = nil) super - method = options && options[:force] ? :set : :add + method = options && options[:unless_exist] ? :add : :set response = @data.send(method, key, value, expires_in(options), raw?(options)) response == Response::STORED rescue MemCache::MemCacheError => e @@ -49,15 +48,37 @@ module ActiveSupport rescue MemCache::MemCacheError => e logger.error("MemCacheError (#{e}): #{e.message}") false + end + + def increment(key, amount = 1) + log("incrementing", key, amount) + + response = @data.incr(key, amount) + response == Response::NOT_FOUND ? nil : response + rescue MemCache::MemCacheError + nil end + def decrement(key, amount = 1) + log("decrement", key, amount) + + response = data.decr(key, amount) + response == Response::NOT_FOUND ? nil : response + rescue MemCache::MemCacheError + nil + end + def delete_matched(matcher, options = nil) super raise "Not supported by Memcache" - end - + end + def clear @data.flush_all + end + + def stats + @data.stats end private diff --git a/activesupport/lib/active_support/cache/memory_store.rb b/activesupport/lib/active_support/cache/memory_store.rb index e0aba6b19a..4872e025cd 100644 --- a/activesupport/lib/active_support/cache/memory_store.rb +++ b/activesupport/lib/active_support/cache/memory_store.rb @@ -24,6 +24,10 @@ module ActiveSupport super @data.delete_if { |k,v| k =~ matcher } end + + def clear + @data.clear + end end end end
\ No newline at end of file diff --git a/activesupport/lib/active_support/core_ext/array/conversions.rb b/activesupport/lib/active_support/core_ext/array/conversions.rb index 34b1551abc..a9882828ca 100644 --- a/activesupport/lib/active_support/core_ext/array/conversions.rb +++ b/activesupport/lib/active_support/core_ext/array/conversions.rb @@ -67,17 +67,35 @@ module ActiveSupport #:nodoc: end end - # Returns a string that represents this array in XML by sending - # <tt>to_xml</tt> to each element. + # Returns a string that represents this array in XML by sending +to_xml+ + # to each element. Active Record collections delegate their representation + # in XML to this method. # - # All elements are expected to respond to <tt>to_xml</tt>, if any of - # them does not an exception is raised. + # All elements are expected to respond to +to_xml+, if any of them does + # not an exception is raised. # # The root node reflects the class name of the first element in plural - # if all elements belong to the same type and that's not <tt>Hash</tt>. - # Otherwise the root element is "records". + # if all elements belong to the same type and that's not Hash: # - # Root children have as node name the one of the root singularized. + # customer.projects.to_xml + # + # <?xml version="1.0" encoding="UTF-8"?> + # <projects type="array"> + # <project> + # <amount type="decimal">20000.0</amount> + # <customer-id type="integer">1567</customer-id> + # <deal-date type="date">2008-04-09</deal-date> + # ... + # </project> + # <project> + # <amount type="decimal">57230.0</amount> + # <customer-id type="integer">1567</customer-id> + # <deal-date type="date">2008-04-15</deal-date> + # ... + # </project> + # </projects> + # + # Otherwise the root element is "records": # # [{:foo => 1, :bar => 2}, {:baz => 3}].to_xml # @@ -92,9 +110,26 @@ module ActiveSupport #:nodoc: # </record> # </records> # + # If the collection is empty the root element is "nil-classes" by default: + # + # [].to_xml + # + # <?xml version="1.0" encoding="UTF-8"?> + # <nil-classes type="array"/> + # + # To ensure a meaningful root element use the <tt>:root</tt> option: + # + # customer_with_no_projects.projects.to_xml(:root => "projects") + # + # <?xml version="1.0" encoding="UTF-8"?> + # <projects type="array"/> + # + # By default root children have as node name the one of the root + # singularized. You can change it with the <tt>:children</tt> option. + # # The +options+ hash is passed downwards: # - # [Message.find(:first)].to_xml(:skip_types => true) + # Message.all.to_xml(:skip_types => true) # # <?xml version="1.0" encoding="UTF-8"?> # <messages> 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 eee61d48c4..186ca69c05 100644 --- a/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/class/attribute_accessors.rb @@ -1,6 +1,12 @@ # Extends the class object with class and instance accessors for class attributes, # just like the native attr* accessors for instance attributes. -class Class # :nodoc: +# +# class Person +# cattr_accessor :hair_colors +# end +# +# Person.hair_colors = [:brown, :black, :blonde, :red] +class Class def cattr_reader(*syms) syms.flatten.each do |sym| next if sym.is_a?(Hash) diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb index bb561f675f..183471706b 100644 --- a/activesupport/lib/active_support/core_ext/date/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date/calculations.rb @@ -70,7 +70,7 @@ module ActiveSupport #:nodoc: end # Provides precise Date calculations for years, months, and days. The +options+ parameter takes a hash with - # any of these keys: :years, :months, :weeks, :days. + # any of these keys: <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>. def advance(options) d = self d = d >> options.delete(:years) * 12 if options[:years] diff --git a/activesupport/lib/active_support/core_ext/date_time/calculations.rb b/activesupport/lib/active_support/core_ext/date_time/calculations.rb index fa444f71b1..155c961a91 100644 --- a/activesupport/lib/active_support/core_ext/date_time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date_time/calculations.rb @@ -42,8 +42,10 @@ module ActiveSupport #:nodoc: ) end - # Uses Date to provide precise Time calculations for years, months, and days. The +options+ parameter takes a hash with - # any of these keys: :years, :months, :weeks, :days, :hours, :minutes, :seconds. + # Uses Date to provide precise Time calculations for years, months, and days. + # The +options+ parameter takes a hash with any of these keys: <tt>:years</tt>, + # <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>, + # <tt>:minutes</tt>, <tt>:seconds</tt>. def advance(options) d = to_date.advance(options) datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day) diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index 8f111e29fc..f1469aa0e3 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -8,7 +8,7 @@ module Enumerable # Example: # # latest_transcripts.group_by(&:day).each do |day, transcripts| - # p "#{day} -> #{transcripts.map(&:class) * ', '}" + # p "#{day} -> #{transcripts.map(&:class).join(', ')}" # end # "2006-03-01 -> Transcript" # "2006-02-28 -> Transcript" @@ -26,21 +26,22 @@ module Enumerable # Calculates a sum from the elements. Examples: # - # payments.sum { |p| p.price * p.tax_rate } - # payments.sum(&:price) + # payments.sum { |p| p.price * p.tax_rate } + # payments.sum(&:price) # - # This is instead of + # The latter is a shortcut for: # - # payments.inject { |sum, p| sum + p.price } + # payments.inject { |sum, p| sum + p.price } # - # Also calculates sums without the use of a block: + # It can also calculate the sum without the use of a block. # - # [5, 15, 10].sum # => 30 + # [5, 15, 10].sum # => 30 + # ["foo", "bar"].sum # => "foobar" + # [[1, 2], [3, 1, 5]].sum => [1, 2, 3, 1, 5] # - # The default identity (sum of an empty list) is zero. - # However, you can override this default: + # The default sum of an empty list is zero. You can override this default: # - # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0) + # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0) # def sum(identity = 0, &block) return identity unless size > 0 diff --git a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb index 0ec0538024..7af10846e7 100644 --- a/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb +++ b/activesupport/lib/active_support/core_ext/hash/reverse_merge.rb @@ -8,7 +8,7 @@ module ActiveSupport #:nodoc: # options.reverse_merge! :size => 25, :velocity => 10 # end # - # The default :size and :velocity is only set if the +options+ passed in doesn't already have those keys set. + # The default <tt>:size</tt> and <tt>:velocity</tt> is only set if the +options+ passed in doesn't already have those keys set. module ReverseMerge # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second. def reverse_merge(other_hash) diff --git a/activesupport/lib/active_support/core_ext/kernel/daemonizing.rb b/activesupport/lib/active_support/core_ext/kernel/daemonizing.rb index 0e78819fdf..ed9d1f9bf2 100644 --- a/activesupport/lib/active_support/core_ext/kernel/daemonizing.rb +++ b/activesupport/lib/active_support/core_ext/kernel/daemonizing.rb @@ -2,14 +2,6 @@ module Kernel # Turns the current script into a daemon process that detaches from the console. # It can be shut down with a TERM signal. def daemonize - exit if fork # Parent exits, child continues. - Process.setsid # Become session leader. - exit if fork # Zap session leader. See [1]. - Dir.chdir "/" # Release old working directory. - File.umask 0000 # Ensure sensible umask. Adjust as needed. - STDIN.reopen "/dev/null" # Free file descriptors and - STDOUT.reopen "/dev/null", "a" # point them somewhere sensible. - STDERR.reopen STDOUT # STDOUT/ERR should better go to a logfile. - trap("TERM") { exit } + Process.daemon end -end
\ No newline at end of file +end 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 58ff363244..51e1c9af90 100644 --- a/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb +++ b/activesupport/lib/active_support/core_ext/module/attribute_accessors.rb @@ -1,6 +1,16 @@ # Extends the module object with module and instance accessors for class attributes, # just like the native attr* accessors for instance attributes. -class Module # :nodoc: +# +# module AppConfiguration +# mattr_accessor :google_api_key +# self.google_api_key = "123456789" +# +# mattr_accessor :paypal_url +# self.paypal_url = "www.sandbox.paypal.com" +# end +# +# AppConfiguration.google_api_key = "overriding the api key!" +class Module def mattr_reader(*syms) syms.each do |sym| next if sym.is_a?(Hash) diff --git a/activesupport/lib/active_support/core_ext/module/delegation.rb b/activesupport/lib/active_support/core_ext/module/delegation.rb index f6647eaed3..e0b5f3e379 100644 --- a/activesupport/lib/active_support/core_ext/module/delegation.rb +++ b/activesupport/lib/active_support/core_ext/module/delegation.rb @@ -1,8 +1,8 @@ class Module # Provides a delegate class method to easily expose contained objects' methods # as your own. Pass one or more methods (specified as symbols or strings) - # and the name of the target object as the final :to option (also a symbol - # or string). At least one method and the :to option are required. + # and the name of the target object as the final <tt>:to</tt> option (also a symbol + # or string). At least one method and the <tt>:to</tt> option are required. # # Delegation is particularly useful with Active Record associations: # @@ -20,6 +20,7 @@ class Module # 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 @@ -28,7 +29,8 @@ class Module # Foo.new.goodbye # => "goodbye" # # Methods can be delegated to instance variables, class variables, or constants - # by providing the variable as a symbol: + # by providing them as a symbols: + # # class Foo # CONSTANT_ARRAY = [0,1,2,3] # @@class_array = [4,5,6,7] diff --git a/activesupport/lib/active_support/core_ext/process.rb b/activesupport/lib/active_support/core_ext/process.rb new file mode 100644 index 0000000000..0b0bc6dc69 --- /dev/null +++ b/activesupport/lib/active_support/core_ext/process.rb @@ -0,0 +1 @@ +require 'active_support/core_ext/process/daemon' diff --git a/activesupport/lib/active_support/core_ext/process/daemon.rb b/activesupport/lib/active_support/core_ext/process/daemon.rb new file mode 100644 index 0000000000..95ad5f8a5d --- /dev/null +++ b/activesupport/lib/active_support/core_ext/process/daemon.rb @@ -0,0 +1,25 @@ +if RUBY_VERSION < "1.9" + module Process + def self.daemon(nochdir = nil, noclose = nil) + exit if fork # Parent exits, child continues. + Process.setsid # Become session leader. + exit if fork # Zap session leader. See [1]. + + unless nochdir + Dir.chdir "/" # Release old working directory. + end + + File.umask 0000 # Ensure sensible umask. Adjust as needed. + + unless noclose + STDIN.reopen "/dev/null" # Free file descriptors and + STDOUT.reopen "/dev/null", "a" # point them somewhere sensible. + STDERR.reopen '/dev/null', 'a' + end + + trap("TERM") { exit } + + return 0 + end + end +end diff --git a/activesupport/lib/active_support/core_ext/range/include_range.rb b/activesupport/lib/active_support/core_ext/range/include_range.rb index cd53cf154a..9a7d235695 100644 --- a/activesupport/lib/active_support/core_ext/range/include_range.rb +++ b/activesupport/lib/active_support/core_ext/range/include_range.rb @@ -7,6 +7,14 @@ module ActiveSupport #:nodoc: base.alias_method_chain :include?, :range end + # Extends the default Range#include? to support range comparisons. + # (1..5).include?(1..5) # => true + # (1..5).include?(2..3) # => true + # (1..5).include?(2..6) # => false + # + # The native Range#include? behavior is untouched. + # ("a".."f").include?("c") # => true + # (5..9).include?(11) # => false def include_with_range?(value) if value.is_a?(::Range) operator = exclude_end? ? :< : :<= diff --git a/activesupport/lib/active_support/core_ext/range/overlaps.rb b/activesupport/lib/active_support/core_ext/range/overlaps.rb index 80ed1bba9d..43c69453e7 100644 --- a/activesupport/lib/active_support/core_ext/range/overlaps.rb +++ b/activesupport/lib/active_support/core_ext/range/overlaps.rb @@ -3,6 +3,9 @@ module ActiveSupport #:nodoc: module Range #:nodoc: # Check if Ranges overlap. module Overlaps + # Compare two ranges and see if they overlap eachother + # (1..5).overlaps?(4..6) # => true + # (1..5).overlaps?(7..9) # => false def overlaps?(other) include?(other.first) || other.include?(first) end diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index ffbdf37789..2cce782676 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -46,12 +46,12 @@ module ActiveSupport #:nodoc: ::DateTime.civil(year, month, day, hour, min, sec, offset) end - # wraps class method time_with_datetime_fallback with utc_or_local == :utc + # Wraps class method +time_with_datetime_fallback+ with +utc_or_local+ set to <tt>:utc</tt>. def utc_time(*args) time_with_datetime_fallback(:utc, *args) end - # wraps class method time_with_datetime_fallback with utc_or_local == :local + # Wraps class method +time_with_datetime_fallback+ with +utc_or_local+ set to <tt>:local</tt>. def local_time(*args) time_with_datetime_fallback(:local, *args) end @@ -78,8 +78,10 @@ module ActiveSupport #:nodoc: ) end - # Uses Date to provide precise Time calculations for years, months, and days. The +options+ parameter takes a hash with - # any of these keys: :years, :months, :weeks, :days, :hours, :minutes, :seconds. + # Uses Date to provide precise Time calculations for years, months, and days. + # The +options+ parameter takes a hash with any of these keys: <tt>:years</tt>, + # <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>, + # <tt>:minutes</tt>, <tt>:seconds</tt>. def advance(options) d = to_date.advance(options) time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day) diff --git a/activesupport/lib/active_support/dependencies.rb b/activesupport/lib/active_support/dependencies.rb index 64b2248e28..eaba46dd9c 100644 --- a/activesupport/lib/active_support/dependencies.rb +++ b/activesupport/lib/active_support/dependencies.rb @@ -120,15 +120,26 @@ module Dependencies #:nodoc: # We can't use defined? because it will invoke const_missing for the parent # of the name we are checking. names.inject(Object) do |mod, name| - return false unless mod.const_defined? name + return false unless uninherited_const_defined?(mod, name) mod.const_get name end return true end + if Module.method(:const_defined?).arity == 1 + # Does this module define this constant? + # Wrapper to accomodate changing Module#const_defined? in Ruby 1.9 + def uninherited_const_defined?(mod, const) + mod.const_defined?(const) + end + else + def uninherited_const_defined?(mod, const) #:nodoc: + mod.const_defined?(const, false) + end + end + # Given +path+, a filesystem path to a ruby file, return an array of constant # paths which would cause Dependencies to attempt to load this file. - # def loadable_constants_for_path(path, bases = load_paths) path = $1 if path =~ /\A(.*)\.rb\Z/ expanded_path = File.expand_path(path) @@ -237,7 +248,7 @@ module Dependencies #:nodoc: raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!" end - raise ArgumentError, "#{from_mod} is not missing constant #{const_name}!" if from_mod.const_defined?(const_name) + raise ArgumentError, "#{from_mod} is not missing constant #{const_name}!" if uninherited_const_defined?(from_mod, const_name) qualified_name = qualified_name_for from_mod, const_name path_suffix = qualified_name.underscore @@ -246,12 +257,12 @@ module Dependencies #:nodoc: file_path = search_for_file(path_suffix) if file_path && ! loaded.include?(File.expand_path(file_path)) # We found a matching file to load require_or_load file_path - raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless from_mod.const_defined?(const_name) + raise LoadError, "Expected #{file_path} to define #{qualified_name}" unless uninherited_const_defined?(from_mod, const_name) return from_mod.const_get(const_name) elsif mod = autoload_module!(from_mod, const_name, qualified_name, path_suffix) return mod elsif (parent = from_mod.parent) && parent != from_mod && - ! from_mod.parents.any? { |p| p.const_defined?(const_name) } + ! from_mod.parents.any? { |p| uninherited_const_defined?(p, const_name) } # If our parents do not have a constant named +const_name+ then we are free # to attempt to load upwards. If they do have such a constant, then this # const_missing must be due to from_mod::const_name, which should not @@ -423,10 +434,12 @@ module Dependencies #:nodoc: protected def log_call(*args) - arg_str = args.collect(&:inspect) * ', ' - /in `([a-z_\?\!]+)'/ =~ caller(1).first - selector = $1 || '<unknown>' - log "called #{selector}(#{arg_str})" + if defined?(RAILS_DEFAULT_LOGGER) && RAILS_DEFAULT_LOGGER && log_activity + arg_str = args.collect(&:inspect) * ', ' + /in `([a-z_\?\!]+)'/ =~ caller(1).first + selector = $1 || '<unknown>' + log "called #{selector}(#{arg_str})" + end end def log(msg) diff --git a/activesupport/lib/active_support/inflector.rb b/activesupport/lib/active_support/inflector.rb index 9f724619e9..c8736549f4 100644 --- a/activesupport/lib/active_support/inflector.rb +++ b/activesupport/lib/active_support/inflector.rb @@ -68,8 +68,9 @@ module Inflector (@uncountables << words).flatten! end - # Clears the loaded inflections within a given scope (default is :all). Give the scope as a symbol of the inflection type, - # the options are: :plurals, :singulars, :uncountables + # 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>. # # Examples: # clear :all @@ -245,13 +246,23 @@ module Inflector underscore(demodulize(class_name)) + (separate_class_name_and_id_with_underscore ? "_id" : "id") 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. + # Tries to find a constant with the name specified in the argument string: # - # Examples - # "Module".constantize #=> Module - # "Class".constantize #=> Class + # "Module".constantize # => Module + # "Test::Unit".constantize # => Test::Unit + # + # 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' + # "C".constantize # => 'outside', same as ::C + # end + # + # NameError is raised when the name is not in CamelCase or the constant is + # unknown. def constantize(camel_cased_word) unless /\A(?:::)?([A-Z]\w*(?:::[A-Z]\w*)*)\z/ =~ camel_cased_word raise NameError, "#{camel_cased_word.inspect} is not a valid constant name!" diff --git a/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb b/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb index 66fe47a604..0166b69ac3 100644 --- a/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb +++ b/activesupport/lib/active_support/multibyte/handlers/utf8_handler.rb @@ -284,7 +284,9 @@ module ActiveSupport::Multibyte::Handlers #:nodoc: # passing strings to databases and validations. # # * <tt>str</tt> - The string to perform normalization on. - # * <tt>form</tt> - The form you want to normalize in. Should be one of the following: :c, :kc, :d or :kd. + # * <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::DEFAULT_NORMALIZATION_FORM. def normalize(str, form=ActiveSupport::Multibyte::DEFAULT_NORMALIZATION_FORM) # See http://www.unicode.org/reports/tr15, Table 1 codepoints = u_unpack(str) diff --git a/activesupport/lib/active_support/ordered_options.rb b/activesupport/lib/active_support/ordered_options.rb index b2b1b0e438..3172f62f0d 100644 --- a/activesupport/lib/active_support/ordered_options.rb +++ b/activesupport/lib/active_support/ordered_options.rb @@ -18,6 +18,12 @@ module ActiveSupport pair = assoc(key) pair ? pair.last : nil end + + def delete(key) + pair = assoc(key) + pair ? array_index = index(pair) : nil + array_index ? delete_at(array_index).last : nil + end def keys collect { |key, value| key } diff --git a/activesupport/lib/active_support/time_with_zone.rb b/activesupport/lib/active_support/time_with_zone.rb index f1a2498298..461d52e40e 100644 --- a/activesupport/lib/active_support/time_with_zone.rb +++ b/activesupport/lib/active_support/time_with_zone.rb @@ -101,7 +101,8 @@ module ActiveSupport end alias_method :rfc822, :rfc2822 - # :db format outputs time in UTC; all others output time in local. Uses TimeWithZone's strftime, so %Z and %z work correctly + # <tt>:db</tt> format outputs time in UTC; all others output time in local. + # Uses TimeWithZone's +strftime+, so <tt>%Z</tt> and <tt>%z</tt> work correctly. def to_s(format = :default) return utc.to_s(format) if format == :db if formatter = ::Time::DATE_FORMATS[format] @@ -111,7 +112,7 @@ module ActiveSupport end end - # Replaces %Z and %z directives with #zone and #formatted_offset, respectively, before passing to + # Replaces <tt>%Z</tt> and <tt>%z</tt> directives with +zone+ and +formatted_offset+, respectively, before passing to # Time#strftime, so that zone information is correct def strftime(format) format = format.gsub('%Z', zone).gsub('%z', formatted_offset(false)) @@ -138,9 +139,9 @@ module ActiveSupport result.in_time_zone(time_zone) end - # If a time-like object is passed in, compare it with #utc - # Else if wrapped #time is a DateTime, use DateTime#ago instead of #- - # Otherwise, just pass on to method missing + # If a time-like object is passed in, compare it with +utc+. + # Else if wrapped +time+ is a DateTime, use DateTime#ago instead of DateTime#-. + # Otherwise, just pass on to +method_missing+. def -(other) if other.acts_like?(:time) utc - other @@ -180,7 +181,7 @@ module ActiveSupport alias_method :hash, :to_i alias_method :tv_sec, :to_i - # A TimeWithZone acts like a Time, so just return self + # A TimeWithZone acts like a Time, so just return +self+. def to_time self end diff --git a/activesupport/lib/active_support/values/time_zone.rb b/activesupport/lib/active_support/values/time_zone.rb index 80057fe832..9cdc2a74ed 100644 --- a/activesupport/lib/active_support/values/time_zone.rb +++ b/activesupport/lib/active_support/values/time_zone.rb @@ -1,149 +1,152 @@ class TimeZone - # Keys are Rails TimeZone names, values are TZInfo identifiers - MAPPING = { - "International Date Line West" => "Pacific/Midway", - "Midway Island" => "Pacific/Midway", - "Samoa" => "Pacific/Pago_Pago", - "Hawaii" => "Pacific/Honolulu", - "Alaska" => "America/Juneau", - "Pacific Time (US & Canada)" => "America/Los_Angeles", - "Tijuana" => "America/Tijuana", - "Mountain Time (US & Canada)" => "America/Denver", - "Arizona" => "America/Phoenix", - "Chihuahua" => "America/Chihuahua", - "Mazatlan" => "America/Mazatlan", - "Central Time (US & Canada)" => "America/Chicago", - "Saskatchewan" => "America/Regina", - "Guadalajara" => "America/Mexico_City", - "Mexico City" => "America/Mexico_City", - "Monterrey" => "America/Monterrey", - "Central America" => "America/Guatemala", - "Eastern Time (US & Canada)" => "America/New_York", - "Indiana (East)" => "America/Indiana/Indianapolis", - "Bogota" => "America/Bogota", - "Lima" => "America/Lima", - "Quito" => "America/Lima", - "Atlantic Time (Canada)" => "America/Halifax", - "Caracas" => "America/Caracas", - "La Paz" => "America/La_Paz", - "Santiago" => "America/Santiago", - "Newfoundland" => "America/St_Johns", - "Brasilia" => "America/Argentina/Buenos_Aires", - "Buenos Aires" => "America/Argentina/Buenos_Aires", - "Georgetown" => "America/Argentina/San_Juan", - "Greenland" => "America/Godthab", - "Mid-Atlantic" => "Atlantic/South_Georgia", - "Azores" => "Atlantic/Azores", - "Cape Verde Is." => "Atlantic/Cape_Verde", - "Dublin" => "Europe/Dublin", - "Edinburgh" => "Europe/Dublin", - "Lisbon" => "Europe/Lisbon", - "London" => "Europe/London", - "Casablanca" => "Africa/Casablanca", - "Monrovia" => "Africa/Monrovia", - "UTC" => "Etc/UTC", - "Belgrade" => "Europe/Belgrade", - "Bratislava" => "Europe/Bratislava", - "Budapest" => "Europe/Budapest", - "Ljubljana" => "Europe/Ljubljana", - "Prague" => "Europe/Prague", - "Sarajevo" => "Europe/Sarajevo", - "Skopje" => "Europe/Skopje", - "Warsaw" => "Europe/Warsaw", - "Zagreb" => "Europe/Zagreb", - "Brussels" => "Europe/Brussels", - "Copenhagen" => "Europe/Copenhagen", - "Madrid" => "Europe/Madrid", - "Paris" => "Europe/Paris", - "Amsterdam" => "Europe/Amsterdam", - "Berlin" => "Europe/Berlin", - "Bern" => "Europe/Berlin", - "Rome" => "Europe/Rome", - "Stockholm" => "Europe/Stockholm", - "Vienna" => "Europe/Vienna", - "West Central Africa" => "Africa/Algiers", - "Bucharest" => "Europe/Bucharest", - "Cairo" => "Africa/Cairo", - "Helsinki" => "Europe/Helsinki", - "Kyev" => "Europe/Kiev", - "Riga" => "Europe/Riga", - "Sofia" => "Europe/Sofia", - "Tallinn" => "Europe/Tallinn", - "Vilnius" => "Europe/Vilnius", - "Athens" => "Europe/Athens", - "Istanbul" => "Europe/Istanbul", - "Minsk" => "Europe/Minsk", - "Jerusalem" => "Asia/Jerusalem", - "Harare" => "Africa/Harare", - "Pretoria" => "Africa/Johannesburg", - "Moscow" => "Europe/Moscow", - "St. Petersburg" => "Europe/Moscow", - "Volgograd" => "Europe/Moscow", - "Kuwait" => "Asia/Kuwait", - "Riyadh" => "Asia/Riyadh", - "Nairobi" => "Africa/Nairobi", - "Baghdad" => "Asia/Baghdad", - "Tehran" => "Asia/Tehran", - "Abu Dhabi" => "Asia/Muscat", - "Muscat" => "Asia/Muscat", - "Baku" => "Asia/Baku", - "Tbilisi" => "Asia/Tbilisi", - "Yerevan" => "Asia/Yerevan", - "Kabul" => "Asia/Kabul", - "Ekaterinburg" => "Asia/Yekaterinburg", - "Islamabad" => "Asia/Karachi", - "Karachi" => "Asia/Karachi", - "Tashkent" => "Asia/Tashkent", - "Chennai" => "Asia/Kolkata", - "Kolkata" => "Asia/Kolkata", - "Mumbai" => "Asia/Kolkata", - "New Delhi" => "Asia/Kolkata", - "Kathmandu" => "Asia/Katmandu", - "Astana" => "Asia/Dhaka", - "Dhaka" => "Asia/Dhaka", - "Sri Jayawardenepura" => "Asia/Dhaka", - "Almaty" => "Asia/Almaty", - "Novosibirsk" => "Asia/Novosibirsk", - "Rangoon" => "Asia/Rangoon", - "Bangkok" => "Asia/Bangkok", - "Hanoi" => "Asia/Bangkok", - "Jakarta" => "Asia/Jakarta", - "Krasnoyarsk" => "Asia/Krasnoyarsk", - "Beijing" => "Asia/Shanghai", - "Chongqing" => "Asia/Chongqing", - "Hong Kong" => "Asia/Hong_Kong", - "Urumqi" => "Asia/Urumqi", - "Kuala Lumpur" => "Asia/Kuala_Lumpur", - "Singapore" => "Asia/Singapore", - "Taipei" => "Asia/Taipei", - "Perth" => "Australia/Perth", - "Irkutsk" => "Asia/Irkutsk", - "Ulaan Bataar" => "Asia/Ulaanbaatar", - "Seoul" => "Asia/Seoul", - "Osaka" => "Asia/Tokyo", - "Sapporo" => "Asia/Tokyo", - "Tokyo" => "Asia/Tokyo", - "Yakutsk" => "Asia/Yakutsk", - "Darwin" => "Australia/Darwin", - "Adelaide" => "Australia/Adelaide", - "Canberra" => "Australia/Melbourne", - "Melbourne" => "Australia/Melbourne", - "Sydney" => "Australia/Sydney", - "Brisbane" => "Australia/Brisbane", - "Hobart" => "Australia/Hobart", - "Vladivostok" => "Asia/Vladivostok", - "Guam" => "Pacific/Guam", - "Port Moresby" => "Pacific/Port_Moresby", - "Magadan" => "Asia/Magadan", - "Solomon Is." => "Asia/Magadan", - "New Caledonia" => "Pacific/Noumea", - "Fiji" => "Pacific/Fiji", - "Kamchatka" => "Asia/Kamchatka", - "Marshall Is." => "Pacific/Majuro", - "Auckland" => "Pacific/Auckland", - "Wellington" => "Pacific/Auckland", - "Nuku'alofa" => "Pacific/Tongatapu" - } + unless const_defined?(:MAPPING) + # Keys are Rails TimeZone names, values are TZInfo identifiers + MAPPING = { + "International Date Line West" => "Pacific/Midway", + "Midway Island" => "Pacific/Midway", + "Samoa" => "Pacific/Pago_Pago", + "Hawaii" => "Pacific/Honolulu", + "Alaska" => "America/Juneau", + "Pacific Time (US & Canada)" => "America/Los_Angeles", + "Tijuana" => "America/Tijuana", + "Mountain Time (US & Canada)" => "America/Denver", + "Arizona" => "America/Phoenix", + "Chihuahua" => "America/Chihuahua", + "Mazatlan" => "America/Mazatlan", + "Central Time (US & Canada)" => "America/Chicago", + "Saskatchewan" => "America/Regina", + "Guadalajara" => "America/Mexico_City", + "Mexico City" => "America/Mexico_City", + "Monterrey" => "America/Monterrey", + "Central America" => "America/Guatemala", + "Eastern Time (US & Canada)" => "America/New_York", + "Indiana (East)" => "America/Indiana/Indianapolis", + "Bogota" => "America/Bogota", + "Lima" => "America/Lima", + "Quito" => "America/Lima", + "Atlantic Time (Canada)" => "America/Halifax", + "Caracas" => "America/Caracas", + "La Paz" => "America/La_Paz", + "Santiago" => "America/Santiago", + "Newfoundland" => "America/St_Johns", + "Brasilia" => "America/Argentina/Buenos_Aires", + "Buenos Aires" => "America/Argentina/Buenos_Aires", + "Georgetown" => "America/Argentina/San_Juan", + "Greenland" => "America/Godthab", + "Mid-Atlantic" => "Atlantic/South_Georgia", + "Azores" => "Atlantic/Azores", + "Cape Verde Is." => "Atlantic/Cape_Verde", + "Dublin" => "Europe/Dublin", + "Edinburgh" => "Europe/Dublin", + "Lisbon" => "Europe/Lisbon", + "London" => "Europe/London", + "Casablanca" => "Africa/Casablanca", + "Monrovia" => "Africa/Monrovia", + "UTC" => "Etc/UTC", + "Belgrade" => "Europe/Belgrade", + "Bratislava" => "Europe/Bratislava", + "Budapest" => "Europe/Budapest", + "Ljubljana" => "Europe/Ljubljana", + "Prague" => "Europe/Prague", + "Sarajevo" => "Europe/Sarajevo", + "Skopje" => "Europe/Skopje", + "Warsaw" => "Europe/Warsaw", + "Zagreb" => "Europe/Zagreb", + "Brussels" => "Europe/Brussels", + "Copenhagen" => "Europe/Copenhagen", + "Madrid" => "Europe/Madrid", + "Paris" => "Europe/Paris", + "Amsterdam" => "Europe/Amsterdam", + "Berlin" => "Europe/Berlin", + "Bern" => "Europe/Berlin", + "Rome" => "Europe/Rome", + "Stockholm" => "Europe/Stockholm", + "Vienna" => "Europe/Vienna", + "West Central Africa" => "Africa/Algiers", + "Bucharest" => "Europe/Bucharest", + "Cairo" => "Africa/Cairo", + "Helsinki" => "Europe/Helsinki", + "Kyev" => "Europe/Kiev", + "Riga" => "Europe/Riga", + "Sofia" => "Europe/Sofia", + "Tallinn" => "Europe/Tallinn", + "Vilnius" => "Europe/Vilnius", + "Athens" => "Europe/Athens", + "Istanbul" => "Europe/Istanbul", + "Minsk" => "Europe/Minsk", + "Jerusalem" => "Asia/Jerusalem", + "Harare" => "Africa/Harare", + "Pretoria" => "Africa/Johannesburg", + "Moscow" => "Europe/Moscow", + "St. Petersburg" => "Europe/Moscow", + "Volgograd" => "Europe/Moscow", + "Kuwait" => "Asia/Kuwait", + "Riyadh" => "Asia/Riyadh", + "Nairobi" => "Africa/Nairobi", + "Baghdad" => "Asia/Baghdad", + "Tehran" => "Asia/Tehran", + "Abu Dhabi" => "Asia/Muscat", + "Muscat" => "Asia/Muscat", + "Baku" => "Asia/Baku", + "Tbilisi" => "Asia/Tbilisi", + "Yerevan" => "Asia/Yerevan", + "Kabul" => "Asia/Kabul", + "Ekaterinburg" => "Asia/Yekaterinburg", + "Islamabad" => "Asia/Karachi", + "Karachi" => "Asia/Karachi", + "Tashkent" => "Asia/Tashkent", + "Chennai" => "Asia/Kolkata", + "Kolkata" => "Asia/Kolkata", + "Mumbai" => "Asia/Kolkata", + "New Delhi" => "Asia/Kolkata", + "Kathmandu" => "Asia/Katmandu", + "Astana" => "Asia/Dhaka", + "Dhaka" => "Asia/Dhaka", + "Sri Jayawardenepura" => "Asia/Dhaka", + "Almaty" => "Asia/Almaty", + "Novosibirsk" => "Asia/Novosibirsk", + "Rangoon" => "Asia/Rangoon", + "Bangkok" => "Asia/Bangkok", + "Hanoi" => "Asia/Bangkok", + "Jakarta" => "Asia/Jakarta", + "Krasnoyarsk" => "Asia/Krasnoyarsk", + "Beijing" => "Asia/Shanghai", + "Chongqing" => "Asia/Chongqing", + "Hong Kong" => "Asia/Hong_Kong", + "Urumqi" => "Asia/Urumqi", + "Kuala Lumpur" => "Asia/Kuala_Lumpur", + "Singapore" => "Asia/Singapore", + "Taipei" => "Asia/Taipei", + "Perth" => "Australia/Perth", + "Irkutsk" => "Asia/Irkutsk", + "Ulaan Bataar" => "Asia/Ulaanbaatar", + "Seoul" => "Asia/Seoul", + "Osaka" => "Asia/Tokyo", + "Sapporo" => "Asia/Tokyo", + "Tokyo" => "Asia/Tokyo", + "Yakutsk" => "Asia/Yakutsk", + "Darwin" => "Australia/Darwin", + "Adelaide" => "Australia/Adelaide", + "Canberra" => "Australia/Melbourne", + "Melbourne" => "Australia/Melbourne", + "Sydney" => "Australia/Sydney", + "Brisbane" => "Australia/Brisbane", + "Hobart" => "Australia/Hobart", + "Vladivostok" => "Asia/Vladivostok", + "Guam" => "Pacific/Guam", + "Port Moresby" => "Pacific/Port_Moresby", + "Magadan" => "Asia/Magadan", + "Solomon Is." => "Asia/Magadan", + "New Caledonia" => "Pacific/Noumea", + "Fiji" => "Pacific/Fiji", + "Kamchatka" => "Asia/Kamchatka", + "Marshall Is." => "Pacific/Majuro", + "Auckland" => "Pacific/Auckland", + "Wellington" => "Pacific/Auckland", + "Nuku'alofa" => "Pacific/Tongatapu" + }.each { |name, zone| name.freeze; zone.freeze } + MAPPING.freeze + end include Comparable attr_reader :name @@ -157,7 +160,7 @@ class TimeZone @utc_offset = utc_offset @tzinfo = tzinfo end - + def utc_offset @utc_offset ||= tzinfo.current_period.utc_offset end @@ -180,7 +183,7 @@ class TimeZone def to_s "(UTC#{formatted_offset}) #{name}" end - + # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from given values. Example: # # Time.zone = "Hawaii" # => "Hawaii" @@ -199,7 +202,7 @@ class TimeZone utc = Time.at(secs).utc rescue DateTime.civil(1970).since(secs) utc.in_time_zone(self) end - + # Method for creating new ActiveSupport::TimeWithZone instance in time zone of +self+ from parsed string. Example: # # Time.zone = "Hawaii" # => "Hawaii" @@ -213,7 +216,7 @@ class TimeZone time = Time.parse(str, now) rescue DateTime.parse(str) ActiveSupport::TimeWithZone.new(nil, self, time) end - + # Returns an ActiveSupport::TimeWithZone instance representing the current time # in the time zone represented by +self+. Example: # @@ -228,12 +231,12 @@ class TimeZone tzinfo.now.to_date end - # Adjust the given time to the simultaneous time in the time zone represented by +self+. Returns a + # Adjust the given time to the simultaneous time in the time zone represented by +self+. Returns a # Time.utc() instance -- if you want an ActiveSupport::TimeWithZone instance, use Time#in_time_zone() instead. def utc_to_local(time) tzinfo.utc_to_local(time) end - + # Adjust the given time to the simultaneous time in UTC. Returns a Time.utc() instance. def local_to_utc(time, dst=true) tzinfo.local_to_utc(time, dst) @@ -248,12 +251,75 @@ class TimeZone def period_for_local(time, dst=true) tzinfo.period_for_local(time, dst) end - + + # TODO: Preload instead of lazy load for thread safety def tzinfo @tzinfo ||= TZInfo::Timezone.get(MAPPING[name]) end - @@zones = nil + unless const_defined?(:ZONES) + ZONES = [] + ZONES_MAP = {} + [[-39_600, "International Date Line West", "Midway Island", "Samoa" ], + [-36_000, "Hawaii" ], + [-32_400, "Alaska" ], + [-28_800, "Pacific Time (US & Canada)", "Tijuana" ], + [-25_200, "Mountain Time (US & Canada)", "Chihuahua", "Mazatlan", + "Arizona" ], + [-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara", + "Mexico City", "Monterrey", "Central America" ], + [-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota", + "Lima", "Quito" ], + [-14_400, "Atlantic Time (Canada)", "Caracas", "La Paz", "Santiago" ], + [-12_600, "Newfoundland" ], + [-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ], + [ -7_200, "Mid-Atlantic" ], + [ -3_600, "Azores", "Cape Verde Is." ], + [ 0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca", + "Monrovia", "UTC" ], + [ 3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague", + "Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels", + "Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin", + "Bern", "Rome", "Stockholm", "Vienna", + "West Central Africa" ], + [ 7_200, "Bucharest", "Cairo", "Helsinki", "Kyev", "Riga", "Sofia", + "Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk", + "Jerusalem", "Harare", "Pretoria" ], + [ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh", + "Nairobi", "Baghdad" ], + [ 12_600, "Tehran" ], + [ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ], + [ 16_200, "Kabul" ], + [ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ], + [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi" ], + [ 20_700, "Kathmandu" ], + [ 21_600, "Astana", "Dhaka", "Sri Jayawardenepura", "Almaty", + "Novosibirsk" ], + [ 23_400, "Rangoon" ], + [ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ], + [ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi", + "Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk", + "Ulaan Bataar" ], + [ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ], + [ 34_200, "Darwin", "Adelaide" ], + [ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart", + "Vladivostok", "Guam", "Port Moresby" ], + [ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ], + [ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland", + "Wellington" ], + [ 46_800, "Nuku'alofa" ]]. + each do |offset, *places| + places.each do |place| + place.freeze + zone = new(place, offset) + ZONES << zone + ZONES_MAP[place] = zone + end + end + ZONES.sort! + ZONES.freeze + ZONES_MAP.freeze + end class << self alias_method :create, :new @@ -269,67 +335,7 @@ class TimeZone # TimeZone objects per time zone, in many cases, to make it easier # for users to find their own time zone. def all - unless @@zones - @@zones = [] - @@zones_map = {} - [[-39_600, "International Date Line West", "Midway Island", "Samoa" ], - [-36_000, "Hawaii" ], - [-32_400, "Alaska" ], - [-28_800, "Pacific Time (US & Canada)", "Tijuana" ], - [-25_200, "Mountain Time (US & Canada)", "Chihuahua", "Mazatlan", - "Arizona" ], - [-21_600, "Central Time (US & Canada)", "Saskatchewan", "Guadalajara", - "Mexico City", "Monterrey", "Central America" ], - [-18_000, "Eastern Time (US & Canada)", "Indiana (East)", "Bogota", - "Lima", "Quito" ], - [-14_400, "Atlantic Time (Canada)", "Caracas", "La Paz", "Santiago" ], - [-12_600, "Newfoundland" ], - [-10_800, "Brasilia", "Buenos Aires", "Georgetown", "Greenland" ], - [ -7_200, "Mid-Atlantic" ], - [ -3_600, "Azores", "Cape Verde Is." ], - [ 0, "Dublin", "Edinburgh", "Lisbon", "London", "Casablanca", - "Monrovia", "UTC" ], - [ 3_600, "Belgrade", "Bratislava", "Budapest", "Ljubljana", "Prague", - "Sarajevo", "Skopje", "Warsaw", "Zagreb", "Brussels", - "Copenhagen", "Madrid", "Paris", "Amsterdam", "Berlin", - "Bern", "Rome", "Stockholm", "Vienna", - "West Central Africa" ], - [ 7_200, "Bucharest", "Cairo", "Helsinki", "Kyev", "Riga", "Sofia", - "Tallinn", "Vilnius", "Athens", "Istanbul", "Minsk", - "Jerusalem", "Harare", "Pretoria" ], - [ 10_800, "Moscow", "St. Petersburg", "Volgograd", "Kuwait", "Riyadh", - "Nairobi", "Baghdad" ], - [ 12_600, "Tehran" ], - [ 14_400, "Abu Dhabi", "Muscat", "Baku", "Tbilisi", "Yerevan" ], - [ 16_200, "Kabul" ], - [ 18_000, "Ekaterinburg", "Islamabad", "Karachi", "Tashkent" ], - [ 19_800, "Chennai", "Kolkata", "Mumbai", "New Delhi" ], - [ 20_700, "Kathmandu" ], - [ 21_600, "Astana", "Dhaka", "Sri Jayawardenepura", "Almaty", - "Novosibirsk" ], - [ 23_400, "Rangoon" ], - [ 25_200, "Bangkok", "Hanoi", "Jakarta", "Krasnoyarsk" ], - [ 28_800, "Beijing", "Chongqing", "Hong Kong", "Urumqi", - "Kuala Lumpur", "Singapore", "Taipei", "Perth", "Irkutsk", - "Ulaan Bataar" ], - [ 32_400, "Seoul", "Osaka", "Sapporo", "Tokyo", "Yakutsk" ], - [ 34_200, "Darwin", "Adelaide" ], - [ 36_000, "Canberra", "Melbourne", "Sydney", "Brisbane", "Hobart", - "Vladivostok", "Guam", "Port Moresby" ], - [ 39_600, "Magadan", "Solomon Is.", "New Caledonia" ], - [ 43_200, "Fiji", "Kamchatka", "Marshall Is.", "Auckland", - "Wellington" ], - [ 46_800, "Nuku'alofa" ]]. - each do |offset, *places| - places.each do |place| - zone = create(place, offset) - @@zones << zone - @@zones_map[place] = zone - end - end - @@zones.sort! - end - @@zones + ZONES end # Locate a specific time zone object. If the argument is a string, it @@ -340,8 +346,7 @@ class TimeZone def [](arg) case arg when String - all # force the zones to be loaded - @@zones_map[arg] + ZONES_MAP[arg] when Numeric, ActiveSupport::Duration arg *= 3600 if arg.abs <= 13 all.find { |z| z.utc_offset == arg.to_i } @@ -352,7 +357,7 @@ class TimeZone # A regular expression that matches the names of all time zones in # the USA. - US_ZONES = /US|Arizona|Indiana|Hawaii|Alaska/ + US_ZONES = /US|Arizona|Indiana|Hawaii|Alaska/.freeze # A convenience method for returning a collection of TimeZone objects # for time zones in the USA. diff --git a/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb b/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb index 375cfb1430..dda7f2c30e 100644 --- a/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb +++ b/activesupport/lib/active_support/vendor/memcache-client-1.5.0/memcache.rb @@ -278,12 +278,12 @@ class MemCache results = {} - server_keys.each do |server, keys| - keys = keys.join ' ' + server_keys.each do |server, keys_for_server| + keys_for_server = keys_for_server.join ' ' values = if @multithread then - threadsafe_cache_get_multi server, keys + threadsafe_cache_get_multi server, keys_for_server else - cache_get_multi server, keys + cache_get_multi server, keys_for_server end values.each do |key, value| results[cache_keys[key]] = Marshal.load value diff --git a/activesupport/lib/active_support/whiny_nil.rb b/activesupport/lib/active_support/whiny_nil.rb index 099619191c..36fe9510ba 100644 --- a/activesupport/lib/active_support/whiny_nil.rb +++ b/activesupport/lib/active_support/whiny_nil.rb @@ -28,12 +28,12 @@ class NilClass WHINERS = [::Array] WHINERS << ::ActiveRecord::Base if defined? ::ActiveRecord - @@method_class_map = Hash.new + METHOD_CLASS_MAP = Hash.new WHINERS.each do |klass| methods = klass.public_instance_methods - public_instance_methods class_name = klass.name - methods.each { |method| @@method_class_map[method.to_sym] = class_name } + methods.each { |method| METHOD_CLASS_MAP[method.to_sym] = class_name } end # Raises a RuntimeError when you attempt to call +id+ on +nil+. @@ -43,7 +43,7 @@ class NilClass private def method_missing(method, *args, &block) - raise_nil_warning_for @@method_class_map[method], method, caller + raise_nil_warning_for METHOD_CLASS_MAP[method], method, caller end # Raises a NoMethodError when you attempt to call a method on +nil+. diff --git a/activesupport/test/inflector_test.rb b/activesupport/test/inflector_test.rb index 00d8f45028..26af245ff7 100644 --- a/activesupport/test/inflector_test.rb +++ b/activesupport/test/inflector_test.rb @@ -120,14 +120,8 @@ class InflectorTest < Test::Unit::TestCase assert_raises(NameError) { Inflector.constantize("InvalidClass\n") } end - if RUBY_VERSION < '1.9.0' - def test_constantize_does_lexical_lookup - assert_raises(NameError) { Inflector.constantize("Ace::Base::InflectorTest") } - end - else - def test_constantize_does_dynamic_lookup - assert_equal self.class, Inflector.constantize("Ace::Base::InflectorTest") - end + def test_constantize_does_lexical_lookup + assert_raises(NameError) { Inflector.constantize("Ace::Base::InflectorTest") } end def test_ordinal diff --git a/activesupport/test/ordered_options_test.rb b/activesupport/test/ordered_options_test.rb index 1a1d0c7648..3d537a0ae4 100644 --- a/activesupport/test/ordered_options_test.rb +++ b/activesupport/test/ordered_options_test.rb @@ -29,6 +29,19 @@ class OrderedHashTest < Test::Unit::TestCase assert_equal value, @ordered_hash.values.last assert_equal value, @ordered_hash[key] end + + def test_delete + key, value = 'white', 'ffffff' + bad_key = 'black' + + @ordered_hash[key] = value + assert_equal @keys.length + 1, @ordered_hash.length + + assert_equal value, @ordered_hash.delete(key) + assert_equal @keys.length, @ordered_hash.length + + assert_nil @ordered_hash.delete(bad_key) + end end class OrderedOptionsTest < Test::Unit::TestCase |