activesupport 6.1.7.2 → 7.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (222) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +866 -411
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +6 -6
  5. data/lib/active_support/actionable_error.rb +4 -2
  6. data/lib/active_support/array_inquirer.rb +2 -2
  7. data/lib/active_support/backtrace_cleaner.rb +27 -7
  8. data/lib/active_support/benchmarkable.rb +3 -2
  9. data/lib/active_support/broadcast_logger.rb +250 -0
  10. data/lib/active_support/builder.rb +1 -1
  11. data/lib/active_support/cache/coder.rb +153 -0
  12. data/lib/active_support/cache/entry.rb +134 -0
  13. data/lib/active_support/cache/file_store.rb +52 -19
  14. data/lib/active_support/cache/mem_cache_store.rb +195 -60
  15. data/lib/active_support/cache/memory_store.rb +86 -24
  16. data/lib/active_support/cache/null_store.rb +16 -2
  17. data/lib/active_support/cache/redis_cache_store.rb +186 -193
  18. data/lib/active_support/cache/serializer_with_fallback.rb +175 -0
  19. data/lib/active_support/cache/strategy/local_cache.rb +63 -71
  20. data/lib/active_support/cache.rb +478 -247
  21. data/lib/active_support/callbacks.rb +227 -105
  22. data/lib/active_support/code_generator.rb +65 -0
  23. data/lib/active_support/concern.rb +9 -7
  24. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +44 -7
  25. data/lib/active_support/concurrency/null_lock.rb +13 -0
  26. data/lib/active_support/concurrency/share_lock.rb +2 -2
  27. data/lib/active_support/configurable.rb +18 -5
  28. data/lib/active_support/configuration_file.rb +1 -1
  29. data/lib/active_support/core_ext/array/access.rb +1 -5
  30. data/lib/active_support/core_ext/array/conversions.rb +15 -13
  31. data/lib/active_support/core_ext/array/grouping.rb +6 -6
  32. data/lib/active_support/core_ext/array/inquiry.rb +2 -2
  33. data/lib/active_support/core_ext/big_decimal/conversions.rb +1 -1
  34. data/lib/active_support/core_ext/class/subclasses.rb +37 -26
  35. data/lib/active_support/core_ext/date/blank.rb +1 -1
  36. data/lib/active_support/core_ext/date/calculations.rb +24 -9
  37. data/lib/active_support/core_ext/date/conversions.rb +16 -15
  38. data/lib/active_support/core_ext/date_and_time/calculations.rb +14 -4
  39. data/lib/active_support/core_ext/date_and_time/compatibility.rb +1 -1
  40. data/lib/active_support/core_ext/date_time/blank.rb +1 -1
  41. data/lib/active_support/core_ext/date_time/calculations.rb +4 -0
  42. data/lib/active_support/core_ext/date_time/conversions.rb +19 -15
  43. data/lib/active_support/core_ext/digest/uuid.rb +30 -14
  44. data/lib/active_support/core_ext/enumerable.rb +85 -83
  45. data/lib/active_support/core_ext/erb/util.rb +196 -0
  46. data/lib/active_support/core_ext/file/atomic.rb +3 -1
  47. data/lib/active_support/core_ext/hash/conversions.rb +1 -2
  48. data/lib/active_support/core_ext/hash/deep_merge.rb +22 -14
  49. data/lib/active_support/core_ext/hash/deep_transform_values.rb +3 -3
  50. data/lib/active_support/core_ext/hash/indifferent_access.rb +3 -3
  51. data/lib/active_support/core_ext/hash/keys.rb +4 -4
  52. data/lib/active_support/core_ext/integer/inflections.rb +12 -12
  53. data/lib/active_support/core_ext/kernel/reporting.rb +4 -4
  54. data/lib/active_support/core_ext/kernel/singleton_class.rb +1 -1
  55. data/lib/active_support/core_ext/module/attribute_accessors.rb +8 -0
  56. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +49 -22
  57. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  58. data/lib/active_support/core_ext/module/delegation.rb +41 -18
  59. data/lib/active_support/core_ext/module/deprecation.rb +15 -12
  60. data/lib/active_support/core_ext/module/introspection.rb +0 -1
  61. data/lib/active_support/core_ext/name_error.rb +2 -8
  62. data/lib/active_support/core_ext/numeric/bytes.rb +9 -0
  63. data/lib/active_support/core_ext/numeric/conversions.rb +82 -77
  64. data/lib/active_support/core_ext/object/acts_like.rb +29 -5
  65. data/lib/active_support/core_ext/object/blank.rb +2 -2
  66. data/lib/active_support/core_ext/object/deep_dup.rb +17 -1
  67. data/lib/active_support/core_ext/object/duplicable.rb +15 -4
  68. data/lib/active_support/core_ext/object/inclusion.rb +13 -5
  69. data/lib/active_support/core_ext/object/instance_variables.rb +22 -12
  70. data/lib/active_support/core_ext/object/json.rb +40 -27
  71. data/lib/active_support/core_ext/object/to_query.rb +2 -4
  72. data/lib/active_support/core_ext/object/try.rb +20 -20
  73. data/lib/active_support/core_ext/object/with.rb +44 -0
  74. data/lib/active_support/core_ext/object/with_options.rb +25 -6
  75. data/lib/active_support/core_ext/object.rb +1 -0
  76. data/lib/active_support/core_ext/pathname/blank.rb +16 -0
  77. data/lib/active_support/core_ext/pathname/existence.rb +23 -0
  78. data/lib/active_support/core_ext/pathname.rb +4 -0
  79. data/lib/active_support/core_ext/range/compare_range.rb +0 -25
  80. data/lib/active_support/core_ext/range/conversions.rb +34 -13
  81. data/lib/active_support/core_ext/range/each.rb +1 -1
  82. data/lib/active_support/core_ext/range/overlap.rb +40 -0
  83. data/lib/active_support/core_ext/range.rb +1 -2
  84. data/lib/active_support/core_ext/securerandom.rb +25 -13
  85. data/lib/active_support/core_ext/string/conversions.rb +2 -2
  86. data/lib/active_support/core_ext/string/filters.rb +21 -15
  87. data/lib/active_support/core_ext/string/indent.rb +1 -1
  88. data/lib/active_support/core_ext/string/inflections.rb +17 -10
  89. data/lib/active_support/core_ext/string/inquiry.rb +1 -1
  90. data/lib/active_support/core_ext/string/output_safety.rb +85 -193
  91. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +0 -8
  92. data/lib/active_support/core_ext/thread/backtrace/location.rb +12 -0
  93. data/lib/active_support/core_ext/time/calculations.rb +29 -10
  94. data/lib/active_support/core_ext/time/conversions.rb +14 -13
  95. data/lib/active_support/core_ext/time/zones.rb +12 -28
  96. data/lib/active_support/core_ext.rb +1 -0
  97. data/lib/active_support/current_attributes.rb +46 -21
  98. data/lib/active_support/deep_mergeable.rb +53 -0
  99. data/lib/active_support/dependencies/autoload.rb +17 -12
  100. data/lib/active_support/dependencies/interlock.rb +10 -18
  101. data/lib/active_support/dependencies/require_dependency.rb +28 -0
  102. data/lib/active_support/dependencies.rb +58 -788
  103. data/lib/active_support/deprecation/behaviors.rb +66 -40
  104. data/lib/active_support/deprecation/constant_accessor.rb +5 -4
  105. data/lib/active_support/deprecation/deprecators.rb +104 -0
  106. data/lib/active_support/deprecation/disallowed.rb +6 -8
  107. data/lib/active_support/deprecation/instance_delegator.rb +31 -4
  108. data/lib/active_support/deprecation/method_wrappers.rb +9 -26
  109. data/lib/active_support/deprecation/proxy_wrappers.rb +38 -23
  110. data/lib/active_support/deprecation/reporting.rb +42 -25
  111. data/lib/active_support/deprecation.rb +32 -5
  112. data/lib/active_support/deprecator.rb +7 -0
  113. data/lib/active_support/descendants_tracker.rb +150 -72
  114. data/lib/active_support/digest.rb +4 -4
  115. data/lib/active_support/duration/iso8601_parser.rb +3 -3
  116. data/lib/active_support/duration/iso8601_serializer.rb +9 -3
  117. data/lib/active_support/duration.rb +79 -49
  118. data/lib/active_support/encrypted_configuration.rb +72 -9
  119. data/lib/active_support/encrypted_file.rb +29 -13
  120. data/lib/active_support/environment_inquirer.rb +23 -3
  121. data/lib/active_support/error_reporter/test_helper.rb +15 -0
  122. data/lib/active_support/error_reporter.rb +203 -0
  123. data/lib/active_support/evented_file_update_checker.rb +20 -7
  124. data/lib/active_support/execution_context/test_helper.rb +13 -0
  125. data/lib/active_support/execution_context.rb +53 -0
  126. data/lib/active_support/execution_wrapper.rb +31 -12
  127. data/lib/active_support/executor/test_helper.rb +7 -0
  128. data/lib/active_support/file_update_checker.rb +4 -2
  129. data/lib/active_support/fork_tracker.rb +28 -13
  130. data/lib/active_support/gem_version.rb +4 -4
  131. data/lib/active_support/gzip.rb +2 -0
  132. data/lib/active_support/hash_with_indifferent_access.rb +38 -18
  133. data/lib/active_support/html_safe_translation.rb +43 -0
  134. data/lib/active_support/i18n.rb +2 -1
  135. data/lib/active_support/i18n_railtie.rb +21 -14
  136. data/lib/active_support/inflector/inflections.rb +25 -7
  137. data/lib/active_support/inflector/methods.rb +50 -63
  138. data/lib/active_support/inflector/transliterate.rb +4 -2
  139. data/lib/active_support/isolated_execution_state.rb +76 -0
  140. data/lib/active_support/json/decoding.rb +2 -1
  141. data/lib/active_support/json/encoding.rb +27 -45
  142. data/lib/active_support/key_generator.rb +31 -6
  143. data/lib/active_support/lazy_load_hooks.rb +33 -7
  144. data/lib/active_support/locale/en.yml +3 -1
  145. data/lib/active_support/log_subscriber/test_helper.rb +2 -2
  146. data/lib/active_support/log_subscriber.rb +96 -35
  147. data/lib/active_support/logger.rb +9 -60
  148. data/lib/active_support/logger_thread_safe_level.rb +11 -34
  149. data/lib/active_support/message_encryptor.rb +206 -56
  150. data/lib/active_support/message_encryptors.rb +141 -0
  151. data/lib/active_support/message_pack/cache_serializer.rb +23 -0
  152. data/lib/active_support/message_pack/extensions.rb +292 -0
  153. data/lib/active_support/message_pack/serializer.rb +63 -0
  154. data/lib/active_support/message_pack.rb +50 -0
  155. data/lib/active_support/message_verifier.rb +235 -84
  156. data/lib/active_support/message_verifiers.rb +135 -0
  157. data/lib/active_support/messages/codec.rb +65 -0
  158. data/lib/active_support/messages/metadata.rb +112 -46
  159. data/lib/active_support/messages/rotation_coordinator.rb +93 -0
  160. data/lib/active_support/messages/rotator.rb +34 -32
  161. data/lib/active_support/messages/serializer_with_fallback.rb +158 -0
  162. data/lib/active_support/multibyte/chars.rb +12 -11
  163. data/lib/active_support/multibyte/unicode.rb +9 -49
  164. data/lib/active_support/multibyte.rb +1 -1
  165. data/lib/active_support/notifications/fanout.rb +304 -114
  166. data/lib/active_support/notifications/instrumenter.rb +109 -35
  167. data/lib/active_support/notifications.rb +24 -24
  168. data/lib/active_support/number_helper/number_converter.rb +14 -7
  169. data/lib/active_support/number_helper/number_to_currency_converter.rb +11 -6
  170. data/lib/active_support/number_helper/number_to_delimited_converter.rb +1 -1
  171. data/lib/active_support/number_helper/number_to_human_size_converter.rb +4 -4
  172. data/lib/active_support/number_helper/number_to_phone_converter.rb +2 -1
  173. data/lib/active_support/number_helper/rounding_helper.rb +1 -5
  174. data/lib/active_support/number_helper.rb +379 -319
  175. data/lib/active_support/option_merger.rb +10 -18
  176. data/lib/active_support/ordered_hash.rb +4 -4
  177. data/lib/active_support/ordered_options.rb +15 -1
  178. data/lib/active_support/parameter_filter.rb +104 -80
  179. data/lib/active_support/proxy_object.rb +2 -0
  180. data/lib/active_support/railtie.rb +83 -21
  181. data/lib/active_support/reloader.rb +12 -4
  182. data/lib/active_support/rescuable.rb +14 -12
  183. data/lib/active_support/ruby_features.rb +7 -0
  184. data/lib/active_support/secure_compare_rotator.rb +18 -11
  185. data/lib/active_support/string_inquirer.rb +3 -3
  186. data/lib/active_support/subscriber.rb +11 -40
  187. data/lib/active_support/syntax_error_proxy.rb +70 -0
  188. data/lib/active_support/tagged_logging.rb +60 -24
  189. data/lib/active_support/test_case.rb +166 -27
  190. data/lib/active_support/testing/assertions.rb +60 -14
  191. data/lib/active_support/testing/autorun.rb +0 -2
  192. data/lib/active_support/testing/constant_stubbing.rb +32 -0
  193. data/lib/active_support/testing/deprecation.rb +53 -2
  194. data/lib/active_support/testing/error_reporter_assertions.rb +107 -0
  195. data/lib/active_support/testing/isolation.rb +30 -29
  196. data/lib/active_support/testing/method_call_assertions.rb +24 -11
  197. data/lib/active_support/testing/parallelization/server.rb +4 -0
  198. data/lib/active_support/testing/parallelization/worker.rb +3 -0
  199. data/lib/active_support/testing/parallelization.rb +4 -0
  200. data/lib/active_support/testing/parallelize_executor.rb +81 -0
  201. data/lib/active_support/testing/stream.rb +4 -6
  202. data/lib/active_support/testing/strict_warnings.rb +39 -0
  203. data/lib/active_support/testing/tagged_logging.rb +1 -1
  204. data/lib/active_support/testing/time_helpers.rb +49 -16
  205. data/lib/active_support/time_with_zone.rb +39 -28
  206. data/lib/active_support/values/time_zone.rb +38 -17
  207. data/lib/active_support/version.rb +1 -1
  208. data/lib/active_support/xml_mini/jdom.rb +4 -11
  209. data/lib/active_support/xml_mini/libxml.rb +5 -5
  210. data/lib/active_support/xml_mini/libxmlsax.rb +1 -1
  211. data/lib/active_support/xml_mini/nokogiri.rb +5 -5
  212. data/lib/active_support/xml_mini/nokogirisax.rb +2 -2
  213. data/lib/active_support/xml_mini/rexml.rb +2 -2
  214. data/lib/active_support/xml_mini.rb +7 -6
  215. data/lib/active_support.rb +28 -1
  216. metadata +107 -18
  217. data/lib/active_support/core_ext/marshal.rb +0 -26
  218. data/lib/active_support/core_ext/range/include_time_with_zone.rb +0 -28
  219. data/lib/active_support/core_ext/range/overlaps.rb +0 -10
  220. data/lib/active_support/core_ext/uri.rb +0 -29
  221. data/lib/active_support/dependencies/zeitwerk_integration.rb +0 -120
  222. data/lib/active_support/per_thread_registry.rb +0 -61
@@ -4,9 +4,7 @@ require "monitor"
4
4
 
5
5
  module ActiveSupport
6
6
  module Concurrency
7
- # A monitor that will permit dependency loading while blocked waiting for
8
- # the lock.
9
- class LoadInterlockAwareMonitor < Monitor
7
+ module LoadInterlockAwareMonitorMixin # :nodoc:
10
8
  EXCEPTION_NEVER = { Exception => :never }.freeze
11
9
  EXCEPTION_IMMEDIATE = { Exception => :immediate }.freeze
12
10
  private_constant :EXCEPTION_NEVER, :EXCEPTION_IMMEDIATE
@@ -17,19 +15,58 @@ module ActiveSupport
17
15
  ActiveSupport::Dependencies.interlock.permit_concurrent_loads { super }
18
16
  end
19
17
 
20
- def synchronize
18
+ def synchronize(&block)
21
19
  Thread.handle_interrupt(EXCEPTION_NEVER) do
22
20
  mon_enter
23
21
 
24
22
  begin
25
- Thread.handle_interrupt(EXCEPTION_IMMEDIATE) do
26
- yield
27
- end
23
+ Thread.handle_interrupt(EXCEPTION_IMMEDIATE, &block)
28
24
  ensure
29
25
  mon_exit
30
26
  end
31
27
  end
32
28
  end
33
29
  end
30
+ # A monitor that will permit dependency loading while blocked waiting for
31
+ # the lock.
32
+ class LoadInterlockAwareMonitor < Monitor
33
+ include LoadInterlockAwareMonitorMixin
34
+ end
35
+
36
+ class ThreadLoadInterlockAwareMonitor # :nodoc:
37
+ prepend LoadInterlockAwareMonitorMixin
38
+
39
+ def initialize
40
+ @owner = nil
41
+ @count = 0
42
+ @mutex = Mutex.new
43
+ end
44
+
45
+ private
46
+ def mon_try_enter
47
+ if @owner != Thread.current
48
+ return false unless @mutex.try_lock
49
+ @owner = Thread.current
50
+ end
51
+ @count += 1
52
+ end
53
+
54
+ def mon_enter
55
+ @mutex.lock if @owner != Thread.current
56
+ @owner = Thread.current
57
+ @count += 1
58
+ end
59
+
60
+ def mon_exit
61
+ unless @owner == Thread.current
62
+ raise ThreadError, "current thread not owner"
63
+ end
64
+
65
+ @count -= 1
66
+ return unless @count == 0
67
+ @owner = nil
68
+ @mutex.unlock
69
+ end
70
+ end
34
71
  end
35
72
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ module Concurrency
5
+ module NullLock # :nodoc:
6
+ extend self
7
+
8
+ def synchronize
9
+ yield
10
+ end
11
+ end
12
+ end
13
+ end
@@ -215,9 +215,9 @@ module ActiveSupport
215
215
  @waiting.any? { |t, (p, _)| compatible.include?(p) && @waiting.all? { |t2, (_, c2)| t == t2 || c2.include?(p) } }
216
216
  end
217
217
 
218
- def wait_for(method)
218
+ def wait_for(method, &block)
219
219
  @sleeping[Thread.current] = method
220
- @cv.wait_while { yield }
220
+ @cv.wait_while(&block)
221
221
  ensure
222
222
  @sleeping.delete Thread.current
223
223
  end
@@ -4,8 +4,10 @@ require "active_support/concern"
4
4
  require "active_support/ordered_options"
5
5
 
6
6
  module ActiveSupport
7
+ # = Active Support \Configurable
8
+ #
7
9
  # Configurable provides a <tt>config</tt> method to store and retrieve
8
- # configuration options as an <tt>OrderedOptions</tt>.
10
+ # configuration options as an OrderedOptions.
9
11
  module Configurable
10
12
  extend ActiveSupport::Concern
11
13
 
@@ -94,17 +96,19 @@ module ActiveSupport
94
96
  # User.new.allowed_access = true # => NoMethodError
95
97
  # User.new.allowed_access # => NoMethodError
96
98
  #
97
- # Also you can pass a block to set up the attribute with a default value.
99
+ # Also you can pass <tt>default</tt> or a block to set up the attribute with a default value.
98
100
  #
99
101
  # class User
100
102
  # include ActiveSupport::Configurable
103
+ # config_accessor :allowed_access, default: false
101
104
  # config_accessor :hair_colors do
102
105
  # [:brown, :black, :blonde, :red]
103
106
  # end
104
107
  # end
105
108
  #
109
+ # User.allowed_access # => false
106
110
  # User.hair_colors # => [:brown, :black, :blonde, :red]
107
- def config_accessor(*names, instance_reader: true, instance_writer: true, instance_accessor: true) # :doc:
111
+ def config_accessor(*names, instance_reader: true, instance_writer: true, instance_accessor: true, default: nil) # :doc:
108
112
  names.each do |name|
109
113
  raise NameError.new("invalid config attribute name") unless /\A[_A-Za-z]\w*\z/.match?(name)
110
114
 
@@ -118,13 +122,22 @@ module ActiveSupport
118
122
  class_eval reader, __FILE__, reader_line if instance_reader
119
123
  class_eval writer, __FILE__, writer_line if instance_writer
120
124
  end
121
- send("#{name}=", yield) if block_given?
125
+
126
+ send("#{name}=", block_given? ? yield : default)
122
127
  end
123
128
  end
124
129
  private :config_accessor
130
+
131
+ private
132
+ def inherited(subclass)
133
+ super
134
+ subclass.class_eval do
135
+ @_config = nil
136
+ end
137
+ end
125
138
  end
126
139
 
127
- # Reads and writes attributes from a configuration <tt>OrderedOptions</tt>.
140
+ # Reads and writes attributes from a configuration OrderedOptions.
128
141
  #
129
142
  # require "active_support/configurable"
130
143
  #
@@ -38,7 +38,7 @@ module ActiveSupport
38
38
 
39
39
  File.read(content_path).tap do |content|
40
40
  if content.include?("\u00A0")
41
- warn "File contains invisible non-breaking spaces, you may want to remove those"
41
+ warn "#{content_path} contains invisible non-breaking spaces, you may want to remove those"
42
42
  end
43
43
  end
44
44
  end
@@ -47,11 +47,7 @@ class Array
47
47
  def excluding(*elements)
48
48
  self - elements.flatten(1)
49
49
  end
50
-
51
- # Alias for #excluding.
52
- def without(*elements)
53
- excluding(*elements)
54
- end
50
+ alias :without :excluding
55
51
 
56
52
  # Equal to <tt>self[1]</tt>.
57
53
  #
@@ -1,6 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require "active_support/xml_mini"
4
3
  require "active_support/core_ext/hash/keys"
5
4
  require "active_support/core_ext/string/inflections"
6
5
  require "active_support/core_ext/object/to_param"
@@ -16,12 +15,12 @@ class Array
16
15
  #
17
16
  # ==== Options
18
17
  #
19
- # * <tt>:words_connector</tt> - The sign or word used to join the elements
20
- # in arrays with two or more elements (default: ", ").
21
- # * <tt>:two_words_connector</tt> - The sign or word used to join the elements
22
- # in arrays with two elements (default: " and ").
18
+ # * <tt>:words_connector</tt> - The sign or word used to join all but the last
19
+ # element in arrays with three or more elements (default: ", ").
23
20
  # * <tt>:last_word_connector</tt> - The sign or word used to join the last element
24
21
  # in arrays with three or more elements (default: ", and ").
22
+ # * <tt>:two_words_connector</tt> - The sign or word used to join the elements
23
+ # in arrays with two elements (default: " and ").
25
24
  # * <tt>:locale</tt> - If +i18n+ is available, you can set a locale and use
26
25
  # the connector options defined on the 'support.array' namespace in the
27
26
  # corresponding dictionary file.
@@ -66,7 +65,7 @@ class Array
66
65
  two_words_connector: " and ",
67
66
  last_word_connector: ", and "
68
67
  }
69
- if defined?(I18n)
68
+ if options[:locale] != false && defined?(I18n)
70
69
  i18n_connectors = I18n.translate(:'support.array', locale: options[:locale], default: {})
71
70
  default_connectors.merge!(i18n_connectors)
72
71
  end
@@ -87,10 +86,12 @@ class Array
87
86
  # Extends <tt>Array#to_s</tt> to convert a collection of elements into a
88
87
  # comma separated id list if <tt>:db</tt> argument is given as the format.
89
88
  #
90
- # Blog.all.to_formatted_s(:db) # => "1,2,3"
91
- # Blog.none.to_formatted_s(:db) # => "null"
92
- # [1,2].to_formatted_s # => "[1, 2]"
93
- def to_formatted_s(format = :default)
89
+ # This method is aliased to <tt>to_formatted_s</tt>.
90
+ #
91
+ # Blog.all.to_fs(:db) # => "1,2,3"
92
+ # Blog.none.to_fs(:db) # => "null"
93
+ # [1,2].to_fs # => "[1, 2]"
94
+ def to_fs(format = :default)
94
95
  case format
95
96
  when :db
96
97
  if empty?
@@ -99,11 +100,12 @@ class Array
99
100
  collect(&:id).join(",")
100
101
  end
101
102
  else
102
- to_default_s
103
+ to_s
103
104
  end
104
105
  end
106
+ alias_method :to_formatted_s, :to_fs
105
107
  alias_method :to_default_s, :to_s
106
- alias_method :to_s, :to_formatted_s
108
+ deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
107
109
 
108
110
  # Returns a string that represents the array in XML by invoking +to_xml+
109
111
  # on each element. Active Record collections delegate their representation
@@ -187,7 +189,7 @@ class Array
187
189
  options[:indent] ||= 2
188
190
  options[:builder] ||= Builder::XmlMarkup.new(indent: options[:indent])
189
191
  options[:root] ||= \
190
- if first.class != Hash && all? { |e| e.is_a?(first.class) }
192
+ if first.class != Hash && all?(first.class)
191
193
  underscored = ActiveSupport::Inflector.underscore(first.class.name)
192
194
  ActiveSupport::Inflector.pluralize(underscored).tr("/", "_")
193
195
  else
@@ -19,7 +19,7 @@ class Array
19
19
  # ["1", "2"]
20
20
  # ["3", "4"]
21
21
  # ["5"]
22
- def in_groups_of(number, fill_with = nil)
22
+ def in_groups_of(number, fill_with = nil, &block)
23
23
  if number.to_i <= 0
24
24
  raise ArgumentError,
25
25
  "Group size must be a positive integer, was #{number.inspect}"
@@ -36,7 +36,7 @@ class Array
36
36
  end
37
37
 
38
38
  if block_given?
39
- collection.each_slice(number) { |slice| yield(slice) }
39
+ collection.each_slice(number, &block)
40
40
  else
41
41
  collection.each_slice(number).to_a
42
42
  end
@@ -59,7 +59,7 @@ class Array
59
59
  # ["1", "2", "3"]
60
60
  # ["4", "5"]
61
61
  # ["6", "7"]
62
- def in_groups(number, fill_with = nil)
62
+ def in_groups(number, fill_with = nil, &block)
63
63
  # size.div number gives minor group size;
64
64
  # size % number gives how many objects need extra accommodation;
65
65
  # each group hold either division or division + 1 items.
@@ -79,7 +79,7 @@ class Array
79
79
  end
80
80
 
81
81
  if block_given?
82
- groups.each { |g| yield(g) }
82
+ groups.each(&block)
83
83
  else
84
84
  groups
85
85
  end
@@ -90,11 +90,11 @@ class Array
90
90
  #
91
91
  # [1, 2, 3, 4, 5].split(3) # => [[1, 2], [4, 5]]
92
92
  # (1..10).to_a.split { |i| i % 3 == 0 } # => [[1, 2], [4, 5], [7, 8], [10]]
93
- def split(value = nil)
93
+ def split(value = nil, &block)
94
94
  arr = dup
95
95
  result = []
96
96
  if block_given?
97
- while (idx = arr.index { |i| yield i })
97
+ while (idx = arr.index(&block))
98
98
  result << arr.shift(idx)
99
99
  arr.shift
100
100
  end
@@ -3,8 +3,8 @@
3
3
  require "active_support/array_inquirer"
4
4
 
5
5
  class Array
6
- # Wraps the array in an +ArrayInquirer+ object, which gives a friendlier way
7
- # to check its string-like contents.
6
+ # Wraps the array in an ActiveSupport::ArrayInquirer object, which gives a
7
+ # friendlier way to check its string-like contents.
8
8
  #
9
9
  # pets = [:cat, :dog].inquiry
10
10
  #
@@ -4,7 +4,7 @@ require "bigdecimal"
4
4
  require "bigdecimal/util"
5
5
 
6
6
  module ActiveSupport
7
- module BigDecimalWithDefaultFormat #:nodoc:
7
+ module BigDecimalWithDefaultFormat # :nodoc:
8
8
  def to_s(format = "F")
9
9
  super(format)
10
10
  end
@@ -1,33 +1,44 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require "active_support/ruby_features"
4
+ require "active_support/descendants_tracker"
5
+
3
6
  class Class
4
- # Returns an array with all classes that are < than its receiver.
5
- #
6
- # class C; end
7
- # C.descendants # => []
8
- #
9
- # class B < C; end
10
- # C.descendants # => [B]
11
- #
12
- # class A < B; end
13
- # C.descendants # => [B, A]
14
- #
15
- # class D < C; end
16
- # C.descendants # => [B, A, D]
17
- def descendants
18
- ObjectSpace.each_object(singleton_class).reject do |k|
19
- k.singleton_class? || k == self
7
+ if ActiveSupport::RubyFeatures::CLASS_SUBCLASSES
8
+ # Returns an array with all classes that are < than its receiver.
9
+ #
10
+ # class C; end
11
+ # C.descendants # => []
12
+ #
13
+ # class B < C; end
14
+ # C.descendants # => [B]
15
+ #
16
+ # class A < B; end
17
+ # C.descendants # => [B, A]
18
+ #
19
+ # class D < C; end
20
+ # C.descendants # => [B, A, D]
21
+ def descendants
22
+ subclasses.concat(subclasses.flat_map(&:descendants))
23
+ end
24
+ else
25
+ def descendants
26
+ ObjectSpace.each_object(singleton_class).reject do |k|
27
+ k.singleton_class? || k == self
28
+ end
20
29
  end
21
- end
22
30
 
23
- # Returns an array with the direct children of +self+.
24
- #
25
- # class Foo; end
26
- # class Bar < Foo; end
27
- # class Baz < Bar; end
28
- #
29
- # Foo.subclasses # => [Bar]
30
- def subclasses
31
- descendants.select { |descendant| descendant.superclass == self }
31
+ # Returns an array with the direct children of +self+.
32
+ #
33
+ # class Foo; end
34
+ # class Bar < Foo; end
35
+ # class Baz < Bar; end
36
+ #
37
+ # Foo.subclasses # => [Bar]
38
+ def subclasses
39
+ descendants.select { |descendant| descendant.superclass == self }
40
+ end
32
41
  end
42
+
43
+ prepend ActiveSupport::DescendantsTracker::ReloadedClassesFiltering
33
44
  end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "date"
4
4
 
5
- class Date #:nodoc:
5
+ class Date # :nodoc:
6
6
  # No Date is blank:
7
7
  #
8
8
  # Date.today.blank? # => false
@@ -13,22 +13,22 @@ class Date
13
13
  class << self
14
14
  attr_accessor :beginning_of_week_default
15
15
 
16
- # Returns the week start (e.g. :monday) for the current request, if this has been set (via Date.beginning_of_week=).
16
+ # Returns the week start (e.g. +:monday+) for the current request, if this has been set (via Date.beginning_of_week=).
17
17
  # If <tt>Date.beginning_of_week</tt> has not been set for the current request, returns the week start specified in <tt>config.beginning_of_week</tt>.
18
- # If no config.beginning_of_week was specified, returns :monday.
18
+ # If no +config.beginning_of_week+ was specified, returns +:monday+.
19
19
  def beginning_of_week
20
- Thread.current[:beginning_of_week] || beginning_of_week_default || :monday
20
+ ::ActiveSupport::IsolatedExecutionState[:beginning_of_week] || beginning_of_week_default || :monday
21
21
  end
22
22
 
23
- # Sets <tt>Date.beginning_of_week</tt> to a week start (e.g. :monday) for current request/thread.
23
+ # Sets <tt>Date.beginning_of_week</tt> to a week start (e.g. +:monday+) for current request/thread.
24
24
  #
25
25
  # This method accepts any of the following day symbols:
26
- # :monday, :tuesday, :wednesday, :thursday, :friday, :saturday, :sunday
26
+ # +:monday+, +:tuesday+, +:wednesday+, +:thursday+, +:friday+, +:saturday+, +:sunday+
27
27
  def beginning_of_week=(week_start)
28
- Thread.current[:beginning_of_week] = find_beginning_of_week!(week_start)
28
+ ::ActiveSupport::IsolatedExecutionState[:beginning_of_week] = find_beginning_of_week!(week_start)
29
29
  end
30
30
 
31
- # Returns week start day symbol (e.g. :monday), or raises an +ArgumentError+ for invalid day symbol.
31
+ # Returns week start day symbol (e.g. +:monday+), or raises an +ArgumentError+ for invalid day symbol.
32
32
  def find_beginning_of_week!(week_start)
33
33
  raise ArgumentError, "Invalid beginning of week: #{week_start}" unless ::Date::DAYS_INTO_WEEK.key?(week_start)
34
34
  week_start
@@ -87,7 +87,7 @@ class Date
87
87
  end
88
88
  alias :at_end_of_day :end_of_day
89
89
 
90
- def plus_with_duration(other) #:nodoc:
90
+ def plus_with_duration(other) # :nodoc:
91
91
  if ActiveSupport::Duration === other
92
92
  other.since(self)
93
93
  else
@@ -97,7 +97,7 @@ class Date
97
97
  alias_method :plus_without_duration, :+
98
98
  alias_method :+, :plus_with_duration
99
99
 
100
- def minus_with_duration(other) #:nodoc:
100
+ def minus_with_duration(other) # :nodoc:
101
101
  if ActiveSupport::Duration === other
102
102
  plus_with_duration(-other)
103
103
  else
@@ -109,6 +109,21 @@ class Date
109
109
 
110
110
  # Provides precise Date calculations for years, months, and days. The +options+ parameter takes a hash with
111
111
  # any of these keys: <tt>:years</tt>, <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>.
112
+ #
113
+ # The increments are applied in order of time units from largest to smallest.
114
+ # In other words, the date is incremented first by +:years+, then by
115
+ # +:months+, then by +:weeks+, then by +:days+. This order can affect the
116
+ # result around the end of a month. For example, incrementing first by months
117
+ # then by days:
118
+ #
119
+ # Date.new(2004, 9, 30).advance(months: 1, days: 1)
120
+ # # => Sun, 31 Oct 2004
121
+ #
122
+ # Whereas incrementing first by days then by months yields a different result:
123
+ #
124
+ # Date.new(2004, 9, 30).advance(days: 1).advance(months: 1)
125
+ # # => Mon, 01 Nov 2004
126
+ #
112
127
  def advance(options)
113
128
  d = self
114
129
 
@@ -22,21 +22,21 @@ class Date
22
22
 
23
23
  # Convert to a formatted string. See DATE_FORMATS for predefined formats.
24
24
  #
25
- # This method is aliased to <tt>to_s</tt>.
25
+ # This method is aliased to <tt>to_formatted_s</tt>.
26
26
  #
27
27
  # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
28
28
  #
29
+ # date.to_fs(:db) # => "2007-11-10"
29
30
  # date.to_formatted_s(:db) # => "2007-11-10"
30
- # date.to_s(:db) # => "2007-11-10"
31
31
  #
32
- # date.to_formatted_s(:short) # => "10 Nov"
33
- # date.to_formatted_s(:number) # => "20071110"
34
- # date.to_formatted_s(:long) # => "November 10, 2007"
35
- # date.to_formatted_s(:long_ordinal) # => "November 10th, 2007"
36
- # date.to_formatted_s(:rfc822) # => "10 Nov 2007"
37
- # date.to_formatted_s(:iso8601) # => "2007-11-10"
32
+ # date.to_fs(:short) # => "10 Nov"
33
+ # date.to_fs(:number) # => "20071110"
34
+ # date.to_fs(:long) # => "November 10, 2007"
35
+ # date.to_fs(:long_ordinal) # => "November 10th, 2007"
36
+ # date.to_fs(:rfc822) # => "10 Nov 2007"
37
+ # date.to_fs(:iso8601) # => "2007-11-10"
38
38
  #
39
- # == Adding your own date formats to to_formatted_s
39
+ # == Adding your own date formats to to_fs
40
40
  # You can add your own formats to the Date::DATE_FORMATS hash.
41
41
  # Use the format name as the hash key and either a strftime string
42
42
  # or Proc instance that takes a date argument as the value.
@@ -44,7 +44,7 @@ class Date
44
44
  # # config/initializers/date_formats.rb
45
45
  # Date::DATE_FORMATS[:month_and_year] = '%B %Y'
46
46
  # Date::DATE_FORMATS[:short_ordinal] = ->(date) { date.strftime("%B #{date.day.ordinalize}") }
47
- def to_formatted_s(format = :default)
47
+ def to_fs(format = :default)
48
48
  if formatter = DATE_FORMATS[format]
49
49
  if formatter.respond_to?(:call)
50
50
  formatter.call(self).to_s
@@ -52,11 +52,12 @@ class Date
52
52
  strftime(formatter)
53
53
  end
54
54
  else
55
- to_default_s
55
+ to_s
56
56
  end
57
57
  end
58
+ alias_method :to_formatted_s, :to_fs
58
59
  alias_method :to_default_s, :to_s
59
- alias_method :to_s, :to_formatted_s
60
+ deprecate to_default_s: :to_s, deprecator: ActiveSupport.deprecator
60
61
 
61
62
  # Overrides the default inspect method with a human readable one, e.g., "Mon, 21 Feb 2005"
62
63
  def readable_inspect
@@ -68,7 +69,7 @@ class Date
68
69
  silence_redefinition_of_method :to_time
69
70
 
70
71
  # Converts a Date instance to a Time, where the time is set to the beginning of the day.
71
- # The timezone can be either :local or :utc (default :local).
72
+ # The timezone can be either +:local+ or +:utc+ (default +:local+).
72
73
  #
73
74
  # date = Date.new(2007, 11, 10) # => Sat, 10 Nov 2007
74
75
  #
@@ -77,8 +78,8 @@ class Date
77
78
  #
78
79
  # date.to_time(:utc) # => 2007-11-10 00:00:00 UTC
79
80
  #
80
- # NOTE: The :local timezone is Ruby's *process* timezone, i.e. ENV['TZ'].
81
- # If the *application's* timezone is needed, then use +in_time_zone+ instead.
81
+ # NOTE: The +:local+ timezone is Ruby's *process* timezone, i.e. <tt>ENV['TZ']</tt>.
82
+ # If the <b>application's</b> timezone is needed, then use +in_time_zone+ instead.
82
83
  def to_time(form = :local)
83
84
  raise ArgumentError, "Expected :local or :utc, got #{form.inspect}." unless [:local, :utc].include?(form)
84
85
  ::Time.public_send(form, year, month, day)
@@ -157,6 +157,16 @@ module DateAndTime
157
157
  end
158
158
  alias :at_end_of_quarter :end_of_quarter
159
159
 
160
+ # Returns the quarter for a date/time.
161
+ #
162
+ # Date.new(2010, 1, 31).quarter # => 1
163
+ # Date.new(2010, 4, 12).quarter # => 2
164
+ # Date.new(2010, 9, 15).quarter # => 3
165
+ # Date.new(2010, 12, 25).quarter # => 4
166
+ def quarter
167
+ (month / 3.0).ceil
168
+ end
169
+
160
170
  # Returns a new date/time at the beginning of the year.
161
171
  #
162
172
  # today = Date.today # => Fri, 10 Jul 2015
@@ -201,7 +211,7 @@ module DateAndTime
201
211
  end
202
212
  end
203
213
 
204
- # Short-hand for months_since(3)
214
+ # Short-hand for <tt>months_since(3)</tt>.
205
215
  def next_quarter
206
216
  months_since(3)
207
217
  end
@@ -226,18 +236,18 @@ module DateAndTime
226
236
  end
227
237
  alias_method :last_weekday, :prev_weekday
228
238
 
229
- # Short-hand for months_ago(1).
239
+ # Short-hand for <tt>months_ago(1)</tt>.
230
240
  def last_month
231
241
  months_ago(1)
232
242
  end
233
243
 
234
- # Short-hand for months_ago(3).
244
+ # Short-hand for <tt>months_ago(3)</tt>.
235
245
  def prev_quarter
236
246
  months_ago(3)
237
247
  end
238
248
  alias_method :last_quarter, :prev_quarter
239
249
 
240
- # Short-hand for years_ago(1).
250
+ # Short-hand for <tt>years_ago(1)</tt>.
241
251
  def last_year
242
252
  years_ago(1)
243
253
  end
@@ -15,7 +15,7 @@ module DateAndTime
15
15
 
16
16
  # Change the output of <tt>ActiveSupport::TimeZone.utc_to_local</tt>.
17
17
  #
18
- # When `true`, it returns local times with an UTC offset, with `false` local
18
+ # When +true+, it returns local times with a UTC offset, with +false+ local
19
19
  # times are returned as UTC.
20
20
  #
21
21
  # # Given this zone:
@@ -2,7 +2,7 @@
2
2
 
3
3
  require "date"
4
4
 
5
- class DateTime #:nodoc:
5
+ class DateTime # :nodoc:
6
6
  # No DateTime is ever blank:
7
7
  #
8
8
  # DateTime.now.blank? # => false
@@ -75,6 +75,10 @@ class DateTime
75
75
  # The +options+ parameter takes a hash with any of these keys: <tt>:years</tt>,
76
76
  # <tt>:months</tt>, <tt>:weeks</tt>, <tt>:days</tt>, <tt>:hours</tt>,
77
77
  # <tt>:minutes</tt>, <tt>:seconds</tt>.
78
+ #
79
+ # Just like Date#advance, increments are applied in order of time units from
80
+ # largest to smallest. This order can affect the result around the end of a
81
+ # month.
78
82
  def advance(options)
79
83
  unless options[:weeks].nil?
80
84
  options[:weeks], partial_weeks = options[:weeks].divmod(1)