activesupport 7.1.1 → 7.1.3

Sign up to get free protection for your applications and to get access to all the features.
Files changed (30) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +104 -0
  3. data/lib/active_support/broadcast_logger.rb +8 -0
  4. data/lib/active_support/cache/entry.rb +7 -1
  5. data/lib/active_support/cache/file_store.rb +1 -1
  6. data/lib/active_support/cache/mem_cache_store.rb +16 -8
  7. data/lib/active_support/cache/memory_store.rb +4 -4
  8. data/lib/active_support/cache/redis_cache_store.rb +21 -14
  9. data/lib/active_support/cache/strategy/local_cache.rb +9 -6
  10. data/lib/active_support/cache.rb +34 -7
  11. data/lib/active_support/core_ext/date/conversions.rb +1 -1
  12. data/lib/active_support/core_ext/module/concerning.rb +6 -6
  13. data/lib/active_support/core_ext/object/with_options.rb +1 -1
  14. data/lib/active_support/core_ext/string/indent.rb +1 -1
  15. data/lib/active_support/deprecation/behaviors.rb +18 -16
  16. data/lib/active_support/deprecation/reporting.rb +7 -4
  17. data/lib/active_support/gem_version.rb +1 -1
  18. data/lib/active_support/inflector/methods.rb +2 -2
  19. data/lib/active_support/json/encoding.rb +1 -1
  20. data/lib/active_support/log_subscriber.rb +8 -2
  21. data/lib/active_support/messages/metadata.rb +1 -1
  22. data/lib/active_support/notifications/fanout.rb +25 -19
  23. data/lib/active_support/number_helper/number_to_human_size_converter.rb +2 -2
  24. data/lib/active_support/number_helper.rb +379 -318
  25. data/lib/active_support/ordered_options.rb +2 -2
  26. data/lib/active_support/syntax_error_proxy.rb +22 -1
  27. data/lib/active_support/testing/assertions.rb +1 -1
  28. data/lib/active_support/testing/strict_warnings.rb +1 -0
  29. data/lib/active_support/testing/time_helpers.rb +5 -1
  30. metadata +5 -5
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: ecb3bcd9549f6429e9a7b2e3e54bd529a71608135834c95ecad50ed60dd8935a
4
- data.tar.gz: 23c6ef54d1fbef9a19494322bae6ed4f4719d1a9f0b60e3f507dc1ccd4cf9adf
3
+ metadata.gz: 5694cfb6b4f9606e418f0719251eddccf4ddb2db2747a3965d22e204d7d53da3
4
+ data.tar.gz: fb6419c22aa79734268b1c3435692cf6e9e7e18a0522d4089f1528a4f401edb2
5
5
  SHA512:
6
- metadata.gz: abdba26b48e19b8f107f9110e2934f315f8f4fcf87340309f4786faf0998903a21e791d362e106550439088016039c692e00c90b380b5b7602b497244ea30419
7
- data.tar.gz: 8f256ca213eea9aed13061094dca338c5886ba2bd3454036cd39649938399cc41ec74ff09ec28beabc21b9a57713c98e60125b13306e63a56aa908ad269b2316
6
+ metadata.gz: 84e38bfcc73526a4f62531d6387a57e235f211112dc65f4dd436a32c6cf88aceaa40990d29cb49612c4458d4768036bb1315cb96265109c029a4faed65fb6e02
7
+ data.tar.gz: 0f0a733d3dcf357ebee24484b1c9832f55b22e362328a537d2d6ee3afe4996e5c880d6ebb78bd90c4e1a7139a75dfcfdaef7bbba06289d90d213ed0dcbfc6abe
data/CHANGELOG.md CHANGED
@@ -1,3 +1,107 @@
1
+ ## Rails 7.1.3 (January 16, 2024) ##
2
+
3
+ * Handle nil `backtrace_locations` in `ActiveSupport::SyntaxErrorProxy`.
4
+
5
+ *Eugene Kenny*
6
+
7
+ * Fix `ActiveSupport::JSON.encode` to prevent duplicate keys.
8
+
9
+ If the same key exist in both String and Symbol form it could
10
+ lead to the same key being emitted twice.
11
+
12
+ *Manish Sharma*
13
+
14
+ * Fix `ActiveSupport::Cache::Store#read_multi` when using a cache namespace
15
+ and local cache strategy.
16
+
17
+ *Mark Oleson*
18
+
19
+ * Fix `Time.now/DateTime.now/Date.today` to return results in a system timezone after `#travel_to`.
20
+
21
+ There is a bug in the current implementation of #travel_to:
22
+ it remembers a timezone of its argument, and all stubbed methods start
23
+ returning results in that remembered timezone. However, the expected
24
+ behaviour is to return results in a system timezone.
25
+
26
+ *Aleksei Chernenkov*
27
+
28
+ * Fix `:unless_exist` option for `MemoryStore#write` (et al) when using a
29
+ cache namespace.
30
+
31
+ *S. Brent Faulkner*
32
+
33
+ * Fix ActiveSupport::Deprecation to handle blaming generated code.
34
+
35
+ *Jean Boussier*, *fatkodima*
36
+
37
+
38
+ ## Rails 7.1.2 (November 10, 2023) ##
39
+
40
+ * Fix `:expires_in` option for `RedisCacheStore#write_multi`.
41
+
42
+ *fatkodima*
43
+
44
+ * Fix deserialization of non-string "purpose" field in Message serializer
45
+
46
+ *Jacopo Beschi*
47
+
48
+ * Prevent global cache options being overwritten when setting dynamic options
49
+ inside a `ActiveSupport::Cache::Store#fetch` block.
50
+
51
+ *Yasha Krasnou*
52
+
53
+ * Fix missing `require` resulting in `NoMethodError` when running
54
+ `bin/rails secrets:show` or `bin/rails secrets:edit`.
55
+
56
+ *Stephen Ierodiaconou*
57
+
58
+ * Ensure `{down,up}case_first` returns non-frozen string.
59
+
60
+ *Jonathan Hefner*
61
+
62
+ * Fix `#to_fs(:human_size)` to correctly work with negative numbers.
63
+
64
+ *Earlopain*
65
+
66
+ * Fix `BroadcastLogger#dup` so that it duplicates the logger's `broadcasts`.
67
+
68
+ *Andrew Novoselac*
69
+
70
+ * Fix issue where `bootstrap.rb` overwrites the `level` of a `BroadcastLogger`'s `broadcasts`.
71
+
72
+ *Andrew Novoselac*
73
+
74
+ * Fix `ActiveSupport::Cache` to handle outdated Marshal payload from Rails 6.1 format.
75
+
76
+ Active Support's Cache is supposed to treat a Marshal payload that can no longer be
77
+ deserialized as a cache miss. It fail to do so for compressed payload in the Rails 6.1
78
+ legacy format.
79
+
80
+ *Jean Boussier*
81
+
82
+ * Fix `OrderedOptions#dig` for array indexes.
83
+
84
+ *fatkodima*
85
+
86
+ * Fix time travel helpers to work when nested using with separate classes.
87
+
88
+ *fatkodima*
89
+
90
+ * Fix `delete_matched` for file cache store to work with keys longer than the
91
+ max filename size.
92
+
93
+ *fatkodima* and *Jonathan Hefner*
94
+
95
+ * Fix compatibility with the `semantic_logger` gem.
96
+
97
+ The `semantic_logger` gem doesn't behave exactly like stdlib logger in that
98
+ `SemanticLogger#level` returns a Symbol while stdlib `Logger#level` returns an Integer.
99
+
100
+ This caused the various `LogSubscriber` classes in Rails to break when assigned a
101
+ `SemanticLogger` instance.
102
+
103
+ *Jean Boussier*, *ojab*
104
+
1
105
  ## Rails 7.1.1 (October 11, 2023) ##
2
106
 
3
107
  * Add support for keyword arguments when delegating calls to custom loggers from `ActiveSupport::BroadcastLogger`.
@@ -218,6 +218,14 @@ module ActiveSupport
218
218
  dispatch { |logger| logger.fatal! }
219
219
  end
220
220
 
221
+ def initialize_copy(other)
222
+ @broadcasts = []
223
+ @progname = other.progname.dup
224
+ @formatter = other.formatter.dup
225
+
226
+ broadcast_to(*other.broadcasts.map(&:dup))
227
+ end
228
+
221
229
  private
222
230
  def dispatch(&block)
223
231
  @broadcasts.each { |logger| block.call(logger) }
@@ -121,7 +121,13 @@ module ActiveSupport
121
121
 
122
122
  private
123
123
  def uncompress(value)
124
- Marshal.load(Zlib::Inflate.inflate(value))
124
+ marshal_load(Zlib::Inflate.inflate(value))
125
+ end
126
+
127
+ def marshal_load(payload)
128
+ Marshal.load(payload)
129
+ rescue ArgumentError => error
130
+ raise Cache::DeserializationError, error.message
125
131
  end
126
132
  end
127
133
  end
@@ -176,7 +176,7 @@ module ActiveSupport
176
176
 
177
177
  # Translate a file path into a key.
178
178
  def file_path_key(path)
179
- fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last
179
+ fname = path[cache_path.to_s.size..-1].split(File::SEPARATOR, 4).last.delete(File::SEPARATOR)
180
180
  URI.decode_www_form_component(fname, Encoding::UTF_8)
181
181
  end
182
182
 
@@ -24,11 +24,11 @@ module ActiveSupport
24
24
  #
25
25
  # Special features:
26
26
  # - Clustering and load balancing. One can specify multiple memcached servers,
27
- # and MemCacheStore will load balance between all available servers. If a
28
- # server goes down, then MemCacheStore will ignore it until it comes back up.
27
+ # and +MemCacheStore+ will load balance between all available servers. If a
28
+ # server goes down, then +MemCacheStore+ will ignore it until it comes back up.
29
29
  #
30
- # MemCacheStore implements the Strategy::LocalCache strategy which implements
31
- # an in-memory cache inside of a block.
30
+ # +MemCacheStore+ implements the Strategy::LocalCache strategy which
31
+ # implements an in-memory cache inside of a block.
32
32
  class MemCacheStore < Store
33
33
  # These options represent behavior overridden by this implementation and should
34
34
  # not be allowed to get down to the Dalli client
@@ -106,14 +106,14 @@ module ActiveSupport
106
106
  end
107
107
  end
108
108
 
109
- # Creates a new MemCacheStore object, with the given memcached server
109
+ # Creates a new +MemCacheStore+ object, with the given memcached server
110
110
  # addresses. Each address is either a host name, or a host-with-port string
111
111
  # in the form of "host_name:port". For example:
112
112
  #
113
113
  # ActiveSupport::Cache::MemCacheStore.new("localhost", "server-downstairs.localnetwork:8229")
114
114
  #
115
115
  # If no addresses are provided, but <tt>ENV['MEMCACHE_SERVERS']</tt> is defined, it will be used instead. Otherwise,
116
- # MemCacheStore will connect to localhost:11211 (the default memcached port).
116
+ # +MemCacheStore+ will connect to localhost:11211 (the default memcached port).
117
117
  # Passing a +Dalli::Client+ instance is deprecated and will be removed. Please pass an address instead.
118
118
  def initialize(*addresses)
119
119
  addresses = addresses.flatten
@@ -270,14 +270,22 @@ module ActiveSupport
270
270
  def read_multi_entries(names, **options)
271
271
  keys_to_names = names.index_by { |name| normalize_key(name, options) }
272
272
 
273
- raw_values = @data.with { |c| c.get_multi(keys_to_names.keys) }
273
+ raw_values = begin
274
+ @data.with { |c| c.get_multi(keys_to_names.keys) }
275
+ rescue Dalli::UnmarshalError
276
+ {}
277
+ end
278
+
274
279
  values = {}
275
280
 
276
281
  raw_values.each do |key, value|
277
282
  entry = deserialize_entry(value, raw: options[:raw])
278
283
 
279
284
  unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(keys_to_names[key], options))
280
- values[keys_to_names[key]] = entry.value
285
+ begin
286
+ values[keys_to_names[key]] = entry.value
287
+ rescue DeserializationError
288
+ end
281
289
  end
282
290
  end
283
291
 
@@ -18,13 +18,13 @@ module ActiveSupport
18
18
  # a cleanup will occur which tries to prune the cache down to three quarters
19
19
  # of the maximum size by removing the least recently used entries.
20
20
  #
21
- # Unlike other Cache store implementations, MemoryStore does not compress
22
- # values by default. MemoryStore does not benefit from compression as much
21
+ # Unlike other Cache store implementations, +MemoryStore+ does not compress
22
+ # values by default. +MemoryStore+ does not benefit from compression as much
23
23
  # as other Store implementations, as it does not send data over a network.
24
24
  # However, when compression is enabled, it still pays the full cost of
25
25
  # compression in terms of cpu use.
26
26
  #
27
- # MemoryStore is thread-safe.
27
+ # +MemoryStore+ is thread-safe.
28
28
  class MemoryStore < Store
29
29
  module DupCoder # :nodoc:
30
30
  extend self
@@ -209,7 +209,7 @@ module ActiveSupport
209
209
  def write_entry(key, entry, **options)
210
210
  payload = serialize_entry(entry, **options)
211
211
  synchronize do
212
- return false if options[:unless_exist] && exist?(key)
212
+ return false if options[:unless_exist] && exist?(key, namespace: nil)
213
213
 
214
214
  old_payload = @data[key]
215
215
  if old_payload
@@ -19,22 +19,23 @@ module ActiveSupport
19
19
  module Cache
20
20
  # = Redis \Cache \Store
21
21
  #
22
- # Deployment note: Take care to use a *dedicated Redis cache* rather
23
- # than pointing this at your existing Redis server. It won't cope well
24
- # with mixed usage patterns and it won't expire cache entries by default.
22
+ # Deployment note: Take care to use a <b>dedicated Redis cache</b> rather
23
+ # than pointing this at a persistent Redis server (for example, one used as
24
+ # an Active Job queue). Redis won't cope well with mixed usage patterns and it
25
+ # won't expire cache entries by default.
25
26
  #
26
27
  # Redis cache server setup guide: https://redis.io/topics/lru-cache
27
28
  #
28
- # * Supports vanilla Redis, hiredis, and Redis::Distributed.
29
- # * Supports Memcached-like sharding across Redises with Redis::Distributed.
29
+ # * Supports vanilla Redis, hiredis, and +Redis::Distributed+.
30
+ # * Supports Memcached-like sharding across Redises with +Redis::Distributed+.
30
31
  # * Fault tolerant. If the Redis server is unavailable, no exceptions are
31
32
  # raised. Cache fetches are all misses and writes are dropped.
32
33
  # * Local cache. Hot in-memory primary cache within block/middleware scope.
33
- # * +read_multi+ and +write_multi+ support for Redis mget/mset. Use Redis::Distributed
34
- # 4.0.1+ for distributed mget support.
34
+ # * +read_multi+ and +write_multi+ support for Redis mget/mset. Use
35
+ # +Redis::Distributed+ 4.0.1+ for distributed mget support.
35
36
  # * +delete_matched+ support for Redis KEYS globs.
36
37
  class RedisCacheStore < Store
37
- # Keys are truncated with the ActiveSupport digest if they exceed 1kB
38
+ # Keys are truncated with the Active Support digest if they exceed 1kB
38
39
  MAX_KEY_BYTESIZE = 1024
39
40
 
40
41
  DEFAULT_REDIS_OPTIONS = {
@@ -110,8 +111,11 @@ module ActiveSupport
110
111
 
111
112
  # Creates a new Redis cache store.
112
113
  #
113
- # Handles four options: :redis block, :redis instance, single :url
114
- # string, and multiple :url strings.
114
+ # There are four ways to provide the Redis client used by the cache: the
115
+ # +:redis+ param can be a Redis instance or a block that returns a Redis
116
+ # instance, or the +:url+ param can be a string or an array of strings
117
+ # which will be used to create a Redis instance or a +Redis::Distributed+
118
+ # instance.
115
119
  #
116
120
  # Option Class Result
117
121
  # :redis Proc -> options[:redis].call
@@ -134,7 +138,7 @@ module ActiveSupport
134
138
  #
135
139
  # Race condition TTL is not set by default. This can be used to avoid
136
140
  # "thundering herd" cache writes when hot cache entries are expired.
137
- # See <tt>ActiveSupport::Cache::Store#fetch</tt> for more.
141
+ # See ActiveSupport::Cache::Store#fetch for more.
138
142
  #
139
143
  # Setting <tt>skip_nil: true</tt> will not cache nil results:
140
144
  #
@@ -242,7 +246,7 @@ module ActiveSupport
242
246
  # Decrement a cached integer value using the Redis decrby atomic operator.
243
247
  # Returns the updated value.
244
248
  #
245
- # If the key is unset or has expired, it will be set to -amount:
249
+ # If the key is unset or has expired, it will be set to +-amount+:
246
250
  #
247
251
  # cache.decrement("foo") # => -1
248
252
  #
@@ -332,7 +336,10 @@ module ActiveSupport
332
336
  if value
333
337
  entry = deserialize_entry(value, raw: raw)
334
338
  unless entry.nil? || entry.expired? || entry.mismatched?(normalize_version(name, options))
335
- results[name] = entry.value
339
+ begin
340
+ results[name] = entry.value
341
+ rescue DeserializationError
342
+ end
336
343
  end
337
344
  end
338
345
  end
@@ -383,7 +390,7 @@ module ActiveSupport
383
390
  end
384
391
 
385
392
  # Nonstandard store provider API to write multiple values at once.
386
- def write_multi_entries(entries, expires_in: nil, race_condition_ttl: nil, **options)
393
+ def write_multi_entries(entries, **options)
387
394
  return if entries.empty?
388
395
 
389
396
  failsafe :write_multi_entries do
@@ -131,17 +131,20 @@ module ActiveSupport
131
131
  end
132
132
  end
133
133
 
134
- def read_multi_entries(keys, **options)
134
+ def read_multi_entries(names, **options)
135
135
  return super unless local_cache
136
136
 
137
- local_entries = local_cache.read_multi_entries(keys)
137
+ keys_to_names = names.index_by { |name| normalize_key(name, options) }
138
+
139
+ local_entries = local_cache.read_multi_entries(keys_to_names.keys)
140
+ local_entries.transform_keys! { |key| keys_to_names[key] }
138
141
  local_entries.transform_values! do |payload|
139
- deserialize_entry(payload)&.value
142
+ deserialize_entry(payload, **options)&.value
140
143
  end
141
- missed_keys = keys - local_entries.keys
144
+ missed_names = names - local_entries.keys
142
145
 
143
- if missed_keys.any?
144
- local_entries.merge!(super(missed_keys, **options))
146
+ if missed_names.any?
147
+ local_entries.merge!(super(missed_names, **options))
145
148
  else
146
149
  local_entries
147
150
  end
@@ -160,8 +160,8 @@ module ActiveSupport
160
160
  # Some implementations may not support all methods beyond the basic cache
161
161
  # methods of #fetch, #write, #read, #exist?, and #delete.
162
162
  #
163
- # ActiveSupport::Cache::Store can store any Ruby object that is supported by
164
- # its +coder+'s +dump+ and +load+ methods.
163
+ # +ActiveSupport::Cache::Store+ can store any Ruby object that is supported
164
+ # by its +coder+'s +dump+ and +load+ methods.
165
165
  #
166
166
  # cache = ActiveSupport::Cache::MemoryStore.new
167
167
  #
@@ -370,8 +370,8 @@ module ActiveSupport
370
370
  #
371
371
  # ==== Options
372
372
  #
373
- # Internally, +fetch+ calls #read_entry, and calls #write_entry on a cache
374
- # miss. Thus, +fetch+ supports the same options as #read and #write.
373
+ # Internally, +fetch+ calls +read_entry+, and calls +write_entry+ on a
374
+ # cache miss. Thus, +fetch+ supports the same options as #read and #write.
375
375
  # Additionally, +fetch+ supports the following options:
376
376
  #
377
377
  # * <tt>force: true</tt> - Forces a cache "miss," meaning we treat the
@@ -459,7 +459,17 @@ module ActiveSupport
459
459
  instrument(:read, name, options) do |payload|
460
460
  cached_entry = read_entry(key, **options, event: payload)
461
461
  entry = handle_expired_entry(cached_entry, key, options)
462
- entry = nil if entry && entry.mismatched?(normalize_version(name, options))
462
+ if entry
463
+ if entry.mismatched?(normalize_version(name, options))
464
+ entry = nil
465
+ else
466
+ begin
467
+ entry.value
468
+ rescue DeserializationError
469
+ entry = nil
470
+ end
471
+ end
472
+ end
463
473
  payload[:super_operation] = :fetch if payload
464
474
  payload[:hit] = !!entry if payload
465
475
  end
@@ -511,7 +521,12 @@ module ActiveSupport
511
521
  nil
512
522
  else
513
523
  payload[:hit] = true if payload
514
- entry.value
524
+ begin
525
+ entry.value
526
+ rescue DeserializationError
527
+ payload[:hit] = false
528
+ nil
529
+ end
515
530
  end
516
531
  else
517
532
  payload[:hit] = false if payload
@@ -803,7 +818,7 @@ module ActiveSupport
803
818
  end
804
819
  end
805
820
 
806
- def deserialize_entry(payload)
821
+ def deserialize_entry(payload, **)
807
822
  payload.nil? ? nil : @coder.load(payload)
808
823
  rescue DeserializationError
809
824
  nil
@@ -1038,6 +1053,8 @@ module ActiveSupport
1038
1053
  end
1039
1054
 
1040
1055
  def save_block_result_to_cache(name, options)
1056
+ options = options.dup
1057
+
1041
1058
  result = instrument(:generate, name, options) do
1042
1059
  yield(name, WriteOptions.new(options))
1043
1060
  end
@@ -1047,6 +1064,10 @@ module ActiveSupport
1047
1064
  end
1048
1065
  end
1049
1066
 
1067
+ # Enables the dynamic configuration of Cache entry options while ensuring
1068
+ # that conflicting options are not both set. When a block is given to
1069
+ # ActiveSupport::Cache::Store#fetch, the second argument will be an
1070
+ # instance of +WriteOptions+.
1050
1071
  class WriteOptions
1051
1072
  def initialize(options) # :nodoc:
1052
1073
  @options = options
@@ -1064,6 +1085,9 @@ module ActiveSupport
1064
1085
  @options[:expires_in]
1065
1086
  end
1066
1087
 
1088
+ # Sets the Cache entry's +expires_in+ value. If an +expires_at+ option was
1089
+ # previously set, this will unset it since +expires_in+ and +expires_at+
1090
+ # cannot both be set.
1067
1091
  def expires_in=(expires_in)
1068
1092
  @options.delete(:expires_at)
1069
1093
  @options[:expires_in] = expires_in
@@ -1073,6 +1097,9 @@ module ActiveSupport
1073
1097
  @options[:expires_at]
1074
1098
  end
1075
1099
 
1100
+ # Sets the Cache entry's +expires_at+ value. If an +expires_in+ option was
1101
+ # previously set, this will unset it since +expires_at+ and +expires_in+
1102
+ # cannot both be set.
1076
1103
  def expires_at=(expires_at)
1077
1104
  @options.delete(:expires_in)
1078
1105
  @options[:expires_at] = expires_at
@@ -52,7 +52,7 @@ class Date
52
52
  strftime(formatter)
53
53
  end
54
54
  else
55
- to_default_s
55
+ to_s
56
56
  end
57
57
  end
58
58
  alias_method :to_formatted_s, :to_fs
@@ -3,7 +3,7 @@
3
3
  require "active_support/concern"
4
4
 
5
5
  class Module
6
- # = Bite-sized separation of concerns
6
+ # == Bite-sized separation of concerns
7
7
  #
8
8
  # We often find ourselves with a medium-sized chunk of behavior that we'd
9
9
  # like to extract, but only mix in to a single class.
@@ -18,9 +18,9 @@ class Module
18
18
  # with a comment, as a least-bad alternative. Using modules in separate files
19
19
  # means tedious sifting to get a big-picture view.
20
20
  #
21
- # = Dissatisfying ways to separate small concerns
21
+ # == Dissatisfying ways to separate small concerns
22
22
  #
23
- # == Using comments:
23
+ # === Using comments:
24
24
  #
25
25
  # class Todo < ApplicationRecord
26
26
  # # Other todo implementation
@@ -37,7 +37,7 @@ class Module
37
37
  # end
38
38
  # end
39
39
  #
40
- # == With an inline module:
40
+ # === With an inline module:
41
41
  #
42
42
  # Noisy syntax.
43
43
  #
@@ -61,7 +61,7 @@ class Module
61
61
  # include EventTracking
62
62
  # end
63
63
  #
64
- # == Mix-in noise exiled to its own file:
64
+ # === Mix-in noise exiled to its own file:
65
65
  #
66
66
  # Once our chunk of behavior starts pushing the scroll-to-understand-it
67
67
  # boundary, we give in and move it to a separate file. At this size, the
@@ -75,7 +75,7 @@ class Module
75
75
  # include TodoEventTracking
76
76
  # end
77
77
  #
78
- # = Introducing Module#concerning
78
+ # == Introducing Module#concerning
79
79
  #
80
80
  # By quieting the mix-in noise, we arrive at a natural, low-ceremony way to
81
81
  # separate bite-sized concerns.
@@ -68,7 +68,7 @@ class Object
68
68
  # You can access these methods using the class name instead:
69
69
  #
70
70
  # class Phone < ActiveRecord::Base
71
- # enum phone_number_type: { home: 0, office: 1, mobile: 2 }
71
+ # enum :phone_number_type, { home: 0, office: 1, mobile: 2 }
72
72
  #
73
73
  # with_options presence: true do
74
74
  # validates :phone_number_type, inclusion: { in: Phone.phone_number_types.keys }
@@ -24,7 +24,7 @@ class String
24
24
  #
25
25
  # The second argument, +indent_string+, specifies which indent string to
26
26
  # use. The default is +nil+, which tells the method to make a guess by
27
- # peeking at the first indented line, and fallback to a space if there is
27
+ # peeking at the first indented line, and fall back to a space if there is
28
28
  # none.
29
29
  #
30
30
  # " foo".indent(2) # => " foo"
@@ -57,15 +57,15 @@ module ActiveSupport
57
57
  # You can create a custom behavior or set any from the +DEFAULT_BEHAVIORS+
58
58
  # constant. Available behaviors are:
59
59
  #
60
- # [+raise+] Raise ActiveSupport::DeprecationException.
61
- # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
62
- # [+log+] Log all deprecation warnings to +Rails.logger+.
63
- # [+notify+] Use ActiveSupport::Notifications to notify +deprecation.rails+.
64
- # [+report+] Use ActiveSupport::ErrorReporter to report deprecations.
65
- # [+silence+] Do nothing. On \Rails, set <tt>config.active_support.report_deprecations = false</tt> to disable all behaviors.
60
+ # [+:raise+] Raise ActiveSupport::DeprecationException.
61
+ # [+:stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
62
+ # [+:log+] Log all deprecation warnings to +Rails.logger+.
63
+ # [+:notify+] Use ActiveSupport::Notifications to notify +deprecation.rails+.
64
+ # [+:report+] Use ActiveSupport::ErrorReporter to report deprecations.
65
+ # [+:silence+] Do nothing. On \Rails, set <tt>config.active_support.report_deprecations = false</tt> to disable all behaviors.
66
66
  #
67
67
  # Setting behaviors only affects deprecations that happen after boot time.
68
- # For more information you can read the documentation of the +behavior=+ method.
68
+ # For more information you can read the documentation of the #behavior= method.
69
69
  module Behavior
70
70
  # Whether to print a backtrace along with the warning.
71
71
  attr_accessor :debug
@@ -85,12 +85,12 @@ module ActiveSupport
85
85
  #
86
86
  # Available behaviors:
87
87
  #
88
- # [+raise+] Raise ActiveSupport::DeprecationException.
89
- # [+stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
90
- # [+log+] Log all deprecation warnings to +Rails.logger+.
91
- # [+notify+] Use ActiveSupport::Notifications to notify +deprecation.rails+.
92
- # [+report+] Use ActiveSupport::ErrorReporter to report deprecations.
93
- # [+silence+] Do nothing.
88
+ # [+:raise+] Raise ActiveSupport::DeprecationException.
89
+ # [+:stderr+] Log all deprecation warnings to <tt>$stderr</tt>.
90
+ # [+:log+] Log all deprecation warnings to +Rails.logger+.
91
+ # [+:notify+] Use ActiveSupport::Notifications to notify +deprecation.rails+.
92
+ # [+:report+] Use ActiveSupport::ErrorReporter to report deprecations.
93
+ # [+:silence+] Do nothing.
94
94
  #
95
95
  # Setting behaviors only affects deprecations that happen after boot time.
96
96
  # Deprecation warnings raised by gems are not affected by this setting
@@ -104,15 +104,17 @@ module ActiveSupport
104
104
  # # custom stuff
105
105
  # }
106
106
  #
107
- # If you are using \Rails, you can set <tt>config.active_support.report_deprecations = false</tt> to disable
108
- # all deprecation behaviors. This is similar to the +silence+ option but more performant.
107
+ # If you are using \Rails, you can set
108
+ # <tt>config.active_support.report_deprecations = false</tt> to disable
109
+ # all deprecation behaviors. This is similar to the +:silence+ option but
110
+ # more performant.
109
111
  def behavior=(behavior)
110
112
  @behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
111
113
  end
112
114
 
113
115
  # Sets the behavior for disallowed deprecations (those configured by
114
116
  # ActiveSupport::Deprecation#disallowed_warnings=) to the specified
115
- # value. As with +behavior=+, this can be a single value, array, or an
117
+ # value. As with #behavior=, this can be a single value, array, or an
116
118
  # object that responds to +call+.
117
119
  def disallowed_behavior=(behavior)
118
120
  @disallowed_behavior = Array(behavior).map { |b| DEFAULT_BEHAVIORS[b] || arity_coerce(b) }
@@ -142,7 +142,9 @@ module ActiveSupport
142
142
  return _extract_callstack(callstack) if callstack.first.is_a? String
143
143
 
144
144
  offending_line = callstack.find { |frame|
145
- frame.absolute_path && !ignored_callstack(frame.absolute_path)
145
+ # Code generated with `eval` doesn't have an `absolute_path`, e.g. templates.
146
+ path = frame.absolute_path || frame.path
147
+ path && !ignored_callstack?(path)
146
148
  } || callstack.first
147
149
 
148
150
  [offending_line.path, offending_line.lineno, offending_line.label]
@@ -150,7 +152,7 @@ module ActiveSupport
150
152
 
151
153
  def _extract_callstack(callstack)
152
154
  warn "Please pass `caller_locations` to the deprecation API" if $VERBOSE
153
- offending_line = callstack.find { |line| !ignored_callstack(line) } || callstack.first
155
+ offending_line = callstack.find { |line| !ignored_callstack?(line) } || callstack.first
154
156
 
155
157
  if offending_line
156
158
  if md = offending_line.match(/^(.+?):(\d+)(?::in `(.*?)')?/)
@@ -162,9 +164,10 @@ module ActiveSupport
162
164
  end
163
165
 
164
166
  RAILS_GEM_ROOT = File.expand_path("../../../..", __dir__) + "/"
167
+ LIB_DIR = RbConfig::CONFIG["libdir"]
165
168
 
166
- def ignored_callstack(path)
167
- path.start_with?(RAILS_GEM_ROOT) || path.start_with?(RbConfig::CONFIG["rubylibdir"])
169
+ def ignored_callstack?(path)
170
+ path.start_with?(RAILS_GEM_ROOT, LIB_DIR)
168
171
  end
169
172
  end
170
173
  end
@@ -9,7 +9,7 @@ module ActiveSupport
9
9
  module VERSION
10
10
  MAJOR = 7
11
11
  MINOR = 1
12
- TINY = 1
12
+ TINY = 3
13
13
  PRE = nil
14
14
 
15
15
  STRING = [MAJOR, MINOR, TINY, PRE].compact.join(".")
@@ -164,7 +164,7 @@ module ActiveSupport
164
164
  # upcase_first('w') # => "W"
165
165
  # upcase_first('') # => ""
166
166
  def upcase_first(string)
167
- string.length > 0 ? string[0].upcase.concat(string[1..-1]) : ""
167
+ string.length > 0 ? string[0].upcase.concat(string[1..-1]) : +""
168
168
  end
169
169
 
170
170
  # Converts the first character in the string to lowercase.
@@ -173,7 +173,7 @@ module ActiveSupport
173
173
  # downcase_first('I') # => "i"
174
174
  # downcase_first('') # => ""
175
175
  def downcase_first(string)
176
- string.length > 0 ? string[0].downcase.concat(string[1..-1]) : ""
176
+ string.length > 0 ? string[0].downcase.concat(string[1..-1]) : +""
177
177
  end
178
178
 
179
179
  # Capitalizes all the words and replaces some characters in the string to