activesupport 4.2.0 → 5.0.0.1

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 (185) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +630 -220
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +2 -3
  5. data/lib/active_support/array_inquirer.rb +44 -0
  6. data/lib/active_support/backtrace_cleaner.rb +1 -1
  7. data/lib/active_support/benchmarkable.rb +1 -1
  8. data/lib/active_support/cache/file_store.rb +36 -22
  9. data/lib/active_support/cache/mem_cache_store.rb +63 -54
  10. data/lib/active_support/cache/memory_store.rb +16 -21
  11. data/lib/active_support/cache/null_store.rb +1 -4
  12. data/lib/active_support/cache/strategy/local_cache.rb +31 -20
  13. data/lib/active_support/cache.rb +73 -89
  14. data/lib/active_support/callbacks.rb +195 -155
  15. data/lib/active_support/concern.rb +2 -2
  16. data/lib/active_support/concurrency/latch.rb +7 -15
  17. data/lib/active_support/concurrency/share_lock.rb +186 -0
  18. data/lib/active_support/configurable.rb +1 -0
  19. data/lib/active_support/core_ext/array/access.rb +27 -1
  20. data/lib/active_support/core_ext/array/conversions.rb +6 -4
  21. data/lib/active_support/core_ext/array/grouping.rb +9 -18
  22. data/lib/active_support/core_ext/array/inquiry.rb +17 -0
  23. data/lib/active_support/core_ext/array/wrap.rb +5 -4
  24. data/lib/active_support/core_ext/array.rb +1 -0
  25. data/lib/active_support/core_ext/big_decimal/conversions.rb +8 -10
  26. data/lib/active_support/core_ext/class/attribute.rb +10 -9
  27. data/lib/active_support/core_ext/class/subclasses.rb +3 -4
  28. data/lib/active_support/core_ext/class.rb +0 -1
  29. data/lib/active_support/core_ext/date/blank.rb +12 -0
  30. data/lib/active_support/core_ext/date/calculations.rb +1 -1
  31. data/lib/active_support/core_ext/date/conversions.rb +13 -6
  32. data/lib/active_support/core_ext/date.rb +1 -1
  33. data/lib/active_support/core_ext/date_and_time/calculations.rb +109 -25
  34. data/lib/active_support/core_ext/date_and_time/compatibility.rb +18 -0
  35. data/lib/active_support/core_ext/date_and_time/zones.rb +3 -4
  36. data/lib/active_support/core_ext/date_time/blank.rb +12 -0
  37. data/lib/active_support/core_ext/date_time/calculations.rb +36 -10
  38. data/lib/active_support/core_ext/date_time/compatibility.rb +5 -0
  39. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  40. data/lib/active_support/core_ext/date_time.rb +2 -1
  41. data/lib/active_support/core_ext/enumerable.rb +49 -5
  42. data/lib/active_support/core_ext/file/atomic.rb +30 -25
  43. data/lib/active_support/core_ext/hash/conversions.rb +23 -4
  44. data/lib/active_support/core_ext/hash/deep_merge.rb +1 -1
  45. data/lib/active_support/core_ext/hash/except.rb +9 -8
  46. data/lib/active_support/core_ext/hash/indifferent_access.rb +1 -1
  47. data/lib/active_support/core_ext/hash/keys.rb +23 -19
  48. data/lib/active_support/core_ext/hash/slice.rb +1 -1
  49. data/lib/active_support/core_ext/hash/transform_values.rb +11 -5
  50. data/lib/active_support/core_ext/integer/time.rb +1 -16
  51. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  52. data/lib/active_support/core_ext/kernel/debugger.rb +3 -10
  53. data/lib/active_support/core_ext/kernel/reporting.rb +2 -83
  54. data/lib/active_support/core_ext/kernel.rb +0 -1
  55. data/lib/active_support/core_ext/load_error.rb +4 -2
  56. data/lib/active_support/core_ext/marshal.rb +12 -11
  57. data/lib/active_support/core_ext/module/aliasing.rb +6 -1
  58. data/lib/active_support/core_ext/module/anonymous.rb +10 -1
  59. data/lib/active_support/core_ext/module/attr_internal.rb +2 -5
  60. data/lib/active_support/core_ext/module/attribute_accessors.rb +15 -15
  61. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +141 -0
  62. data/lib/active_support/core_ext/module/concerning.rb +4 -4
  63. data/lib/active_support/core_ext/module/delegation.rb +35 -25
  64. data/lib/active_support/core_ext/module/deprecation.rb +2 -2
  65. data/lib/active_support/core_ext/module/introspection.rb +4 -0
  66. data/lib/active_support/core_ext/module/method_transplanting.rb +3 -11
  67. data/lib/active_support/core_ext/module/qualified_const.rb +30 -12
  68. data/lib/active_support/core_ext/module/remove_method.rb +23 -0
  69. data/lib/active_support/core_ext/module.rb +1 -0
  70. data/lib/active_support/core_ext/name_error.rb +15 -2
  71. data/lib/active_support/core_ext/numeric/bytes.rb +20 -0
  72. data/lib/active_support/core_ext/numeric/conversions.rb +74 -64
  73. data/lib/active_support/core_ext/numeric/inquiry.rb +26 -0
  74. data/lib/active_support/core_ext/numeric/time.rb +24 -19
  75. data/lib/active_support/core_ext/numeric.rb +1 -0
  76. data/lib/active_support/core_ext/object/blank.rb +17 -5
  77. data/lib/active_support/core_ext/object/deep_dup.rb +10 -3
  78. data/lib/active_support/core_ext/object/duplicable.rb +8 -13
  79. data/lib/active_support/core_ext/object/inclusion.rb +2 -2
  80. data/lib/active_support/core_ext/object/instance_variables.rb +1 -1
  81. data/lib/active_support/core_ext/object/json.rb +15 -7
  82. data/lib/active_support/core_ext/object/to_query.rb +1 -1
  83. data/lib/active_support/core_ext/object/try.rb +68 -22
  84. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  85. data/lib/active_support/core_ext/object.rb +0 -1
  86. data/lib/active_support/core_ext/range/conversions.rb +18 -6
  87. data/lib/active_support/core_ext/range/each.rb +16 -18
  88. data/lib/active_support/core_ext/range/include_range.rb +20 -20
  89. data/lib/active_support/core_ext/securerandom.rb +23 -0
  90. data/lib/active_support/core_ext/string/access.rb +1 -1
  91. data/lib/active_support/core_ext/string/behavior.rb +1 -1
  92. data/lib/active_support/core_ext/string/conversions.rb +4 -3
  93. data/lib/active_support/core_ext/string/filters.rb +5 -5
  94. data/lib/active_support/core_ext/string/inflections.rb +32 -5
  95. data/lib/active_support/core_ext/string/multibyte.rb +11 -7
  96. data/lib/active_support/core_ext/string/output_safety.rb +18 -16
  97. data/lib/active_support/core_ext/string/strip.rb +3 -6
  98. data/lib/active_support/core_ext/struct.rb +3 -6
  99. data/lib/active_support/core_ext/time/calculations.rb +36 -11
  100. data/lib/active_support/core_ext/time/compatibility.rb +5 -0
  101. data/lib/active_support/core_ext/time/conversions.rb +4 -2
  102. data/lib/active_support/core_ext/time/marshal.rb +2 -29
  103. data/lib/active_support/core_ext/time/zones.rb +36 -4
  104. data/lib/active_support/core_ext/time.rb +1 -1
  105. data/lib/active_support/core_ext/uri.rb +1 -3
  106. data/lib/active_support/core_ext.rb +2 -1
  107. data/lib/active_support/dependencies/interlock.rb +51 -0
  108. data/lib/active_support/dependencies.rb +87 -95
  109. data/lib/active_support/deprecation/behaviors.rb +16 -2
  110. data/lib/active_support/deprecation/method_wrappers.rb +42 -16
  111. data/lib/active_support/deprecation/proxy_wrappers.rb +47 -24
  112. data/lib/active_support/deprecation/reporting.rb +23 -5
  113. data/lib/active_support/deprecation.rb +1 -1
  114. data/lib/active_support/duration/iso8601_parser.rb +122 -0
  115. data/lib/active_support/duration/iso8601_serializer.rb +51 -0
  116. data/lib/active_support/duration.rb +55 -10
  117. data/lib/active_support/evented_file_update_checker.rb +194 -0
  118. data/lib/active_support/execution_wrapper.rb +117 -0
  119. data/lib/active_support/executor.rb +6 -0
  120. data/lib/active_support/file_update_checker.rb +23 -3
  121. data/lib/active_support/gem_version.rb +4 -4
  122. data/lib/active_support/hash_with_indifferent_access.rb +46 -13
  123. data/lib/active_support/i18n_railtie.rb +25 -4
  124. data/lib/active_support/inflector/inflections.rb +36 -5
  125. data/lib/active_support/inflector/methods.rb +97 -90
  126. data/lib/active_support/inflector/transliterate.rb +36 -21
  127. data/lib/active_support/json/decoding.rb +11 -10
  128. data/lib/active_support/json/encoding.rb +4 -49
  129. data/lib/active_support/key_generator.rb +7 -9
  130. data/lib/active_support/locale/en.yml +2 -0
  131. data/lib/active_support/log_subscriber/test_helper.rb +3 -3
  132. data/lib/active_support/log_subscriber.rb +1 -1
  133. data/lib/active_support/logger.rb +50 -1
  134. data/lib/active_support/logger_silence.rb +8 -4
  135. data/lib/active_support/logger_thread_safe_level.rb +31 -0
  136. data/lib/active_support/message_encryptor.rb +4 -4
  137. data/lib/active_support/message_verifier.rb +70 -8
  138. data/lib/active_support/multibyte/chars.rb +13 -4
  139. data/lib/active_support/multibyte/unicode.rb +44 -21
  140. data/lib/active_support/notifications/fanout.rb +6 -6
  141. data/lib/active_support/notifications/instrumenter.rb +20 -2
  142. data/lib/active_support/notifications.rb +2 -2
  143. data/lib/active_support/number_helper/number_to_currency_converter.rb +7 -9
  144. data/lib/active_support/number_helper/number_to_delimited_converter.rb +8 -3
  145. data/lib/active_support/number_helper/number_to_human_converter.rb +6 -4
  146. data/lib/active_support/number_helper/number_to_human_size_converter.rb +6 -2
  147. data/lib/active_support/number_helper/number_to_percentage_converter.rb +1 -1
  148. data/lib/active_support/number_helper/number_to_phone_converter.rb +11 -2
  149. data/lib/active_support/number_helper/number_to_rounded_converter.rb +30 -25
  150. data/lib/active_support/number_helper.rb +90 -67
  151. data/lib/active_support/ordered_hash.rb +1 -1
  152. data/lib/active_support/ordered_options.rb +15 -1
  153. data/lib/active_support/per_thread_registry.rb +8 -3
  154. data/lib/active_support/rails.rb +2 -2
  155. data/lib/active_support/railtie.rb +6 -1
  156. data/lib/active_support/reloader.rb +129 -0
  157. data/lib/active_support/rescuable.rb +93 -47
  158. data/lib/active_support/security_utils.rb +7 -0
  159. data/lib/active_support/string_inquirer.rb +1 -1
  160. data/lib/active_support/subscriber.rb +5 -10
  161. data/lib/active_support/tagged_logging.rb +3 -1
  162. data/lib/active_support/test_case.rb +15 -29
  163. data/lib/active_support/testing/assertions.rb +15 -13
  164. data/lib/active_support/testing/autorun.rb +8 -1
  165. data/lib/active_support/testing/deprecation.rb +9 -8
  166. data/lib/active_support/testing/file_fixtures.rb +34 -0
  167. data/lib/active_support/testing/isolation.rb +22 -8
  168. data/lib/active_support/testing/method_call_assertions.rb +41 -0
  169. data/lib/active_support/testing/stream.rb +42 -0
  170. data/lib/active_support/testing/time_helpers.rb +13 -10
  171. data/lib/active_support/time_with_zone.rb +135 -46
  172. data/lib/active_support/values/time_zone.rb +95 -47
  173. data/lib/active_support/values/unicode_tables.dat +0 -0
  174. data/lib/active_support/xml_mini/jdom.rb +7 -6
  175. data/lib/active_support/xml_mini/libxml.rb +2 -2
  176. data/lib/active_support/xml_mini/nokogiri.rb +2 -2
  177. data/lib/active_support/xml_mini/rexml.rb +7 -8
  178. data/lib/active_support/xml_mini.rb +22 -14
  179. data/lib/active_support.rb +20 -6
  180. metadata +33 -35
  181. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -14
  182. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  183. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  184. data/lib/active_support/core_ext/object/itself.rb +0 -15
  185. data/lib/active_support/core_ext/thread.rb +0 -86
@@ -1,6 +1,6 @@
1
1
  require 'set'
2
2
  require 'thread'
3
- require 'thread_safe'
3
+ require 'concurrent/map'
4
4
  require 'pathname'
5
5
  require 'active_support/core_ext/module/aliasing'
6
6
  require 'active_support/core_ext/module/attribute_accessors'
@@ -12,12 +12,40 @@ require 'active_support/core_ext/kernel/reporting'
12
12
  require 'active_support/core_ext/load_error'
13
13
  require 'active_support/core_ext/name_error'
14
14
  require 'active_support/core_ext/string/starts_ends_with'
15
+ require "active_support/dependencies/interlock"
15
16
  require 'active_support/inflector'
16
17
 
17
18
  module ActiveSupport #:nodoc:
18
19
  module Dependencies #:nodoc:
19
20
  extend self
20
21
 
22
+ mattr_accessor :interlock
23
+ self.interlock = Interlock.new
24
+
25
+ # :doc:
26
+
27
+ # Execute the supplied block without interference from any
28
+ # concurrent loads.
29
+ def self.run_interlock
30
+ Dependencies.interlock.running { yield }
31
+ end
32
+
33
+ # Execute the supplied block while holding an exclusive lock,
34
+ # preventing any other thread from being inside a #run_interlock
35
+ # block at the same time.
36
+ def self.load_interlock
37
+ Dependencies.interlock.loading { yield }
38
+ end
39
+
40
+ # Execute the supplied block while holding an exclusive lock,
41
+ # preventing any other thread from being inside a #run_interlock
42
+ # block at the same time.
43
+ def self.unload_interlock
44
+ Dependencies.interlock.unloading { yield }
45
+ end
46
+
47
+ # :nodoc:
48
+
21
49
  # Should we turn on Ruby warnings on the first load of dependent files?
22
50
  mattr_accessor :warnings_on_first_load
23
51
  self.warnings_on_first_load = false
@@ -60,15 +88,6 @@ module ActiveSupport #:nodoc:
60
88
  mattr_accessor :explicitly_unloadable_constants
61
89
  self.explicitly_unloadable_constants = []
62
90
 
63
- # The logger is used for generating information on the action run-time
64
- # (including benchmarking) if available. Can be set to nil for no logging.
65
- # Compatible with both Ruby's own Logger and Log4r loggers.
66
- mattr_accessor :logger
67
-
68
- # Set to +true+ to enable logging of const_missing and file loads.
69
- mattr_accessor :log_activity
70
- self.log_activity = false
71
-
72
91
  # The WatchStack keeps a stack of the modules being watched as files are
73
92
  # loaded. If a file in the process of being loaded (parent.rb) triggers the
74
93
  # load of another file (child.rb) the stack will ensure that child.rb
@@ -115,11 +134,11 @@ module ActiveSupport #:nodoc:
115
134
  next unless mod.is_a?(Module)
116
135
 
117
136
  # Get a list of the constants that were added
118
- new_constants = mod.local_constants - original_constants
137
+ new_constants = mod.constants(false) - original_constants
119
138
 
120
- # self[namespace] returns an Array of the constants that are being evaluated
139
+ # @stack[namespace] returns an Array of the constants that are being evaluated
121
140
  # for that namespace. For instance, if parent.rb requires child.rb, the first
122
- # element of self[Object] will be an Array of the constants that were present
141
+ # element of @stack[Object] will be an Array of the constants that were present
123
142
  # before parent.rb was required. The second element will be an Array of the
124
143
  # constants that were present before child.rb was required.
125
144
  @stack[namespace].each do |namespace_constants|
@@ -128,7 +147,7 @@ module ActiveSupport #:nodoc:
128
147
 
129
148
  # Normalize the list of new constants, and add them to the list we will return
130
149
  new_constants.each do |suffix|
131
- constants << ([namespace, suffix] - ["Object"]).join("::")
150
+ constants << ([namespace, suffix] - ["Object"]).join("::".freeze)
132
151
  end
133
152
  end
134
153
  constants
@@ -143,7 +162,7 @@ module ActiveSupport #:nodoc:
143
162
  @watching << namespaces.map do |namespace|
144
163
  module_name = Dependencies.to_constant_name(namespace)
145
164
  original_constants = Dependencies.qualified_const_defined?(module_name) ?
146
- Inflector.constantize(module_name).local_constants : []
165
+ Inflector.constantize(module_name).constants(false) : []
147
166
 
148
167
  @stack[module_name] << original_constants
149
168
  module_name
@@ -234,7 +253,7 @@ module ActiveSupport #:nodoc:
234
253
  end
235
254
 
236
255
  def load_dependency(file)
237
- if Dependencies.load? && ActiveSupport::Dependencies.constant_watch_stack.watching?
256
+ if Dependencies.load? && Dependencies.constant_watch_stack.watching?
238
257
  Dependencies.new_constants_in(Object) { yield }
239
258
  else
240
259
  yield
@@ -324,56 +343,58 @@ module ActiveSupport #:nodoc:
324
343
  end
325
344
 
326
345
  def clear
327
- log_call
328
- loaded.clear
329
- loading.clear
330
- remove_unloadable_constants!
346
+ Dependencies.unload_interlock do
347
+ loaded.clear
348
+ loading.clear
349
+ remove_unloadable_constants!
350
+ end
331
351
  end
332
352
 
333
353
  def require_or_load(file_name, const_path = nil)
334
- log_call file_name, const_path
335
354
  file_name = $` if file_name =~ /\.rb\z/
336
355
  expanded = File.expand_path(file_name)
337
356
  return if loaded.include?(expanded)
338
357
 
339
- # Record that we've seen this file *before* loading it to avoid an
340
- # infinite loop with mutual dependencies.
341
- loaded << expanded
342
- loading << expanded
343
-
344
- begin
345
- if load?
346
- log "loading #{file_name}"
358
+ Dependencies.load_interlock do
359
+ # Maybe it got loaded while we were waiting for our lock:
360
+ return if loaded.include?(expanded)
347
361
 
348
- # Enable warnings if this file has not been loaded before and
349
- # warnings_on_first_load is set.
350
- load_args = ["#{file_name}.rb"]
351
- load_args << const_path unless const_path.nil?
362
+ # Record that we've seen this file *before* loading it to avoid an
363
+ # infinite loop with mutual dependencies.
364
+ loaded << expanded
365
+ loading << expanded
352
366
 
353
- if !warnings_on_first_load or history.include?(expanded)
354
- result = load_file(*load_args)
367
+ begin
368
+ if load?
369
+ # Enable warnings if this file has not been loaded before and
370
+ # warnings_on_first_load is set.
371
+ load_args = ["#{file_name}.rb"]
372
+ load_args << const_path unless const_path.nil?
373
+
374
+ if !warnings_on_first_load or history.include?(expanded)
375
+ result = load_file(*load_args)
376
+ else
377
+ enable_warnings { result = load_file(*load_args) }
378
+ end
355
379
  else
356
- enable_warnings { result = load_file(*load_args) }
380
+ result = require file_name
357
381
  end
358
- else
359
- log "requiring #{file_name}"
360
- result = require file_name
382
+ rescue Exception
383
+ loaded.delete expanded
384
+ raise
385
+ ensure
386
+ loading.pop
361
387
  end
362
- rescue Exception
363
- loaded.delete expanded
364
- raise
365
- ensure
366
- loading.pop
367
- end
368
388
 
369
- # Record history *after* loading so first load gets warnings.
370
- history << expanded
371
- result
389
+ # Record history *after* loading so first load gets warnings.
390
+ history << expanded
391
+ result
392
+ end
372
393
  end
373
394
 
374
395
  # Is the provided constant path defined?
375
396
  def qualified_const_defined?(path)
376
- Object.qualified_const_defined?(path.sub(/^::/, ''), false)
397
+ Object.const_defined?(path, false)
377
398
  end
378
399
 
379
400
  # Given +path+, a filesystem path to a ruby file, return an array of
@@ -386,13 +407,13 @@ module ActiveSupport #:nodoc:
386
407
 
387
408
  bases.each do |root|
388
409
  expanded_root = File.expand_path(root)
389
- next unless %r{\A#{Regexp.escape(expanded_root)}(/|\\)} =~ expanded_path
410
+ next unless expanded_path.start_with?(expanded_root)
390
411
 
391
- nesting = expanded_path[(expanded_root.size)..-1]
392
- nesting = nesting[1..-1] if nesting && nesting[0] == ?/
393
- next if nesting.blank?
412
+ root_size = expanded_root.size
413
+ next if expanded_path[root_size] != ?/.freeze
394
414
 
395
- paths << nesting.camelize
415
+ nesting = expanded_path[(root_size + 1)..-1]
416
+ paths << nesting.camelize unless nesting.blank?
396
417
  end
397
418
 
398
419
  paths.uniq!
@@ -401,7 +422,7 @@ module ActiveSupport #:nodoc:
401
422
 
402
423
  # Search for a file in autoload_paths matching the provided suffix.
403
424
  def search_for_file(path_suffix)
404
- path_suffix = path_suffix.sub(/(\.rb)?$/, ".rb")
425
+ path_suffix = path_suffix.sub(/(\.rb)?$/, ".rb".freeze)
405
426
 
406
427
  autoload_paths.each do |root|
407
428
  path = File.join(root, path_suffix)
@@ -421,7 +442,7 @@ module ActiveSupport #:nodoc:
421
442
  end
422
443
 
423
444
  def load_once_path?(path)
424
- # to_s works around a ruby1.9 issue where String#starts_with?(Pathname)
445
+ # to_s works around a ruby issue where String#starts_with?(Pathname)
425
446
  # will raise a TypeError: no implicit conversion of Pathname into String
426
447
  autoload_once_paths.any? { |base| path.starts_with? base.to_s }
427
448
  end
@@ -448,7 +469,6 @@ module ActiveSupport #:nodoc:
448
469
  # set of names that the file at +path+ may define. See
449
470
  # +loadable_constants_for_path+ for more details.
450
471
  def load_file(path, const_paths = loadable_constants_for_path(path))
451
- log_call path, const_paths
452
472
  const_paths = [const_paths].compact unless const_paths.is_a? Array
453
473
  parent_paths = const_paths.collect { |const_path| const_path[/.*(?=::)/] || ::Object }
454
474
 
@@ -459,7 +479,6 @@ module ActiveSupport #:nodoc:
459
479
 
460
480
  autoloaded_constants.concat newly_defined_paths unless load_once_path?(path)
461
481
  autoloaded_constants.uniq!
462
- log "loading #{path} defined #{newly_defined_paths * ', '}" unless newly_defined_paths.empty?
463
482
  result
464
483
  end
465
484
 
@@ -473,8 +492,6 @@ module ActiveSupport #:nodoc:
473
492
  # it is not possible to load the constant into from_mod, try its parent
474
493
  # module using +const_missing+.
475
494
  def load_missing_constant(from_mod, const_name)
476
- log_call from_mod, const_name
477
-
478
495
  unless qualified_const_defined?(from_mod.name) && Inflector.constantize(from_mod.name).equal?(from_mod)
479
496
  raise ArgumentError, "A copy of #{from_mod} has been removed from the module tree but is still active!"
480
497
  end
@@ -486,7 +503,7 @@ module ActiveSupport #:nodoc:
486
503
 
487
504
  if file_path
488
505
  expanded = File.expand_path(file_path)
489
- expanded.sub!(/\.rb\z/, '')
506
+ expanded.sub!(/\.rb\z/, ''.freeze)
490
507
 
491
508
  if loading.include?(expanded)
492
509
  raise "Circular dependency detected while autoloading constant #{qualified_name}"
@@ -550,7 +567,7 @@ module ActiveSupport #:nodoc:
550
567
 
551
568
  class ClassCache
552
569
  def initialize
553
- @store = ThreadSafe::Cache.new
570
+ @store = Concurrent::Map.new
554
571
  end
555
572
 
556
573
  def empty?
@@ -607,7 +624,7 @@ module ActiveSupport #:nodoc:
607
624
  def autoloaded?(desc)
608
625
  return false if desc.is_a?(Module) && desc.anonymous?
609
626
  name = to_constant_name desc
610
- return false unless qualified_const_defined? name
627
+ return false unless qualified_const_defined?(name)
611
628
  return autoloaded_constants.include?(name)
612
629
  end
613
630
 
@@ -638,25 +655,20 @@ module ActiveSupport #:nodoc:
638
655
  # exception, any new constants are regarded as being only partially defined
639
656
  # and will be removed immediately.
640
657
  def new_constants_in(*descs)
641
- log_call(*descs)
642
-
643
658
  constant_watch_stack.watch_namespaces(descs)
644
- aborting = true
659
+ success = false
645
660
 
646
661
  begin
647
662
  yield # Now yield to the code that is to define new constants.
648
- aborting = false
663
+ success = true
649
664
  ensure
650
665
  new_constants = constant_watch_stack.new_constants
651
666
 
652
- log "New constants: #{new_constants * ', '}"
653
- return new_constants unless aborting
667
+ return new_constants if success
654
668
 
655
- log "Error during loading, removing partially loaded constants "
656
- new_constants.each { |c| remove_constant(c) }.clear
669
+ # Remove partially loaded constants.
670
+ new_constants.each { |c| remove_constant(c) }
657
671
  end
658
-
659
- []
660
672
  end
661
673
 
662
674
  # Convert the provided const desc to a qualified constant name (as a string).
@@ -703,8 +715,6 @@ module ActiveSupport #:nodoc:
703
715
  parent = constantize(parent_name)
704
716
  end
705
717
 
706
- log "removing constant #{const}"
707
-
708
718
  # In an autoloaded user.rb like this
709
719
  #
710
720
  # autoload :Foo, 'foo'
@@ -725,7 +735,7 @@ module ActiveSupport #:nodoc:
725
735
  begin
726
736
  constantized = parent.const_get(to_remove, false)
727
737
  rescue NameError
728
- log "the constant #{const} is not reachable anymore, skipping"
738
+ # The constant is no longer reachable, just skip it.
729
739
  return
730
740
  else
731
741
  constantized.before_remove_const if constantized.respond_to?(:before_remove_const)
@@ -735,27 +745,9 @@ module ActiveSupport #:nodoc:
735
745
  begin
736
746
  parent.instance_eval { remove_const to_remove }
737
747
  rescue NameError
738
- log "the constant #{const} is not reachable anymore, skipping"
748
+ # The constant is no longer reachable, just skip it.
739
749
  end
740
750
  end
741
-
742
- protected
743
- def log_call(*args)
744
- if log_activity?
745
- arg_str = args.collect { |arg| arg.inspect } * ', '
746
- /in `([a-z_\?\!]+)'/ =~ caller(1).first
747
- selector = $1 || '<unknown>'
748
- log "called #{selector}(#{arg_str})"
749
- end
750
- end
751
-
752
- def log(msg)
753
- logger.debug "Dependencies: #{msg}" if log_activity?
754
- end
755
-
756
- def log_activity?
757
- logger && log_activity
758
- end
759
751
  end
760
752
  end
761
753
 
@@ -1,6 +1,8 @@
1
1
  require "active_support/notifications"
2
2
 
3
3
  module ActiveSupport
4
+ # Raised when <tt>ActiveSupport::Deprecation::Behavior#behavior</tt> is set with <tt>:raise</tt>.
5
+ # You would set <tt>:raise</tt>, as a behaviour to raise errors and proactively report exceptions from deprecations.
4
6
  class DeprecationException < StandardError
5
7
  end
6
8
 
@@ -9,7 +11,7 @@ module ActiveSupport
9
11
  DEFAULT_BEHAVIORS = {
10
12
  raise: ->(message, callstack) {
11
13
  e = DeprecationException.new(message)
12
- e.set_backtrace(callstack)
14
+ e.set_backtrace(callstack.map(&:to_s))
13
15
  raise e
14
16
  },
15
17
 
@@ -20,7 +22,7 @@ module ActiveSupport
20
22
 
21
23
  log: ->(message, callstack) {
22
24
  logger =
23
- if defined?(Rails) && Rails.logger
25
+ if defined?(Rails.logger) && Rails.logger
24
26
  Rails.logger
25
27
  else
26
28
  require 'active_support/logger'
@@ -38,6 +40,18 @@ module ActiveSupport
38
40
  silence: ->(message, callstack) {},
39
41
  }
40
42
 
43
+ # Behavior module allows to determine how to display deprecation messages.
44
+ # You can create a custom behavior or set any from the +DEFAULT_BEHAVIORS+
45
+ # constant. Available behaviors are:
46
+ #
47
+ # [+raise+] Raise <tt>ActiveSupport::DeprecationException</tt>.
48
+ # [+stderr+] Log all deprecation warnings to +$stderr+.
49
+ # [+log+] Log all deprecation warnings to +Rails.logger+.
50
+ # [+notify+] Use +ActiveSupport::Notifications+ to notify +deprecation.rails+.
51
+ # [+silence+] Do nothing.
52
+ #
53
+ # Setting behaviors only affects deprecations that happen after boot time.
54
+ # For more information you can read the documentation of the +behavior=+ method.
41
55
  module Behavior
42
56
  # Whether to print a backtrace along with the warning.
43
57
  attr_accessor :debug
@@ -9,35 +9,61 @@ module ActiveSupport
9
9
  # module Fred
10
10
  # extend self
11
11
  #
12
- # def foo; end
13
- # def bar; end
14
- # def baz; end
12
+ # def aaa; end
13
+ # def bbb; end
14
+ # def ccc; end
15
+ # def ddd; end
16
+ # def eee; end
15
17
  # end
16
18
  #
17
- # ActiveSupport::Deprecation.deprecate_methods(Fred, :foo, bar: :qux, baz: 'use Bar#baz instead')
18
- # # => [:foo, :bar, :baz]
19
+ # Using the default deprecator:
20
+ # ActiveSupport::Deprecation.deprecate_methods(Fred, :aaa, bbb: :zzz, ccc: 'use Bar#ccc instead')
21
+ # # => [:aaa, :bbb, :ccc]
19
22
  #
20
- # Fred.foo
21
- # # => "DEPRECATION WARNING: foo is deprecated and will be removed from Rails 4.1."
23
+ # Fred.aaa
24
+ # # DEPRECATION WARNING: aaa is deprecated and will be removed from Rails 5.1. (called from irb_binding at (irb):10)
25
+ # # => nil
22
26
  #
23
- # Fred.bar
24
- # # => "DEPRECATION WARNING: bar is deprecated and will be removed from Rails 4.1 (use qux instead)."
27
+ # Fred.bbb
28
+ # # DEPRECATION WARNING: bbb is deprecated and will be removed from Rails 5.1 (use zzz instead). (called from irb_binding at (irb):11)
29
+ # # => nil
25
30
  #
26
- # Fred.baz
27
- # # => "DEPRECATION WARNING: baz is deprecated and will be removed from Rails 4.1 (use Bar#baz instead)."
31
+ # Fred.ccc
32
+ # # DEPRECATION WARNING: ccc is deprecated and will be removed from Rails 5.1 (use Bar#ccc instead). (called from irb_binding at (irb):12)
33
+ # # => nil
34
+ #
35
+ # Passing in a custom deprecator:
36
+ # custom_deprecator = ActiveSupport::Deprecation.new('next-release', 'MyGem')
37
+ # ActiveSupport::Deprecation.deprecate_methods(Fred, ddd: :zzz, deprecator: custom_deprecator)
38
+ # # => [:ddd]
39
+ #
40
+ # Fred.ddd
41
+ # DEPRECATION WARNING: ddd is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):15)
42
+ # # => nil
43
+ #
44
+ # Using a custom deprecator directly:
45
+ # custom_deprecator = ActiveSupport::Deprecation.new('next-release', 'MyGem')
46
+ # custom_deprecator.deprecate_methods(Fred, eee: :zzz)
47
+ # # => [:eee]
48
+ #
49
+ # Fred.eee
50
+ # DEPRECATION WARNING: eee is deprecated and will be removed from MyGem next-release (use zzz instead). (called from irb_binding at (irb):18)
51
+ # # => nil
28
52
  def deprecate_methods(target_module, *method_names)
29
53
  options = method_names.extract_options!
30
- deprecator = options.delete(:deprecator) || ActiveSupport::Deprecation.instance
54
+ deprecator = options.delete(:deprecator) || self
31
55
  method_names += options.keys
32
56
 
33
- method_names.each do |method_name|
34
- target_module.alias_method_chain(method_name, :deprecation) do |target, punctuation|
35
- target_module.send(:define_method, "#{target}_with_deprecation#{punctuation}") do |*args, &block|
57
+ mod = Module.new do
58
+ method_names.each do |method_name|
59
+ define_method(method_name) do |*args, &block|
36
60
  deprecator.deprecation_warning(method_name, options[method_name])
37
- send(:"#{target}_without_deprecation#{punctuation}", *args, &block)
61
+ super(*args, &block)
38
62
  end
39
63
  end
40
64
  end
65
+
66
+ target_module.prepend(mod)
41
67
  end
42
68
  end
43
69
  end
@@ -20,20 +20,22 @@ module ActiveSupport
20
20
 
21
21
  private
22
22
  def method_missing(called, *args, &block)
23
- warn caller, called, args
23
+ warn caller_locations, called, args
24
24
  target.__send__(called, *args, &block)
25
25
  end
26
26
  end
27
27
 
28
- # This DeprecatedObjectProxy transforms object to deprecated object.
28
+ # DeprecatedObjectProxy transforms an object into a deprecated one. It
29
+ # takes an object, a deprecation message and optionally a deprecator. The
30
+ # deprecator defaults to +ActiveSupport::Deprecator+ if none is specified.
29
31
  #
30
- # @old_object = DeprecatedObjectProxy.new(Object.new, "Don't use this object anymore!")
31
- # @old_object = DeprecatedObjectProxy.new(Object.new, "Don't use this object anymore!", deprecator_instance)
32
+ # deprecated_object = ActiveSupport::Deprecation::DeprecatedObjectProxy.new(Object.new, "This object is now deprecated")
33
+ # # => #<Object:0x007fb9b34c34b0>
32
34
  #
33
- # When someone executes any method except +inspect+ on proxy object this will
34
- # trigger +warn+ method on +deprecator_instance+.
35
- #
36
- # Default deprecator is <tt>ActiveSupport::Deprecation</tt>
35
+ # deprecated_object.to_s
36
+ # DEPRECATION WARNING: This object is now deprecated.
37
+ # (Backtrace)
38
+ # # => "#<Object:0x007fb9b34c34b0>"
37
39
  class DeprecatedObjectProxy < DeprecationProxy
38
40
  def initialize(object, message, deprecator = ActiveSupport::Deprecation.instance)
39
41
  @object = object
@@ -51,13 +53,16 @@ module ActiveSupport
51
53
  end
52
54
  end
53
55
 
54
- # This DeprecatedInstanceVariableProxy transforms instance variable to
55
- # deprecated instance variable.
56
+ # DeprecatedInstanceVariableProxy transforms an instance variable into a
57
+ # deprecated one. It takes an instance of a class, a method on that class
58
+ # and an instance variable. It optionally takes a deprecator as the last
59
+ # argument. The deprecator defaults to +ActiveSupport::Deprecator+ if none
60
+ # is specified.
56
61
  #
57
62
  # class Example
58
- # def initialize(deprecator)
59
- # @request = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :request, :@request, deprecator)
60
- # @_request = :a_request
63
+ # def initialize
64
+ # @request = ActiveSupport::Deprecation::DeprecatedInstanceVariableProxy.new(self, :request, :@request)
65
+ # @_request = :special_request
61
66
  # end
62
67
  #
63
68
  # def request
@@ -69,12 +74,17 @@ module ActiveSupport
69
74
  # end
70
75
  # end
71
76
  #
72
- # When someone execute any method on @request variable this will trigger
73
- # +warn+ method on +deprecator_instance+ and will fetch <tt>@_request</tt>
74
- # variable via +request+ method and execute the same method on non-proxy
75
- # instance variable.
77
+ # example = Example.new
78
+ # # => #<Example:0x007fb9b31090b8 @_request=:special_request, @request=:special_request>
79
+ #
80
+ # example.old_request.to_s
81
+ # # => DEPRECATION WARNING: @request is deprecated! Call request.to_s instead of
82
+ # @request.to_s
83
+ # (Backtrace information…)
84
+ # "special_request"
76
85
  #
77
- # Default deprecator is <tt>ActiveSupport::Deprecation</tt>.
86
+ # example.request.to_s
87
+ # # => "special_request"
78
88
  class DeprecatedInstanceVariableProxy < DeprecationProxy
79
89
  def initialize(instance, method, var = "@#{method}", deprecator = ActiveSupport::Deprecation.instance)
80
90
  @instance = instance
@@ -93,15 +103,23 @@ module ActiveSupport
93
103
  end
94
104
  end
95
105
 
96
- # This DeprecatedConstantProxy transforms constant to deprecated constant.
106
+ # DeprecatedConstantProxy transforms a constant into a deprecated one. It
107
+ # takes the names of an old (deprecated) constant and of a new constant
108
+ # (both in string form) and optionally a deprecator. The deprecator defaults
109
+ # to +ActiveSupport::Deprecator+ if none is specified. The deprecated constant
110
+ # now returns the value of the new one.
111
+ #
112
+ # PLANETS = %w(mercury venus earth mars jupiter saturn uranus neptune pluto)
97
113
  #
98
- # OLD_CONST = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('OLD_CONST', 'NEW_CONST')
99
- # OLD_CONST = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('OLD_CONST', 'NEW_CONST', deprecator_instance)
114
+ # (In a later update, the original implementation of `PLANETS` has been removed.)
100
115
  #
101
- # When someone use old constant this will trigger +warn+ method on
102
- # +deprecator_instance+.
116
+ # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
117
+ # PLANETS = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('PLANETS', 'PLANETS_POST_2006')
103
118
  #
104
- # Default deprecator is <tt>ActiveSupport::Deprecation</tt>.
119
+ # PLANETS.map { |planet| planet.capitalize }
120
+ # # => DEPRECATION WARNING: PLANETS is deprecated! Use PLANETS_POST_2006 instead.
121
+ # (Backtrace information…)
122
+ # ["Mercury", "Venus", "Earth", "Mars", "Jupiter", "Saturn", "Uranus", "Neptune"]
105
123
  class DeprecatedConstantProxy < DeprecationProxy
106
124
  def initialize(old_const, new_const, deprecator = ActiveSupport::Deprecation.instance)
107
125
  @old_const = old_const
@@ -109,6 +127,11 @@ module ActiveSupport
109
127
  @deprecator = deprecator
110
128
  end
111
129
 
130
+ # Returns the class of the new constant.
131
+ #
132
+ # PLANETS_POST_2006 = %w(mercury venus earth mars jupiter saturn uranus neptune)
133
+ # PLANETS = ActiveSupport::Deprecation::DeprecatedConstantProxy.new('PLANETS', 'PLANETS_POST_2006')
134
+ # PLANETS.class # => Array
112
135
  def class
113
136
  target.class
114
137
  end
@@ -1,3 +1,5 @@
1
+ require 'rbconfig'
2
+
1
3
  module ActiveSupport
2
4
  class Deprecation
3
5
  module Reporting
@@ -14,7 +16,7 @@ module ActiveSupport
14
16
  def warn(message = nil, callstack = nil)
15
17
  return if silenced
16
18
 
17
- callstack ||= caller(2)
19
+ callstack ||= caller_locations(2)
18
20
  deprecation_message(callstack, message).tap do |m|
19
21
  behavior.each { |b| b.call(m, callstack) }
20
22
  end
@@ -37,7 +39,7 @@ module ActiveSupport
37
39
  end
38
40
 
39
41
  def deprecation_warning(deprecated_method_name, message = nil, caller_backtrace = nil)
40
- caller_backtrace ||= caller(2)
42
+ caller_backtrace ||= caller_locations(2)
41
43
  deprecated_method_warning(deprecated_method_name, message).tap do |msg|
42
44
  warn(msg, caller_backtrace)
43
45
  end
@@ -63,7 +65,6 @@ module ActiveSupport
63
65
 
64
66
  def deprecation_message(callstack, message = nil)
65
67
  message ||= "You are using deprecated behavior which will be removed from the next major or minor release."
66
- message += '.' unless message =~ /\.$/
67
68
  "DEPRECATION WARNING: #{message} #{deprecation_caller_message(callstack)}"
68
69
  end
69
70
 
@@ -79,8 +80,19 @@ module ActiveSupport
79
80
  end
80
81
 
81
82
  def extract_callstack(callstack)
82
- rails_gem_root = File.expand_path("../../../../..", __FILE__) + "/"
83
- offending_line = callstack.find { |line| !line.start_with?(rails_gem_root) } || callstack.first
83
+ return _extract_callstack(callstack) if callstack.first.is_a? String
84
+
85
+ offending_line = callstack.find { |frame|
86
+ frame.absolute_path && !ignored_callstack(frame.absolute_path)
87
+ } || callstack.first
88
+
89
+ [offending_line.path, offending_line.lineno, offending_line.label]
90
+ end
91
+
92
+ def _extract_callstack(callstack)
93
+ warn "Please pass `caller_locations` to the deprecation API" if $VERBOSE
94
+ offending_line = callstack.find { |line| !ignored_callstack(line) } || callstack.first
95
+
84
96
  if offending_line
85
97
  if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
86
98
  md.captures
@@ -89,6 +101,12 @@ module ActiveSupport
89
101
  end
90
102
  end
91
103
  end
104
+
105
+ RAILS_GEM_ROOT = File.expand_path("../../../../..", __FILE__) + "/"
106
+
107
+ def ignored_callstack(path)
108
+ path.start_with?(RAILS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG['rubylibdir'])
109
+ end
92
110
  end
93
111
  end
94
112
  end