activesupport 4.0.13 → 4.2.11.3

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 (166) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +406 -418
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +7 -2
  5. data/lib/active_support/backtrace_cleaner.rb +8 -8
  6. data/lib/active_support/benchmarkable.rb +0 -10
  7. data/lib/active_support/cache/file_store.rb +32 -22
  8. data/lib/active_support/cache/mem_cache_store.rb +5 -7
  9. data/lib/active_support/cache/memory_store.rb +1 -0
  10. data/lib/active_support/cache/strategy/local_cache.rb +11 -30
  11. data/lib/active_support/cache/strategy/local_cache_middleware.rb +44 -0
  12. data/lib/active_support/cache.rb +75 -41
  13. data/lib/active_support/callbacks.rb +482 -261
  14. data/lib/active_support/concern.rb +23 -7
  15. data/lib/active_support/configurable.rb +1 -1
  16. data/lib/active_support/core_ext/array/access.rb +11 -1
  17. data/lib/active_support/core_ext/array/conversions.rb +2 -17
  18. data/lib/active_support/core_ext/array/grouping.rb +29 -12
  19. data/lib/active_support/core_ext/array/prepend_and_append.rb +2 -2
  20. data/lib/active_support/core_ext/array.rb +0 -1
  21. data/lib/active_support/core_ext/big_decimal/conversions.rb +0 -15
  22. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +16 -0
  23. data/lib/active_support/core_ext/class/attribute.rb +1 -2
  24. data/lib/active_support/core_ext/class/attribute_accessors.rb +4 -170
  25. data/lib/active_support/core_ext/class/delegating_attributes.rb +13 -8
  26. data/lib/active_support/core_ext/class/subclasses.rb +0 -2
  27. data/lib/active_support/core_ext/class.rb +0 -1
  28. data/lib/active_support/core_ext/date/calculations.rb +10 -0
  29. data/lib/active_support/core_ext/date/conversions.rb +9 -1
  30. data/lib/active_support/core_ext/date/zones.rb +2 -33
  31. data/lib/active_support/core_ext/date_and_time/calculations.rb +41 -11
  32. data/lib/active_support/core_ext/date_and_time/compatibility.rb +15 -0
  33. data/lib/active_support/core_ext/date_and_time/zones.rb +41 -0
  34. data/lib/active_support/core_ext/date_time/calculations.rb +45 -22
  35. data/lib/active_support/core_ext/date_time/compatibility.rb +16 -0
  36. data/lib/active_support/core_ext/date_time/conversions.rb +4 -2
  37. data/lib/active_support/core_ext/date_time/zones.rb +3 -21
  38. data/lib/active_support/core_ext/date_time.rb +1 -0
  39. data/lib/active_support/core_ext/digest/uuid.rb +51 -0
  40. data/lib/active_support/core_ext/enumerable.rb +17 -1
  41. data/lib/active_support/core_ext/file/atomic.rb +1 -1
  42. data/lib/active_support/core_ext/hash/compact.rb +24 -0
  43. data/lib/active_support/core_ext/hash/conversions.rb +9 -8
  44. data/lib/active_support/core_ext/hash/except.rb +8 -2
  45. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -0
  46. data/lib/active_support/core_ext/hash/keys.rb +25 -19
  47. data/lib/active_support/core_ext/hash/slice.rb +8 -2
  48. data/lib/active_support/core_ext/hash/transform_values.rb +23 -0
  49. data/lib/active_support/core_ext/hash.rb +2 -1
  50. data/lib/active_support/core_ext/integer/time.rb +0 -15
  51. data/lib/active_support/core_ext/kernel/concern.rb +10 -0
  52. data/lib/active_support/core_ext/kernel/debugger.rb +1 -1
  53. data/lib/active_support/core_ext/kernel/reporting.rb +13 -2
  54. data/lib/active_support/core_ext/kernel.rb +3 -2
  55. data/lib/active_support/core_ext/load_error.rb +4 -1
  56. data/lib/active_support/core_ext/marshal.rb +8 -5
  57. data/lib/active_support/core_ext/module/aliasing.rb +2 -2
  58. data/lib/active_support/core_ext/module/attr_internal.rb +2 -1
  59. data/lib/active_support/core_ext/module/attribute_accessors.rb +160 -14
  60. data/lib/active_support/core_ext/module/concerning.rb +135 -0
  61. data/lib/active_support/core_ext/module/delegation.rb +53 -25
  62. data/lib/active_support/core_ext/module/deprecation.rb +0 -2
  63. data/lib/active_support/core_ext/module/introspection.rb +0 -16
  64. data/lib/active_support/core_ext/module/method_transplanting.rb +13 -0
  65. data/lib/active_support/core_ext/module.rb +1 -0
  66. data/lib/active_support/core_ext/numeric/conversions.rb +11 -3
  67. data/lib/active_support/core_ext/numeric/time.rb +4 -29
  68. data/lib/active_support/core_ext/object/blank.rb +44 -18
  69. data/lib/active_support/core_ext/object/deep_dup.rb +6 -6
  70. data/lib/active_support/core_ext/object/duplicable.rb +72 -33
  71. data/lib/active_support/core_ext/object/inclusion.rb +16 -15
  72. data/lib/active_support/core_ext/object/itself.rb +15 -0
  73. data/lib/active_support/core_ext/object/json.rb +197 -0
  74. data/lib/active_support/core_ext/object/to_query.rb +14 -6
  75. data/lib/active_support/core_ext/object/try.rb +36 -14
  76. data/lib/active_support/core_ext/object/with_options.rb +30 -3
  77. data/lib/active_support/core_ext/object.rb +2 -1
  78. data/lib/active_support/core_ext/string/access.rb +35 -35
  79. data/lib/active_support/core_ext/string/conversions.rb +10 -9
  80. data/lib/active_support/core_ext/string/exclude.rb +3 -3
  81. data/lib/active_support/core_ext/string/filters.rb +51 -3
  82. data/lib/active_support/core_ext/string/inflections.rb +15 -10
  83. data/lib/active_support/core_ext/string/output_safety.rb +97 -33
  84. data/lib/active_support/core_ext/string/zones.rb +1 -0
  85. data/lib/active_support/core_ext/thread.rb +12 -5
  86. data/lib/active_support/core_ext/time/calculations.rb +47 -68
  87. data/lib/active_support/core_ext/time/compatibility.rb +14 -0
  88. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  89. data/lib/active_support/core_ext/time/zones.rb +2 -20
  90. data/lib/active_support/core_ext/time.rb +1 -0
  91. data/lib/active_support/core_ext.rb +0 -1
  92. data/lib/active_support/dependencies/autoload.rb +1 -1
  93. data/lib/active_support/dependencies.rb +64 -25
  94. data/lib/active_support/deprecation/behaviors.rb +4 -4
  95. data/lib/active_support/deprecation.rb +4 -4
  96. data/lib/active_support/duration.rb +55 -11
  97. data/lib/active_support/file_update_checker.rb +1 -1
  98. data/lib/active_support/gem_version.rb +15 -0
  99. data/lib/active_support/hash_with_indifferent_access.rb +39 -11
  100. data/lib/active_support/i18n.rb +4 -4
  101. data/lib/active_support/i18n_railtie.rb +1 -7
  102. data/lib/active_support/inflections.rb +6 -1
  103. data/lib/active_support/inflector/inflections.rb +19 -19
  104. data/lib/active_support/inflector/methods.rb +66 -25
  105. data/lib/active_support/json/decoding.rb +15 -22
  106. data/lib/active_support/json/encoding.rb +125 -286
  107. data/lib/active_support/key_generator.rb +8 -10
  108. data/lib/active_support/lazy_load_hooks.rb +1 -1
  109. data/lib/active_support/log_subscriber/test_helper.rb +1 -1
  110. data/lib/active_support/logger.rb +51 -1
  111. data/lib/active_support/logger_silence.rb +7 -4
  112. data/lib/active_support/logger_thread_safe_level.rb +32 -0
  113. data/lib/active_support/message_encryptor.rb +14 -6
  114. data/lib/active_support/message_verifier.rb +16 -12
  115. data/lib/active_support/multibyte/chars.rb +2 -3
  116. data/lib/active_support/multibyte/unicode.rb +46 -58
  117. data/lib/active_support/notifications/fanout.rb +12 -7
  118. data/lib/active_support/notifications/instrumenter.rb +2 -1
  119. data/lib/active_support/notifications.rb +11 -6
  120. data/lib/active_support/number_helper/number_converter.rb +182 -0
  121. data/lib/active_support/number_helper/number_to_currency_converter.rb +46 -0
  122. data/lib/active_support/number_helper/number_to_delimited_converter.rb +23 -0
  123. data/lib/active_support/number_helper/number_to_human_converter.rb +66 -0
  124. data/lib/active_support/number_helper/number_to_human_size_converter.rb +58 -0
  125. data/lib/active_support/number_helper/number_to_percentage_converter.rb +12 -0
  126. data/lib/active_support/number_helper/number_to_phone_converter.rb +49 -0
  127. data/lib/active_support/number_helper/number_to_rounded_converter.rb +87 -0
  128. data/lib/active_support/number_helper.rb +32 -324
  129. data/lib/active_support/ordered_options.rb +8 -0
  130. data/lib/active_support/per_thread_registry.rb +13 -10
  131. data/lib/active_support/security_utils.rb +27 -0
  132. data/lib/active_support/subscriber.rb +35 -3
  133. data/lib/active_support/test_case.rb +52 -19
  134. data/lib/active_support/testing/assertions.rb +1 -31
  135. data/lib/active_support/testing/autorun.rb +2 -2
  136. data/lib/active_support/testing/constant_lookup.rb +1 -5
  137. data/lib/active_support/testing/declarative.rb +7 -21
  138. data/lib/active_support/testing/isolation.rb +29 -69
  139. data/lib/active_support/testing/setup_and_teardown.rb +17 -2
  140. data/lib/active_support/testing/tagged_logging.rb +2 -2
  141. data/lib/active_support/testing/time_helpers.rb +134 -0
  142. data/lib/active_support/time.rb +0 -2
  143. data/lib/active_support/time_with_zone.rb +60 -40
  144. data/lib/active_support/values/time_zone.rb +101 -101
  145. data/lib/active_support/values/unicode_tables.dat +0 -0
  146. data/lib/active_support/version.rb +4 -7
  147. data/lib/active_support/xml_mini/jdom.rb +6 -5
  148. data/lib/active_support/xml_mini/libxml.rb +1 -3
  149. data/lib/active_support/xml_mini/libxmlsax.rb +1 -4
  150. data/lib/active_support/xml_mini/nokogiri.rb +1 -3
  151. data/lib/active_support/xml_mini/nokogirisax.rb +1 -3
  152. data/lib/active_support/xml_mini/rexml.rb +7 -8
  153. data/lib/active_support/xml_mini.rb +33 -15
  154. data/lib/active_support.rb +27 -2
  155. metadata +43 -43
  156. data/lib/active_support/basic_object.rb +0 -11
  157. data/lib/active_support/buffered_logger.rb +0 -21
  158. data/lib/active_support/core_ext/array/uniq_by.rb +0 -19
  159. data/lib/active_support/core_ext/hash/diff.rb +0 -14
  160. data/lib/active_support/core_ext/logger.rb +0 -67
  161. data/lib/active_support/core_ext/object/to_json.rb +0 -27
  162. data/lib/active_support/core_ext/proc.rb +0 -17
  163. data/lib/active_support/core_ext/string/encoding.rb +0 -8
  164. data/lib/active_support/file_watcher.rb +0 -36
  165. data/lib/active_support/json/variable.rb +0 -18
  166. data/lib/active_support/testing/pending.rb +0 -14
@@ -1,4 +1,5 @@
1
1
  require 'active_support/core_ext/hash/keys'
2
+ require 'active_support/core_ext/hash/reverse_merge'
2
3
 
3
4
  module ActiveSupport
4
5
  # Implements a hash where keys <tt>:foo</tt> and <tt>"foo"</tt> are considered
@@ -55,7 +56,7 @@ module ActiveSupport
55
56
  end
56
57
 
57
58
  def initialize(constructor = {})
58
- if constructor.is_a?(Hash)
59
+ if constructor.respond_to?(:to_hash)
59
60
  super()
60
61
  update(constructor)
61
62
  else
@@ -75,6 +76,7 @@ module ActiveSupport
75
76
  hash = hash.to_hash
76
77
  new(hash).tap do |new_hash|
77
78
  new_hash.default = hash.default
79
+ new_hash.default_proc = hash.default_proc if hash.default_proc
78
80
  end
79
81
  end
80
82
 
@@ -160,7 +162,7 @@ module ActiveSupport
160
162
  #
161
163
  # counters.fetch('foo') # => 1
162
164
  # counters.fetch(:bar, 0) # => 0
163
- # counters.fetch(:bar) {|key| 0} # => 0
165
+ # counters.fetch(:bar) { |key| 0 } # => 0
164
166
  # counters.fetch(:zoo) # => KeyError: key not found: "zoo"
165
167
  def fetch(key, *extras)
166
168
  super(convert_key(key), *extras)
@@ -173,13 +175,20 @@ module ActiveSupport
173
175
  # hash[:b] = 'y'
174
176
  # hash.values_at('a', 'b') # => ["x", "y"]
175
177
  def values_at(*indices)
176
- indices.collect {|key| self[convert_key(key)]}
178
+ indices.collect { |key| self[convert_key(key)] }
177
179
  end
178
180
 
179
- # Returns an exact copy of the hash.
181
+ # Returns a shallow copy of the hash.
182
+ #
183
+ # hash = ActiveSupport::HashWithIndifferentAccess.new({ a: { b: 'b' } })
184
+ # dup = hash.dup
185
+ # dup[:a][:c] = 'c'
186
+ #
187
+ # hash[:a][:c] # => nil
188
+ # dup[:a][:c] # => "c"
180
189
  def dup
181
190
  self.class.new(self).tap do |new_hash|
182
- new_hash.default = default
191
+ set_defaults(new_hash)
183
192
  end
184
193
  end
185
194
 
@@ -208,7 +217,7 @@ module ActiveSupport
208
217
  # Replaces the contents of this hash with other_hash.
209
218
  #
210
219
  # h = { "a" => 100, "b" => 200 }
211
- # h.replace({ "c" => 300, "d" => 400 }) #=> {"c"=>300, "d"=>400}
220
+ # h.replace({ "c" => 300, "d" => 400 }) # => {"c"=>300, "d"=>400}
212
221
  def replace(other_hash)
213
222
  super(self.class.new_from_hash_copying_default(other_hash))
214
223
  end
@@ -225,7 +234,7 @@ module ActiveSupport
225
234
  undef :symbolize_keys!
226
235
  undef :deep_symbolize_keys!
227
236
  def symbolize_keys; to_hash.symbolize_keys! end
228
- def deep_symbolize_keys; to_hash.deep_symbolize_keys end
237
+ def deep_symbolize_keys; to_hash.deep_symbolize_keys! end
229
238
  def to_options!; self end
230
239
 
231
240
  def select(*args, &block)
@@ -236,13 +245,24 @@ module ActiveSupport
236
245
  dup.tap { |hash| hash.reject!(*args, &block) }
237
246
  end
238
247
 
248
+ def transform_values(*args, &block)
249
+ return to_enum(:transform_values) unless block_given?
250
+ dup.tap { |hash| hash.transform_values!(*args, &block) }
251
+ end
252
+
253
+ def compact
254
+ dup.tap(&:compact!)
255
+ end
256
+
239
257
  # Convert to a regular hash with string keys.
240
258
  def to_hash
241
- _new_hash= {}
259
+ _new_hash = Hash.new
260
+ set_defaults(_new_hash)
261
+
242
262
  each do |key, value|
243
- _new_hash[convert_key(key)] = convert_value(value, for: :to_hash)
263
+ _new_hash[key] = convert_value(value, for: :to_hash)
244
264
  end
245
- Hash.new(default).merge!(_new_hash)
265
+ _new_hash
246
266
  end
247
267
 
248
268
  protected
@@ -258,7 +278,7 @@ module ActiveSupport
258
278
  value.nested_under_indifferent_access
259
279
  end
260
280
  elsif value.is_a?(Array)
261
- unless options[:for] == :assignment
281
+ if options[:for] != :assignment || value.frozen?
262
282
  value = value.dup
263
283
  end
264
284
  value.map! { |e| convert_value(e, options) }
@@ -266,6 +286,14 @@ module ActiveSupport
266
286
  value
267
287
  end
268
288
  end
289
+
290
+ def set_defaults(target)
291
+ if default_proc
292
+ target.default_proc = default_proc.dup
293
+ else
294
+ target.default = default
295
+ end
296
+ end
269
297
  end
270
298
  end
271
299
 
@@ -1,13 +1,13 @@
1
+ require 'active_support/core_ext/hash/deep_merge'
2
+ require 'active_support/core_ext/hash/except'
3
+ require 'active_support/core_ext/hash/slice'
1
4
  begin
2
- require 'active_support/core_ext/hash/deep_merge'
3
- require 'active_support/core_ext/hash/except'
4
- require 'active_support/core_ext/hash/slice'
5
5
  require 'i18n'
6
- require 'active_support/lazy_load_hooks'
7
6
  rescue LoadError => e
8
7
  $stderr.puts "The i18n gem is not available. Please add it to your Gemfile and run bundle install"
9
8
  raise e
10
9
  end
10
+ require 'active_support/lazy_load_hooks'
11
11
 
12
12
  ActiveSupport.run_load_hooks(:i18n)
13
13
  I18n.load_path << "#{File.dirname(__FILE__)}/locale/en.yml"
@@ -8,8 +8,6 @@ module I18n
8
8
  config.i18n.railties_load_path = []
9
9
  config.i18n.load_path = []
10
10
  config.i18n.fallbacks = ActiveSupport::OrderedOptions.new
11
- # Enforce I18n to check the available locales when setting a locale.
12
- config.i18n.enforce_available_locales = true
13
11
 
14
12
  # Set the i18n configuration after initialization since a lot of
15
13
  # configuration is still usually done in application initializers.
@@ -36,11 +34,7 @@ module I18n
36
34
  # Avoid issues with setting the default_locale by disabling available locales
37
35
  # check while configuring.
38
36
  enforce_available_locales = app.config.i18n.delete(:enforce_available_locales)
39
-
40
- if enforce_available_locales.nil?
41
- enforce_available_locales = I18n.enforce_available_locales
42
- end
43
-
37
+ enforce_available_locales = I18n.enforce_available_locales if enforce_available_locales.nil?
44
38
  I18n.enforce_available_locales = false
45
39
 
46
40
  app.config.i18n.each do |setting, value|
@@ -1,5 +1,11 @@
1
1
  require 'active_support/inflector/inflections'
2
2
 
3
+ #--
4
+ # Defines the standard inflection rules. These are the starting point for
5
+ # new projects and are not considered complete. The current set of inflection
6
+ # rules is frozen. This means, we do not change them to become more complete.
7
+ # This is a safety measure to keep existing applications from breaking.
8
+ #++
3
9
  module ActiveSupport
4
10
  Inflector.inflections(:en) do |inflect|
5
11
  inflect.plural(/$/, 's')
@@ -57,7 +63,6 @@ module ActiveSupport
57
63
  inflect.irregular('child', 'children')
58
64
  inflect.irregular('sex', 'sexes')
59
65
  inflect.irregular('move', 'moves')
60
- inflect.irregular('cow', 'kine')
61
66
  inflect.irregular('zombie', 'zombies')
62
67
 
63
68
  inflect.uncountable(%w(equipment information rice money species series fish sheep jeans police))
@@ -52,21 +52,21 @@ module ActiveSupport
52
52
  # into a non-delimited single lowercase word when passed to +underscore+.
53
53
  #
54
54
  # acronym 'HTML'
55
- # titleize 'html' #=> 'HTML'
56
- # camelize 'html' #=> 'HTML'
57
- # underscore 'MyHTML' #=> 'my_html'
55
+ # titleize 'html' # => 'HTML'
56
+ # camelize 'html' # => 'HTML'
57
+ # underscore 'MyHTML' # => 'my_html'
58
58
  #
59
59
  # The acronym, however, must occur as a delimited unit and not be part of
60
60
  # another word for conversions to recognize it:
61
61
  #
62
62
  # acronym 'HTTP'
63
- # camelize 'my_http_delimited' #=> 'MyHTTPDelimited'
64
- # camelize 'https' #=> 'Https', not 'HTTPs'
65
- # underscore 'HTTPS' #=> 'http_s', not 'https'
63
+ # camelize 'my_http_delimited' # => 'MyHTTPDelimited'
64
+ # camelize 'https' # => 'Https', not 'HTTPs'
65
+ # underscore 'HTTPS' # => 'http_s', not 'https'
66
66
  #
67
67
  # acronym 'HTTPS'
68
- # camelize 'https' #=> 'HTTPS'
69
- # underscore 'HTTPS' #=> 'https'
68
+ # camelize 'https' # => 'HTTPS'
69
+ # underscore 'HTTPS' # => 'https'
70
70
  #
71
71
  # Note: Acronyms that are passed to +pluralize+ will no longer be
72
72
  # recognized, since the acronym will not occur as a delimited unit in the
@@ -74,25 +74,25 @@ module ActiveSupport
74
74
  # form as an acronym as well:
75
75
  #
76
76
  # acronym 'API'
77
- # camelize(pluralize('api')) #=> 'Apis'
77
+ # camelize(pluralize('api')) # => 'Apis'
78
78
  #
79
79
  # acronym 'APIs'
80
- # camelize(pluralize('api')) #=> 'APIs'
80
+ # camelize(pluralize('api')) # => 'APIs'
81
81
  #
82
82
  # +acronym+ may be used to specify any word that contains an acronym or
83
83
  # otherwise needs to maintain a non-standard capitalization. The only
84
84
  # restriction is that the word must begin with a capital letter.
85
85
  #
86
86
  # acronym 'RESTful'
87
- # underscore 'RESTful' #=> 'restful'
88
- # underscore 'RESTfulController' #=> 'restful_controller'
89
- # titleize 'RESTfulController' #=> 'RESTful Controller'
90
- # camelize 'restful' #=> 'RESTful'
91
- # camelize 'restful_controller' #=> 'RESTfulController'
87
+ # underscore 'RESTful' # => 'restful'
88
+ # underscore 'RESTfulController' # => 'restful_controller'
89
+ # titleize 'RESTfulController' # => 'RESTful Controller'
90
+ # camelize 'restful' # => 'RESTful'
91
+ # camelize 'restful_controller' # => 'RESTfulController'
92
92
  #
93
93
  # acronym 'McDonald'
94
- # underscore 'McDonald' #=> 'mcdonald'
95
- # camelize 'mcdonald' #=> 'McDonald'
94
+ # underscore 'McDonald' # => 'mcdonald'
95
+ # camelize 'mcdonald' # => 'McDonald'
96
96
  def acronym(word)
97
97
  @acronyms[word.downcase] = word
98
98
  @acronym_regex = /#{@acronyms.values.join("|")}/
@@ -154,13 +154,13 @@ module ActiveSupport
154
154
  end
155
155
  end
156
156
 
157
- # Add uncountable words that shouldn't be attempted inflected.
157
+ # Specifies words that are uncountable and should not be inflected.
158
158
  #
159
159
  # uncountable 'money'
160
160
  # uncountable 'money', 'information'
161
161
  # uncountable %w( money information rice )
162
162
  def uncountable(*words)
163
- (@uncountables << words).flatten!
163
+ @uncountables += words.flatten.map(&:downcase)
164
164
  end
165
165
 
166
166
  # Specifies a humanized form of a string by a regular expression rule or
@@ -1,6 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
- require 'active_support/inflector/inflections'
4
3
  require 'active_support/inflections'
5
4
 
6
5
  module ActiveSupport
@@ -37,7 +36,7 @@ module ActiveSupport
37
36
  # string.
38
37
  #
39
38
  # If passed an optional +locale+ parameter, the word will be
40
- # pluralized using rules defined for that language. By default,
39
+ # singularized using rules defined for that language. By default,
41
40
  # this parameter is set to <tt>:en</tt>.
42
41
  #
43
42
  # 'posts'.singularize # => "post"
@@ -73,7 +72,9 @@ module ActiveSupport
73
72
  else
74
73
  string = string.sub(/^(?:#{inflections.acronym_regex}(?=\b|[A-Z_])|\w)/) { $&.downcase }
75
74
  end
76
- string.gsub(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }.gsub('/', '::')
75
+ string.gsub!(/(?:_|(\/))([a-z\d]*)/i) { "#{$1}#{inflections.acronyms[$2] || $2.capitalize}" }
76
+ string.gsub!(/\//, '::')
77
+ string
77
78
  end
78
79
 
79
80
  # Makes an underscored, lowercase form from the expression in the string.
@@ -88,9 +89,9 @@ module ActiveSupport
88
89
  #
89
90
  # 'SSLError'.underscore.camelize # => "SslError"
90
91
  def underscore(camel_cased_word)
91
- word = camel_cased_word.to_s.dup
92
- word.gsub!('::', '/')
93
- word.gsub!(/(?:([A-Za-z\d])|^)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1}#{$1 && '_'}#{$2.downcase}" }
92
+ return camel_cased_word unless camel_cased_word =~ /[A-Z-]|::/
93
+ word = camel_cased_word.to_s.gsub(/::/, '/')
94
+ word.gsub!(/(?:(?<=([A-Za-z\d]))|\b)(#{inflections.acronym_regex})(?=\b|[^a-z])/) { "#{$1 && '_'}#{$2.downcase}" }
94
95
  word.gsub!(/([A-Z\d]+)([A-Z][a-z])/,'\1_\2')
95
96
  word.gsub!(/([a-z\d])([A-Z])/,'\1_\2')
96
97
  word.tr!("-", "_")
@@ -98,20 +99,47 @@ module ActiveSupport
98
99
  word
99
100
  end
100
101
 
101
- # Capitalizes the first word and turns underscores into spaces and strips a
102
- # trailing "_id", if any. Like +titleize+, this is meant for creating pretty
103
- # output.
102
+ # Tweaks an attribute name for display to end users.
103
+ #
104
+ # Specifically, +humanize+ performs these transformations:
105
+ #
106
+ # * Applies human inflection rules to the argument.
107
+ # * Deletes leading underscores, if any.
108
+ # * Removes a "_id" suffix if present.
109
+ # * Replaces underscores with spaces, if any.
110
+ # * Downcases all words except acronyms.
111
+ # * Capitalizes the first word.
112
+ #
113
+ # The capitalization of the first word can be turned off by setting the
114
+ # +:capitalize+ option to false (default is true).
115
+ #
116
+ # humanize('employee_salary') # => "Employee salary"
117
+ # humanize('author_id') # => "Author"
118
+ # humanize('author_id', capitalize: false) # => "author"
119
+ # humanize('_id') # => "Id"
104
120
  #
105
- # 'employee_salary'.humanize # => "Employee salary"
106
- # 'author_id'.humanize # => "Author"
107
- def humanize(lower_case_and_underscored_word)
121
+ # If "SSL" was defined to be an acronym:
122
+ #
123
+ # humanize('ssl_error') # => "SSL error"
124
+ #
125
+ def humanize(lower_case_and_underscored_word, options = {})
108
126
  result = lower_case_and_underscored_word.to_s.dup
127
+
109
128
  inflections.humans.each { |(rule, replacement)| break if result.sub!(rule, replacement) }
110
- result.gsub!(/_id$/, "")
129
+
130
+ result.sub!(/\A_+/, '')
131
+ result.sub!(/_id\z/, '')
111
132
  result.tr!('_', ' ')
112
- result.gsub(/([a-z\d]*)/i) { |match|
133
+
134
+ result.gsub!(/([a-z\d]*)/i) do |match|
113
135
  "#{inflections.acronyms[match] || match.downcase}"
114
- }.gsub(/^\w/) { $&.upcase }
136
+ end
137
+
138
+ if options.fetch(:capitalize, true)
139
+ result.sub!(/\A\w/) { |match| match.upcase }
140
+ end
141
+
142
+ result
115
143
  end
116
144
 
117
145
  # Capitalizes all the words and replaces some characters in the string to
@@ -125,7 +153,7 @@ module ActiveSupport
125
153
  # 'TheManWithoutAPast'.titleize # => "The Man Without A Past"
126
154
  # 'raiders_of_the_lost_ark'.titleize # => "Raiders Of The Lost Ark"
127
155
  def titleize(word)
128
- humanize(underscore(word)).gsub(/\b(?<!['’`])[a-z]/) { $&.capitalize }
156
+ humanize(underscore(word)).gsub(/\b(?<!['’`])[a-z]/) { |match| match.capitalize }
129
157
  end
130
158
 
131
159
  # Create the name of a table like Rails does for models to table names. This
@@ -147,7 +175,7 @@ module ActiveSupport
147
175
  #
148
176
  # Singular names are not handled correctly:
149
177
  #
150
- # 'business'.classify # => "Busines"
178
+ # 'calculus'.classify # => "Calculu"
151
179
  def classify(table_name)
152
180
  # strip out any leading schema name
153
181
  camelize(singularize(table_name.to_s.sub(/.*\./, '')))
@@ -164,6 +192,8 @@ module ActiveSupport
164
192
  #
165
193
  # 'ActiveRecord::CoreExtensions::String::Inflections'.demodulize # => "Inflections"
166
194
  # 'Inflections'.demodulize # => "Inflections"
195
+ # '::Inflections'.demodulize # => "Inflections"
196
+ # ''.demodulize # => ""
167
197
  #
168
198
  # See also +deconstantize+.
169
199
  def demodulize(path)
@@ -185,7 +215,7 @@ module ActiveSupport
185
215
  #
186
216
  # See also +demodulize+.
187
217
  def deconstantize(path)
188
- path.to_s[0...(path.rindex('::') || 0)] # implementation based on the one in facets' Module#spacename
218
+ path.to_s[0, path.rindex('::') || 0] # implementation based on the one in facets' Module#spacename
189
219
  end
190
220
 
191
221
  # Creates a foreign key name from a class name.
@@ -219,7 +249,12 @@ module ActiveSupport
219
249
  # unknown.
220
250
  def constantize(camel_cased_word)
221
251
  names = camel_cased_word.split('::')
222
- names.shift if names.empty? || names.first.empty?
252
+
253
+ # Trigger a built-in NameError exception including the ill-formed constant in the message.
254
+ Object.const_get(camel_cased_word) if names.empty?
255
+
256
+ # Remove the first blank element in case of '::ClassName' notation.
257
+ names.shift if names.size > 1 && names.first.empty?
223
258
 
224
259
  names.inject(Object) do |constant, name|
225
260
  if constant == Object
@@ -229,8 +264,8 @@ module ActiveSupport
229
264
  next candidate if constant.const_defined?(name, false)
230
265
  next candidate unless Object.const_defined?(name)
231
266
 
232
- # Go down the ancestors to check it it's owned
233
- # directly before we reach Object or the end of ancestors.
267
+ # Go down the ancestors to check if it is owned directly. The check
268
+ # stops when we reach Object or the end of ancestors tree.
234
269
  constant = constant.ancestors.inject do |const, ancestor|
235
270
  break const if ancestor == Object
236
271
  break ancestor if ancestor.const_defined?(name, false)
@@ -268,8 +303,8 @@ module ActiveSupport
268
303
  def safe_constantize(camel_cased_word)
269
304
  constantize(camel_cased_word)
270
305
  rescue NameError => e
271
- raise unless e.message =~ /(uninitialized constant|wrong constant name) #{const_regexp(camel_cased_word)}$/ ||
272
- e.name.to_s == camel_cased_word.to_s
306
+ raise if e.name && !(camel_cased_word.to_s.split("::").include?(e.name.to_s) ||
307
+ e.name.to_s == camel_cased_word.to_s)
273
308
  rescue ArgumentError => e
274
309
  raise unless e.message =~ /not missing constant #{const_regexp(camel_cased_word)}\!$/
275
310
  end
@@ -313,10 +348,16 @@ module ActiveSupport
313
348
 
314
349
  private
315
350
 
316
- # Mount a regular expression that will match part by part of the constant.
317
- # For instance, Foo::Bar::Baz will generate Foo(::Bar(::Baz)?)?
351
+ # Mounts a regular expression, returned as a string to ease interpolation,
352
+ # that will match part by part the given constant.
353
+ #
354
+ # const_regexp("Foo::Bar::Baz") # => "Foo(::Bar(::Baz)?)?"
355
+ # const_regexp("::") # => "::"
318
356
  def const_regexp(camel_cased_word) #:nodoc:
319
357
  parts = camel_cased_word.split("::")
358
+
359
+ return Regexp.escape(camel_cased_word) if parts.blank?
360
+
320
361
  last = parts.pop
321
362
 
322
363
  parts.reverse.inject(last) do |acc, part|
@@ -1,20 +1,30 @@
1
1
  require 'active_support/core_ext/module/attribute_accessors'
2
2
  require 'active_support/core_ext/module/delegation'
3
- require 'multi_json'
3
+ require 'json'
4
4
 
5
5
  module ActiveSupport
6
6
  # Look for and parse json strings that look like ISO 8601 times.
7
7
  mattr_accessor :parse_json_times
8
8
 
9
9
  module JSON
10
+ # matches YAML-formatted dates
11
+ DATE_REGEX = /^(?:\d{4}-\d{2}-\d{2}|\d{4}-\d{1,2}-\d{1,2}[T \t]+\d{1,2}:\d{2}:\d{2}(\.[0-9]*)?(([ \t]*)Z|[-+]\d{2}?(:\d{2})?))$/
12
+
10
13
  class << self
11
14
  # Parses a JSON string (JavaScript Object Notation) into a hash.
12
- # See www.json.org for more info.
15
+ # See http://www.json.org for more info.
13
16
  #
14
17
  # ActiveSupport::JSON.decode("{\"team\":\"rails\",\"players\":\"36\"}")
15
18
  # => {"team" => "rails", "players" => "36"}
16
- def decode(json, options ={})
17
- data = MultiJson.load(json, options)
19
+ def decode(json, options = {})
20
+ if options.present?
21
+ raise ArgumentError, "In Rails 4.1, ActiveSupport::JSON.decode no longer " \
22
+ "accepts an options hash for MultiJSON. MultiJSON reached its end of life " \
23
+ "and has been removed."
24
+ end
25
+
26
+ data = ::JSON.parse(json, quirks_mode: true)
27
+
18
28
  if ActiveSupport.parse_json_times
19
29
  convert_dates_from(data)
20
30
  else
@@ -22,23 +32,6 @@ module ActiveSupport
22
32
  end
23
33
  end
24
34
 
25
- def engine
26
- MultiJson.adapter
27
- end
28
- alias :backend :engine
29
-
30
- def engine=(name)
31
- MultiJson.use(name)
32
- end
33
- alias :backend= :engine=
34
-
35
- def with_backend(name)
36
- old_backend, self.backend = backend, name
37
- yield
38
- ensure
39
- self.backend = old_backend
40
- end
41
-
42
35
  # Returns the class of the error that will be raised when there is an
43
36
  # error in decoding JSON. Using this method means you won't directly
44
37
  # depend on the ActiveSupport's JSON implementation, in case it changes
@@ -50,7 +43,7 @@ module ActiveSupport
50
43
  # Rails.logger.warn("Attempted to decode invalid JSON: #{some_string}")
51
44
  # end
52
45
  def parse_error
53
- MultiJson::DecodeError
46
+ ::JSON::ParserError
54
47
  end
55
48
 
56
49
  private