activesupport 4.2.11.1 → 6.1.7.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 (272) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +464 -391
  3. data/MIT-LICENSE +2 -2
  4. data/README.rdoc +7 -7
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/all.rb +5 -3
  7. data/lib/active_support/array_inquirer.rb +50 -0
  8. data/lib/active_support/backtrace_cleaner.rb +34 -6
  9. data/lib/active_support/benchmarkable.rb +6 -4
  10. data/lib/active_support/builder.rb +3 -1
  11. data/lib/active_support/cache/file_store.rb +61 -55
  12. data/lib/active_support/cache/mem_cache_store.rb +115 -100
  13. data/lib/active_support/cache/memory_store.rb +81 -58
  14. data/lib/active_support/cache/null_store.rb +11 -7
  15. data/lib/active_support/cache/redis_cache_store.rb +493 -0
  16. data/lib/active_support/cache/strategy/local_cache.rb +90 -42
  17. data/lib/active_support/cache/strategy/local_cache_middleware.rb +10 -9
  18. data/lib/active_support/cache.rb +386 -225
  19. data/lib/active_support/callbacks.rb +661 -594
  20. data/lib/active_support/concern.rb +80 -7
  21. data/lib/active_support/concurrency/load_interlock_aware_monitor.rb +35 -0
  22. data/lib/active_support/concurrency/share_lock.rb +226 -0
  23. data/lib/active_support/configurable.rb +16 -17
  24. data/lib/active_support/configuration_file.rb +51 -0
  25. data/lib/active_support/core_ext/array/access.rb +41 -1
  26. data/lib/active_support/core_ext/array/conversions.rb +24 -20
  27. data/lib/active_support/core_ext/array/extract.rb +21 -0
  28. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  29. data/lib/active_support/core_ext/array/grouping.rb +11 -18
  30. data/lib/active_support/core_ext/array/inquiry.rb +19 -0
  31. data/lib/active_support/core_ext/array/wrap.rb +7 -4
  32. data/lib/active_support/core_ext/array.rb +9 -6
  33. data/lib/active_support/core_ext/benchmark.rb +5 -3
  34. data/lib/active_support/core_ext/big_decimal/conversions.rb +10 -12
  35. data/lib/active_support/core_ext/big_decimal.rb +3 -1
  36. data/lib/active_support/core_ext/class/attribute.rb +52 -48
  37. data/lib/active_support/core_ext/class/attribute_accessors.rb +3 -1
  38. data/lib/active_support/core_ext/class/subclasses.rb +18 -25
  39. data/lib/active_support/core_ext/class.rb +4 -3
  40. data/lib/active_support/core_ext/date/acts_like.rb +3 -1
  41. data/lib/active_support/core_ext/date/blank.rb +14 -0
  42. data/lib/active_support/core_ext/date/calculations.rb +17 -14
  43. data/lib/active_support/core_ext/date/conversions.rb +27 -24
  44. data/lib/active_support/core_ext/date/zones.rb +4 -2
  45. data/lib/active_support/core_ext/date.rb +6 -4
  46. data/lib/active_support/core_ext/date_and_time/calculations.rb +167 -65
  47. data/lib/active_support/core_ext/date_and_time/compatibility.rb +19 -3
  48. data/lib/active_support/core_ext/date_and_time/zones.rb +12 -13
  49. data/lib/active_support/core_ext/date_time/acts_like.rb +4 -2
  50. data/lib/active_support/core_ext/date_time/blank.rb +14 -0
  51. data/lib/active_support/core_ext/date_time/calculations.rb +37 -19
  52. data/lib/active_support/core_ext/date_time/compatibility.rb +8 -6
  53. data/lib/active_support/core_ext/date_time/conversions.rb +16 -13
  54. data/lib/active_support/core_ext/date_time.rb +7 -5
  55. data/lib/active_support/core_ext/digest/uuid.rb +8 -5
  56. data/lib/active_support/core_ext/digest.rb +3 -0
  57. data/lib/active_support/core_ext/enumerable.rb +186 -22
  58. data/lib/active_support/core_ext/file/atomic.rb +38 -31
  59. data/lib/active_support/core_ext/file.rb +3 -1
  60. data/lib/active_support/core_ext/hash/conversions.rb +62 -41
  61. data/lib/active_support/core_ext/hash/deep_merge.rb +9 -13
  62. data/lib/active_support/core_ext/hash/deep_transform_values.rb +46 -0
  63. data/lib/active_support/core_ext/hash/except.rb +13 -10
  64. data/lib/active_support/core_ext/hash/indifferent_access.rb +4 -3
  65. data/lib/active_support/core_ext/hash/keys.rb +20 -43
  66. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  67. data/lib/active_support/core_ext/hash/slice.rb +8 -29
  68. data/lib/active_support/core_ext/hash.rb +10 -9
  69. data/lib/active_support/core_ext/integer/inflections.rb +3 -1
  70. data/lib/active_support/core_ext/integer/multiple.rb +3 -1
  71. data/lib/active_support/core_ext/integer/time.rb +11 -18
  72. data/lib/active_support/core_ext/integer.rb +5 -3
  73. data/lib/active_support/core_ext/kernel/concern.rb +5 -1
  74. data/lib/active_support/core_ext/kernel/reporting.rb +4 -84
  75. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  76. data/lib/active_support/core_ext/kernel.rb +5 -5
  77. data/lib/active_support/core_ext/load_error.rb +3 -22
  78. data/lib/active_support/core_ext/marshal.rb +10 -8
  79. data/lib/active_support/core_ext/module/aliasing.rb +6 -44
  80. data/lib/active_support/core_ext/module/anonymous.rb +12 -1
  81. data/lib/active_support/core_ext/module/attr_internal.rb +8 -9
  82. data/lib/active_support/core_ext/module/attribute_accessors.rb +63 -69
  83. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +148 -0
  84. data/lib/active_support/core_ext/module/concerning.rb +19 -14
  85. data/lib/active_support/core_ext/module/delegation.rb +164 -51
  86. data/lib/active_support/core_ext/module/deprecation.rb +4 -2
  87. data/lib/active_support/core_ext/module/introspection.rb +23 -22
  88. data/lib/active_support/core_ext/module/redefine_method.rb +40 -0
  89. data/lib/active_support/core_ext/module/remove_method.rb +8 -3
  90. data/lib/active_support/core_ext/module.rb +13 -11
  91. data/lib/active_support/core_ext/name_error.rb +51 -4
  92. data/lib/active_support/core_ext/numeric/bytes.rb +22 -0
  93. data/lib/active_support/core_ext/numeric/conversions.rb +133 -136
  94. data/lib/active_support/core_ext/numeric/time.rb +35 -23
  95. data/lib/active_support/core_ext/numeric.rb +5 -3
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +27 -3
  98. data/lib/active_support/core_ext/object/conversions.rb +6 -4
  99. data/lib/active_support/core_ext/object/deep_dup.rb +13 -4
  100. data/lib/active_support/core_ext/object/duplicable.rb +13 -93
  101. data/lib/active_support/core_ext/object/inclusion.rb +5 -3
  102. data/lib/active_support/core_ext/object/instance_variables.rb +3 -1
  103. data/lib/active_support/core_ext/object/json.rb +63 -21
  104. data/lib/active_support/core_ext/object/to_param.rb +3 -1
  105. data/lib/active_support/core_ext/object/to_query.rb +10 -5
  106. data/lib/active_support/core_ext/object/try.rb +81 -23
  107. data/lib/active_support/core_ext/object/with_options.rb +16 -3
  108. data/lib/active_support/core_ext/object.rb +14 -13
  109. data/lib/active_support/core_ext/range/compare_range.rb +82 -0
  110. data/lib/active_support/core_ext/range/conversions.rb +37 -15
  111. data/lib/active_support/core_ext/range/each.rb +18 -17
  112. data/lib/active_support/core_ext/range/include_time_with_zone.rb +28 -0
  113. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  114. data/lib/active_support/core_ext/range.rb +7 -4
  115. data/lib/active_support/core_ext/regexp.rb +10 -1
  116. data/lib/active_support/core_ext/securerandom.rb +45 -0
  117. data/lib/active_support/core_ext/string/access.rb +9 -18
  118. data/lib/active_support/core_ext/string/behavior.rb +3 -1
  119. data/lib/active_support/core_ext/string/conversions.rb +8 -4
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +48 -6
  122. data/lib/active_support/core_ext/string/indent.rb +6 -4
  123. data/lib/active_support/core_ext/string/inflections.rb +102 -26
  124. data/lib/active_support/core_ext/string/inquiry.rb +4 -1
  125. data/lib/active_support/core_ext/string/multibyte.rb +18 -9
  126. data/lib/active_support/core_ext/string/output_safety.rb +125 -40
  127. data/lib/active_support/core_ext/string/starts_ends_with.rb +4 -2
  128. data/lib/active_support/core_ext/string/strip.rb +6 -5
  129. data/lib/active_support/core_ext/string/zones.rb +4 -2
  130. data/lib/active_support/core_ext/string.rb +15 -13
  131. data/lib/active_support/core_ext/symbol/starts_ends_with.rb +14 -0
  132. data/lib/active_support/core_ext/symbol.rb +3 -0
  133. data/lib/active_support/core_ext/time/acts_like.rb +3 -1
  134. data/lib/active_support/core_ext/time/calculations.rb +137 -53
  135. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  136. data/lib/active_support/core_ext/time/conversions.rb +22 -13
  137. data/lib/active_support/core_ext/time/zones.rb +41 -7
  138. data/lib/active_support/core_ext/time.rb +7 -6
  139. data/lib/active_support/core_ext/uri.rb +11 -8
  140. data/lib/active_support/core_ext.rb +3 -1
  141. data/lib/active_support/current_attributes/test_helper.rb +13 -0
  142. data/lib/active_support/current_attributes.rb +210 -0
  143. data/lib/active_support/dependencies/autoload.rb +2 -0
  144. data/lib/active_support/dependencies/interlock.rb +57 -0
  145. data/lib/active_support/dependencies/zeitwerk_integration.rb +120 -0
  146. data/lib/active_support/dependencies.rb +241 -175
  147. data/lib/active_support/deprecation/behaviors.rb +58 -12
  148. data/lib/active_support/deprecation/constant_accessor.rb +52 -0
  149. data/lib/active_support/deprecation/disallowed.rb +56 -0
  150. data/lib/active_support/deprecation/instance_delegator.rb +16 -2
  151. data/lib/active_support/deprecation/method_wrappers.rb +62 -21
  152. data/lib/active_support/deprecation/proxy_wrappers.rb +81 -30
  153. data/lib/active_support/deprecation/reporting.rb +81 -18
  154. data/lib/active_support/deprecation.rb +17 -9
  155. data/lib/active_support/descendants_tracker.rb +61 -9
  156. data/lib/active_support/digest.rb +22 -0
  157. data/lib/active_support/duration/iso8601_parser.rb +123 -0
  158. data/lib/active_support/duration/iso8601_serializer.rb +59 -0
  159. data/lib/active_support/duration.rb +364 -39
  160. data/lib/active_support/encrypted_configuration.rb +45 -0
  161. data/lib/active_support/encrypted_file.rb +117 -0
  162. data/lib/active_support/environment_inquirer.rb +20 -0
  163. data/lib/active_support/evented_file_update_checker.rb +170 -0
  164. data/lib/active_support/execution_wrapper.rb +132 -0
  165. data/lib/active_support/executor.rb +8 -0
  166. data/lib/active_support/file_update_checker.rb +62 -37
  167. data/lib/active_support/fork_tracker.rb +64 -0
  168. data/lib/active_support/gem_version.rb +7 -5
  169. data/lib/active_support/gzip.rb +7 -5
  170. data/lib/active_support/hash_with_indifferent_access.rb +171 -48
  171. data/lib/active_support/i18n.rb +9 -6
  172. data/lib/active_support/i18n_railtie.rb +47 -16
  173. data/lib/active_support/inflections.rb +13 -11
  174. data/lib/active_support/inflector/inflections.rb +58 -14
  175. data/lib/active_support/inflector/methods.rb +186 -169
  176. data/lib/active_support/inflector/transliterate.rb +83 -33
  177. data/lib/active_support/inflector.rb +7 -5
  178. data/lib/active_support/json/decoding.rb +32 -30
  179. data/lib/active_support/json/encoding.rb +22 -61
  180. data/lib/active_support/json.rb +4 -2
  181. data/lib/active_support/key_generator.rb +11 -43
  182. data/lib/active_support/lazy_load_hooks.rb +53 -20
  183. data/lib/active_support/locale/en.rb +33 -0
  184. data/lib/active_support/locale/en.yml +9 -3
  185. data/lib/active_support/log_subscriber/test_helper.rb +14 -12
  186. data/lib/active_support/log_subscriber.rb +52 -19
  187. data/lib/active_support/logger.rb +10 -24
  188. data/lib/active_support/logger_silence.rb +14 -20
  189. data/lib/active_support/logger_thread_safe_level.rb +56 -10
  190. data/lib/active_support/message_encryptor.rb +167 -57
  191. data/lib/active_support/message_verifier.rb +151 -18
  192. data/lib/active_support/messages/metadata.rb +80 -0
  193. data/lib/active_support/messages/rotation_configuration.rb +23 -0
  194. data/lib/active_support/messages/rotator.rb +57 -0
  195. data/lib/active_support/multibyte/chars.rb +35 -80
  196. data/lib/active_support/multibyte/unicode.rb +22 -330
  197. data/lib/active_support/multibyte.rb +4 -2
  198. data/lib/active_support/notifications/fanout.rb +125 -23
  199. data/lib/active_support/notifications/instrumenter.rb +98 -16
  200. data/lib/active_support/notifications.rb +82 -14
  201. data/lib/active_support/number_helper/number_converter.rb +17 -16
  202. data/lib/active_support/number_helper/number_to_currency_converter.rb +9 -14
  203. data/lib/active_support/number_helper/number_to_delimited_converter.rb +11 -4
  204. data/lib/active_support/number_helper/number_to_human_converter.rb +14 -11
  205. data/lib/active_support/number_helper/number_to_human_size_converter.rb +12 -10
  206. data/lib/active_support/number_helper/number_to_percentage_converter.rb +5 -1
  207. data/lib/active_support/number_helper/number_to_phone_converter.rb +15 -5
  208. data/lib/active_support/number_helper/number_to_rounded_converter.rb +29 -57
  209. data/lib/active_support/number_helper/rounding_helper.rb +50 -0
  210. data/lib/active_support/number_helper.rb +123 -71
  211. data/lib/active_support/option_merger.rb +25 -4
  212. data/lib/active_support/ordered_hash.rb +7 -5
  213. data/lib/active_support/ordered_options.rb +35 -7
  214. data/lib/active_support/parameter_filter.rb +133 -0
  215. data/lib/active_support/per_thread_registry.rb +10 -4
  216. data/lib/active_support/proxy_object.rb +2 -0
  217. data/lib/active_support/rails.rb +10 -11
  218. data/lib/active_support/railtie.rb +66 -10
  219. data/lib/active_support/reloader.rb +130 -0
  220. data/lib/active_support/rescuable.rb +112 -57
  221. data/lib/active_support/secure_compare_rotator.rb +51 -0
  222. data/lib/active_support/security_utils.rb +26 -15
  223. data/lib/active_support/string_inquirer.rb +13 -4
  224. data/lib/active_support/subscriber.rb +80 -31
  225. data/lib/active_support/tagged_logging.rb +54 -17
  226. data/lib/active_support/test_case.rb +107 -44
  227. data/lib/active_support/testing/assertions.rb +158 -20
  228. data/lib/active_support/testing/autorun.rb +4 -2
  229. data/lib/active_support/testing/constant_lookup.rb +2 -1
  230. data/lib/active_support/testing/declarative.rb +3 -1
  231. data/lib/active_support/testing/deprecation.rb +13 -10
  232. data/lib/active_support/testing/file_fixtures.rb +38 -0
  233. data/lib/active_support/testing/isolation.rb +35 -26
  234. data/lib/active_support/testing/method_call_assertions.rb +70 -0
  235. data/lib/active_support/testing/parallelization/server.rb +78 -0
  236. data/lib/active_support/testing/parallelization/worker.rb +100 -0
  237. data/lib/active_support/testing/parallelization.rb +51 -0
  238. data/lib/active_support/testing/setup_and_teardown.rb +13 -8
  239. data/lib/active_support/testing/stream.rb +43 -0
  240. data/lib/active_support/testing/tagged_logging.rb +3 -1
  241. data/lib/active_support/testing/time_helpers.rb +121 -20
  242. data/lib/active_support/time.rb +14 -12
  243. data/lib/active_support/time_with_zone.rb +215 -51
  244. data/lib/active_support/values/time_zone.rb +223 -71
  245. data/lib/active_support/version.rb +3 -1
  246. data/lib/active_support/xml_mini/jdom.rb +116 -115
  247. data/lib/active_support/xml_mini/libxml.rb +16 -13
  248. data/lib/active_support/xml_mini/libxmlsax.rb +15 -14
  249. data/lib/active_support/xml_mini/nokogiri.rb +14 -12
  250. data/lib/active_support/xml_mini/nokogirisax.rb +14 -13
  251. data/lib/active_support/xml_mini/rexml.rb +18 -9
  252. data/lib/active_support/xml_mini.rb +38 -46
  253. data/lib/active_support.rb +25 -11
  254. metadata +100 -43
  255. data/lib/active_support/concurrency/latch.rb +0 -27
  256. data/lib/active_support/core_ext/array/prepend_and_append.rb +0 -7
  257. data/lib/active_support/core_ext/big_decimal/yaml_conversions.rb +0 -16
  258. data/lib/active_support/core_ext/class/delegating_attributes.rb +0 -45
  259. data/lib/active_support/core_ext/date_time/zones.rb +0 -6
  260. data/lib/active_support/core_ext/hash/compact.rb +0 -24
  261. data/lib/active_support/core_ext/hash/transform_values.rb +0 -23
  262. data/lib/active_support/core_ext/kernel/agnostics.rb +0 -11
  263. data/lib/active_support/core_ext/kernel/debugger.rb +0 -10
  264. data/lib/active_support/core_ext/module/method_transplanting.rb +0 -13
  265. data/lib/active_support/core_ext/module/qualified_const.rb +0 -52
  266. data/lib/active_support/core_ext/module/reachable.rb +0 -8
  267. data/lib/active_support/core_ext/object/itself.rb +0 -15
  268. data/lib/active_support/core_ext/range/include_range.rb +0 -23
  269. data/lib/active_support/core_ext/struct.rb +0 -6
  270. data/lib/active_support/core_ext/thread.rb +0 -86
  271. data/lib/active_support/core_ext/time/marshal.rb +0 -30
  272. data/lib/active_support/values/unicode_tables.dat +0 -0
@@ -1,4 +1,6 @@
1
- require 'date'
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
2
4
 
3
5
  class DateTime
4
6
  class << self
@@ -10,7 +12,11 @@ class DateTime
10
12
  end
11
13
  end
12
14
 
13
- # Seconds since midnight: DateTime.now.seconds_since_midnight.
15
+ # Returns the number of seconds since 00:00:00.
16
+ #
17
+ # DateTime.new(2012, 8, 29, 0, 0, 0).seconds_since_midnight # => 0
18
+ # DateTime.new(2012, 8, 29, 12, 34, 56).seconds_since_midnight # => 45296
19
+ # DateTime.new(2012, 8, 29, 23, 59, 59).seconds_since_midnight # => 86399
14
20
  def seconds_since_midnight
15
21
  sec + (min * 60) + (hour * 3600)
16
22
  end
@@ -43,13 +49,23 @@ class DateTime
43
49
  # DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, day: 1) # => DateTime.new(1981, 8, 1, 22, 35, 0)
44
50
  # DateTime.new(2012, 8, 29, 22, 35, 0).change(year: 1981, hour: 0) # => DateTime.new(1981, 8, 29, 0, 0, 0)
45
51
  def change(options)
52
+ if new_nsec = options[:nsec]
53
+ raise ArgumentError, "Can't change both :nsec and :usec at the same time: #{options.inspect}" if options[:usec]
54
+ new_fraction = Rational(new_nsec, 1000000000)
55
+ else
56
+ new_usec = options.fetch(:usec, (options[:hour] || options[:min] || options[:sec]) ? 0 : Rational(nsec, 1000))
57
+ new_fraction = Rational(new_usec, 1000000)
58
+ end
59
+
60
+ raise ArgumentError, "argument out of range" if new_fraction >= 1
61
+
46
62
  ::DateTime.civil(
47
63
  options.fetch(:year, year),
48
64
  options.fetch(:month, month),
49
65
  options.fetch(:day, day),
50
66
  options.fetch(:hour, hour),
51
67
  options.fetch(:min, options[:hour] ? 0 : min),
52
- options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec + sec_fraction),
68
+ options.fetch(:sec, (options[:hour] || options[:min]) ? 0 : sec) + new_fraction,
53
69
  options.fetch(:offset, offset),
54
70
  options.fetch(:start, start)
55
71
  )
@@ -71,7 +87,7 @@ class DateTime
71
87
  end
72
88
 
73
89
  d = to_date.advance(options)
74
- datetime_advanced_by_date = change(:year => d.year, :month => d.month, :day => d.day)
90
+ datetime_advanced_by_date = change(year: d.year, month: d.month, day: d.day)
75
91
  seconds_to_advance = \
76
92
  options.fetch(:seconds, 0) +
77
93
  options.fetch(:minutes, 0) * 60 +
@@ -94,13 +110,13 @@ class DateTime
94
110
  # instance time. Do not use this method in combination with x.months, use
95
111
  # months_since instead!
96
112
  def since(seconds)
97
- self + Rational(seconds.round, 86400)
113
+ self + Rational(seconds, 86400)
98
114
  end
99
115
  alias :in :since
100
116
 
101
117
  # Returns a new DateTime representing the start of the day (0:00).
102
118
  def beginning_of_day
103
- change(:hour => 0)
119
+ change(hour: 0)
104
120
  end
105
121
  alias :midnight :beginning_of_day
106
122
  alias :at_midnight :beginning_of_day
@@ -108,7 +124,7 @@ class DateTime
108
124
 
109
125
  # Returns a new DateTime representing the middle of the day (12:00)
110
126
  def middle_of_day
111
- change(:hour => 12)
127
+ change(hour: 12)
112
128
  end
113
129
  alias :midday :middle_of_day
114
130
  alias :noon :middle_of_day
@@ -118,31 +134,31 @@ class DateTime
118
134
 
119
135
  # Returns a new DateTime representing the end of the day (23:59:59).
120
136
  def end_of_day
121
- change(:hour => 23, :min => 59, :sec => 59)
137
+ change(hour: 23, min: 59, sec: 59, usec: Rational(999999999, 1000))
122
138
  end
123
139
  alias :at_end_of_day :end_of_day
124
140
 
125
141
  # Returns a new DateTime representing the start of the hour (hh:00:00).
126
142
  def beginning_of_hour
127
- change(:min => 0)
143
+ change(min: 0)
128
144
  end
129
145
  alias :at_beginning_of_hour :beginning_of_hour
130
146
 
131
147
  # Returns a new DateTime representing the end of the hour (hh:59:59).
132
148
  def end_of_hour
133
- change(:min => 59, :sec => 59)
149
+ change(min: 59, sec: 59, usec: Rational(999999999, 1000))
134
150
  end
135
151
  alias :at_end_of_hour :end_of_hour
136
152
 
137
153
  # Returns a new DateTime representing the start of the minute (hh:mm:00).
138
154
  def beginning_of_minute
139
- change(:sec => 0)
155
+ change(sec: 0)
140
156
  end
141
157
  alias :at_beginning_of_minute :beginning_of_minute
142
158
 
143
159
  # Returns a new DateTime representing the end of the minute (hh:mm:59).
144
160
  def end_of_minute
145
- change(:sec => 59)
161
+ change(sec: 59, usec: Rational(999999999, 1000))
146
162
  end
147
163
  alias :at_end_of_minute :end_of_minute
148
164
 
@@ -157,12 +173,17 @@ class DateTime
157
173
  end
158
174
  alias_method :getlocal, :localtime
159
175
 
160
- # Returns a <tt>DateTime</tt> instance of the simultaneous time in the UTC timezone.
176
+ # Returns a <tt>Time</tt> instance of the simultaneous time in the UTC timezone.
161
177
  #
162
178
  # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)) # => Mon, 21 Feb 2005 10:11:12 -0600
163
179
  # DateTime.civil(2005, 2, 21, 10, 11, 12, Rational(-6, 24)).utc # => Mon, 21 Feb 2005 16:11:12 UTC
164
180
  def utc
165
- new_offset(0)
181
+ utc = new_offset(0)
182
+
183
+ Time.utc(
184
+ utc.year, utc.month, utc.day,
185
+ utc.hour, utc.min, utc.sec + utc.sec_fraction
186
+ )
166
187
  end
167
188
  alias_method :getgm, :utc
168
189
  alias_method :getutc, :utc
@@ -181,13 +202,10 @@ class DateTime
181
202
  # Layers additional behavior on DateTime#<=> so that Time and
182
203
  # ActiveSupport::TimeWithZone instances can be compared with a DateTime.
183
204
  def <=>(other)
184
- if other.kind_of?(Infinity)
185
- super
186
- elsif other.respond_to? :to_datetime
205
+ if other.respond_to? :to_datetime
187
206
  super other.to_datetime rescue nil
188
207
  else
189
- nil
208
+ super
190
209
  end
191
210
  end
192
-
193
211
  end
@@ -1,14 +1,16 @@
1
- require 'active_support/core_ext/date_and_time/compatibility'
2
- require 'active_support/core_ext/module/remove_method'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/date_and_time/compatibility"
4
+ require "active_support/core_ext/module/redefine_method"
3
5
 
4
6
  class DateTime
5
7
  include DateAndTime::Compatibility
6
8
 
7
- remove_possible_method :to_time
9
+ silence_redefinition_of_method :to_time
8
10
 
9
- # Either return an instance of `Time` with the same UTC offset
10
- # as +self+ or an instance of `Time` representing the same time
11
- # in the the local system timezone depending on the setting of
11
+ # Either return an instance of +Time+ with the same UTC offset
12
+ # as +self+ or an instance of +Time+ representing the same time
13
+ # in the local system timezone depending on the setting of
12
14
  # on the setting of +ActiveSupport.to_time_preserves_timezone+.
13
15
  def to_time
14
16
  preserve_timezone ? getlocal(utc_offset) : getlocal
@@ -1,8 +1,10 @@
1
- require 'date'
2
- require 'active_support/inflector/methods'
3
- require 'active_support/core_ext/time/conversions'
4
- require 'active_support/core_ext/date_time/calculations'
5
- require 'active_support/values/time_zone'
1
+ # frozen_string_literal: true
2
+
3
+ require "date"
4
+ require "active_support/inflector/methods"
5
+ require "active_support/core_ext/time/conversions"
6
+ require "active_support/core_ext/date_time/calculations"
7
+ require "active_support/values/time_zone"
6
8
 
7
9
  class DateTime
8
10
  # Convert to a formatted string. See Time::DATE_FORMATS for predefined formats.
@@ -40,6 +42,8 @@ class DateTime
40
42
  alias_method :to_default_s, :to_s if instance_methods(false).include?(:to_s)
41
43
  alias_method :to_s, :to_formatted_s
42
44
 
45
+ # Returns a formatted string of the offset from UTC, or an alternative
46
+ # string if the time zone is already UTC.
43
47
  #
44
48
  # datetime = DateTime.civil(2000, 1, 1, 0, 0, 0, Rational(-6, 24))
45
49
  # datetime.formatted_offset # => "-06:00"
@@ -62,7 +66,7 @@ class DateTime
62
66
  # # => Sun, 01 Jan 2012 00:00:00 +0300
63
67
  # DateTime.civil_from_format :local, 2012, 12, 17
64
68
  # # => Mon, 17 Dec 2012 00:00:00 +0000
65
- def self.civil_from_format(utc_or_local, year, month=1, day=1, hour=0, min=0, sec=0)
69
+ def self.civil_from_format(utc_or_local, year, month = 1, day = 1, hour = 0, min = 0, sec = 0)
66
70
  if utc_or_local.to_sym == :local
67
71
  offset = ::Time.local(year, month, day).utc_offset.to_r / 86400
68
72
  else
@@ -92,12 +96,11 @@ class DateTime
92
96
  end
93
97
 
94
98
  private
99
+ def offset_in_seconds
100
+ (offset * 86400).to_i
101
+ end
95
102
 
96
- def offset_in_seconds
97
- (offset * 86400).to_i
98
- end
99
-
100
- def seconds_since_unix_epoch
101
- (jd - 2440588) * 86400 - offset_in_seconds + seconds_since_midnight
102
- end
103
+ def seconds_since_unix_epoch
104
+ (jd - 2440588) * 86400 - offset_in_seconds + seconds_since_midnight
105
+ end
103
106
  end
@@ -1,5 +1,7 @@
1
- require 'active_support/core_ext/date_time/acts_like'
2
- require 'active_support/core_ext/date_time/calculations'
3
- require 'active_support/core_ext/date_time/compatibility'
4
- require 'active_support/core_ext/date_time/conversions'
5
- require 'active_support/core_ext/date_time/zones'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/date_time/acts_like"
4
+ require "active_support/core_ext/date_time/blank"
5
+ require "active_support/core_ext/date_time/calculations"
6
+ require "active_support/core_ext/date_time/compatibility"
7
+ require "active_support/core_ext/date_time/conversions"
@@ -1,4 +1,7 @@
1
- require 'securerandom'
1
+ # frozen_string_literal: true
2
+
3
+ require "securerandom"
4
+ require "digest"
2
5
 
3
6
  module Digest
4
7
  module UUID
@@ -12,7 +15,7 @@ module Digest
12
15
  # Using Digest::MD5 generates version 3 UUIDs; Digest::SHA1 generates version 5 UUIDs.
13
16
  # uuid_from_hash always generates the same UUID for a given name and namespace combination.
14
17
  #
15
- # See RFC 4122 for details of UUID at: http://www.ietf.org/rfc/rfc4122.txt
18
+ # See RFC 4122 for details of UUID at: https://www.ietf.org/rfc/rfc4122.txt
16
19
  def self.uuid_from_hash(hash_class, uuid_namespace, name)
17
20
  if hash_class == Digest::MD5
18
21
  version = 3
@@ -26,7 +29,7 @@ module Digest
26
29
  hash.update(uuid_namespace)
27
30
  hash.update(name)
28
31
 
29
- ary = hash.digest.unpack('NnnnnN')
32
+ ary = hash.digest.unpack("NnnnnN")
30
33
  ary[2] = (ary[2] & 0x0FFF) | (version << 12)
31
34
  ary[3] = (ary[3] & 0x3FFF) | 0x8000
32
35
 
@@ -35,12 +38,12 @@ module Digest
35
38
 
36
39
  # Convenience method for uuid_from_hash using Digest::MD5.
37
40
  def self.uuid_v3(uuid_namespace, name)
38
- self.uuid_from_hash(Digest::MD5, uuid_namespace, name)
41
+ uuid_from_hash(Digest::MD5, uuid_namespace, name)
39
42
  end
40
43
 
41
44
  # Convenience method for uuid_from_hash using Digest::SHA1.
42
45
  def self.uuid_v5(uuid_namespace, name)
43
- self.uuid_from_hash(Digest::SHA1, uuid_namespace, name)
46
+ uuid_from_hash(Digest::SHA1, uuid_namespace, name)
44
47
  end
45
48
 
46
49
  # Convenience method for SecureRandom.uuid.
@@ -0,0 +1,3 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/digest/uuid"
@@ -1,4 +1,21 @@
1
+ # frozen_string_literal: true
2
+
1
3
  module Enumerable
4
+ INDEX_WITH_DEFAULT = Object.new
5
+ private_constant :INDEX_WITH_DEFAULT
6
+
7
+ # Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements
8
+ # when we omit an identity.
9
+
10
+ # :stopdoc:
11
+
12
+ # We can't use Refinements here because Refinements with Module which will be prepended
13
+ # doesn't work well https://bugs.ruby-lang.org/issues/13446
14
+ alias :_original_sum_with_required_identity :sum
15
+ private :_original_sum_with_required_identity
16
+
17
+ # :startdoc:
18
+
2
19
  # Calculates a sum from the elements.
3
20
  #
4
21
  # payments.sum { |p| p.price * p.tax_rate }
@@ -12,33 +29,66 @@ module Enumerable
12
29
  #
13
30
  # [5, 15, 10].sum # => 30
14
31
  # ['foo', 'bar'].sum # => "foobar"
15
- # [[1, 2], [3, 1, 5]].sum => [1, 2, 3, 1, 5]
32
+ # [[1, 2], [3, 1, 5]].sum # => [1, 2, 3, 1, 5]
16
33
  #
17
34
  # The default sum of an empty list is zero. You can override this default:
18
35
  #
19
36
  # [].sum(Payment.new(0)) { |i| i.amount } # => Payment.new(0)
20
- def sum(identity = 0, &block)
21
- if block_given?
37
+ def sum(identity = nil, &block)
38
+ if identity
39
+ _original_sum_with_required_identity(identity, &block)
40
+ elsif block_given?
22
41
  map(&block).sum(identity)
23
42
  else
24
- inject { |sum, element| sum + element } || identity
43
+ inject(:+) || 0
25
44
  end
26
45
  end
27
46
 
28
- # Convert an enumerable to a hash.
47
+ # Convert an enumerable to a hash, using the block result as the key and the
48
+ # element as the value.
29
49
  #
30
50
  # people.index_by(&:login)
31
- # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
51
+ # # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
52
+ #
32
53
  # people.index_by { |person| "#{person.first_name} #{person.last_name}" }
33
- # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
54
+ # # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
34
55
  def index_by
35
56
  if block_given?
36
- Hash[map { |elem| [yield(elem), elem] }]
57
+ result = {}
58
+ each { |elem| result[yield(elem)] = elem }
59
+ result
37
60
  else
38
61
  to_enum(:index_by) { size if respond_to?(:size) }
39
62
  end
40
63
  end
41
64
 
65
+ # Convert an enumerable to a hash, using the element as the key and the block
66
+ # result as the value.
67
+ #
68
+ # post = Post.new(title: "hey there", body: "what's up?")
69
+ #
70
+ # %i( title body ).index_with { |attr_name| post.public_send(attr_name) }
71
+ # # => { title: "hey there", body: "what's up?" }
72
+ #
73
+ # If an argument is passed instead of a block, it will be used as the value
74
+ # for all elements:
75
+ #
76
+ # %i( created_at updated_at ).index_with(Time.now)
77
+ # # => { created_at: 2020-03-09 22:31:47, updated_at: 2020-03-09 22:31:47 }
78
+ def index_with(default = INDEX_WITH_DEFAULT)
79
+ if block_given?
80
+ result = {}
81
+ each { |elem| result[elem] = yield(elem) }
82
+ result
83
+ elsif default != INDEX_WITH_DEFAULT
84
+ result = {}
85
+ each { |elem| result[elem] = default }
86
+ result
87
+ else
88
+ to_enum(:index_with) { size if respond_to?(:size) }
89
+ end
90
+ end
91
+
42
92
  # Returns +true+ if the enumerable has more than 1 element. Functionally
43
93
  # equivalent to <tt>enum.to_a.size > 1</tt>. Can be called with a block too,
44
94
  # much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns +true+
@@ -55,42 +105,156 @@ module Enumerable
55
105
  end
56
106
  end
57
107
 
108
+ # Returns a new array that includes the passed elements.
109
+ #
110
+ # [ 1, 2, 3 ].including(4, 5)
111
+ # # => [ 1, 2, 3, 4, 5 ]
112
+ #
113
+ # ["David", "Rafael"].including %w[ Aaron Todd ]
114
+ # # => ["David", "Rafael", "Aaron", "Todd"]
115
+ def including(*elements)
116
+ to_a.including(*elements)
117
+ end
118
+
58
119
  # The negative of the <tt>Enumerable#include?</tt>. Returns +true+ if the
59
120
  # collection does not include the object.
60
121
  def exclude?(object)
61
122
  !include?(object)
62
123
  end
124
+
125
+ # Returns a copy of the enumerable excluding the specified elements.
126
+ #
127
+ # ["David", "Rafael", "Aaron", "Todd"].excluding "Aaron", "Todd"
128
+ # # => ["David", "Rafael"]
129
+ #
130
+ # ["David", "Rafael", "Aaron", "Todd"].excluding %w[ Aaron Todd ]
131
+ # # => ["David", "Rafael"]
132
+ #
133
+ # {foo: 1, bar: 2, baz: 3}.excluding :bar
134
+ # # => {foo: 1, baz: 3}
135
+ def excluding(*elements)
136
+ elements.flatten!(1)
137
+ reject { |element| elements.include?(element) }
138
+ end
139
+
140
+ # Alias for #excluding.
141
+ def without(*elements)
142
+ excluding(*elements)
143
+ end
144
+
145
+ # Extract the given key from each element in the enumerable.
146
+ #
147
+ # [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pluck(:name)
148
+ # # => ["David", "Rafael", "Aaron"]
149
+ #
150
+ # [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pluck(:id, :name)
151
+ # # => [[1, "David"], [2, "Rafael"]]
152
+ def pluck(*keys)
153
+ if keys.many?
154
+ map { |element| keys.map { |key| element[key] } }
155
+ else
156
+ key = keys.first
157
+ map { |element| element[key] }
158
+ end
159
+ end
160
+
161
+ # Extract the given key from the first element in the enumerable.
162
+ #
163
+ # [{ name: "David" }, { name: "Rafael" }, { name: "Aaron" }].pick(:name)
164
+ # # => "David"
165
+ #
166
+ # [{ id: 1, name: "David" }, { id: 2, name: "Rafael" }].pick(:id, :name)
167
+ # # => [1, "David"]
168
+ def pick(*keys)
169
+ return if none?
170
+
171
+ if keys.many?
172
+ keys.map { |key| first[key] }
173
+ else
174
+ first[keys.first]
175
+ end
176
+ end
177
+
178
+ # Returns a new +Array+ without the blank items.
179
+ # Uses Object#blank? for determining if an item is blank.
180
+ #
181
+ # [1, "", nil, 2, " ", [], {}, false, true].compact_blank
182
+ # # => [1, 2, true]
183
+ #
184
+ # Set.new([nil, "", 1, 2])
185
+ # # => [2, 1] (or [1, 2])
186
+ #
187
+ # When called on a +Hash+, returns a new +Hash+ without the blank values.
188
+ #
189
+ # { a: "", b: 1, c: nil, d: [], e: false, f: true }.compact_blank
190
+ # #=> { b: 1, f: true }
191
+ def compact_blank
192
+ reject(&:blank?)
193
+ end
194
+ end
195
+
196
+ class Hash
197
+ # Hash#reject has its own definition, so this needs one too.
198
+ def compact_blank #:nodoc:
199
+ reject { |_k, v| v.blank? }
200
+ end
201
+
202
+ # Removes all blank values from the +Hash+ in place and returns self.
203
+ # Uses Object#blank? for determining if a value is blank.
204
+ #
205
+ # h = { a: "", b: 1, c: nil, d: [], e: false, f: true }
206
+ # h.compact_blank!
207
+ # # => { b: 1, f: true }
208
+ def compact_blank!
209
+ # use delete_if rather than reject! because it always returns self even if nothing changed
210
+ delete_if { |_k, v| v.blank? }
211
+ end
63
212
  end
64
213
 
65
214
  class Range #:nodoc:
66
215
  # Optimize range sum to use arithmetic progression if a block is not given and
67
216
  # we have a range of numeric values.
68
- def sum(identity = 0)
217
+ def sum(identity = nil)
69
218
  if block_given? || !(first.is_a?(Integer) && last.is_a?(Integer))
70
219
  super
71
220
  else
72
221
  actual_last = exclude_end? ? (last - 1) : last
73
222
  if actual_last >= first
74
- (actual_last - first + 1) * (actual_last + first) / 2
223
+ sum = identity || 0
224
+ sum + (actual_last - first + 1) * (actual_last + first) / 2
75
225
  else
76
- identity
226
+ identity || 0
77
227
  end
78
228
  end
79
229
  end
80
230
  end
81
231
 
82
- # Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
83
- #
84
- # We tried shimming it to attempt the fast native method, rescue TypeError,
85
- # and fall back to the compatible implementation, but that's much slower than
86
- # just calling the compat method in the first place.
87
- if Array.instance_methods(false).include?(:sum) && !(%w[a].sum rescue false)
88
- class Array
89
- remove_method :sum
90
-
91
- def sum(*args) #:nodoc:
92
- # Use Enumerable#sum instead.
232
+ # Using Refinements here in order not to expose our internal method
233
+ using Module.new {
234
+ refine Array do
235
+ alias :orig_sum :sum
236
+ end
237
+ }
238
+
239
+ class Array #:nodoc:
240
+ # Array#sum was added in Ruby 2.4 but it only works with Numeric elements.
241
+ def sum(init = nil, &block)
242
+ if init.is_a?(Numeric) || first.is_a?(Numeric)
243
+ init ||= 0
244
+ orig_sum(init, &block)
245
+ else
93
246
  super
94
247
  end
95
248
  end
249
+
250
+ # Removes all blank elements from the +Array+ in place and returns self.
251
+ # Uses Object#blank? for determining if an item is blank.
252
+ #
253
+ # a = [1, "", nil, 2, " ", [], {}, false, true]
254
+ # a.compact_blank!
255
+ # # => [1, 2, true]
256
+ def compact_blank!
257
+ # use delete_if rather than reject! because it always returns self even if nothing changed
258
+ delete_if(&:blank?)
259
+ end
96
260
  end
@@ -1,4 +1,6 @@
1
- require 'fileutils'
1
+ # frozen_string_literal: true
2
+
3
+ require "fileutils"
2
4
 
3
5
  class File
4
6
  # Write to a file atomically. Useful for situations where you don't
@@ -8,51 +10,56 @@ class File
8
10
  # file.write('hello')
9
11
  # end
10
12
  #
11
- # If your temp directory is not on the same filesystem as the file you're
12
- # trying to write, you can provide a different temporary directory.
13
+ # This method needs to create a temporary file. By default it will create it
14
+ # in the same directory as the destination file. If you don't like this
15
+ # behavior you can provide a different directory but it must be on the
16
+ # same physical filesystem as the file you're trying to write.
13
17
  #
14
18
  # File.atomic_write('/data/something.important', '/data/tmp') do |file|
15
19
  # file.write('hello')
16
20
  # end
17
- def self.atomic_write(file_name, temp_dir = Dir.tmpdir)
18
- require 'tempfile' unless defined?(Tempfile)
19
- require 'fileutils' unless defined?(FileUtils)
20
-
21
- temp_file = Tempfile.new(basename(file_name), temp_dir)
22
- temp_file.binmode
23
- yield temp_file
24
- temp_file.close
25
-
26
- if File.exist?(file_name)
27
- # Get original file permissions
28
- old_stat = stat(file_name)
29
- else
30
- # If not possible, probe which are the default permissions in the
31
- # destination directory.
32
- old_stat = probe_stat_in(dirname(file_name))
33
- end
21
+ def self.atomic_write(file_name, temp_dir = dirname(file_name))
22
+ require "tempfile" unless defined?(Tempfile)
23
+
24
+ Tempfile.open(".#{basename(file_name)}", temp_dir) do |temp_file|
25
+ temp_file.binmode
26
+ return_val = yield temp_file
27
+ temp_file.close
28
+
29
+ old_stat = if exist?(file_name)
30
+ # Get original file permissions
31
+ stat(file_name)
32
+ else
33
+ # If not possible, probe which are the default permissions in the
34
+ # destination directory.
35
+ probe_stat_in(dirname(file_name))
36
+ end
34
37
 
35
- # Overwrite original file with temp file
36
- FileUtils.mv(temp_file.path, file_name)
38
+ if old_stat
39
+ # Set correct permissions on new file
40
+ begin
41
+ chown(old_stat.uid, old_stat.gid, temp_file.path)
42
+ # This operation will affect filesystem ACL's
43
+ chmod(old_stat.mode, temp_file.path)
44
+ rescue Errno::EPERM, Errno::EACCES
45
+ # Changing file ownership failed, moving on.
46
+ end
47
+ end
37
48
 
38
- # Set correct permissions on new file
39
- begin
40
- chown(old_stat.uid, old_stat.gid, file_name)
41
- # This operation will affect filesystem ACL's
42
- chmod(old_stat.mode, file_name)
43
- rescue Errno::EPERM, Errno::EACCES
44
- # Changing file ownership failed, moving on.
49
+ # Overwrite original file with temp file
50
+ rename(temp_file.path, file_name)
51
+ return_val
45
52
  end
46
53
  end
47
54
 
48
55
  # Private utility method.
49
56
  def self.probe_stat_in(dir) #:nodoc:
50
57
  basename = [
51
- '.permissions_check',
58
+ ".permissions_check",
52
59
  Thread.current.object_id,
53
60
  Process.pid,
54
61
  rand(1000000)
55
- ].join('.')
62
+ ].join(".")
56
63
 
57
64
  file_name = join(dir, basename)
58
65
  FileUtils.touch(file_name)
@@ -1 +1,3 @@
1
- require 'active_support/core_ext/file/atomic'
1
+ # frozen_string_literal: true
2
+
3
+ require "active_support/core_ext/file/atomic"