From 8b86a6f61f630ed7dd2b40f93820978a28bd956d Mon Sep 17 00:00:00 2001 From: Alexei Emam Date: Thu, 22 Aug 2019 16:11:42 +0100 Subject: [PATCH] Improve Duration.build String input support Addresses rails/rails github issue #37012 by ensuring the value in the objects instantiated by .build is always an integer or float --- activesupport/lib/active_support/duration.rb | 11 ++++++- activesupport/test/core_ext/duration_test.rb | 32 ++++++++++++++++++++ 2 files changed, 42 insertions(+), 1 deletion(-) diff --git a/activesupport/lib/active_support/duration.rb b/activesupport/lib/active_support/duration.rb index 2b4f1288f11f0..a2eaa06409c2a 100644 --- a/activesupport/lib/active_support/duration.rb +++ b/activesupport/lib/active_support/duration.rb @@ -182,6 +182,7 @@ def years(value) #:nodoc: # def build(value) parts = {} + remainder = value.to_f PARTS.each do |part| @@ -194,7 +195,15 @@ def build(value) parts[:seconds] = remainder - new(value, parts) + value_to_instantiate = + case value.class + when Integer + value + else + value_as_processed = value.to_f + (value_as_processed % 1 == 0) ? value_as_processed.to_i : value_as_processed + end + new(value_to_instantiate, parts) end private diff --git a/activesupport/test/core_ext/duration_test.rb b/activesupport/test/core_ext/duration_test.rb index 63934e243372c..bbb997950e074 100644 --- a/activesupport/test/core_ext/duration_test.rb +++ b/activesupport/test/core_ext/duration_test.rb @@ -661,6 +661,26 @@ def test_durations_survive_yaml_serialization assert_equal 660, (d1 + 60).to_i end + def test_less_than_comparator_following_build + a_duration_from_string, a_duration_from_integer = durations_for_build_test + string_duration_smaller_than_integer_duration = + begin + a_duration_from_string < a_duration_from_integer + rescue ArgumentError => _e + "error raised" + end + + assert_not string_duration_smaller_than_integer_duration == "error raised" + assert string_duration_smaller_than_integer_duration == false + end + + def test_equality_following_build + a_duration_from_string, a_duration_from_integer = durations_for_build_test + string_duration_equals_integer_duration = a_duration_from_string == a_duration_from_integer + + assert string_duration_equals_integer_duration == true + end + private def eastern_time_zone if Gem.win_platform? @@ -669,4 +689,16 @@ def eastern_time_zone "America/New_York" end end + + def durations_for_build_test + the_duration_seconds = 23 + [ + build(the_duration_seconds.to_s), + build(the_duration_seconds) + ] + end + + def build(it) + ActiveSupport::Duration.build(it) + end end