1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
|
* Add `Array#extract!`.
The method removes and returns the elements for which the block returns a true value.
If no block is given, an Enumerator is returned instead.
numbers = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
odd_numbers = numbers.extract! { |number| number.odd? } # => [1, 3, 5, 7, 9]
numbers # => [0, 2, 4, 6, 8]
*bogdanvlviv*
* Support not to cache `nil` for `ActiveSupport::Cache#fetch`.
cache.fetch('bar', skip_nil: true) { nil }
cache.exist?('bar') # => false
*Martin Hong*
* Add "event object" support to the notification system.
Before this change, end users were forced to create hand made artisanal
event objects on their own, like this:
ActiveSupport::Notifications.subscribe('wait') do |*args|
@event = ActiveSupport::Notifications::Event.new(*args)
end
ActiveSupport::Notifications.instrument('wait') do
sleep 1
end
@event.duration # => 1000.138
After this change, if the block passed to `subscribe` only takes one
parameter, the framework will yield an event object to the block. Now
end users are no longer required to make their own:
ActiveSupport::Notifications.subscribe('wait') do |event|
@event = event
end
ActiveSupport::Notifications.instrument('wait') do
sleep 1
end
p @event.allocations # => 7
p @event.cpu_time # => 0.256
p @event.idle_time # => 1003.2399
Now you can enjoy event objects without making them yourself. Neat!
*Aaron "t.lo" Patterson*
* Add cpu_time, idle_time, and allocations to Event
*Eileen M. Uchitelle*, *Aaron Patterson*
* RedisCacheStore: support key expiry in increment/decrement.
Pass `:expires_in` to `#increment` and `#decrement` to set a Redis EXPIRE on the key.
If the key is already set to expire, RedisCacheStore won't extend its expiry.
Rails.cache.increment("some_key", 1, expires_in: 2.minutes)
*Jason Lee*
* Allow Range#=== and Range#cover? on Range
`Range#cover?` can now accept a range argument like `Range#include?` and
`Range#===`. `Range#===` works correctly on Ruby 2.6. `Range#include?` is moved
into a new file, with these two methods.
*Requiring active_support/core_ext/range/include_range is now deprecated.*
*Use `require "active_support/core_ext/range/compare_range"` instead.*
*utilum*
* Add `index_with` to Enumerable.
Allows creating a hash from an enumerable with the value from a passed block
or a default argument.
%i( title body ).index_with { |attr| post.public_send(attr) }
# => { title: "hey", body: "what's up?" }
%i( title body ).index_with(nil)
# => { title: nil, body: nil }
Closely linked with `index_by`, which creates a hash where the keys are extracted from a block.
*Kasper Timm Hansen*
* Fix bug where `ActiveSupport::Timezone.all` would fail when tzinfo data for
any timezone defined in `ActiveSupport::TimeZone::MAPPING` is missing.
*Dominik Sander*
* Redis cache store: `delete_matched` no longer blocks the Redis server.
(Switches from evaled Lua to a batched SCAN + DEL loop.)
*Gleb Mazovetskiy*
* Fix bug where `ActiveSupport::Cache` will massively inflate the storage
size when compression is enabled (which is true by default). This patch
does not attempt to repair existing data: please manually flush the cache
to clear out the problematic entries.
*Godfrey Chan*
* Fix bug where `URI.unescape` would fail with mixed Unicode/escaped character input:
URI.unescape("\xe3\x83\x90") # => "バ"
URI.unescape("%E3%83%90") # => "バ"
URI.unescape("\xe3\x83\x90%E3%83%90") # => Encoding::CompatibilityError
*Ashe Connor*, *Aaron Patterson*
* Add `before?` and `after?` methods to `Date`, `DateTime`,
`Time`, and `TimeWithZone`.
*Nick Holden*
* `ActiveSupport::Inflector#ordinal` and `ActiveSupport::Inflector#ordinalize` now support
translations through I18n.
# locale/fr.rb
{
fr: {
number: {
nth: {
ordinals: lambda do |_key, number:, **_options|
if number.to_i.abs == 1
'er'
else
'e'
end
end,
ordinalized: lambda do |_key, number:, **_options|
"#{number}#{ActiveSupport::Inflector.ordinal(number)}"
end
}
}
}
}
*Christian Blais*
* Add `:private` option to ActiveSupport's `Module#delegate`
in order to delegate methods as private:
class User < ActiveRecord::Base
has_one :profile
delegate :date_of_birth, to: :profile, private: true
def age
Date.today.year - date_of_birth.year
end
end
# User.new.age # => 29
# User.new.date_of_birth
# => NoMethodError: private method `date_of_birth' called for #<User:0x00000008221340>
*Tomas Valent*
* `String#truncate_bytes` to truncate a string to a maximum bytesize without
breaking multibyte characters or grapheme clusters like 👩👩👦👦.
*Jeremy Daer*
* `String#strip_heredoc` preserves frozenness.
"foo".freeze.strip_heredoc.frozen? # => true
Fixes that frozen string literals would inadvertently become unfrozen:
# frozen_string_literal: true
foo = <<-MSG.strip_heredoc
la la la
MSG
foo.frozen? # => false !??
*Jeremy Daer*
* Rails 6 requires Ruby 2.4.1 or newer.
*Jeremy Daer*
* Adds parallel testing to Rails.
Parallelize your test suite with forked processes or threads.
*Eileen M. Uchitelle*, *Aaron Patterson*
Please check [5-2-stable](https://github.com/rails/rails/blob/5-2-stable/activesupport/CHANGELOG.md) for previous changes.
|