activesupport 6.0.0.beta3 → 6.0.0.rc1

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 (36) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +149 -1
  3. data/README.rdoc +2 -1
  4. data/lib/active_support.rb +1 -0
  5. data/lib/active_support/actionable_error.rb +48 -0
  6. data/lib/active_support/backtrace_cleaner.rb +5 -1
  7. data/lib/active_support/cache.rb +5 -5
  8. data/lib/active_support/cache/redis_cache_store.rb +8 -5
  9. data/lib/active_support/concern.rb +24 -1
  10. data/lib/active_support/configurable.rb +3 -3
  11. data/lib/active_support/core_ext/array/access.rb +18 -6
  12. data/lib/active_support/core_ext/class/attribute.rb +10 -15
  13. data/lib/active_support/core_ext/enumerable.rb +24 -4
  14. data/lib/active_support/core_ext/hash/except.rb +1 -1
  15. data/lib/active_support/core_ext/module/attribute_accessors.rb +5 -5
  16. data/lib/active_support/core_ext/module/attribute_accessors_per_thread.rb +5 -5
  17. data/lib/active_support/core_ext/range/compare_range.rb +21 -12
  18. data/lib/active_support/core_ext/string/inflections.rb +7 -2
  19. data/lib/active_support/core_ext/string/output_safety.rb +49 -4
  20. data/lib/active_support/core_ext/time/calculations.rb +1 -2
  21. data/lib/active_support/dependencies.rb +5 -0
  22. data/lib/active_support/dependencies/zeitwerk_integration.rb +22 -18
  23. data/lib/active_support/deprecation/method_wrappers.rb +7 -18
  24. data/lib/active_support/descendants_tracker.rb +52 -6
  25. data/lib/active_support/duration.rb +0 -1
  26. data/lib/active_support/evented_file_update_checker.rb +3 -1
  27. data/lib/active_support/gem_version.rb +1 -1
  28. data/lib/active_support/hash_with_indifferent_access.rb +6 -3
  29. data/lib/active_support/i18n_railtie.rb +2 -1
  30. data/lib/active_support/inflector/transliterate.rb +16 -13
  31. data/lib/active_support/notifications/fanout.rb +4 -4
  32. data/lib/active_support/notifications/instrumenter.rb +8 -8
  33. data/lib/active_support/security_utils.rb +1 -1
  34. data/lib/active_support/subscriber.rb +55 -6
  35. data/lib/active_support/testing/parallelization.rb +13 -2
  36. metadata +10 -9
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 99b9851bbeeac26a9d5991ab86865b1475b44a197941819902c8b8aa298319ff
4
- data.tar.gz: d2abae2569905e69d2dbf9c778f6f6407d4f3ffb7fe8f3f0de071c9bafcc5007
3
+ metadata.gz: 5824eb9bee53907d29aeb5fb77f421600014d77d12a1bde43f157d1d5800295d
4
+ data.tar.gz: 7eba1dd34b2969d726c40864d0a5d3b0e001863bfef65a839f8cc98d3c920067
5
5
  SHA512:
6
- metadata.gz: 66ced4ae57566a0063f24c7b1c4a778bbb56897414a88ca7e1f8736cc7ba1b33deb549a75a556ba0ac1cbec17cf326e57f3f5bde9a04c53c3ef0059e2bb81d74
7
- data.tar.gz: 29783c4224cc61b14fdc1f227d30a090edaed71a5f5535221ce091e82a398e80f9beb103d1353581bb19fdc05e855c7e00a5bba898364043c017f74dbbc06d40
6
+ metadata.gz: a1129a67ccf6eee1a76959d74161260dcaae3dc2e14af46996075ea6c5293dfe993f8575d98ac196a873d38e1d9256c70929d34b3d6655f7a92b4d2930dad188
7
+ data.tar.gz: 69081cf5038e340c1cf8f8e5bbbd1f1481561954762041d724d38a3c887a566047d27ea418f8ca407b81f0508da5c9e22783f4f1eac4afca417d00735fea7341
@@ -1,3 +1,150 @@
1
+ ## Rails 6.0.0.rc1 (April 24, 2019) ##
2
+
3
+ * Introduce `ActiveSupport::ActionableError`.
4
+
5
+ Actionable errors let's you dispatch actions from Rails' error pages. This
6
+ can help you save time if you have a clear action for the resolution of
7
+ common development errors.
8
+
9
+ The de-facto example are pending migrations. Every time pending migrations
10
+ are found, a middleware raises an error. With actionable errors, you can
11
+ run the migrations right from the error page. Other examples include Rails
12
+ plugins that need to run a rake task to setup themselves. They can now
13
+ raise actionable errors to run the setup straight from the error pages.
14
+
15
+ Here is how to define an actionable error:
16
+
17
+ ```ruby
18
+ class PendingMigrationError < MigrationError #:nodoc:
19
+ include ActiveSupport::ActionableError
20
+
21
+ action "Run pending migrations" do
22
+ ActiveRecord::Tasks::DatabaseTasks.migrate
23
+ end
24
+ end
25
+ ```
26
+
27
+ To make an error actionable, include the `ActiveSupport::ActionableError`
28
+ module and invoke the `action` class macro to define the action. An action
29
+ needs a name and a procedure to execute. The name is shown as the name of a
30
+ button on the error pages. Once clicked, it will invoke the given
31
+ procedure.
32
+
33
+ *Vipul A M*, *Yao Jie*, *Genadi Samokovarov*
34
+
35
+ * Preserve `html_safe?` status on `ActiveSupport::SafeBuffer#*`.
36
+
37
+ Before:
38
+
39
+ ("<br />".html_safe * 2).html_safe? #=> nil
40
+
41
+ After:
42
+
43
+ ("<br />".html_safe * 2).html_safe? #=> true
44
+
45
+ *Ryo Nakamura*
46
+
47
+ * Calling test methods with `with_info_handler` method to allow minitest-hooks
48
+ plugin to work.
49
+
50
+ *Mauri Mustonen*
51
+
52
+ * The Zeitwerk compatibility interface for `ActiveSupport::Dependencies` no
53
+ longer implements `autoloaded_constants` or `autoloaded?` (undocumented,
54
+ anyway). Experience shows introspection does not have many use cases, and
55
+ troubleshooting is done by logging. With this design trade-off we are able
56
+ to use even less memory in all environments.
57
+
58
+ *Xavier Noria*
59
+
60
+ * Depends on Zeitwerk 2, which stores less metadata if reloading is disabled
61
+ and hence uses less memory when `config.cache_classes` is `true`, a standard
62
+ setup in production.
63
+
64
+ *Xavier Noria*
65
+
66
+ * In `:zeitwerk` mode, eager load directories in engines and applications only
67
+ if present in their respective `config.eager_load_paths`.
68
+
69
+ A common use case for this is adding `lib` to `config.autoload_paths`, but
70
+ not to `config.eager_load_paths`. In that configuration, for example, files
71
+ in the `lib` directory should not be eager loaded.
72
+
73
+ *Xavier Noria*
74
+
75
+ * Fix bug in Range comparisons when comparing to an excluded-end Range
76
+
77
+ Before:
78
+
79
+ (1..10).cover?(1...11) # => false
80
+
81
+ After:
82
+
83
+ (1..10).cover?(1...11) # => true
84
+
85
+ With the same change for `Range#include?` and `Range#===`.
86
+
87
+ *Owen Stephens*
88
+
89
+ * Use weak references in descendants tracker to allow anonymous subclasses to
90
+ be garbage collected.
91
+
92
+ *Edgars Beigarts*
93
+
94
+ * Update `ActiveSupport::Notifications::Instrumenter#instrument` to make
95
+ passing a block optional. This will let users use
96
+ `ActiveSupport::Notifications` messaging features outside of
97
+ instrumentation.
98
+
99
+ *Ali Ibrahim*
100
+
101
+ * Fix `Time#advance` to work with dates before 1001-03-07
102
+
103
+ Before:
104
+
105
+ Time.utc(1001, 3, 6).advance(years: -1) # => 1000-03-05 00:00:00 UTC
106
+
107
+ After
108
+
109
+ Time.utc(1001, 3, 6).advance(years: -1) # => 1000-03-06 00:00:00 UTC
110
+
111
+ Note that this doesn't affect `DateTime#advance` as that doesn't use a proleptic calendar.
112
+
113
+ *Andrew White*
114
+
115
+ * In Zeitwerk mode, engines are now managed by the `main` autoloader. Engines may reference application constants, if the application is reloaded and we do not reload engines, they won't use the reloaded application code.
116
+
117
+ *Xavier Noria*
118
+
119
+ * Add support for supplying `locale` to `transliterate` and `parameterize`.
120
+
121
+ I18n.backend.store_translations(:de, i18n: { transliterate: { rule: { "ü" => "ue" } } })
122
+
123
+ ActiveSupport::Inflector.transliterate("ü", locale: :de) # => "ue"
124
+ "Fünf autos".parameterize(locale: :de) # => "fuenf-autos"
125
+ ActiveSupport::Inflector.parameterize("Fünf autos", locale: :de) # => "fuenf-autos"
126
+
127
+ *Kaan Ozkan*, *Sharang Dashputre*
128
+
129
+ * Allow `Array#excluding` and `Enumerable#excluding` to deal with a passed array gracefully.
130
+
131
+ [ 1, 2, 3, 4, 5 ].excluding([4, 5]) # => [ 1, 2, 3 ]
132
+
133
+ *DHH*
134
+
135
+ * Renamed `Array#without` and `Enumerable#without` to `Array#excluding` and `Enumerable#excluding`, to create parity with
136
+ `Array#including` and `Enumerable#including`. Retained the old names as aliases.
137
+
138
+ *DHH*
139
+
140
+ * Added `Array#including` and `Enumerable#including` to conveniently enlarge a collection with more members using a method rather than an operator:
141
+
142
+ [ 1, 2, 3 ].including(4, 5) # => [ 1, 2, 3, 4, 5 ]
143
+ post.authors.including(Current.person) # => All the authors plus the current person!
144
+
145
+ *DHH*
146
+
147
+
1
148
  ## Rails 6.0.0.beta3 (March 11, 2019) ##
2
149
 
3
150
  * No changes.
@@ -31,6 +178,7 @@
31
178
 
32
179
  *Guillermo Iguaran*
33
180
 
181
+
34
182
  ## Rails 6.0.0.beta1 (January 18, 2019) ##
35
183
 
36
184
  * Remove deprecated `Module#reachable?` method.
@@ -238,7 +386,7 @@
238
386
 
239
387
  *Kasper Timm Hansen*
240
388
 
241
- * Fix bug where `ActiveSupport::Timezone.all` would fail when tzinfo data for
389
+ * Fix bug where `ActiveSupport::TimeZone.all` would fail when tzinfo data for
242
390
  any timezone defined in `ActiveSupport::TimeZone::MAPPING` is missing.
243
391
 
244
392
  *Dominik Sander*
@@ -5,6 +5,7 @@ extensions that were found useful for the Rails framework. These additions
5
5
  reside in this package so they can be loaded as needed in Ruby projects
6
6
  outside of Rails.
7
7
 
8
+ You can read more about the extensions in the {Active Support Core Extensions}[https://edgeguides.rubyonrails.org/active_support_core_extensions.html] guide.
8
9
 
9
10
  == Download and installation
10
11
 
@@ -28,7 +29,7 @@ Active Support is released under the MIT license:
28
29
 
29
30
  API documentation is at:
30
31
 
31
- * http://api.rubyonrails.org
32
+ * https://api.rubyonrails.org
32
33
 
33
34
  Bug reports for the Ruby on Rails project can be filed here:
34
35
 
@@ -34,6 +34,7 @@ module ActiveSupport
34
34
  extend ActiveSupport::Autoload
35
35
 
36
36
  autoload :Concern
37
+ autoload :ActionableError
37
38
  autoload :CurrentAttributes
38
39
  autoload :Dependencies
39
40
  autoload :DescendantsTracker
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module ActiveSupport
4
+ # Actionable errors let's you define actions to resolve an error.
5
+ #
6
+ # To make an error actionable, include the <tt>ActiveSupport::ActionableError</tt>
7
+ # module and invoke the +action+ class macro to define the action. An action
8
+ # needs a name and a block to execute.
9
+ module ActionableError
10
+ extend Concern
11
+
12
+ class NonActionable < StandardError; end
13
+
14
+ included do
15
+ class_attribute :_actions, default: {}
16
+ end
17
+
18
+ def self.actions(error) # :nodoc:
19
+ case error
20
+ when ActionableError, -> it { Class === it && it < ActionableError }
21
+ error._actions
22
+ else
23
+ {}
24
+ end
25
+ end
26
+
27
+ def self.dispatch(error, name) # :nodoc:
28
+ actions(error).fetch(name).call
29
+ rescue KeyError
30
+ raise NonActionable, "Cannot find action \"#{name}\""
31
+ end
32
+
33
+ module ClassMethods
34
+ # Defines an action that can resolve the error.
35
+ #
36
+ # class PendingMigrationError < MigrationError
37
+ # include ActiveSupport::ActionableError
38
+ #
39
+ # action "Run pending migrations" do
40
+ # ActiveRecord::Tasks::DatabaseTasks.migrate
41
+ # end
42
+ # end
43
+ def action(name, &block)
44
+ _actions[name] = block
45
+ end
46
+ end
47
+ end
48
+ end
@@ -122,7 +122,11 @@ module ActiveSupport
122
122
  end
123
123
 
124
124
  def noise(backtrace)
125
- backtrace - silence(backtrace)
125
+ backtrace.select do |line|
126
+ @silencers.any? do |s|
127
+ s.call(line)
128
+ end
129
+ end
126
130
  end
127
131
  end
128
132
  end
@@ -492,7 +492,7 @@ module ActiveSupport
492
492
  #
493
493
  # Options are passed to the underlying cache implementation.
494
494
  #
495
- # All implementations may not support this method.
495
+ # Some implementations may not support this method.
496
496
  def delete_matched(matcher, options = nil)
497
497
  raise NotImplementedError.new("#{self.class.name} does not support delete_matched")
498
498
  end
@@ -501,7 +501,7 @@ module ActiveSupport
501
501
  #
502
502
  # Options are passed to the underlying cache implementation.
503
503
  #
504
- # All implementations may not support this method.
504
+ # Some implementations may not support this method.
505
505
  def increment(name, amount = 1, options = nil)
506
506
  raise NotImplementedError.new("#{self.class.name} does not support increment")
507
507
  end
@@ -510,7 +510,7 @@ module ActiveSupport
510
510
  #
511
511
  # Options are passed to the underlying cache implementation.
512
512
  #
513
- # All implementations may not support this method.
513
+ # Some implementations may not support this method.
514
514
  def decrement(name, amount = 1, options = nil)
515
515
  raise NotImplementedError.new("#{self.class.name} does not support decrement")
516
516
  end
@@ -519,7 +519,7 @@ module ActiveSupport
519
519
  #
520
520
  # Options are passed to the underlying cache implementation.
521
521
  #
522
- # All implementations may not support this method.
522
+ # Some implementations may not support this method.
523
523
  def cleanup(options = nil)
524
524
  raise NotImplementedError.new("#{self.class.name} does not support cleanup")
525
525
  end
@@ -529,7 +529,7 @@ module ActiveSupport
529
529
  #
530
530
  # The options hash is passed to the underlying cache implementation.
531
531
  #
532
- # All implementations may not support this method.
532
+ # Some implementations may not support this method.
533
533
  def clear(options = nil)
534
534
  raise NotImplementedError.new("#{self.class.name} does not support clear")
535
535
  end
@@ -152,12 +152,14 @@ module ActiveSupport
152
152
 
153
153
  # Creates a new Redis cache store.
154
154
  #
155
- # Handles three options: block provided to instantiate, single URL
156
- # provided, and multiple URLs provided.
155
+ # Handles four options: :redis block, :redis instance, single :url
156
+ # string, and multiple :url strings.
157
157
  #
158
- # :redis Proc -> options[:redis].call
159
- # :url String -> Redis.new(url: …)
160
- # :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …])
158
+ # Option Class Result
159
+ # :redis Proc -> options[:redis].call
160
+ # :redis Object -> options[:redis]
161
+ # :url String -> Redis.new(url: …)
162
+ # :url Array -> Redis::Distributed.new([{ url: … }, { url: … }, …])
161
163
  #
162
164
  # No namespace is set by default. Provide one if the Redis cache
163
165
  # server is shared with other apps: <tt>namespace: 'myapp-cache'</tt>.
@@ -361,6 +363,7 @@ module ActiveSupport
361
363
  def read_multi_mget(*names)
362
364
  options = names.extract_options!
363
365
  options = merged_options(options)
366
+ return {} if names == []
364
367
 
365
368
  keys = names.map { |name| normalize_key(name, options) }
366
369
 
@@ -110,7 +110,7 @@ module ActiveSupport
110
110
  base.instance_variable_set(:@_dependencies, [])
111
111
  end
112
112
 
113
- def append_features(base)
113
+ def append_features(base) #:nodoc:
114
114
  if base.instance_variable_defined?(:@_dependencies)
115
115
  base.instance_variable_get(:@_dependencies) << self
116
116
  false
@@ -123,6 +123,9 @@ module ActiveSupport
123
123
  end
124
124
  end
125
125
 
126
+ # Evaluate given block in context of base class,
127
+ # so that you can write class macros here.
128
+ # When you define more than one +included+ block, it raises an exception.
126
129
  def included(base = nil, &block)
127
130
  if base.nil?
128
131
  if instance_variable_defined?(:@_included_block)
@@ -137,6 +140,26 @@ module ActiveSupport
137
140
  end
138
141
  end
139
142
 
143
+ # Define class methods from given block.
144
+ # You can define private class methods as well.
145
+ #
146
+ # module Example
147
+ # extend ActiveSupport::Concern
148
+ #
149
+ # class_methods do
150
+ # def foo; puts 'foo'; end
151
+ #
152
+ # private
153
+ # def bar; puts 'bar'; end
154
+ # end
155
+ # end
156
+ #
157
+ # class Buzz
158
+ # include Example
159
+ # end
160
+ #
161
+ # Buzz.foo # => "foo"
162
+ # Buzz.bar # => private method 'bar' called for Buzz:Class(NoMethodError)
140
163
  def class_methods(&class_methods_module_definition)
141
164
  mod = const_defined?(:ClassMethods, false) ?
142
165
  const_get(:ClassMethods) :
@@ -67,8 +67,8 @@ module ActiveSupport
67
67
  # end
68
68
  # # => NameError: invalid config attribute name
69
69
  #
70
- # To opt out of the instance writer method, pass <tt>instance_writer: false</tt>.
71
- # To opt out of the instance reader method, pass <tt>instance_reader: false</tt>.
70
+ # To omit the instance writer method, pass <tt>instance_writer: false</tt>.
71
+ # To omit the instance reader method, pass <tt>instance_reader: false</tt>.
72
72
  #
73
73
  # class User
74
74
  # include ActiveSupport::Configurable
@@ -81,7 +81,7 @@ module ActiveSupport
81
81
  # User.new.allowed_access = true # => NoMethodError
82
82
  # User.new.allowed_access # => NoMethodError
83
83
  #
84
- # Or pass <tt>instance_accessor: false</tt>, to opt out both instance methods.
84
+ # Or pass <tt>instance_accessor: false</tt>, to omit both instance methods.
85
85
  #
86
86
  # class User
87
87
  # include ActiveSupport::Configurable
@@ -29,16 +29,28 @@ class Array
29
29
  end
30
30
  end
31
31
 
32
- # Returns a copy of the Array without the specified elements.
32
+ # Returns a new array that includes the passed elements.
33
33
  #
34
- # people = ["David", "Rafael", "Aaron", "Todd"]
35
- # people.without "Aaron", "Todd"
36
- # # => ["David", "Rafael"]
34
+ # [ 1, 2, 3 ].including(4, 5) # => [ 1, 2, 3, 4, 5 ]
35
+ # [ [ 0, 1 ] ].including([ [ 1, 0 ] ]) # => [ [ 0, 1 ], [ 1, 0 ] ]
36
+ def including(*elements)
37
+ self + elements.flatten(1)
38
+ end
39
+
40
+ # Returns a copy of the Array excluding the specified elements.
41
+ #
42
+ # ["David", "Rafael", "Aaron", "Todd"].excluding("Aaron", "Todd") # => ["David", "Rafael"]
43
+ # [ [ 0, 1 ], [ 1, 0 ] ].excluding([ [ 1, 0 ] ]) # => [ [ 0, 1 ] ]
37
44
  #
38
- # Note: This is an optimization of <tt>Enumerable#without</tt> that uses <tt>Array#-</tt>
45
+ # Note: This is an optimization of <tt>Enumerable#excluding</tt> that uses <tt>Array#-</tt>
39
46
  # instead of <tt>Array#reject</tt> for performance reasons.
47
+ def excluding(*elements)
48
+ self - elements.flatten(1)
49
+ end
50
+
51
+ # Alias for #excluding.
40
52
  def without(*elements)
41
- self - elements
53
+ excluding(*elements)
42
54
  end
43
55
 
44
56
  # Equal to <tt>self[1]</tt>.
@@ -84,16 +84,17 @@ class Class
84
84
  # To set a default value for the attribute, pass <tt>default:</tt>, like so:
85
85
  #
86
86
  # class_attribute :settings, default: {}
87
- def class_attribute(*attrs)
88
- options = attrs.extract_options!
89
- instance_reader = options.fetch(:instance_accessor, true) && options.fetch(:instance_reader, true)
90
- instance_writer = options.fetch(:instance_accessor, true) && options.fetch(:instance_writer, true)
91
- instance_predicate = options.fetch(:instance_predicate, true)
92
- default_value = options.fetch(:default, nil)
93
-
87
+ def class_attribute(
88
+ *attrs,
89
+ instance_accessor: true,
90
+ instance_reader: instance_accessor,
91
+ instance_writer: instance_accessor,
92
+ instance_predicate: true,
93
+ default: nil
94
+ )
94
95
  attrs.each do |name|
95
96
  singleton_class.silence_redefinition_of_method(name)
96
- define_singleton_method(name) { nil }
97
+ define_singleton_method(name) { default }
97
98
 
98
99
  singleton_class.silence_redefinition_of_method("#{name}?")
99
100
  define_singleton_method("#{name}?") { !!public_send(name) } if instance_predicate
@@ -102,9 +103,7 @@ class Class
102
103
 
103
104
  singleton_class.silence_redefinition_of_method("#{name}=")
104
105
  define_singleton_method("#{name}=") do |val|
105
- singleton_class.class_eval do
106
- redefine_method(name) { val }
107
- end
106
+ redefine_singleton_method(name) { val }
108
107
 
109
108
  if singleton_class?
110
109
  class_eval do
@@ -137,10 +136,6 @@ class Class
137
136
  instance_variable_set ivar, val
138
137
  end
139
138
  end
140
-
141
- unless default_value.nil?
142
- self.send("#{name}=", default_value)
143
- end
144
139
  end
145
140
  end
146
141
  end