activesupport 3.0.0.rc → 3.0.0.rc2

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of activesupport might be problematic. Click here for more details.

Files changed (68) hide show
  1. data/CHANGELOG +42 -37
  2. data/lib/active_support/base64.rb +3 -3
  3. data/lib/active_support/benchmarkable.rb +3 -3
  4. data/lib/active_support/cache.rb +46 -56
  5. data/lib/active_support/cache/mem_cache_store.rb +3 -4
  6. data/lib/active_support/cache/memory_store.rb +5 -5
  7. data/lib/active_support/cache/strategy/local_cache.rb +5 -5
  8. data/lib/active_support/callbacks.rb +13 -3
  9. data/lib/active_support/concern.rb +35 -0
  10. data/lib/active_support/configurable.rb +2 -2
  11. data/lib/active_support/core_ext/array/conversions.rb +6 -6
  12. data/lib/active_support/core_ext/array/random_access.rb +4 -4
  13. data/lib/active_support/core_ext/array/uniq_by.rb +1 -1
  14. data/lib/active_support/core_ext/array/wrap.rb +30 -4
  15. data/lib/active_support/core_ext/class/attribute.rb +27 -4
  16. data/lib/active_support/core_ext/class/attribute_accessors.rb +16 -0
  17. data/lib/active_support/core_ext/class/inheritable_attributes.rb +25 -3
  18. data/lib/active_support/core_ext/date/calculations.rb +15 -15
  19. data/lib/active_support/core_ext/date_time/conversions.rb +6 -6
  20. data/lib/active_support/core_ext/date_time/zones.rb +1 -1
  21. data/lib/active_support/core_ext/enumerable.rb +6 -5
  22. data/lib/active_support/core_ext/hash/conversions.rb +11 -11
  23. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -3
  24. data/lib/active_support/core_ext/integer/time.rb +2 -2
  25. data/lib/active_support/core_ext/kernel/reporting.rb +1 -1
  26. data/lib/active_support/core_ext/module/anonymous.rb +1 -1
  27. data/lib/active_support/core_ext/module/attr_accessor_with_default.rb +2 -2
  28. data/lib/active_support/core_ext/module/attribute_accessors.rb +1 -1
  29. data/lib/active_support/core_ext/module/remove_method.rb +1 -1
  30. data/lib/active_support/core_ext/module/synchronization.rb +2 -2
  31. data/lib/active_support/core_ext/numeric/time.rb +9 -9
  32. data/lib/active_support/core_ext/object.rb +1 -0
  33. data/lib/active_support/core_ext/object/blank.rb +1 -1
  34. data/lib/active_support/core_ext/object/instance_variables.rb +5 -5
  35. data/lib/active_support/core_ext/object/returning.rb +43 -0
  36. data/lib/active_support/core_ext/range/conversions.rb +1 -1
  37. data/lib/active_support/core_ext/string/access.rb +7 -7
  38. data/lib/active_support/core_ext/string/inflections.rb +8 -6
  39. data/lib/active_support/core_ext/string/multibyte.rb +5 -5
  40. data/lib/active_support/core_ext/time/calculations.rb +2 -2
  41. data/lib/active_support/core_ext/time/conversions.rb +1 -1
  42. data/lib/active_support/core_ext/time/zones.rb +3 -3
  43. data/lib/active_support/dependencies.rb +56 -38
  44. data/lib/active_support/duration.rb +1 -1
  45. data/lib/active_support/hash_with_indifferent_access.rb +9 -3
  46. data/lib/active_support/i18n_railtie.rb +1 -1
  47. data/lib/active_support/lazy_load_hooks.rb +20 -1
  48. data/lib/active_support/locale/en.yml +3 -3
  49. data/lib/active_support/log_subscriber.rb +32 -33
  50. data/lib/active_support/log_subscriber/test_helper.rb +1 -1
  51. data/lib/active_support/message_encryptor.rb +17 -17
  52. data/lib/active_support/message_verifier.rb +7 -7
  53. data/lib/active_support/multibyte.rb +1 -1
  54. data/lib/active_support/multibyte/chars.rb +37 -36
  55. data/lib/active_support/multibyte/unicode.rb +4 -4
  56. data/lib/active_support/notifications.rb +3 -3
  57. data/lib/active_support/secure_random.rb +13 -13
  58. data/lib/active_support/testing/assertions.rb +8 -6
  59. data/lib/active_support/testing/declarative.rb +4 -4
  60. data/lib/active_support/testing/isolation.rb +1 -1
  61. data/lib/active_support/testing/pending.rb +3 -3
  62. data/lib/active_support/testing/performance.rb +9 -5
  63. data/lib/active_support/time_with_zone.rb +2 -2
  64. data/lib/active_support/version.rb +1 -1
  65. data/lib/active_support/xml_mini/nokogiri.rb +6 -1
  66. data/lib/active_support/xml_mini/nokogirisax.rb +7 -2
  67. data/lib/active_support/xml_mini/rexml.rb +1 -1
  68. metadata +5 -4
@@ -1,3 +1,5 @@
1
+ require 'active_support/inflector/methods'
2
+ require 'active_support/inflector/inflections'
1
3
  # String inflections define new methods on the String class to transform names for different purposes.
2
4
  # For instance, you can figure out the name of a database from the name of a class.
3
5
  #
@@ -70,7 +72,7 @@ class String
70
72
  alias_method :titlecase, :titleize
71
73
 
72
74
  # The reverse of +camelize+. Makes an underscored, lowercase form from the expression in the string.
73
- #
75
+ #
74
76
  # +underscore+ will also change '::' to '/' to convert namespaces to paths.
75
77
  #
76
78
  # "ActiveRecord".underscore # => "active_record"
@@ -95,7 +97,7 @@ class String
95
97
  end
96
98
 
97
99
  # Replaces special characters in a string so that it may be used as part of a 'pretty' URL.
98
- #
100
+ #
99
101
  # ==== Examples
100
102
  #
101
103
  # class Person
@@ -103,10 +105,10 @@ class String
103
105
  # "#{id}-#{name.parameterize}"
104
106
  # end
105
107
  # end
106
- #
108
+ #
107
109
  # @person = Person.find(1)
108
110
  # # => #<Person id: 1, name: "Donald E. Knuth">
109
- #
111
+ #
110
112
  # <%= link_to(@person.name, person_path %>
111
113
  # # => <a href="/person/1-donald-e-knuth">Donald E. Knuth</a>
112
114
  def parameterize(sep = '-')
@@ -136,11 +138,11 @@ class String
136
138
  def classify
137
139
  ActiveSupport::Inflector.classify(self)
138
140
  end
139
-
141
+
140
142
  # Capitalizes the first word, turns underscores into spaces, and strips '_id'.
141
143
  # Like +titleize+, this is meant for creating pretty output.
142
144
  #
143
- # "employee_salary" # => "Employee salary"
145
+ # "employee_salary" # => "Employee salary"
144
146
  # "author_id" # => "Author"
145
147
  def humanize
146
148
  ActiveSupport::Inflector.humanize(self)
@@ -12,11 +12,11 @@ class String
12
12
  # class. If the proxy class doesn't respond to a certain method, it's forwarded to the encapsuled string.
13
13
  #
14
14
  # name = 'Claus Müller'
15
- # name.reverse #=> "rell??M sualC"
16
- # name.length #=> 13
15
+ # name.reverse # => "rell??M sualC"
16
+ # name.length # => 13
17
17
  #
18
- # name.mb_chars.reverse.to_s #=> "rellüM sualC"
19
- # name.mb_chars.length #=> 12
18
+ # name.mb_chars.reverse.to_s # => "rellüM sualC"
19
+ # name.mb_chars.length # => 12
20
20
  #
21
21
  # In Ruby 1.9 and newer +mb_chars+ returns +self+ because String is (mostly) encoding aware. This means that
22
22
  # it becomes easy to run one version of your code on multiple Ruby versions.
@@ -26,7 +26,7 @@ class String
26
26
  # All the methods on the Chars proxy which normally return a string will return a Chars object. This allows
27
27
  # method chaining on the result of any of these methods.
28
28
  #
29
- # name.mb_chars.reverse.length #=> 12
29
+ # name.mb_chars.reverse.length # => 12
30
30
  #
31
31
  # == Interoperability and configuration
32
32
  #
@@ -92,12 +92,12 @@ class Time
92
92
  options[:weeks], partial_weeks = options[:weeks].divmod(1)
93
93
  options[:days] = (options[:days] || 0) + 7 * partial_weeks
94
94
  end
95
-
95
+
96
96
  unless options[:days].nil?
97
97
  options[:days], partial_days = options[:days].divmod(1)
98
98
  options[:hours] = (options[:hours] || 0) + 24 * partial_days
99
99
  end
100
-
100
+
101
101
  d = to_date.advance(options)
102
102
  time_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
103
103
  seconds_to_advance = (options[:seconds] || 0) + (options[:minutes] || 0) * 60 + (options[:hours] || 0) * 3600
@@ -46,7 +46,7 @@ class Time
46
46
  end
47
47
  alias_method :to_default_s, :to_s
48
48
  alias_method :to_s, :to_formatted_s
49
-
49
+
50
50
  # Returns the UTC offset as an +HH:MM formatted string.
51
51
  #
52
52
  # Time.local(2000).formatted_offset # => "-06:00"
@@ -4,13 +4,13 @@ class Time
4
4
  class << self
5
5
  attr_accessor :zone_default
6
6
 
7
- # Returns the TimeZone for the current request, if this has been set (via Time.zone=).
7
+ # Returns the TimeZone for the current request, if this has been set (via Time.zone=).
8
8
  # If <tt>Time.zone</tt> has not been set for the current request, returns the TimeZone specified in <tt>config.time_zone</tt>.
9
9
  def zone
10
10
  Thread.current[:time_zone] || zone_default
11
11
  end
12
12
 
13
- # Sets <tt>Time.zone</tt> to a TimeZone object for the current request/thread.
13
+ # Sets <tt>Time.zone</tt> to a TimeZone object for the current request/thread.
14
14
  #
15
15
  # This method accepts any of the following:
16
16
  #
@@ -63,7 +63,7 @@ class Time
63
63
  # This method is similar to Time#localtime, except that it uses <tt>Time.zone</tt> as the local zone
64
64
  # instead of the operating system's time zone.
65
65
  #
66
- # You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument,
66
+ # You can also pass in a TimeZone instance or string that identifies a TimeZone as an argument,
67
67
  # and the conversion will be based on that zone instead of <tt>Time.zone</tt>.
68
68
  #
69
69
  # Time.utc(2000).in_time_zone('Alaska') # => Fri, 31 Dec 1999 15:00:00 AKST -09:00
@@ -63,58 +63,78 @@ module ActiveSupport #:nodoc:
63
63
  mattr_accessor :log_activity
64
64
  self.log_activity = false
65
65
 
66
- class WatchStack < Array
66
+ # The WatchStack keeps a stack of the modules being watched as files are loaded.
67
+ # If a file in the process of being loaded (parent.rb) triggers the load of
68
+ # another file (child.rb) the stack will ensure that child.rb handles the new
69
+ # constants.
70
+ #
71
+ # If child.rb is being autoloaded, its constants will be added to
72
+ # autoloaded_constants. If it was being `require`d, they will be discarded.
73
+ #
74
+ # This is handled by walking back up the watch stack and adding the constants
75
+ # found by child.rb to the list of original constants in parent.rb
76
+ class WatchStack < Hash
77
+ # @watching is a stack of lists of constants being watched. For instance,
78
+ # if parent.rb is autoloaded, the stack will look like [[Object]]. If parent.rb
79
+ # then requires namespace/child.rb, the stack will look like [[Object], [Namespace]].
80
+
67
81
  def initialize
68
- @mutex = Mutex.new
82
+ @watching = []
83
+ super { |h,k| h[k] = [] }
69
84
  end
70
85
 
71
- def self.locked(*methods)
72
- methods.each { |m| class_eval "def #{m}(*) lock { super } end", __FILE__, __LINE__ }
73
- end
86
+ # return a list of new constants found since the last call to watch_modules
87
+ def new_constants
88
+ constants = []
74
89
 
75
- locked :concat, :each, :delete_if, :<<
90
+ # Grab the list of namespaces that we're looking for new constants under
91
+ @watching.last.each do |namespace|
92
+ # Retrieve the constants that were present under the namespace when watch_modules
93
+ # was originally called
94
+ original_constants = self[namespace].last
76
95
 
77
- def new_constants_for(frames)
78
- constants = []
79
- frames.each do |mod_name, prior_constants|
80
- mod = Inflector.constantize(mod_name) if Dependencies.qualified_const_defined?(mod_name)
96
+ mod = Inflector.constantize(namespace) if Dependencies.qualified_const_defined?(namespace)
81
97
  next unless mod.is_a?(Module)
82
98
 
83
- new_constants = mod.local_constant_names - prior_constants
84
-
85
- # If we are checking for constants under, say, :Object, nested under something
86
- # else that is checking for constants also under :Object, make sure the
87
- # parent knows that we have found, and taken care of, the constant.
88
- #
89
- # In particular, this means that since Kernel.require discards the constants
90
- # it finds, parents will be notified that about those constants, and not
91
- # consider them "new". As a result, they will not be added to the
92
- # autoloaded_constants list.
93
- each do |key, value|
94
- value.concat(new_constants) if key == mod_name
99
+ # Get a list of the constants that were added
100
+ new_constants = mod.local_constant_names - original_constants
101
+
102
+ # self[namespace] returns an Array of the constants that are being evaluated
103
+ # for that namespace. For instance, if parent.rb requires child.rb, the first
104
+ # element of self[Object] will be an Array of the constants that were present
105
+ # before parent.rb was required. The second element will be an Array of the
106
+ # constants that were present before child.rb was required.
107
+ self[namespace].each do |namespace_constants|
108
+ namespace_constants.concat(new_constants)
95
109
  end
96
110
 
111
+ # Normalize the list of new constants, and add them to the list we will return
97
112
  new_constants.each do |suffix|
98
- constants << ([mod_name, suffix] - ["Object"]).join("::")
113
+ constants << ([namespace, suffix] - ["Object"]).join("::")
99
114
  end
100
115
  end
101
116
  constants
117
+ ensure
118
+ # A call to new_constants is always called after a call to watch_modules
119
+ pop_modules(@watching.pop)
102
120
  end
103
121
 
104
122
  # Add a set of modules to the watch stack, remembering the initial constants
105
- def add_modules(modules)
106
- list = modules.map do |desc|
107
- name = Dependencies.to_constant_name(desc)
108
- consts = Dependencies.qualified_const_defined?(name) ?
109
- Inflector.constantize(name).local_constant_names : []
110
- [name, consts]
123
+ def watch_namespaces(namespaces)
124
+ watching = []
125
+ namespaces.map do |namespace|
126
+ module_name = Dependencies.to_constant_name(namespace)
127
+ original_constants = Dependencies.qualified_const_defined?(module_name) ?
128
+ Inflector.constantize(module_name).local_constant_names : []
129
+
130
+ watching << module_name
131
+ self[module_name] << original_constants
111
132
  end
112
- concat(list)
113
- list
133
+ @watching << watching
114
134
  end
115
135
 
116
- def lock
117
- @mutex.synchronize { yield self }
136
+ def pop_modules(modules)
137
+ modules.each { |mod| self[mod].pop }
118
138
  end
119
139
  end
120
140
 
@@ -563,14 +583,15 @@ module ActiveSupport #:nodoc:
563
583
  # and will be removed immediately.
564
584
  def new_constants_in(*descs)
565
585
  log_call(*descs)
566
- watch_frames = constant_watch_stack.add_modules(descs)
567
586
 
587
+ constant_watch_stack.watch_namespaces(descs)
568
588
  aborting = true
589
+
569
590
  begin
570
591
  yield # Now yield to the code that is to define new constants.
571
592
  aborting = false
572
593
  ensure
573
- new_constants = constant_watch_stack.new_constants_for(watch_frames)
594
+ new_constants = constant_watch_stack.new_constants
574
595
 
575
596
  log "New constants: #{new_constants * ', '}"
576
597
  return new_constants unless aborting
@@ -580,9 +601,6 @@ module ActiveSupport #:nodoc:
580
601
  end
581
602
 
582
603
  return []
583
- ensure
584
- # Remove the stack frames that we added.
585
- watch_frames.each {|f| constant_watch_stack.delete(f) } if watch_frames.present?
586
604
  end
587
605
 
588
606
  class LoadingModule #:nodoc:
@@ -3,7 +3,7 @@ require 'active_support/core_ext/array/conversions'
3
3
  require 'active_support/core_ext/object/acts_like'
4
4
 
5
5
  module ActiveSupport
6
- # Provides accurate date and time measurements using Date#advance and
6
+ # Provides accurate date and time measurements using Date#advance and
7
7
  # Time#advance, respectively. It mainly supports the methods on Numeric.
8
8
  # Example:
9
9
  #
@@ -27,6 +27,12 @@ module ActiveSupport
27
27
  end
28
28
  end
29
29
 
30
+ def self.new_from_hash_copying_default(hash)
31
+ ActiveSupport::HashWithIndifferentAccess.new(hash).tap do |new_hash|
32
+ new_hash.default = hash.default
33
+ end
34
+ end
35
+
30
36
  alias_method :regular_writer, :[]= unless method_defined?(:regular_writer)
31
37
  alias_method :regular_update, :update unless method_defined?(:regular_update)
32
38
 
@@ -101,7 +107,7 @@ module ActiveSupport
101
107
  # Performs the opposite of merge, with the keys and values from the first hash taking precedence over the second.
102
108
  # This overloaded definition prevents returning a regular hash, if reverse_merge is called on a HashWithDifferentAccess.
103
109
  def reverse_merge(other_hash)
104
- super other_hash.with_indifferent_access
110
+ super self.class.new_from_hash_copying_default(other_hash)
105
111
  end
106
112
 
107
113
  def reverse_merge!(other_hash)
@@ -132,9 +138,9 @@ module ActiveSupport
132
138
  def convert_value(value)
133
139
  case value
134
140
  when Hash
135
- value.with_indifferent_access
141
+ self.class.new_from_hash_copying_default(value)
136
142
  when Array
137
- value.collect { |e| e.is_a?(Hash) ? e.with_indifferent_access : e }
143
+ value.collect { |e| e.is_a?(Hash) ? self.class.new_from_hash_copying_default(e) : e }
138
144
  else
139
145
  value
140
146
  end
@@ -66,7 +66,7 @@ module I18n
66
66
 
67
67
  I18n.fallbacks = I18n::Locale::Fallbacks.new(*args)
68
68
  end
69
-
69
+
70
70
  def self.validate_fallbacks(fallbacks)
71
71
  case fallbacks
72
72
  when ActiveSupport::OrderedOptions
@@ -1,3 +1,22 @@
1
+ # lazy_load_hooks allows rails to lazily load a lot of components and thus making the app boot faster. Because of
2
+ # this feature now there is no need to require <tt>ActiveRecord::Base</tt> at boot time purely to apply configuration. Instead
3
+ # a hook is registered that applies configuration once <tt>ActiveRecord::Base</tt> is loaded. Here <tt>ActiveRecord::Base</tt> is used
4
+ # as example but this feature can be applied elsewhere too.
5
+ #
6
+ # Here is an example where +on_load+ method is called to register a hook.
7
+ #
8
+ # initializer "active_record.initialize_timezone" do
9
+ # ActiveSupport.on_load(:active_record) do
10
+ # self.time_zone_aware_attributes = true
11
+ # self.default_timezone = :utc
12
+ # end
13
+ # end
14
+ #
15
+ # When the entirety of +activerecord/lib/active_record/base.rb+ has been evaluated then +run_load_hooks+ is invoked.
16
+ # The very last line of +activerecord/lib/active_record/base.rb+ is:
17
+ #
18
+ # ActiveSupport.run_load_hooks(:active_record, ActiveRecord::Base)
19
+ #
1
20
  module ActiveSupport
2
21
  @load_hooks = Hash.new {|h,k| h[k] = [] }
3
22
  @loaded = {}
@@ -24,4 +43,4 @@ module ActiveSupport
24
43
  execute_hook(base, options, hook)
25
44
  end
26
45
  end
27
- end
46
+ end
@@ -7,10 +7,10 @@ en:
7
7
  default: "%Y-%m-%d"
8
8
  short: "%b %d"
9
9
  long: "%B %d, %Y"
10
-
10
+
11
11
  day_names: [Sunday, Monday, Tuesday, Wednesday, Thursday, Friday, Saturday]
12
12
  abbr_day_names: [Sun, Mon, Tue, Wed, Thu, Fri, Sat]
13
-
13
+
14
14
  # Don't forget the nil at the beginning; there's no such thing as a 0th month
15
15
  month_names: [~, January, February, March, April, May, June, July, August, September, October, November, December]
16
16
  abbr_month_names: [~, Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec]
@@ -27,7 +27,7 @@ en:
27
27
  long: "%B %d, %Y %H:%M"
28
28
  am: "am"
29
29
  pm: "pm"
30
-
30
+
31
31
  # Used in array.to_sentence.
32
32
  support:
33
33
  array:
@@ -31,23 +31,10 @@ module ActiveSupport
31
31
  # all logs when the request finishes (via action_dispatch.callback notification) in
32
32
  # a Rails environment.
33
33
  class LogSubscriber
34
- mattr_accessor :colorize_logging
35
- self.colorize_logging = true
36
-
37
- class_attribute :logger
38
-
39
- class << self
40
- remove_method :logger
41
- end
42
-
43
- def self.logger
44
- @logger ||= Rails.logger if defined?(Rails)
45
- end
46
-
47
34
  # Embed in a String to clear all previous ANSI sequences.
48
35
  CLEAR = "\e[0m"
49
36
  BOLD = "\e[1m"
50
-
37
+
51
38
  # Colors
52
39
  BLACK = "\e[30m"
53
40
  RED = "\e[31m"
@@ -58,32 +45,44 @@ module ActiveSupport
58
45
  CYAN = "\e[36m"
59
46
  WHITE = "\e[37m"
60
47
 
61
- def self.attach_to(namespace, log_subscriber=new, notifier=ActiveSupport::Notifications)
62
- log_subscribers << log_subscriber
63
- @@flushable_loggers = nil
48
+ mattr_accessor :colorize_logging
49
+ self.colorize_logging = true
50
+
51
+ class_attribute :logger
52
+
53
+ class << self
54
+ remove_method :logger
55
+ def logger
56
+ @logger ||= Rails.logger if defined?(Rails)
57
+ end
58
+
59
+ def attach_to(namespace, log_subscriber=new, notifier=ActiveSupport::Notifications)
60
+ log_subscribers << log_subscriber
61
+ @@flushable_loggers = nil
64
62
 
65
- log_subscriber.public_methods(false).each do |event|
66
- next if 'call' == event.to_s
63
+ log_subscriber.public_methods(false).each do |event|
64
+ next if 'call' == event.to_s
67
65
 
68
- notifier.subscribe("#{event}.#{namespace}", log_subscriber)
66
+ notifier.subscribe("#{event}.#{namespace}", log_subscriber)
67
+ end
69
68
  end
70
- end
71
69
 
72
- def self.log_subscribers
73
- @@log_subscribers ||= []
74
- end
70
+ def log_subscribers
71
+ @@log_subscribers ||= []
72
+ end
75
73
 
76
- def self.flushable_loggers
77
- @@flushable_loggers ||= begin
78
- loggers = log_subscribers.map(&:logger)
79
- loggers.uniq!
80
- loggers.select { |l| l.respond_to?(:flush) }
74
+ def flushable_loggers
75
+ @@flushable_loggers ||= begin
76
+ loggers = log_subscribers.map(&:logger)
77
+ loggers.uniq!
78
+ loggers.select { |l| l.respond_to?(:flush) }
79
+ end
81
80
  end
82
- end
83
81
 
84
- # Flush all log_subscribers' logger.
85
- def self.flush_all!
86
- flushable_loggers.each(&:flush)
82
+ # Flush all log_subscribers' logger.
83
+ def flush_all!
84
+ flushable_loggers.each(&:flush)
85
+ end
87
86
  end
88
87
 
89
88
  def call(message, *args)