aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--actionpack/lib/action_controller/metal/request_forgery_protection.rb11
-rw-r--r--activejob/test/jobs/retry_job.rb4
-rw-r--r--activerecord/lib/active_record/reflection.rb2
-rw-r--r--activestorage/CHANGELOG.md10
-rw-r--r--activestorage/app/models/active_storage/variation.rb22
-rw-r--r--activestorage/test/models/variant_test.rb61
-rw-r--r--activesupport/CHANGELOG.md26
-rw-r--r--activesupport/lib/active_support/core_ext/enumerable.rb26
-rw-r--r--activesupport/lib/active_support/core_ext/range.rb2
-rw-r--r--activesupport/lib/active_support/core_ext/range/compare_range.rb61
-rw-r--r--activesupport/lib/active_support/core_ext/range/include_range.rb28
-rw-r--r--activesupport/test/core_ext/enumerable_test.rb15
-rw-r--r--guides/source/active_support_core_extensions.md34
13 files changed, 253 insertions, 49 deletions
diff --git a/actionpack/lib/action_controller/metal/request_forgery_protection.rb b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
index fc9cf8aaff..953f3c47ed 100644
--- a/actionpack/lib/action_controller/metal/request_forgery_protection.rb
+++ b/actionpack/lib/action_controller/metal/request_forgery_protection.rb
@@ -400,9 +400,14 @@ module ActionController #:nodoc:
end
def xor_byte_strings(s1, s2) # :doc:
- s2_bytes = s2.bytes
- s1.each_byte.with_index { |c1, i| s2_bytes[i] ^= c1 }
- s2_bytes.pack("C*")
+ s2 = s2.dup
+ size = s1.bytesize
+ i = 0
+ while i < size
+ s2.setbyte(i, s1.getbyte(i) ^ s2.getbyte(i))
+ i += 1
+ end
+ s2
end
# The form's authenticity parameter. Override to provide your own.
diff --git a/activejob/test/jobs/retry_job.rb b/activejob/test/jobs/retry_job.rb
index 56c9a78a2e..a12c65015b 100644
--- a/activejob/test/jobs/retry_job.rb
+++ b/activejob/test/jobs/retry_job.rb
@@ -18,9 +18,9 @@ class RetryJob < ActiveJob::Base
retry_on ShortWaitTenAttemptsError, wait: 1.second, attempts: 10
retry_on ExponentialWaitTenAttemptsError, wait: :exponentially_longer, attempts: 10
retry_on CustomWaitTenAttemptsError, wait: ->(executions) { executions * 2 }, attempts: 10
- retry_on(CustomCatchError) { |job, exception| JobBuffer.add("Dealt with a job that failed to retry in a custom way after #{job.arguments.second} attempts. Message: #{exception.message}") }
+ retry_on(CustomCatchError) { |job, error| JobBuffer.add("Dealt with a job that failed to retry in a custom way after #{job.arguments.second} attempts. Message: #{error.message}") }
discard_on DiscardableError
- discard_on(CustomDiscardableError) { |job, exception| JobBuffer.add("Dealt with a job that was discarded in a custom way. Message: #{exception.message}") }
+ discard_on(CustomDiscardableError) { |job, error| JobBuffer.add("Dealt with a job that was discarded in a custom way. Message: #{error.message}") }
def perform(raising, attempts)
if executions < attempts
diff --git a/activerecord/lib/active_record/reflection.rb b/activerecord/lib/active_record/reflection.rb
index 2f43d005f3..22d195c9a4 100644
--- a/activerecord/lib/active_record/reflection.rb
+++ b/activerecord/lib/active_record/reflection.rb
@@ -417,7 +417,7 @@ module ActiveRecord
class AssociationReflection < MacroReflection #:nodoc:
def compute_class(name)
if polymorphic?
- raise ArgumentError, "Polymorphic association does not support to compute class."
+ raise ArgumentError, "Polymorphic associations do not support computing the class."
end
active_record.send(:compute_type, name)
end
diff --git a/activestorage/CHANGELOG.md b/activestorage/CHANGELOG.md
index 7b724b7b81..c8911fe611 100644
--- a/activestorage/CHANGELOG.md
+++ b/activestorage/CHANGELOG.md
@@ -1,3 +1,13 @@
+* Variant arguments of `false` or `nil` will no longer be passed to the
+ processor. For example, the following will not have the monochrome
+ variation applied:
+
+ ```ruby
+ avatar.variant(monochrome: false)
+ ```
+
+ *Jacob Smith*
+
* Generated attachment getter and setter methods are created
within the model's `GeneratedAssociationMethods` module to
allow overriding and composition using `super`.
diff --git a/activestorage/app/models/active_storage/variation.rb b/activestorage/app/models/active_storage/variation.rb
index 42f00beb82..806af6366d 100644
--- a/activestorage/app/models/active_storage/variation.rb
+++ b/activestorage/app/models/active_storage/variation.rb
@@ -66,11 +66,13 @@ class ActiveStorage::Variation
# Applies image transformations using the ImageProcessing gem.
def image_processing_transform(file, format)
operations = transformations.inject([]) do |list, (name, argument)|
- if name.to_s == "combine_options"
- ActiveSupport::Deprecation.warn("The ImageProcessing ActiveStorage variant backend doesn't need :combine_options, as it already generates a single MiniMagick command. In Rails 6.1 :combine_options will not be supported anymore.")
- list.concat argument.to_a
- else
- list << [name, argument]
+ list.tap do |list|
+ if name.to_s == "combine_options"
+ ActiveSupport::Deprecation.warn("The ImageProcessing ActiveStorage variant backend doesn't need :combine_options, as it already generates a single MiniMagick command. In Rails 6.1 :combine_options will not be supported anymore.")
+ list.concat argument.keep_if { |key, value| value.present? }.to_a
+ elsif argument.present?
+ list << [name, argument]
+ end
end
end
@@ -116,14 +118,10 @@ class ActiveStorage::Variation
end
def pass_transform_argument(command, method, argument)
- if eligible_argument?(argument)
- command.public_send(method, argument)
- else
+ if argument == true
command.public_send(method)
+ elsif argument.present?
+ command.public_send(method, argument)
end
end
-
- def eligible_argument?(argument)
- argument.present? && argument != true
- end
end
diff --git a/activestorage/test/models/variant_test.rb b/activestorage/test/models/variant_test.rb
index e74bbc9ab4..6577f1cd9f 100644
--- a/activestorage/test/models/variant_test.rb
+++ b/activestorage/test/models/variant_test.rb
@@ -25,6 +25,67 @@ class ActiveStorage::VariantTest < ActiveSupport::TestCase
assert_match(/Gray/, image.colorspace)
end
+ test "monochrome with default variant_processor" do
+ begin
+ ActiveStorage.variant_processor = nil
+
+ blob = create_file_blob(filename: "racecar.jpg")
+ variant = blob.variant(monochrome: true).processed
+ image = read_image(variant)
+ assert_match(/Gray/, image.colorspace)
+ ensure
+ ActiveStorage.variant_processor = :mini_magick
+ end
+ end
+
+ test "disabled variation of JPEG blob" do
+ blob = create_file_blob(filename: "racecar.jpg")
+ variant = blob.variant(resize: "100x100", monochrome: false).processed
+ assert_match(/racecar\.jpg/, variant.service_url)
+
+ image = read_image(variant)
+ assert_equal 100, image.width
+ assert_equal 67, image.height
+ assert_match(/RGB/, image.colorspace)
+ end
+
+ test "disabled variation of JPEG blob with :combine_options" do
+ blob = create_file_blob(filename: "racecar.jpg")
+ variant = ActiveSupport::Deprecation.silence do
+ blob.variant(combine_options: {
+ resize: "100x100",
+ monochrome: false
+ }).processed
+ end
+ assert_match(/racecar\.jpg/, variant.service_url)
+
+ image = read_image(variant)
+ assert_equal 100, image.width
+ assert_equal 67, image.height
+ assert_match(/RGB/, image.colorspace)
+ end
+
+ test "disabled variation using :combine_options" do
+ begin
+ ActiveStorage.variant_processor = nil
+ blob = create_file_blob(filename: "racecar.jpg")
+ variant = ActiveSupport::Deprecation.silence do
+ blob.variant(combine_options: {
+ crop: "100x100+0+0",
+ monochrome: false
+ }).processed
+ end
+ assert_match(/racecar\.jpg/, variant.service_url)
+
+ image = read_image(variant)
+ assert_equal 100, image.width
+ assert_equal 100, image.height
+ assert_match(/RGB/, image.colorspace)
+ ensure
+ ActiveStorage.variant_processor = :mini_magick
+ end
+ end
+
test "center-weighted crop of JPEG blob using :combine_options" do
begin
ActiveStorage.variant_processor = nil
diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md
index 62c0f612a8..91818c3112 100644
--- a/activesupport/CHANGELOG.md
+++ b/activesupport/CHANGELOG.md
@@ -1,3 +1,29 @@
+* 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 its brethen `index_by`.
+
+ *Kasper Timm Hansen*
+
* Fix bug where `ActiveSupport::Timezone.all` would fail when tzinfo data for
any timezone defined in `ActiveSupport::TimeZone::MAPPING` is missing.
diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb
index edde4f46b9..7713c52cb1 100644
--- a/activesupport/lib/active_support/core_ext/enumerable.rb
+++ b/activesupport/lib/active_support/core_ext/enumerable.rb
@@ -1,6 +1,9 @@
# frozen_string_literal: true
module Enumerable
+ INDEX_WITH_DEFAULT = Object.new
+ private_constant :INDEX_WITH_DEFAULT
+
# Enumerable#sum was added in Ruby 2.4, but it only works with Numeric elements
# when we omit an identity.
@@ -37,10 +40,11 @@ module Enumerable
end
end
- # Convert an enumerable to a hash.
+ # Convert an enumerable to a hash keying it by the block return value.
#
# people.index_by(&:login)
# # => { "nextangle" => <Person ...>, "chade-" => <Person ...>, ...}
+ #
# people.index_by { |person| "#{person.first_name} #{person.last_name}" }
# # => { "Chade- Fowlersburg-e" => <Person ...>, "David Heinemeier Hansson" => <Person ...>, ...}
def index_by
@@ -53,6 +57,26 @@ module Enumerable
end
end
+ # Convert an enumerable to a hash keying it with the enumerable items and with the values returned in the block.
+ #
+ # post = Post.new(title: "hey there", body: "what's up?")
+ #
+ # %i( title body ).index_with { |attr_name| post.public_send(attr_name) }
+ # # => { title: "hey there", body: "what's up?" }
+ def index_with(default = INDEX_WITH_DEFAULT)
+ if block_given?
+ result = {}
+ each { |elem| result[elem] = yield(elem) }
+ result
+ elsif default != INDEX_WITH_DEFAULT
+ result = {}
+ each { |elem| result[elem] = default }
+ result
+ else
+ to_enum(:index_with) { size if respond_to?(:size) }
+ end
+ end
+
# Returns +true+ if the enumerable has more than 1 element. Functionally
# equivalent to <tt>enum.to_a.size > 1</tt>. Can be called with a block too,
# much like any?, so <tt>people.many? { |p| p.age > 26 }</tt> returns +true+
diff --git a/activesupport/lib/active_support/core_ext/range.rb b/activesupport/lib/active_support/core_ext/range.rb
index 4074e91d17..78814fd189 100644
--- a/activesupport/lib/active_support/core_ext/range.rb
+++ b/activesupport/lib/active_support/core_ext/range.rb
@@ -1,7 +1,7 @@
# frozen_string_literal: true
require "active_support/core_ext/range/conversions"
-require "active_support/core_ext/range/include_range"
+require "active_support/core_ext/range/compare_range"
require "active_support/core_ext/range/include_time_with_zone"
require "active_support/core_ext/range/overlaps"
require "active_support/core_ext/range/each"
diff --git a/activesupport/lib/active_support/core_ext/range/compare_range.rb b/activesupport/lib/active_support/core_ext/range/compare_range.rb
new file mode 100644
index 0000000000..704041f6de
--- /dev/null
+++ b/activesupport/lib/active_support/core_ext/range/compare_range.rb
@@ -0,0 +1,61 @@
+# frozen_string_literal: true
+
+module ActiveSupport
+ module CompareWithRange #:nodoc:
+ # Extends the default Range#=== to support range comparisons.
+ # (1..5) === (1..5) # => true
+ # (1..5) === (2..3) # => true
+ # (1..5) === (2..6) # => false
+ #
+ # The native Range#=== behavior is untouched.
+ # ('a'..'f') === ('c') # => true
+ # (5..9) === (11) # => false
+ def ===(value)
+ if value.is_a?(::Range)
+ # 1...10 includes 1..9 but it does not include 1..10.
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
+ super(value.first) && value.last.send(operator, last)
+ else
+ super
+ end
+ end
+
+ # Extends the default Range#include? to support range comparisons.
+ # (1..5).include?(1..5) # => true
+ # (1..5).include?(2..3) # => true
+ # (1..5).include?(2..6) # => false
+ #
+ # The native Range#include? behavior is untouched.
+ # ('a'..'f').include?('c') # => true
+ # (5..9).include?(11) # => false
+ def include?(value)
+ if value.is_a?(::Range)
+ # 1...10 includes 1..9 but it does not include 1..10.
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
+ super(value.first) && value.last.send(operator, last)
+ else
+ super
+ end
+ end
+
+ # Extends the default Range#cover? to support range comparisons.
+ # (1..5).cover?(1..5) # => true
+ # (1..5).cover?(2..3) # => true
+ # (1..5).cover?(2..6) # => false
+ #
+ # The native Range#cover? behavior is untouched.
+ # ('a'..'f').cover?('c') # => true
+ # (5..9).cover?(11) # => false
+ def cover?(value)
+ if value.is_a?(::Range)
+ # 1...10 covers 1..9 but it does not cover 1..10.
+ operator = exclude_end? && !value.exclude_end? ? :< : :<=
+ super(value.first) && value.last.send(operator, last)
+ else
+ super
+ end
+ end
+ end
+end
+
+Range.prepend(ActiveSupport::CompareWithRange)
diff --git a/activesupport/lib/active_support/core_ext/range/include_range.rb b/activesupport/lib/active_support/core_ext/range/include_range.rb
index 7ba1011921..2da2c587a3 100644
--- a/activesupport/lib/active_support/core_ext/range/include_range.rb
+++ b/activesupport/lib/active_support/core_ext/range/include_range.rb
@@ -1,25 +1,9 @@
# frozen_string_literal: true
-module ActiveSupport
- module IncludeWithRange #:nodoc:
- # Extends the default Range#include? to support range comparisons.
- # (1..5).include?(1..5) # => true
- # (1..5).include?(2..3) # => true
- # (1..5).include?(2..6) # => false
- #
- # The native Range#include? behavior is untouched.
- # ('a'..'f').include?('c') # => true
- # (5..9).include?(11) # => false
- def include?(value)
- if value.is_a?(::Range)
- # 1...10 includes 1..9 but it does not include 1..10.
- operator = exclude_end? && !value.exclude_end? ? :< : :<=
- super(value.first) && value.last.send(operator, last)
- else
- super
- end
- end
- end
-end
+require "active_support/deprecation"
-Range.prepend(ActiveSupport::IncludeWithRange)
+ActiveSupport::Deprecation.warn "You have required `active_support/core_ext/range/include_range`. " \
+"This file will be removed in Rails 6.1. You should require `active_support/core_ext/range/compare_range` " \
+ "instead."
+
+require "active_support/core_ext/range/compare_range"
diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb
index 8d71320931..b63464a36a 100644
--- a/activesupport/test/core_ext/enumerable_test.rb
+++ b/activesupport/test/core_ext/enumerable_test.rb
@@ -179,6 +179,21 @@ class EnumerableTests < ActiveSupport::TestCase
payments.index_by.each(&:price))
end
+ def test_index_with
+ payments = GenericEnumerable.new([ Payment.new(5), Payment.new(15), Payment.new(10) ])
+
+ assert_equal({ Payment.new(5) => 5, Payment.new(15) => 15, Payment.new(10) => 10 }, payments.index_with(&:price))
+
+ assert_equal({ title: nil, body: nil }, %i( title body ).index_with(nil))
+ assert_equal({ title: [], body: [] }, %i( title body ).index_with([]))
+ assert_equal({ title: {}, body: {} }, %i( title body ).index_with({}))
+
+ assert_equal Enumerator, payments.index_with.class
+ assert_nil payments.index_with.size
+ assert_equal 42, (1..42).index_with.size
+ assert_equal({ Payment.new(5) => 5, Payment.new(15) => 15, Payment.new(10) => 10 }, payments.index_with.each(&:price))
+ end
+
def test_many
assert_equal false, GenericEnumerable.new([]).many?
assert_equal false, GenericEnumerable.new([ 1 ]).many?
diff --git a/guides/source/active_support_core_extensions.md b/guides/source/active_support_core_extensions.md
index ae2e1faf14..057651e0cf 100644
--- a/guides/source/active_support_core_extensions.md
+++ b/guides/source/active_support_core_extensions.md
@@ -2039,6 +2039,21 @@ WARNING. Keys should normally be unique. If the block returns the same value for
NOTE: Defined in `active_support/core_ext/enumerable.rb`.
+### `index_with`
+
+The method `index_with` generates a hash with the elements of an enumerable as keys. The value
+is either a passed default or returned in a block.
+
+```ruby
+%i( title body created_at ).index_with { |attr_name| public_send(attr_name) }
+# => { title: "hey", body: "what's up?", … }
+
+WEEKDAYS.index_with([ Interval.all_day ])
+# => { monday: [ 0, 1440 ], … }
+```
+
+NOTE: Defined in `active_support/core_ext/enumerable.rb`.
+
### `many?`
The method `many?` is shorthand for `collection.size > 1`:
@@ -2874,9 +2889,9 @@ As the example depicts, the `:db` format generates a `BETWEEN` SQL clause. That
NOTE: Defined in `active_support/core_ext/range/conversions.rb`.
-### `include?`
+### `===`, `include?`, and `cover?`
-The methods `Range#include?` and `Range#===` say whether some value falls between the ends of a given instance:
+The methods `Range#===`, `Range#include?`, and `Range#cover?` say whether some value falls between the ends of a given instance:
```ruby
(2..3).include?(Math::E) # => true
@@ -2885,18 +2900,23 @@ The methods `Range#include?` and `Range#===` say whether some value falls betwee
Active Support extends these methods so that the argument may be another range in turn. In that case we test whether the ends of the argument range belong to the receiver themselves:
```ruby
+(1..10) === (3..7) # => true
+(1..10) === (0..7) # => false
+(1..10) === (3..11) # => false
+(1...9) === (3..9) # => false
+
(1..10).include?(3..7) # => true
(1..10).include?(0..7) # => false
(1..10).include?(3..11) # => false
(1...9).include?(3..9) # => false
-(1..10) === (3..7) # => true
-(1..10) === (0..7) # => false
-(1..10) === (3..11) # => false
-(1...9) === (3..9) # => false
+(1..10).cover?(3..7) # => true
+(1..10).cover?(0..7) # => false
+(1..10).cover?(3..11) # => false
+(1...9).cover?(3..9) # => false
```
-NOTE: Defined in `active_support/core_ext/range/include_range.rb`.
+NOTE: Defined in `active_support/core_ext/range/compare_range.rb`.
### `overlaps?`