From 2526938b32da14fc2244e5bdc29da437afec6f4c Mon Sep 17 00:00:00 2001 From: Ayrton De Craene Date: Thu, 11 Feb 2021 11:15:10 +0100 Subject: [PATCH] Calculate the minimum/maximum from an enumerable's extracted elements ``` payments = [Payment.new(5), Payment.new(15), Payment.new(10)] payments.minimum(:price) # => 5 payments.maximum(:price) # => 20 ``` --- actionpack/test/controller/render_test.rb | 37 +++++++++++++++++++ activesupport/CHANGELOG.md | 15 ++++++++ .../lib/active_support/core_ext/enumerable.rb | 16 ++++++++ .../test/core_ext/enumerable_test.rb | 10 +++++ 4 files changed, 78 insertions(+) diff --git a/actionpack/test/controller/render_test.rb b/actionpack/test/controller/render_test.rb index 6494f3cb5f..4bc3c3d374 100644 --- a/actionpack/test/controller/render_test.rb +++ b/actionpack/test/controller/render_test.rb @@ -100,6 +100,15 @@ class TestController < ActionController::Base end end + def conditional_hello_with_array_of_records + record = Struct.new(:updated_at, :cache_key).new(Time.now.utc.beginning_of_day, "foo/123") + old_record = Struct.new(:updated_at, :cache_key).new(Time.now.utc.beginning_of_day.yesterday, "bar/123") + + if stale?([record, old_record]) + render action: "hello_world" + end + end + def dynamic_render render params[:id] # => String, AC::Params end @@ -522,6 +531,34 @@ class LastModifiedRenderTest < ActionController::TestCase assert_equal @last_modified, @response.headers["Last-Modified"] end + def test_responds_with_last_modified_with_array_of_records + get :conditional_hello_with_array_of_records + assert_equal @last_modified, @response.headers["Last-Modified"] + end + + def test_request_not_modified_with_array_of_records + @request.if_modified_since = @last_modified + get :conditional_hello_with_array_of_records + assert_equal 304, @response.status.to_i + assert_predicate @response.body, :blank? + assert_equal @last_modified, @response.headers["Last-Modified"] + end + + def test_request_not_modified_but_etag_differs_with_array_of_records + @request.if_modified_since = @last_modified + @request.if_none_match = '"234"' + get :conditional_hello_with_array_of_records + assert_response :success + end + + def test_request_modified_with_array_of_records + @request.if_modified_since = "Thu, 16 Jul 2008 00:00:00 GMT" + get :conditional_hello_with_array_of_records + assert_equal 200, @response.status.to_i + assert_predicate @response.body, :present? + assert_equal @last_modified, @response.headers["Last-Modified"] + end + def test_responds_with_last_modified_with_collection_of_records get :conditional_hello_with_collection_of_records assert_equal @last_modified, @response.headers["Last-Modified"] diff --git a/activesupport/CHANGELOG.md b/activesupport/CHANGELOG.md index 24ba068a6e..7b8c26d2c3 100644 --- a/activesupport/CHANGELOG.md +++ b/activesupport/CHANGELOG.md @@ -1,3 +1,18 @@ +* Add `Enumerable#maximum` and `Enumerable#minimum` to easily calculate the maximum or minimum from extracted + elements of an enumerable. + + ```ruby + payments = [Payment.new(5), Payment.new(15), Payment.new(10)] + + payments.minimum(:price) # => 5 + payments.maximum(:price) # => 20 + ``` + + This also allows passing enumerables to `fresh_when` and `stale?` in Action Controller. + See PR [#41404](https://github.com/rails/rails/pull/41404) for an example. + + *Ayrton De Craene* + * `ActiveSupport::Cache::MemCacheStore` now accepts an explicit `nil` for its `addresses` argument. ```ruby diff --git a/activesupport/lib/active_support/core_ext/enumerable.rb b/activesupport/lib/active_support/core_ext/enumerable.rb index e2daa3988f..bfd6c64566 100644 --- a/activesupport/lib/active_support/core_ext/enumerable.rb +++ b/activesupport/lib/active_support/core_ext/enumerable.rb @@ -16,6 +16,22 @@ module Enumerable # :startdoc: + # Calculates the minimum from the extracted elements. + # + # payments = [Payment.new(5), Payment.new(15), Payment.new(10)] + # payments.minimum(:price) # => 5 + def minimum(key) + map(&key).min + end + + # Calculates the maximum from the extracted elements. + # + # payments = [Payment.new(5), Payment.new(15), Payment.new(10)] + # payments.maximum(:price) # => 15 + def maximum(key) + map(&key).max + end + # Calculates a sum from the elements. # # payments.sum { |p| p.price * p.tax_rate } diff --git a/activesupport/test/core_ext/enumerable_test.rb b/activesupport/test/core_ext/enumerable_test.rb index 7e2f50b6dd..9caac2d1ff 100644 --- a/activesupport/test/core_ext/enumerable_test.rb +++ b/activesupport/test/core_ext/enumerable_test.rb @@ -29,6 +29,16 @@ class EnumerableTests < ActiveSupport::TestCase assert_equal(e, v, msg) end + def test_minimum + payments = GenericEnumerable.new([ Payment.new(5), Payment.new(15), Payment.new(10) ]) + assert_equal 5, payments.minimum(:price) + end + + def test_maximum + payments = GenericEnumerable.new([ Payment.new(5), Payment.new(15), Payment.new(10) ]) + assert_equal 15, payments.maximum(:price) + end + def test_sums enum = GenericEnumerable.new([5, 15, 10]) assert_equal 30, enum.sum