activesupport 5.1.6 → 5.2.0

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 (240) hide show
  1. checksums.yaml +5 -5
  2. data/CHANGELOG.md +325 -576
  3. data/MIT-LICENSE +1 -1
  4. data/README.rdoc +3 -3
  5. data/lib/active_support/all.rb +2 -0
  6. data/lib/active_support/array_inquirer.rb +2 -0
  7. data/lib/active_support/backtrace_cleaner.rb +2 -0
  8. data/lib/active_support/benchmarkable.rb +2 -0
  9. data/lib/active_support/builder.rb +2 -0
  10. data/lib/active_support/cache/file_store.rb +5 -4
  11. data/lib/active_support/cache/mem_cache_store.rb +37 -27
  12. data/lib/active_support/cache/memory_store.rb +2 -0
  13. data/lib/active_support/cache/null_store.rb +2 -0
  14. data/lib/active_support/cache/redis_cache_store.rb +454 -0
  15. data/lib/active_support/cache/strategy/local_cache.rb +33 -2
  16. data/lib/active_support/cache/strategy/local_cache_middleware.rb +2 -0
  17. data/lib/active_support/cache.rb +181 -64
  18. data/lib/active_support/callbacks.rb +28 -39
  19. data/lib/active_support/concern.rb +3 -1
  20. data/lib/active_support/concurrency/share_lock.rb +2 -0
  21. data/lib/active_support/configurable.rb +2 -0
  22. data/lib/active_support/core_ext/array/access.rb +4 -2
  23. data/lib/active_support/core_ext/array/conversions.rb +2 -0
  24. data/lib/active_support/core_ext/array/extract_options.rb +2 -0
  25. data/lib/active_support/core_ext/array/grouping.rb +2 -0
  26. data/lib/active_support/core_ext/array/inquiry.rb +2 -0
  27. data/lib/active_support/core_ext/array/prepend_and_append.rb +4 -2
  28. data/lib/active_support/core_ext/array/wrap.rb +2 -0
  29. data/lib/active_support/core_ext/array.rb +2 -0
  30. data/lib/active_support/core_ext/benchmark.rb +2 -0
  31. data/lib/active_support/core_ext/big_decimal/conversions.rb +2 -0
  32. data/lib/active_support/core_ext/big_decimal.rb +2 -0
  33. data/lib/active_support/core_ext/class/attribute.rb +34 -16
  34. data/lib/active_support/core_ext/class/attribute_accessors.rb +2 -0
  35. data/lib/active_support/core_ext/class/subclasses.rb +1 -2
  36. data/lib/active_support/core_ext/class.rb +2 -0
  37. data/lib/active_support/core_ext/date/acts_like.rb +2 -0
  38. data/lib/active_support/core_ext/date/blank.rb +2 -0
  39. data/lib/active_support/core_ext/date/calculations.rb +2 -0
  40. data/lib/active_support/core_ext/date/conversions.rb +10 -9
  41. data/lib/active_support/core_ext/date/zones.rb +2 -0
  42. data/lib/active_support/core_ext/date.rb +2 -0
  43. data/lib/active_support/core_ext/date_and_time/calculations.rb +50 -16
  44. data/lib/active_support/core_ext/date_and_time/compatibility.rb +3 -1
  45. data/lib/active_support/core_ext/date_and_time/zones.rb +2 -0
  46. data/lib/active_support/core_ext/date_time/acts_like.rb +2 -0
  47. data/lib/active_support/core_ext/date_time/blank.rb +2 -0
  48. data/lib/active_support/core_ext/date_time/calculations.rb +2 -0
  49. data/lib/active_support/core_ext/date_time/compatibility.rb +7 -5
  50. data/lib/active_support/core_ext/date_time/conversions.rb +2 -0
  51. data/lib/active_support/core_ext/date_time.rb +2 -0
  52. data/lib/active_support/core_ext/digest/uuid.rb +3 -1
  53. data/lib/active_support/core_ext/enumerable.rb +3 -1
  54. data/lib/active_support/core_ext/file/atomic.rb +2 -0
  55. data/lib/active_support/core_ext/file.rb +2 -0
  56. data/lib/active_support/core_ext/hash/compact.rb +2 -0
  57. data/lib/active_support/core_ext/hash/conversions.rb +4 -2
  58. data/lib/active_support/core_ext/hash/deep_merge.rb +8 -12
  59. data/lib/active_support/core_ext/hash/except.rb +2 -0
  60. data/lib/active_support/core_ext/hash/indifferent_access.rb +2 -0
  61. data/lib/active_support/core_ext/hash/keys.rb +2 -0
  62. data/lib/active_support/core_ext/hash/reverse_merge.rb +5 -2
  63. data/lib/active_support/core_ext/hash/slice.rb +4 -4
  64. data/lib/active_support/core_ext/hash/transform_values.rb +2 -0
  65. data/lib/active_support/core_ext/hash.rb +2 -0
  66. data/lib/active_support/core_ext/integer/inflections.rb +2 -0
  67. data/lib/active_support/core_ext/integer/multiple.rb +2 -0
  68. data/lib/active_support/core_ext/integer/time.rb +7 -14
  69. data/lib/active_support/core_ext/integer.rb +2 -0
  70. data/lib/active_support/core_ext/kernel/agnostics.rb +2 -0
  71. data/lib/active_support/core_ext/kernel/concern.rb +2 -0
  72. data/lib/active_support/core_ext/kernel/reporting.rb +2 -0
  73. data/lib/active_support/core_ext/kernel/singleton_class.rb +2 -0
  74. data/lib/active_support/core_ext/kernel.rb +2 -0
  75. data/lib/active_support/core_ext/load_error.rb +2 -7
  76. data/lib/active_support/core_ext/marshal.rb +2 -0
  77. data/lib/active_support/core_ext/module/aliasing.rb +2 -0
  78. data/lib/active_support/core_ext/module/anonymous.rb +2 -0
  79. data/lib/active_support/core_ext/module/attr_internal.rb +2 -0
  80. data/lib/active_support/core_ext/module/attribute_accessors.rb +21 -24
  81. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +2 -0
  82. data/lib/active_support/core_ext/module/concerning.rb +7 -8
  83. data/lib/active_support/core_ext/module/delegation.rb +31 -29
  84. data/lib/active_support/core_ext/module/deprecation.rb +2 -0
  85. data/lib/active_support/core_ext/module/introspection.rb +2 -0
  86. data/lib/active_support/core_ext/module/reachable.rb +3 -0
  87. data/lib/active_support/core_ext/module/redefine_method.rb +49 -0
  88. data/lib/active_support/core_ext/module/remove_method.rb +5 -23
  89. data/lib/active_support/core_ext/module.rb +3 -0
  90. data/lib/active_support/core_ext/name_error.rb +7 -0
  91. data/lib/active_support/core_ext/numeric/bytes.rb +2 -0
  92. data/lib/active_support/core_ext/numeric/conversions.rb +9 -7
  93. data/lib/active_support/core_ext/numeric/inquiry.rb +2 -0
  94. data/lib/active_support/core_ext/numeric/time.rb +7 -15
  95. data/lib/active_support/core_ext/numeric.rb +2 -0
  96. data/lib/active_support/core_ext/object/acts_like.rb +12 -1
  97. data/lib/active_support/core_ext/object/blank.rb +12 -1
  98. data/lib/active_support/core_ext/object/conversions.rb +2 -0
  99. data/lib/active_support/core_ext/object/deep_dup.rb +2 -0
  100. data/lib/active_support/core_ext/object/duplicable.rb +10 -8
  101. data/lib/active_support/core_ext/object/inclusion.rb +2 -0
  102. data/lib/active_support/core_ext/object/instance_variables.rb +2 -0
  103. data/lib/active_support/core_ext/object/json.rb +8 -0
  104. data/lib/active_support/core_ext/object/to_param.rb +2 -0
  105. data/lib/active_support/core_ext/object/to_query.rb +2 -0
  106. data/lib/active_support/core_ext/object/try.rb +2 -0
  107. data/lib/active_support/core_ext/object/with_options.rb +3 -1
  108. data/lib/active_support/core_ext/object.rb +2 -0
  109. data/lib/active_support/core_ext/range/conversions.rb +9 -1
  110. data/lib/active_support/core_ext/range/each.rb +5 -1
  111. data/lib/active_support/core_ext/range/include_range.rb +2 -0
  112. data/lib/active_support/core_ext/range/include_time_with_zone.rb +23 -0
  113. data/lib/active_support/core_ext/range/overlaps.rb +2 -0
  114. data/lib/active_support/core_ext/range.rb +3 -0
  115. data/lib/active_support/core_ext/regexp.rb +2 -0
  116. data/lib/active_support/core_ext/securerandom.rb +2 -0
  117. data/lib/active_support/core_ext/string/access.rb +2 -0
  118. data/lib/active_support/core_ext/string/behavior.rb +2 -0
  119. data/lib/active_support/core_ext/string/conversions.rb +2 -0
  120. data/lib/active_support/core_ext/string/exclude.rb +2 -0
  121. data/lib/active_support/core_ext/string/filters.rb +2 -0
  122. data/lib/active_support/core_ext/string/indent.rb +2 -0
  123. data/lib/active_support/core_ext/string/inflections.rb +26 -12
  124. data/lib/active_support/core_ext/string/inquiry.rb +2 -0
  125. data/lib/active_support/core_ext/string/multibyte.rb +4 -0
  126. data/lib/active_support/core_ext/string/output_safety.rb +6 -7
  127. data/lib/active_support/core_ext/string/starts_ends_with.rb +2 -0
  128. data/lib/active_support/core_ext/string/strip.rb +2 -0
  129. data/lib/active_support/core_ext/string/zones.rb +2 -0
  130. data/lib/active_support/core_ext/string.rb +2 -0
  131. data/lib/active_support/core_ext/time/acts_like.rb +2 -0
  132. data/lib/active_support/core_ext/time/calculations.rb +23 -15
  133. data/lib/active_support/core_ext/time/compatibility.rb +4 -2
  134. data/lib/active_support/core_ext/time/conversions.rb +2 -0
  135. data/lib/active_support/core_ext/time/zones.rb +6 -4
  136. data/lib/active_support/core_ext/time.rb +2 -0
  137. data/lib/active_support/core_ext/uri.rb +4 -1
  138. data/lib/active_support/core_ext.rb +3 -1
  139. data/lib/active_support/current_attributes.rb +195 -0
  140. data/lib/active_support/dependencies/autoload.rb +2 -0
  141. data/lib/active_support/dependencies/interlock.rb +2 -0
  142. data/lib/active_support/dependencies.rb +16 -25
  143. data/lib/active_support/deprecation/behaviors.rb +24 -9
  144. data/lib/active_support/deprecation/constant_accessor.rb +4 -2
  145. data/lib/active_support/deprecation/instance_delegator.rb +2 -0
  146. data/lib/active_support/deprecation/method_wrappers.rb +8 -8
  147. data/lib/active_support/deprecation/proxy_wrappers.rb +5 -2
  148. data/lib/active_support/deprecation/reporting.rb +5 -3
  149. data/lib/active_support/deprecation.rb +4 -2
  150. data/lib/active_support/descendants_tracker.rb +2 -0
  151. data/lib/active_support/digest.rb +20 -0
  152. data/lib/active_support/duration/iso8601_parser.rb +4 -2
  153. data/lib/active_support/duration/iso8601_serializer.rb +4 -2
  154. data/lib/active_support/duration.rb +11 -7
  155. data/lib/active_support/encrypted_configuration.rb +49 -0
  156. data/lib/active_support/encrypted_file.rb +99 -0
  157. data/lib/active_support/evented_file_update_checker.rb +2 -0
  158. data/lib/active_support/execution_wrapper.rb +2 -0
  159. data/lib/active_support/executor.rb +2 -0
  160. data/lib/active_support/file_update_checker.rb +2 -0
  161. data/lib/active_support/gem_version.rb +4 -2
  162. data/lib/active_support/gzip.rb +2 -0
  163. data/lib/active_support/hash_with_indifferent_access.rb +41 -1
  164. data/lib/active_support/i18n.rb +3 -1
  165. data/lib/active_support/i18n_railtie.rb +4 -6
  166. data/lib/active_support/inflections.rb +2 -0
  167. data/lib/active_support/inflector/inflections.rb +20 -4
  168. data/lib/active_support/inflector/methods.rb +41 -24
  169. data/lib/active_support/inflector/transliterate.rb +17 -8
  170. data/lib/active_support/inflector.rb +2 -0
  171. data/lib/active_support/json/decoding.rb +2 -0
  172. data/lib/active_support/json/encoding.rb +2 -0
  173. data/lib/active_support/json.rb +2 -0
  174. data/lib/active_support/key_generator.rb +3 -1
  175. data/lib/active_support/lazy_load_hooks.rb +2 -0
  176. data/lib/active_support/log_subscriber/test_helper.rb +2 -0
  177. data/lib/active_support/log_subscriber.rb +3 -2
  178. data/lib/active_support/logger.rb +2 -0
  179. data/lib/active_support/logger_silence.rb +3 -2
  180. data/lib/active_support/logger_thread_safe_level.rb +2 -0
  181. data/lib/active_support/message_encryptor.rb +95 -22
  182. data/lib/active_support/message_verifier.rb +78 -7
  183. data/lib/active_support/messages/metadata.rb +71 -0
  184. data/lib/active_support/messages/rotation_configuration.rb +22 -0
  185. data/lib/active_support/messages/rotator.rb +56 -0
  186. data/lib/active_support/multibyte/chars.rb +2 -0
  187. data/lib/active_support/multibyte/unicode.rb +4 -2
  188. data/lib/active_support/multibyte.rb +2 -0
  189. data/lib/active_support/notifications/fanout.rb +2 -0
  190. data/lib/active_support/notifications/instrumenter.rb +2 -0
  191. data/lib/active_support/notifications.rb +2 -0
  192. data/lib/active_support/number_helper/number_converter.rb +2 -0
  193. data/lib/active_support/number_helper/number_to_currency_converter.rb +2 -0
  194. data/lib/active_support/number_helper/number_to_delimited_converter.rb +2 -0
  195. data/lib/active_support/number_helper/number_to_human_converter.rb +2 -0
  196. data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -0
  197. data/lib/active_support/number_helper/number_to_percentage_converter.rb +2 -0
  198. data/lib/active_support/number_helper/number_to_phone_converter.rb +3 -1
  199. data/lib/active_support/number_helper/number_to_rounded_converter.rb +2 -20
  200. data/lib/active_support/number_helper/rounding_helper.rb +6 -4
  201. data/lib/active_support/number_helper.rb +2 -0
  202. data/lib/active_support/option_merger.rb +2 -0
  203. data/lib/active_support/ordered_hash.rb +2 -0
  204. data/lib/active_support/ordered_options.rb +4 -2
  205. data/lib/active_support/per_thread_registry.rb +2 -0
  206. data/lib/active_support/proxy_object.rb +2 -0
  207. data/lib/active_support/rails.rb +2 -0
  208. data/lib/active_support/railtie.rb +37 -8
  209. data/lib/active_support/reloader.rb +7 -5
  210. data/lib/active_support/rescuable.rb +3 -2
  211. data/lib/active_support/security_utils.rb +15 -11
  212. data/lib/active_support/string_inquirer.rb +2 -0
  213. data/lib/active_support/subscriber.rb +2 -0
  214. data/lib/active_support/tagged_logging.rb +2 -0
  215. data/lib/active_support/test_case.rb +2 -1
  216. data/lib/active_support/testing/assertions.rb +31 -14
  217. data/lib/active_support/testing/autorun.rb +2 -0
  218. data/lib/active_support/testing/constant_lookup.rb +2 -0
  219. data/lib/active_support/testing/declarative.rb +2 -0
  220. data/lib/active_support/testing/deprecation.rb +2 -0
  221. data/lib/active_support/testing/file_fixtures.rb +2 -0
  222. data/lib/active_support/testing/isolation.rb +3 -1
  223. data/lib/active_support/testing/method_call_assertions.rb +2 -0
  224. data/lib/active_support/testing/setup_and_teardown.rb +10 -1
  225. data/lib/active_support/testing/stream.rb +2 -0
  226. data/lib/active_support/testing/tagged_logging.rb +2 -0
  227. data/lib/active_support/testing/time_helpers.rb +33 -3
  228. data/lib/active_support/time.rb +2 -0
  229. data/lib/active_support/time_with_zone.rb +38 -0
  230. data/lib/active_support/values/time_zone.rb +19 -8
  231. data/lib/active_support/version.rb +2 -0
  232. data/lib/active_support/xml_mini/jdom.rb +4 -2
  233. data/lib/active_support/xml_mini/libxml.rb +3 -1
  234. data/lib/active_support/xml_mini/libxmlsax.rb +4 -2
  235. data/lib/active_support/xml_mini/nokogiri.rb +3 -1
  236. data/lib/active_support/xml_mini/nokogirisax.rb +3 -1
  237. data/lib/active_support/xml_mini/rexml.rb +3 -1
  238. data/lib/active_support/xml_mini.rb +3 -1
  239. data/lib/active_support.rb +5 -13
  240. metadata +15 -5
data/CHANGELOG.md CHANGED
@@ -1,6 +1,11 @@
1
- ## Rails 5.1.6 (March 29, 2018) ##
1
+ ## Rails 5.2.0 (April 09, 2018) ##
2
2
 
3
- * Return all mappings for a timezone identifier in `country_zones`
3
+ * Caching: MemCache and Redis `read_multi` and `fetch_multi` speedup.
4
+ Read from the local in-memory cache before consulting the backend.
5
+
6
+ *Gabriel Sobrinho*
7
+
8
+ * Return all mappings for a timezone identifier in `country_zones`.
4
9
 
5
10
  Some timezones like `Europe/London` have multiple mappings in
6
11
  `ActiveSupport::TimeZone::MAPPING` so return all of them instead
@@ -16,758 +21,502 @@
16
21
 
17
22
  *Andrew White*
18
23
 
24
+ * Add support for connection pooling on RedisCacheStore.
19
25
 
20
- ## Rails 5.1.5 (February 14, 2018) ##
21
-
22
- * No changes.
23
-
24
-
25
- ## Rails 5.1.4 (September 07, 2017) ##
26
-
27
- * No changes.
28
-
29
-
30
- ## Rails 5.1.4.rc1 (August 24, 2017) ##
31
-
32
- * No changes.
33
-
34
-
35
- ## Rails 5.1.3 (August 03, 2017) ##
36
-
37
- * No changes.
38
-
39
-
40
- ## Rails 5.1.3.rc3 (July 31, 2017) ##
41
-
42
- * Fix modulo operations involving durations
43
-
44
- Rails 5.1 introduce an `ActiveSupport::Duration::Scalar` class as a wrapper
45
- around a numeric value as a way of ensuring a duration was the outcome of
46
- an expression. However the implementation was missing support for modulo
47
- operations. This support has now been added and should result in a duration
48
- being returned from expressions involving modulo operations.
49
-
50
- Prior to Rails 5.1:
51
-
52
- 5.minutes % 2.minutes
53
- => 60
54
-
55
- Now:
56
-
57
- 5.minutes % 2.minutes
58
- => 1 minute
59
-
60
- Fixes #29603 and #29743.
61
-
62
- *Sayan Chakraborty*, *Andrew White*
63
-
64
- * Fix division where a duration is the denominator
65
-
66
- PR #29163 introduced a change in behavior when a duration was the denominator
67
- in a calculation - this was incorrect as dividing by a duration should always
68
- return a `Numeric`. The behavior of previous versions of Rails has been restored.
69
-
70
- Fixes #29592.
71
-
72
- *Andrew White*
73
-
74
-
75
- ## Rails 5.1.3.rc2 (July 25, 2017) ##
76
-
77
- * No changes.
78
-
79
-
80
- ## Rails 5.1.3.rc1 (July 19, 2017) ##
81
-
82
- * No changes.
83
-
84
-
85
- ## Rails 5.1.2 (June 26, 2017) ##
86
-
87
- * Cache: Restore the `options = nil` argument for `LocalStore#clear`
88
- that was removed in 5.1.0. Restores compatibility with backends that
89
- take an options argument and use the local cache strategy.
90
-
91
- *Jeremy Daer*
92
-
93
- * Fix implicit coercion calculations with scalars and durations
94
-
95
- Previously calculations where the scalar is first would be converted to a duration
96
- of seconds but this causes issues with dates being converted to times, e.g:
97
-
98
- Time.zone = "Beijing" # => Asia/Shanghai
99
- date = Date.civil(2017, 5, 20) # => Mon, 20 May 2017
100
- 2 * 1.day # => 172800 seconds
101
- date + 2 * 1.day # => Mon, 22 May 2017 00:00:00 CST +08:00
102
-
103
- Now the `ActiveSupport::Duration::Scalar` calculation methods will try to maintain
104
- the part structure of the duration where possible, e.g:
105
-
106
- Time.zone = "Beijing" # => Asia/Shanghai
107
- date = Date.civil(2017, 5, 20) # => Mon, 20 May 2017
108
- 2 * 1.day # => 2 days
109
- date + 2 * 1.day # => Mon, 22 May 2017
110
-
111
- Fixes #29160, #28970.
112
-
113
- *Andrew White*
114
-
115
-
116
- ## Rails 5.1.1 (May 12, 2017) ##
26
+ *fatkodima*
117
27
 
118
- * No changes.
28
+ * Support hash as first argument in `assert_difference`. This allows to specify multiple
29
+ numeric differences in the same assertion.
119
30
 
31
+ assert_difference ->{ Article.count } => 1, ->{ Post.count } => 2
120
32
 
121
- ## Rails 5.1.0 (April 27, 2017) ##
33
+ *Julien Meichelbeck*
122
34
 
123
- * `ActiveSupport::EventedFileUpdateChecker` no longer listens to
124
- directories outside of the application directory.
35
+ * Add missing instrumentation for `read_multi` in `ActiveSupport::Cache::Store`.
125
36
 
126
- *radiospiel*
37
+ *Ignatius Reza Lesmana*
127
38
 
128
- * Return unmapped timezones from `country_zones`
39
+ * `assert_changes` will always assert that the expression changes,
40
+ regardless of `from:` and `to:` argument combinations.
129
41
 
130
- If a country doesn't exist in the MAPPINGS hash then create a new
131
- `ActiveSupport::Timezone` instance using the supplied timezone id.
42
+ *Daniel Ma*
132
43
 
133
- Fixes #28431.
44
+ * Use SHA-1 to generate non-sensitive digests, such as the ETag header.
134
45
 
135
- *Andrew White*
46
+ Enabled by default for new apps; upgrading apps can opt in by setting
47
+ `config.active_support.use_sha1_digests = true`.
136
48
 
137
- * Add ActiveSupport::Deprecation::DeprecatedConstantAccessor
49
+ *Dmitri Dolguikh*, *Eugene Kenny*
138
50
 
139
- Provides transparent deprecation of constants, compatible with exceptions.
140
- Example usage:
51
+ * Changed default behaviour of `ActiveSupport::SecurityUtils.secure_compare`,
52
+ to make it not leak length information even for variable length string.
141
53
 
142
- module Example
143
- include ActiveSupport::Deprecation::DeprecatedConstantAccessor
144
- deprecate_constant 'OldException', 'Elsewhere::NewException'
145
- end
54
+ Renamed old `ActiveSupport::SecurityUtils.secure_compare` to `fixed_length_secure_compare`,
55
+ and started raising `ArgumentError` in case of length mismatch of passed strings.
146
56
 
147
- *Dominic Cleal*
148
-
149
- * Fixed bug in `DateAndTime::Compatibility#to_time` that caused it to
150
- raise `RuntimeError: can't modify frozen Time` when called on any frozen `Time`.
151
- Properly pass through the frozen `Time` or `ActiveSupport::TimeWithZone` object
152
- when calling `#to_time`.
153
-
154
- *Kevin McPhillips* & *Andrew White*
57
+ *Vipul A M*
155
58
 
156
- * Remove implicit coercion deprecation of durations
59
+ * Make `ActiveSupport::TimeZone.all` return only time zones that are in
60
+ `ActiveSupport::TimeZone::MAPPING`.
157
61
 
158
- In #28204 we deprecated implicit conversion of durations to a numeric which
159
- represented the number of seconds in the duration because of unwanted side
160
- effects with calculations on durations and dates. This unfortunately had
161
- the side effect of forcing a explicit cast when configuring third-party
162
- libraries like expiration in Redis, e.g:
62
+ Fixes #7245.
163
63
 
164
- redis.expire("foo", 5.minutes)
64
+ *Chris LaRose*
165
65
 
166
- To work around this we've removed the deprecation and added a private class
167
- that wraps the numeric and can perform calculation involving durations and
168
- ensure that they remain a duration irrespective of the order of operations.
66
+ * MemCacheStore: Support expiring counters.
169
67
 
170
- *Andrew White*
68
+ Pass `expires_in: [seconds]` to `#increment` and `#decrement` options
69
+ to set the Memcached TTL (time-to-live) if the counter doesn't exist.
70
+ If the counter exists, Memcached doesn't extend its expiry when it's
71
+ incremented or decremented.
171
72
 
172
- * Update `titleize` regex to allow apostrophes
73
+ ```
74
+ Rails.cache.increment("my_counter", 1, expires_in: 2.minutes)
75
+ ```
173
76
 
174
- In 4b685aa the regex in `titleize` was updated to not match apostrophes to
175
- better reflect the nature of the transformation. Unfortunately, this had the
176
- side effect of breaking capitalization on the first word of a sub-string, e.g:
77
+ *Takumasa Ochi*
177
78
 
178
- >> "This was 'fake news'".titleize
179
- => "This Was 'fake News'"
79
+ * Handle `TZInfo::AmbiguousTime` errors.
180
80
 
181
- This is fixed by extending the look-behind to also check for a word
182
- character on the other side of the apostrophe.
81
+ Make `ActiveSupport::TimeWithZone` match Ruby's handling of ambiguous
82
+ times by choosing the later period, e.g.
183
83
 
184
- Fixes #28312.
84
+ Ruby:
85
+ ```
86
+ ENV["TZ"] = "Europe/Moscow"
87
+ Time.local(2014, 10, 26, 1, 0, 0) # => 2014-10-26 01:00:00 +0300
88
+ ```
185
89
 
186
- *Andrew White*
90
+ Before:
91
+ ```
92
+ >> "2014-10-26 01:00:00".in_time_zone("Moscow")
93
+ TZInfo::AmbiguousTime: 26/10/2014 01:00 is an ambiguous local time.
94
+ ```
187
95
 
188
- * Add `rfc3339` aliases to `xmlschema` for `Time` and `ActiveSupport::TimeWithZone`
96
+ After:
97
+ ```
98
+ >> "2014-10-26 01:00:00".in_time_zone("Moscow")
99
+ => Sun, 26 Oct 2014 01:00:00 MSK +03:00
100
+ ```
189
101
 
190
- For naming consistency when using the RFC 3339 profile of ISO 8601 in applications.
102
+ Fixes #17395.
191
103
 
192
104
  *Andrew White*
193
105
 
194
- * Add `Time.rfc3339` parsing method
195
-
196
- `Time.xmlschema` and consequently its alias `iso8601` accepts timestamps
197
- without a offset in contravention of the RFC 3339 standard. This method
198
- enforces that constraint and raises an `ArgumentError` if it doesn't.
106
+ * Redis cache store.
107
+
108
+ ```
109
+ # Defaults to `redis://localhost:6379/0`. Only use for dev/test.
110
+ config.cache_store = :redis_cache_store
111
+
112
+ # Supports all common cache store options (:namespace, :compress,
113
+ # :compress_threshold, :expires_in, :race_condition_ttl) and all
114
+ # Redis options.
115
+ cache_password = Rails.application.secrets.redis_cache_password
116
+ config.cache_store = :redis_cache_store, driver: :hiredis,
117
+ namespace: 'myapp-cache', compress: true, timeout: 1,
118
+ url: "redis://:#{cache_password}@myapp-cache-1:6379/0"
119
+
120
+ # Supports Redis::Distributed with multiple hosts
121
+ config.cache_store = :redis_cache_store, driver: :hiredis
122
+ namespace: 'myapp-cache', compress: true,
123
+ url: %w[
124
+ redis://myapp-cache-1:6379/0
125
+ redis://myapp-cache-1:6380/0
126
+ redis://myapp-cache-2:6379/0
127
+ redis://myapp-cache-2:6380/0
128
+ redis://myapp-cache-3:6379/0
129
+ redis://myapp-cache-3:6380/0
130
+ ]
131
+
132
+ # Or pass a builder block
133
+ config.cache_store = :redis_cache_store,
134
+ namespace: 'myapp-cache', compress: true,
135
+ redis: -> { Redis.new … }
136
+ ```
137
+
138
+ Deployment note: Take care to use a *dedicated Redis cache* rather
139
+ than pointing this at your existing Redis server. It won't cope well
140
+ with mixed usage patterns and it won't expire cache entries by default.
141
+
142
+ Redis cache server setup guide: https://redis.io/topics/lru-cache
199
143
 
200
- *Andrew White*
144
+ *Jeremy Daer*
201
145
 
202
- * Add `ActiveSupport::TimeZone.rfc3339` parsing method
146
+ * Cache: Enable compression by default for values > 1kB.
203
147
 
204
- Previously, there was no way to get a RFC 3339 timestamp into a specific
205
- timezone without either using `parse` or chaining methods. The new method
206
- allows parsing directly into the timezone, e.g:
148
+ Compression has long been available, but opt-in and at a 16kB threshold.
149
+ It wasn't enabled by default due to CPU cost. Today it's cheap and typical
150
+ cache data is eminently compressible, such as HTML or JSON fragments.
151
+ Compression dramatically reduces Memcached/Redis mem usage, which means
152
+ the same cache servers can store more data, which means higher hit rates.
207
153
 
208
- >> Time.zone = "Hawaii"
209
- => "Hawaii"
210
- >> Time.zone.rfc3339("1999-12-31T14:00:00Z")
211
- => Fri, 31 Dec 1999 14:00:00 HST -10:00
154
+ To disable compression, pass `compress: false` to the initializer.
212
155
 
213
- This new method has stricter semantics than the current `parse` method,
214
- and will raise an `ArgumentError` instead of returning nil, e.g:
156
+ *Jeremy Daer*
215
157
 
216
- >> Time.zone = "Hawaii"
217
- => "Hawaii"
218
- >> Time.zone.rfc3339("foobar")
219
- ArgumentError: invalid date
220
- >> Time.zone.parse("foobar")
221
- => nil
158
+ * Allow `Range#include?` on TWZ ranges.
222
159
 
223
- It will also raise an `ArgumentError` when either the time or offset
224
- components are missing, e.g:
160
+ In #11474 we prevented TWZ ranges being iterated over which matched
161
+ Ruby's handling of Time ranges and as a consequence `include?`
162
+ stopped working with both Time ranges and TWZ ranges. However in
163
+ ruby/ruby@b061634 support was added for `include?` to use `cover?`
164
+ for 'linear' objects. Since we have no way of making Ruby consider
165
+ TWZ instances as 'linear' we have to override `Range#include?`.
225
166
 
226
- >> Time.zone = "Hawaii"
227
- => "Hawaii"
228
- >> Time.zone.rfc3339("1999-12-31")
229
- ArgumentError: invalid date
230
- >> Time.zone.rfc3339("1999-12-31T14:00:00")
231
- ArgumentError: invalid date
167
+ Fixes #30799.
232
168
 
233
169
  *Andrew White*
234
170
 
235
- * Add `ActiveSupport::TimeZone.iso8601` parsing method
236
-
237
- Previously, there was no way to get a ISO 8601 timestamp into a specific
238
- timezone without either using `parse` or chaining methods. The new method
239
- allows parsing directly into the timezone, e.g:
240
-
241
- >> Time.zone = "Hawaii"
242
- => "Hawaii"
243
- >> Time.zone.iso8601("1999-12-31T14:00:00Z")
244
- => Fri, 31 Dec 1999 14:00:00 HST -10:00
171
+ * Fix acronym support in `humanize`.
245
172
 
246
- If the timestamp is a ISO 8601 date (YYYY-MM-DD), then the time is set
247
- to midnight, e.g:
173
+ Acronym inflections are stored with lowercase keys in the hash but
174
+ the match wasn't being lowercased before being looked up in the hash.
175
+ This shouldn't have any performance impact because before it would
176
+ fail to find the acronym and perform the `downcase` operation anyway.
248
177
 
249
- >> Time.zone = "Hawaii"
250
- => "Hawaii"
251
- >> Time.zone.iso8601("1999-12-31")
252
- => Fri, 31 Dec 1999 00:00:00 HST -10:00
253
-
254
- This new method has stricter semantics than the current `parse` method,
255
- and will raise an `ArgumentError` instead of returning nil, e.g:
256
-
257
- >> Time.zone = "Hawaii"
258
- => "Hawaii"
259
- >> Time.zone.iso8601("foobar")
260
- ArgumentError: invalid date
261
- >> Time.zone.parse("foobar")
262
- => nil
178
+ Fixes #31052.
263
179
 
264
180
  *Andrew White*
265
181
 
266
- * Deprecate implicit coercion of `ActiveSupport::Duration`
267
-
268
- Currently `ActiveSupport::Duration` implicitly converts to a seconds
269
- value when used in a calculation except for the explicit examples of
270
- addition and subtraction where the duration is the receiver, e.g:
271
-
272
- >> 2 * 1.day
273
- => 172800
274
-
275
- This results in lots of confusion especially when using durations
276
- with dates because adding/subtracting a value from a date treats
277
- integers as a day and not a second, e.g:
278
-
279
- >> Date.today
280
- => Wed, 01 Mar 2017
281
- >> Date.today + 2 * 1.day
282
- => Mon, 10 Apr 2490
182
+ * Add same method signature for `Time#prev_year` and `Time#next_year`
183
+ in accordance with `Date#prev_year`, `Date#next_year`.
283
184
 
284
- To fix this we're implementing `coerce` so that we can provide a
285
- deprecation warning with the intent of removing the implicit coercion
286
- in Rails 5.2, e.g:
185
+ Allows pass argument for `Time#prev_year` and `Time#next_year`.
287
186
 
288
- >> 2 * 1.day
289
- DEPRECATION WARNING: Implicit coercion of ActiveSupport::Duration
290
- to a Numeric is deprecated and will raise a TypeError in Rails 5.2.
291
- => 172800
292
-
293
- In Rails 5.2 it will raise `TypeError`, e.g:
294
-
295
- >> 2 * 1.day
296
- TypeError: ActiveSupport::Duration can't be coerced into Integer
187
+ Before:
188
+ ```
189
+ Time.new(2017, 9, 16, 17, 0).prev_year # => 2016-09-16 17:00:00 +0300
190
+ Time.new(2017, 9, 16, 17, 0).prev_year(1)
191
+ # => ArgumentError: wrong number of arguments (given 1, expected 0)
297
192
 
298
- This is the same behavior as with other types in Ruby, e.g:
193
+ Time.new(2017, 9, 16, 17, 0).next_year # => 2018-09-16 17:00:00 +0300
194
+ Time.new(2017, 9, 16, 17, 0).next_year(1)
195
+ # => ArgumentError: wrong number of arguments (given 1, expected 0)
196
+ ```
299
197
 
300
- >> 2 * "foo"
301
- TypeError: String can't be coerced into Integer
302
- >> "foo" * 2
303
- => "foofoo"
198
+ After:
199
+ ```
200
+ Time.new(2017, 9, 16, 17, 0).prev_year # => 2016-09-16 17:00:00 +0300
201
+ Time.new(2017, 9, 16, 17, 0).prev_year(1) # => 2016-09-16 17:00:00 +0300
304
202
 
305
- As part of this deprecation add `*` and `/` methods to `AS::Duration`
306
- so that calculations that keep the duration as the receiver work
307
- correctly whether the final receiver is a `Date` or `Time`, e.g:
203
+ Time.new(2017, 9, 16, 17, 0).next_year # => 2018-09-16 17:00:00 +0300
204
+ Time.new(2017, 9, 16, 17, 0).next_year(1) # => 2018-09-16 17:00:00 +0300
205
+ ```
308
206
 
309
- >> Date.today
310
- => Wed, 01 Mar 2017
311
- >> Date.today + 1.day * 2
312
- => Fri, 03 Mar 2017
207
+ *bogdanvlviv*
313
208
 
314
- Fixes #27457.
209
+ * Add same method signature for `Time#prev_month` and `Time#next_month`
210
+ in accordance with `Date#prev_month`, `Date#next_month`.
315
211
 
316
- *Andrew White*
212
+ Allows pass argument for `Time#prev_month` and `Time#next_month`.
317
213
 
318
- * Update `DateTime#change` to support `:usec` and `:nsec` options.
214
+ Before:
215
+ ```
216
+ Time.new(2017, 9, 16, 17, 0).prev_month # => 2017-08-16 17:00:00 +0300
217
+ Time.new(2017, 9, 16, 17, 0).prev_month(1)
218
+ # => ArgumentError: wrong number of arguments (given 1, expected 0)
319
219
 
320
- Adding support for these options now allows us to update the `DateTime#end_of`
321
- methods to match the equivalent `Time#end_of` methods, e.g:
220
+ Time.new(2017, 9, 16, 17, 0).next_month # => 2017-10-16 17:00:00 +0300
221
+ Time.new(2017, 9, 16, 17, 0).next_month(1)
222
+ # => ArgumentError: wrong number of arguments (given 1, expected 0)
223
+ ```
322
224
 
323
- datetime = DateTime.now.end_of_day
324
- datetime.nsec == 999999999 # => true
225
+ After:
226
+ ```
227
+ Time.new(2017, 9, 16, 17, 0).prev_month # => 2017-08-16 17:00:00 +0300
228
+ Time.new(2017, 9, 16, 17, 0).prev_month(1) # => 2017-08-16 17:00:00 +0300
325
229
 
326
- Fixes #21424.
230
+ Time.new(2017, 9, 16, 17, 0).next_month # => 2017-10-16 17:00:00 +0300
231
+ Time.new(2017, 9, 16, 17, 0).next_month(1) # => 2017-10-16 17:00:00 +0300
232
+ ```
327
233
 
328
- *Dan Moore*, *Andrew White*
234
+ *bogdanvlviv*
329
235
 
330
- * Add `ActiveSupport::Duration#before` and `#after` as aliases for `#until` and `#since`
236
+ * Add same method signature for `Time#prev_day` and `Time#next_day`
237
+ in accordance with `Date#prev_day`, `Date#next_day`.
331
238
 
332
- These read more like English and require less mental gymnastics to read and write.
239
+ Allows pass argument for `Time#prev_day` and `Time#next_day`.
333
240
 
334
241
  Before:
242
+ ```
243
+ Time.new(2017, 9, 16, 17, 0).prev_day # => 2017-09-15 17:00:00 +0300
244
+ Time.new(2017, 9, 16, 17, 0).prev_day(1)
245
+ # => ArgumentError: wrong number of arguments (given 1, expected 0)
335
246
 
336
- 2.weeks.since(customer_start_date)
337
- 5.days.until(today)
247
+ Time.new(2017, 9, 16, 17, 0).next_day # => 2017-09-17 17:00:00 +0300
248
+ Time.new(2017, 9, 16, 17, 0).next_day(1)
249
+ # => ArgumentError: wrong number of arguments (given 1, expected 0)
250
+ ```
338
251
 
339
252
  After:
253
+ ```
254
+ Time.new(2017, 9, 16, 17, 0).prev_day # => 2017-09-15 17:00:00 +0300
255
+ Time.new(2017, 9, 16, 17, 0).prev_day(1) # => 2017-09-15 17:00:00 +0300
340
256
 
341
- 2.weeks.after(customer_start_date)
342
- 5.days.before(today)
343
-
344
- *Nick Johnstone*
345
-
346
- * Soft-deprecated the top-level `HashWithIndifferentAccess` constant.
347
- `ActiveSupport::HashWithIndifferentAccess` should be used instead.
348
-
349
- Fixes #28157.
350
-
351
- *Robin Dupret*
352
-
353
- * In Core Extensions, make `MarshalWithAutoloading#load` pass through the second, optional
354
- argument for `Marshal#load( source [, proc] )`. This way we don't have to do
355
- `Marshal.method(:load).super_method.call(source, proc)` just to be able to pass a proc.
257
+ Time.new(2017, 9, 16, 17, 0).next_day # => 2017-09-17 17:00:00 +0300
258
+ Time.new(2017, 9, 16, 17, 0).next_day(1) # => 2017-09-17 17:00:00 +0300
259
+ ```
356
260
 
357
- *Jeff Latz*
261
+ *bogdanvlviv*
358
262
 
359
- * `ActiveSupport::Gzip.decompress` now checks checksum and length in footer.
263
+ * `IO#to_json` now returns the `to_s` representation, rather than
264
+ attempting to convert to an array. This fixes a bug where `IO#to_json`
265
+ would raise an `IOError` when called on an unreadable object.
360
266
 
361
- *Dylan Thacker-Smith*
267
+ Fixes #26132.
362
268
 
363
- * Cache `ActiveSupport::TimeWithZone#to_datetime` before freezing.
269
+ *Paul Kuruvilla*
364
270
 
365
- *Adam Rice*
366
-
367
- * Deprecate `ActiveSupport.halt_callback_chains_on_return_false`.
271
+ * Remove deprecated `halt_callback_chains_on_return_false` option.
368
272
 
369
273
  *Rafael Mendonça França*
370
274
 
371
- * Remove deprecated behavior that halts callbacks when the return is false.
275
+ * Remove deprecated `:if` and `:unless` string filter for callbacks.
372
276
 
373
277
  *Rafael Mendonça França*
374
278
 
375
- * Deprecate passing string to `:if` and `:unless` conditional options
376
- on `set_callback` and `skip_callback`.
377
-
378
- *Ryuta Kamizono*
379
-
380
- * Raise `ArgumentError` when passing string to define callback.
381
-
382
- *Ryuta Kamizono*
383
-
384
- * Updated Unicode version to 9.0.0
385
-
386
- Now we can handle new emojis such like "👩‍👩‍👧‍👦" ("\u{1F469}\u{200D}\u{1F469}\u{200D}\u{1F467}\u{200D}\u{1F466}").
387
-
388
- version 8.0.0
389
-
390
- "👩‍👩‍👧‍👦".mb_chars.grapheme_length # => 4
391
- "👩‍👩‍👧‍👦".mb_chars.reverse # => "👦👧‍👩‍👩‍"
392
-
393
- version 9.0.0
394
-
395
- "👩‍👩‍👧‍👦".mb_chars.grapheme_length # => 1
396
- "👩‍👩‍👧‍👦".mb_chars.reverse # => "👩‍👩‍👧‍👦"
397
-
398
- *Fumiaki MATSUSHIMA*
399
-
400
- * Changed `ActiveSupport::Inflector#transliterate` to raise `ArgumentError` when it receives
401
- anything except a string.
402
-
403
- *Kevin McPhillips*
404
-
405
- * Fixed bugs that `StringInquirer#respond_to_missing?` and
406
- `ArrayInquirer#respond_to_missing?` do not fallback to `super`.
279
+ * `Hash#slice` now falls back to Ruby 2.5+'s built-in definition if defined.
407
280
 
408
281
  *Akira Matsuda*
409
282
 
410
- * Fix inconsistent results when parsing large durations and constructing durations from code
411
-
412
- ActiveSupport::Duration.parse('P3Y') == 3.years # It should be true
413
-
414
- Duration parsing made independent from any moment of time:
415
- Fixed length in seconds is assigned to each duration part during parsing.
416
-
417
- Changed duration of months and years in seconds to more accurate and logical:
418
-
419
- 1. The value of 365.2425 days in Gregorian year is more accurate
420
- as it accounts for every 400th non-leap year.
421
-
422
- 2. Month's length is bound to year's duration, which makes
423
- sensible comparisons like `12.months == 1.year` to be `true`
424
- and nonsensical ones like `30.days == 1.month` to be `false`.
425
-
426
- Calculations on times and dates with durations shouldn't be affected as
427
- duration's numeric value isn't used in calculations, only parts are used.
283
+ * Deprecate `secrets.secret_token`.
428
284
 
429
- Methods on `Numeric` like `2.days` now use these predefined durations
430
- to avoid duplication of duration constants through the codebase and
431
- eliminate creation of intermediate durations.
285
+ The architecture for secrets had a big upgrade between Rails 3 and Rails 4,
286
+ when the default changed from using `secret_token` to `secret_key_base`.
432
287
 
433
- *Andrey Novikov*, *Andrew White*
288
+ `secret_token` has been soft deprecated in documentation for four years
289
+ but is still in place to support apps created before Rails 4.
290
+ Deprecation warnings have been added to help developers upgrade their
291
+ applications to `secret_key_base`.
434
292
 
435
- * Change return value of `Rational#duplicable?`, `ComplexClass#duplicable?`
436
- to false.
293
+ *claudiob*, *Kasper Timm Hansen*
437
294
 
438
- *utilum*
439
-
440
- * Change return value of `NilClass#duplicable?`, `FalseClass#duplicable?`,
441
- `TrueClass#duplicable?`, `Symbol#duplicable?` and `Numeric#duplicable?`
442
- to true with Ruby 2.4+. These classes can dup with Ruby 2.4+.
295
+ * Return an instance of `HashWithIndifferentAccess` from `HashWithIndifferentAccess#transform_keys`.
443
296
 
444
297
  *Yuji Yaginuma*
445
298
 
446
- * Remove deprecated class `ActiveSupport::Concurrency::Latch`.
299
+ * Add key rotation support to `MessageEncryptor` and `MessageVerifier`.
447
300
 
448
- *Andrew White*
301
+ This change introduces a `rotate` method to both the `MessageEncryptor` and
302
+ `MessageVerifier` classes. This method accepts the same arguments and
303
+ options as the given classes' constructor. The `encrypt_and_verify` method
304
+ for `MessageEncryptor` and the `verified` method for `MessageVerifier` also
305
+ accept an optional keyword argument `:on_rotation` block which is called
306
+ when a rotated instance is used to decrypt or verify the message.
449
307
 
450
- * Remove deprecated separator argument from `parameterize`.
308
+ *Michael J Coyne*
451
309
 
452
- *Andrew White*
310
+ * Deprecate `Module#reachable?` method.
453
311
 
454
- * Remove deprecated method `Numeric#to_formatted_s`.
312
+ *bogdanvlviv*
455
313
 
456
- *Andrew White*
314
+ * Add `config/credentials.yml.enc` to store production app secrets.
457
315
 
458
- * Remove deprecated method `alias_method_chain`.
316
+ Allows saving any authentication credentials for third party services
317
+ directly in repo encrypted with `config/master.key` or `ENV["RAILS_MASTER_KEY"]`.
459
318
 
460
- *Andrew White*
319
+ This will eventually replace `Rails.application.secrets` and the encrypted
320
+ secrets introduced in Rails 5.1.
461
321
 
462
- * Remove deprecated constant `MissingSourceFile`.
322
+ *DHH*, *Kasper Timm Hansen*
463
323
 
464
- *Andrew White*
324
+ * Add `ActiveSupport::EncryptedFile` and `ActiveSupport::EncryptedConfiguration`.
465
325
 
466
- * Remove deprecated methods `Module.qualified_const_defined?`,
467
- `Module.qualified_const_get` and `Module.qualified_const_set`.
326
+ Allows for stashing encrypted files or configuration directly in repo by
327
+ encrypting it with a key.
468
328
 
469
- *Andrew White*
329
+ Backs the new credentials setup above, but can also be used independently.
470
330
 
471
- * Remove deprecated `:prefix` option from `number_to_human_size`.
331
+ *DHH*, *Kasper Timm Hansen*
472
332
 
473
- *Andrew White*
333
+ * `Module#delegate_missing_to` now raises `DelegationError` if target is nil,
334
+ similar to `Module#delegate`.
474
335
 
475
- * Remove deprecated method `ActiveSupport::HashWithIndifferentAccess.new_from_hash_copying_default`.
336
+ *Anton Khamets*
476
337
 
477
- *Andrew White*
338
+ * Update `String#camelize` to provide feedback when wrong option is passed.
478
339
 
479
- * Remove deprecated file `active_support/core_ext/time/marshal.rb`.
340
+ `String#camelize` was returning nil without any feedback when an
341
+ invalid option was passed as a parameter.
480
342
 
481
- *Andrew White*
482
-
483
- * Remove deprecated file `active_support/core_ext/struct.rb`.
484
-
485
- *Andrew White*
486
-
487
- * Remove deprecated file `active_support/core_ext/module/method_transplanting.rb`.
488
-
489
- *Andrew White*
490
-
491
- * Remove deprecated method `Module.local_constants`.
492
-
493
- *Andrew White*
343
+ Previously:
494
344
 
495
- * Remove deprecated file `active_support/core_ext/kernel/debugger.rb`.
345
+ 'one_two'.camelize(true)
346
+ # => nil
496
347
 
497
- *Andrew White*
348
+ Now:
498
349
 
499
- * Remove deprecated method `ActiveSupport::Cache::Store#namespaced_key`.
350
+ 'one_two'.camelize(true)
351
+ # => ArgumentError: Invalid option, use either :upper or :lower.
500
352
 
501
- *Andrew White*
353
+ *Ricardo Díaz*
502
354
 
503
- * Remove deprecated method `ActiveSupport::Cache::Strategy::LocalCache::LocalStore#set_cache_value`.
355
+ * Fix modulo operations involving durations.
504
356
 
505
- *Andrew White*
357
+ Rails 5.1 introduced `ActiveSupport::Duration::Scalar` as a wrapper
358
+ around numeric values as a way of ensuring a duration was the outcome of
359
+ an expression. However, the implementation was missing support for modulo
360
+ operations. This support has now been added and should result in a duration
361
+ being returned from expressions involving modulo operations.
506
362
 
507
- * Remove deprecated method `ActiveSupport::Cache::MemCacheStore#escape_key`.
363
+ Prior to Rails 5.1:
508
364
 
509
- *Andrew White*
365
+ 5.minutes % 2.minutes
366
+ # => 60
510
367
 
511
- * Remove deprecated method `ActiveSupport::Cache::FileStore#key_file_path`.
368
+ Now:
512
369
 
513
- *Andrew White*
370
+ 5.minutes % 2.minutes
371
+ # => 1 minute
514
372
 
515
- * Ensure duration parsing is consistent across DST changes.
373
+ Fixes #29603 and #29743.
516
374
 
517
- Previously `ActiveSupport::Duration.parse` used `Time.current` and
518
- `Time#advance` to calculate the number of seconds in the duration
519
- from an arbitrary collection of parts. However as `advance` tries to
520
- be consistent across DST boundaries this meant that either the
521
- duration was shorter or longer depending on the time of year.
375
+ *Sayan Chakraborty*, *Andrew White*
522
376
 
523
- This was fixed by using an absolute reference point in UTC which
524
- isn't subject to DST transitions. An arbitrary date of Jan 1st, 2000
525
- was chosen for no other reason that it seemed appropriate.
377
+ * Fix division where a duration is the denominator.
526
378
 
527
- Additionally, duration parsing should now be marginally faster as we
528
- are no longer creating instances of `ActiveSupport::TimeWithZone`
529
- every time we parse a duration string.
379
+ PR #29163 introduced a change in behavior when a duration was the denominator
380
+ in a calculation - this was incorrect as dividing by a duration should always
381
+ return a `Numeric`. The behavior of previous versions of Rails has been restored.
530
382
 
531
- Fixes #26941.
383
+ Fixes #29592.
532
384
 
533
385
  *Andrew White*
534
386
 
535
- * Use `Hash#compact` and `Hash#compact!` from Ruby 2.4. Old Ruby versions
536
- will continue to get these methods from Active Support as before.
537
-
538
- *Prathamesh Sonpatki*
539
-
540
- * Fix `ActiveSupport::TimeZone#strptime`.
541
- Support for timestamps in format of seconds (%s) and milliseconds (%Q).
542
-
543
- Fixes #26840.
544
-
545
- *Lev Denisov*
546
-
547
- * Fix `DateAndTime::Calculations#copy_time_to`. Copy `nsec` instead of `usec`.
548
-
549
- Jumping forward or backward between weeks now preserves nanosecond digits.
550
-
551
- *Josua Schmid*
552
-
553
- * Fix `ActiveSupport::TimeWithZone#in` across DST boundaries.
554
-
555
- Previously calls to `in` were being sent to the non-DST aware
556
- method `Time#since` via `method_missing`. It is now aliased to
557
- the DST aware `ActiveSupport::TimeWithZone#+` which handles
558
- transitions across DST boundaries, e.g:
559
-
560
- Time.zone = "US/Eastern"
561
-
562
- t = Time.zone.local(2016,11,6,1)
563
- # => Sun, 06 Nov 2016 01:00:00 EDT -05:00
564
-
565
- t.in(1.hour)
566
- # => Sun, 06 Nov 2016 01:00:00 EST -05:00
567
-
568
- Fixes #26580.
569
-
570
- *Thomas Balthazar*
571
-
572
- * Remove unused parameter `options = nil` for `#clear` of
573
- `ActiveSupport::Cache::Strategy::LocalCache::LocalStore` and
574
- `ActiveSupport::Cache::Strategy::LocalCache`.
575
-
576
- *Yosuke Kabuto*
577
-
578
- * Fix `thread_mattr_accessor` subclass no longer overwrites parent.
579
-
580
- Assigning a value to a subclass using `thread_mattr_accessor` no
581
- longer changes the value of the parent class. This brings the
582
- behavior inline with the documentation.
387
+ * Add purpose and expiry support to `ActiveSupport::MessageVerifier` and
388
+ `ActiveSupport::MessageEncryptor`.
583
389
 
584
- Given:
390
+ For instance, to ensure a message is only usable for one intended purpose:
585
391
 
586
- class Account
587
- thread_mattr_accessor :user
588
- end
392
+ token = @verifier.generate("x", purpose: :shipping)
589
393
 
590
- class Customer < Account
591
- end
394
+ @verifier.verified(token, purpose: :shipping) # => "x"
395
+ @verifier.verified(token) # => nil
592
396
 
593
- Account.user = "DHH"
594
- Customer.user = "Rafael"
397
+ Or make it expire after a set time:
595
398
 
596
- Before:
597
-
598
- Account.user # => "Rafael"
399
+ @verifier.generate("x", expires_in: 1.month)
400
+ @verifier.generate("y", expires_at: Time.now.end_of_year)
599
401
 
600
- After:
402
+ Showcased with `ActiveSupport::MessageVerifier`, but works the same for
403
+ `ActiveSupport::MessageEncryptor`'s `encrypt_and_sign` and `decrypt_and_verify`.
601
404
 
602
- Account.user # => "DHH"
405
+ Pull requests: #29599, #29854
603
406
 
604
- *Shinichi Maeshima*
407
+ *Assain Jaleel*
605
408
 
606
- * Since weeks are no longer converted to days, add `:weeks` to the list of
607
- parts that `ActiveSupport::TimeWithZone` will recognize as possibly being
608
- of variable duration to take account of DST transitions.
409
+ * Make the order of `Hash#reverse_merge!` consistent with `HashWithIndifferentAccess`.
609
410
 
610
- Fixes #26039.
411
+ *Erol Fornoles*
611
412
 
612
- *Andrew White*
413
+ * Add `freeze_time` helper which freezes time to `Time.now` in tests.
613
414
 
614
- * Defines `Regexp.match?` for Ruby versions prior to 2.4. The predicate
615
- has the same interface, but it does not have the performance boost. Its
616
- purpose is to be able to write 2.4 compatible code.
617
-
618
- *Xavier Noria*
619
-
620
- * Allow `MessageEncryptor` to take advantage of authenticated encryption modes.
415
+ *Prathamesh Sonpatki*
621
416
 
622
- AEAD modes like `aes-256-gcm` provide both confidentiality and data
623
- authenticity, eliminating the need to use `MessageVerifier` to check if the
624
- encrypted data has been tampered with. This speeds up encryption/decryption
625
- and results in shorter cipher text.
417
+ * Default `ActiveSupport::MessageEncryptor` to use AES 256 GCM encryption.
626
418
 
627
- *Bart de Water*
419
+ On for new Rails 5.2 apps. Upgrading apps can find the config as a new
420
+ framework default.
628
421
 
629
- * Introduce `assert_changes` and `assert_no_changes`.
422
+ *Assain Jaleel*
630
423
 
631
- `assert_changes` is a more general `assert_difference` that works with any
632
- value.
424
+ * Cache: `write_multi`.
633
425
 
634
- assert_changes 'Error.current', from: nil, to: 'ERR' do
635
- expected_bad_operation
636
- end
426
+ Rails.cache.write_multi foo: 'bar', baz: 'qux'
637
427
 
638
- Can be called with strings, to be evaluated in the binding (context) of
639
- the block given to the assertion, or a lambda.
428
+ Plus faster fetch_multi with stores that implement `write_multi_entries`.
429
+ Keys that aren't found may be written to the cache store in one shot
430
+ instead of separate writes.
640
431
 
641
- assert_changes -> { Error.current }, from: nil, to: 'ERR' do
642
- expected_bad_operation
643
- end
432
+ The default implementation simply calls `write_entry` for each entry.
433
+ Stores may override if they're capable of one-shot bulk writes, like
434
+ Redis `MSET`.
644
435
 
645
- The `from` and `to` arguments are compared with the case operator (`===`).
436
+ *Jeremy Daer*
646
437
 
647
- assert_changes 'Error.current', from: nil, to: Error do
648
- expected_bad_operation
649
- end
438
+ * Add default option to module and class attribute accessors.
650
439
 
651
- This is pretty useful, if you need to loosely compare a value. For example,
652
- you need to test a token has been generated and it has that many random
653
- characters.
440
+ mattr_accessor :settings, default: {}
654
441
 
655
- user = User.start_registration
656
- assert_changes 'user.token', to: /\w{32}/ do
657
- user.finish_registration
658
- end
442
+ Works for `mattr_reader`, `mattr_writer`, `cattr_accessor`, `cattr_reader`,
443
+ and `cattr_writer` as well.
659
444
 
660
445
  *Genadi Samokovarov*
661
446
 
662
- * Fix `ActiveSupport::TimeZone#strptime`. Now raises `ArgumentError` when the
663
- given time doesn't match the format. The error is the same as the one given
664
- by Ruby's `Date.strptime`. Previously it raised
665
- `NoMethodError: undefined method empty? for nil:NilClass.` due to a bug.
447
+ * Add `Date#prev_occurring` and `Date#next_occurring` to return specified next/previous occurring day of week.
666
448
 
667
- Fixes #25701.
449
+ *Shota Iguchi*
668
450
 
669
- *John Gesimondo*
451
+ * Add default option to `class_attribute`.
670
452
 
671
- * `travel/travel_to` travel time helpers, now raise on nested calls,
672
- as this can lead to confusing time stubbing.
453
+ Before:
673
454
 
674
- Instead of:
455
+ class_attribute :settings
456
+ self.settings = {}
675
457
 
676
- travel_to 2.days.from_now do
677
- # 2 days from today
678
- travel_to 3.days.from_now do
679
- # 5 days from today
680
- end
681
- end
458
+ Now:
682
459
 
683
- preferred way to achieve above is:
460
+ class_attribute :settings, default: {}
684
461
 
685
- travel 2.days do
686
- # 2 days from today
687
- end
462
+ *DHH*
688
463
 
689
- travel 5.days do
690
- # 5 days from today
691
- end
464
+ * `#singularize` and `#pluralize` now respect uncountables for the specified locale.
692
465
 
693
- *Vipul A M*
466
+ *Eilis Hamilton*
694
467
 
695
- * Support parsing JSON time in ISO8601 local time strings in
696
- `ActiveSupport::JSON.decode` when `parse_json_times` is enabled.
697
- Strings in the format of `YYYY-MM-DD hh:mm:ss` (without a `Z` at
698
- the end) will be parsed in the local timezone (`Time.zone`). In
699
- addition, date strings (`YYYY-MM-DD`) are now parsed into `Date`
700
- objects.
468
+ * Add `ActiveSupport::CurrentAttributes` to provide a thread-isolated attributes singleton.
469
+ Primary use case is keeping all the per-request attributes easily available to the whole system.
701
470
 
702
- *Grzegorz Witek*
471
+ *DHH*
703
472
 
704
- * Fixed `ActiveSupport::Logger.broadcast` so that calls to `#silence` now
705
- properly delegate to all loggers. Silencing now properly suppresses logging
706
- to both the log and the console.
473
+ * Fix implicit coercion calculations with scalars and durations.
707
474
 
708
- *Kevin McPhillips*
475
+ Previously, calculations where the scalar is first would be converted to a duration
476
+ of seconds, but this causes issues with dates being converted to times, e.g:
709
477
 
710
- * Remove deprecated arguments in `assert_nothing_raised`.
478
+ Time.zone = "Beijing" # => Asia/Shanghai
479
+ date = Date.civil(2017, 5, 20) # => Mon, 20 May 2017
480
+ 2 * 1.day # => 172800 seconds
481
+ date + 2 * 1.day # => Mon, 22 May 2017 00:00:00 CST +08:00
711
482
 
712
- *Rafel Mendonça França*
483
+ Now, the `ActiveSupport::Duration::Scalar` calculation methods will try to maintain
484
+ the part structure of the duration where possible, e.g:
713
485
 
714
- * `Date.to_s` doesn't produce too many spaces. For example, `to_s(:short)`
715
- will now produce `01 Feb` instead of ` 1 Feb`.
486
+ Time.zone = "Beijing" # => Asia/Shanghai
487
+ date = Date.civil(2017, 5, 20) # => Mon, 20 May 2017
488
+ 2 * 1.day # => 2 days
489
+ date + 2 * 1.day # => Mon, 22 May 2017
716
490
 
717
- Fixes #25251.
491
+ Fixes #29160, #28970.
718
492
 
719
- *Sean Griffin*
493
+ *Andrew White*
720
494
 
721
- * Introduce `Module#delegate_missing_to`.
495
+ * Add support for versioned cache entries. This enables the cache stores to recycle cache keys, greatly saving
496
+ on storage in cases with frequent churn. Works together with the separation of `#cache_key` and `#cache_version`
497
+ in Active Record and its use in Action Pack's fragment caching.
722
498
 
723
- When building a decorator, a common pattern emerges:
499
+ *DHH*
724
500
 
725
- class Partition
726
- def initialize(first_event)
727
- @events = [ first_event ]
728
- end
501
+ * Pass gem name and deprecation horizon to deprecation notifications.
729
502
 
730
- def people
731
- if @events.first.detail.people.any?
732
- @events.collect { |e| Array(e.detail.people) }.flatten.uniq
733
- else
734
- @events.collect(&:creator).uniq
735
- end
736
- end
503
+ *Willem van Bergen*
737
504
 
738
- private
739
- def respond_to_missing?(name, include_private = false)
740
- @events.respond_to?(name, include_private)
741
- end
505
+ * Add support for `:offset` and `:zone` to `ActiveSupport::TimeWithZone#change`.
742
506
 
743
- def method_missing(method, *args, &block)
744
- @events.send(method, *args, &block)
745
- end
746
- end
507
+ *Andrew White*
747
508
 
748
- With `Module#delegate_missing_to`, the above is condensed to:
509
+ * Add support for `:offset` to `Time#change`.
749
510
 
750
- class Partition
751
- delegate_missing_to :@events
511
+ Fixes #28723.
752
512
 
753
- def initialize(first_event)
754
- @events = [ first_event ]
755
- end
513
+ *Andrew White*
756
514
 
757
- def people
758
- if @events.first.detail.people.any?
759
- @events.collect { |e| Array(e.detail.people) }.flatten.uniq
760
- else
761
- @events.collect(&:creator).uniq
762
- end
763
- end
764
- end
515
+ * Add `fetch_values` for `HashWithIndifferentAccess`.
765
516
 
766
- *Genadi Samokovarov*, *DHH*
517
+ The method was originally added to `Hash` in Ruby 2.3.0.
767
518
 
768
- * Rescuable: If a handler doesn't match the exception, check for handlers
769
- matching the exception's cause.
519
+ *Josh Pencheon*
770
520
 
771
- *Jeremy Daer*
772
521
 
773
- Please check [5-0-stable](https://github.com/rails/rails/blob/5-0-stable/activesupport/CHANGELOG.md) for previous changes.
522
+ Please check [5-1-stable](https://github.com/rails/rails/blob/5-1-stable/activesupport/CHANGELOG.md) for previous changes.