diff options
Diffstat (limited to 'activesupport/lib')
11 files changed, 144 insertions, 46 deletions
diff --git a/activesupport/lib/active_support/core_ext/date/calculations.rb b/activesupport/lib/active_support/core_ext/date/calculations.rb index 8a7eb6bc6b..7fe4161fb4 100644 --- a/activesupport/lib/active_support/core_ext/date/calculations.rb +++ b/activesupport/lib/active_support/core_ext/date/calculations.rb @@ -202,6 +202,17 @@ class Date acts_like?(:time) ? result.change(:hour => 0) : result end + # Short-hand for months_ago(3) + def prev_quarter + months_ago(3) + end + alias_method :last_quarter, :prev_quarter + + # Short-hand for months_since(3) + def next_quarter + months_since(3) + end + # Returns a new Date/DateTime representing the start of the month (1st of the month; DateTime objects will have time set to 0:00) def beginning_of_month acts_like?(:time) ? change(:day => 1, :hour => 0) : change(:day => 1) diff --git a/activesupport/lib/active_support/core_ext/string/inflections.rb b/activesupport/lib/active_support/core_ext/string/inflections.rb index 070bfd7af6..efa2d43f20 100644 --- a/activesupport/lib/active_support/core_ext/string/inflections.rb +++ b/activesupport/lib/active_support/core_ext/string/inflections.rb @@ -107,7 +107,7 @@ class String # Replaces underscores with dashes in the string. # - # 'puni_puni' # => "puni-puni" + # 'puni_puni'.dasherize # => "puni-puni" def dasherize ActiveSupport::Inflector.dasherize(self) end diff --git a/activesupport/lib/active_support/core_ext/time/calculations.rb b/activesupport/lib/active_support/core_ext/time/calculations.rb index 92b8417150..28c8b53b78 100644 --- a/activesupport/lib/active_support/core_ext/time/calculations.rb +++ b/activesupport/lib/active_support/core_ext/time/calculations.rb @@ -186,6 +186,17 @@ class Time months_since(1) end + # Short-hand for months_ago(3) + def prev_quarter + months_ago(3) + end + alias_method :last_quarter, :prev_quarter + + # Short-hand for months_since(3) + def next_quarter + months_since(3) + end + # Returns number of days to start of this week, week starts on start_day (default is :monday). def days_to_week_start(start_day = :monday) start_day_number = DAYS_INTO_WEEK[start_day] diff --git a/activesupport/lib/active_support/deprecation.rb b/activesupport/lib/active_support/deprecation.rb index 176edefa42..e3b4a7240e 100644 --- a/activesupport/lib/active_support/deprecation.rb +++ b/activesupport/lib/active_support/deprecation.rb @@ -10,10 +10,10 @@ module ActiveSupport # The version the deprecated behavior will be removed, by default. attr_accessor :deprecation_horizon end - self.deprecation_horizon = '3.2' + self.deprecation_horizon = '4.1' # By default, warnings are not silenced and debugging is off. self.silenced = false self.debug = false end -end +end
\ No newline at end of file diff --git a/activesupport/lib/active_support/hash_with_indifferent_access.rb b/activesupport/lib/active_support/hash_with_indifferent_access.rb index 6e1c0da991..3e6c8893e9 100644 --- a/activesupport/lib/active_support/hash_with_indifferent_access.rb +++ b/activesupport/lib/active_support/hash_with_indifferent_access.rb @@ -164,7 +164,8 @@ module ActiveSupport if value.is_a? Hash value.nested_under_indifferent_access elsif value.is_a?(Array) - value.dup.replace(value.map { |e| convert_value(e) }) + value = value.dup if value.frozen? + value.map! { |e| convert_value(e) } else value end diff --git a/activesupport/lib/active_support/log_subscriber.rb b/activesupport/lib/active_support/log_subscriber.rb index bea2ca17f1..e5b4ca2738 100644 --- a/activesupport/lib/active_support/log_subscriber.rb +++ b/activesupport/lib/active_support/log_subscriber.rb @@ -48,20 +48,19 @@ module ActiveSupport mattr_accessor :colorize_logging self.colorize_logging = true - class_attribute :logger - class << self - remove_method :logger def logger @logger ||= Rails.logger if defined?(Rails) + @logger end + attr_writer :logger + def attach_to(namespace, log_subscriber=new, notifier=ActiveSupport::Notifications) log_subscribers << log_subscriber - @@flushable_loggers = nil log_subscriber.public_methods(false).each do |event| - next if :call == event + next if %w{ start finish }.include?(event.to_s) notifier.subscribe("#{event}.#{namespace}", log_subscriber) end @@ -71,29 +70,44 @@ module ActiveSupport @@log_subscribers ||= [] end - def flushable_loggers - @@flushable_loggers ||= begin - loggers = log_subscribers.map(&:logger) - loggers.uniq! - loggers.select! { |l| l.respond_to?(:flush) } - loggers - end - end - # Flush all log_subscribers' logger. def flush_all! - flushable_loggers.each { |log| log.flush } + logger.flush if logger.respond_to?(:flush) end end - def call(message, *args) + def initialize + @queue_key = [self.class.name, object_id].join "-" + super + end + + def logger + LogSubscriber.logger + end + + def start(name, id, payload) return unless logger - method = message.split('.').first + e = ActiveSupport::Notifications::Event.new(name, Time.now, nil, id, payload) + parent = event_stack.last + parent << e if parent + + event_stack.push e + end + + def finish(name, id, payload) + return unless logger + + finished = Time.now + event = event_stack.pop + event.end = finished + event.payload.merge!(payload) + + method = name.split('.').first begin - send(method, ActiveSupport::Notifications::Event.new(message, *args)) + send(method, event) rescue Exception => e - logger.error "Could not log #{message.inspect} event. #{e.class}: #{e.message} #{e.backtrace}" + logger.error "Could not log #{name.inspect} event. #{e.class}: #{e.message} #{e.backtrace}" end end @@ -118,5 +132,11 @@ module ActiveSupport bold = bold ? BOLD : "" "#{bold}#{color}#{text}#{CLEAR}" end + + private + + def event_stack + Thread.current[@queue_key] ||= [] + end end end diff --git a/activesupport/lib/active_support/multibyte/unicode.rb b/activesupport/lib/active_support/multibyte/unicode.rb index 678f551193..ef1711c60a 100644 --- a/activesupport/lib/active_support/multibyte/unicode.rb +++ b/activesupport/lib/active_support/multibyte/unicode.rb @@ -331,7 +331,7 @@ module ActiveSupport def load begin @codepoints, @composition_exclusion, @composition_map, @boundary, @cp1252 = File.open(self.class.filename, 'rb') { |f| Marshal.load f.read } - rescue Exception => e + rescue => e raise IOError.new("Couldn't load the Unicode tables for UTF8Handler (#{e.message}), ActiveSupport::Multibyte is unusable") end diff --git a/activesupport/lib/active_support/notifications.rb b/activesupport/lib/active_support/notifications.rb index 6735c561d3..b4657a8ba9 100644 --- a/activesupport/lib/active_support/notifications.rb +++ b/activesupport/lib/active_support/notifications.rb @@ -33,7 +33,7 @@ module ActiveSupport # end # # That code returns right away, you are just subscribing to "render" events. - # The block will be called asynchronously whenever someone instruments "render": + # The block is saved and will be called whenever someone instruments "render": # # ActiveSupport::Notifications.instrument("render", :extra => :information) do # render :text => "Foo" @@ -135,8 +135,6 @@ module ActiveSupport # to log subscribers in a thread. You can use any queue implementation you want. # module Notifications - @instrumenters = Hash.new { |h,k| h[k] = notifier.listening?(k) } - class << self attr_accessor :notifier @@ -145,7 +143,7 @@ module ActiveSupport end def instrument(name, payload = {}) - if @instrumenters[name] + if notifier.listening?(name) instrumenter.instrument(name, payload) { yield payload if block_given? } else yield payload if block_given? @@ -153,9 +151,7 @@ module ActiveSupport end def subscribe(*args, &block) - notifier.subscribe(*args, &block).tap do - @instrumenters.clear - end + notifier.subscribe(*args, &block) end def subscribed(callback, *args, &block) @@ -167,7 +163,6 @@ module ActiveSupport def unsubscribe(args) notifier.unsubscribe(args) - @instrumenters.clear end def instrumenter diff --git a/activesupport/lib/active_support/notifications/fanout.rb b/activesupport/lib/active_support/notifications/fanout.rb index 17c99089c1..6ffc091233 100644 --- a/activesupport/lib/active_support/notifications/fanout.rb +++ b/activesupport/lib/active_support/notifications/fanout.rb @@ -1,23 +1,34 @@ +require 'mutex_m' + module ActiveSupport module Notifications # This is a default queue implementation that ships with Notifications. # It just pushes events to all registered log subscribers. + # + # This class is thread safe. All methods are reentrant. class Fanout + include Mutex_m + def initialize @subscribers = [] @listeners_for = {} + super end def subscribe(pattern = nil, block = Proc.new) subscriber = Subscribers.new pattern, block - @subscribers << subscriber - @listeners_for.clear + synchronize do + @subscribers << subscriber + @listeners_for.clear + end subscriber end def unsubscribe(subscriber) - @subscribers.reject! { |s| s.matches?(subscriber) } - @listeners_for.clear + synchronize do + @subscribers.reject! { |s| s.matches?(subscriber) } + @listeners_for.clear + end end def start(name, id, payload) @@ -33,7 +44,9 @@ module ActiveSupport end def listeners_for(name) - @listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) } + synchronize do + @listeners_for[name] ||= @subscribers.select { |s| s.subscribed_to?(name) } + end end def listening?(name) @@ -85,9 +98,7 @@ module ActiveSupport class Timed < Evented def initialize(pattern, delegate) - @timestack = Hash.new { |h,id| - h[id] = Hash.new { |ids,name| ids[name] = [] } - } + @timestack = [] super end @@ -96,11 +107,11 @@ module ActiveSupport end def start(name, id, payload) - @timestack[id][name].push Time.now + @timestack.push Time.now end def finish(name, id, payload) - started = @timestack[id][name].pop + started = @timestack.pop @delegate.call(name, started, Time.now, id, payload) end end diff --git a/activesupport/lib/active_support/notifications/instrumenter.rb b/activesupport/lib/active_support/notifications/instrumenter.rb index 58e292c658..78d0397f1f 100644 --- a/activesupport/lib/active_support/notifications/instrumenter.rb +++ b/activesupport/lib/active_support/notifications/instrumenter.rb @@ -1,3 +1,5 @@ +require 'securerandom' + module ActiveSupport module Notifications # Instrumentors are stored in a thread local. @@ -31,7 +33,8 @@ module ActiveSupport end class Event - attr_reader :name, :time, :end, :transaction_id, :payload, :duration + attr_reader :name, :time, :transaction_id, :payload, :children + attr_accessor :end def initialize(name, start, ending, transaction_id, payload) @name = name @@ -39,12 +42,19 @@ module ActiveSupport @time = start @transaction_id = transaction_id @end = ending - @duration = 1000.0 * (@end - @time) + @children = [] + end + + def duration + 1000.0 * (self.end - time) + end + + def <<(event) + @children << event end def parent_of?(event) - start = (time - event.time) * 1000 - start <= 0 && (start + duration >= event.duration) + @children.include? event end end end diff --git a/activesupport/lib/active_support/testing/isolation.rb b/activesupport/lib/active_support/testing/isolation.rb index 1a0681e850..50ec50ca52 100644 --- a/activesupport/lib/active_support/testing/isolation.rb +++ b/activesupport/lib/active_support/testing/isolation.rb @@ -33,6 +33,45 @@ module ActiveSupport end module Isolation + require 'thread' + + class ParallelEach + include Enumerable + + # default to 2 cores + CORES = (ENV['TEST_CORES'] || 2).to_i + + def initialize list + @list = list + @queue = SizedQueue.new CORES + end + + def grep pattern + self.class.new super + end + + def each + threads = CORES.times.map { + Thread.new { + while job = @queue.pop + yield job + end + } + } + @list.each { |i| @queue << i } + CORES.times { @queue << nil } + threads.each(&:join) + end + end + + def self.included klass + klass.extend(Module.new { + def test_methods + ParallelEach.new super + end + }) + end + def self.forking_env? !ENV["NO_FORK"] && ((RbConfig::CONFIG['host_os'] !~ /mswin|mingw/) && (RUBY_PLATFORM !~ /java/)) end |