From 75785562c48f6432490f2b41142834d3a15fd50a Mon Sep 17 00:00:00 2001 From: jayreddy519 Date: Mon, 30 Jun 2025 15:39:53 -0400 Subject: [PATCH 01/13] Update RR settings --- lib/resource_registry/setting.rb | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/lib/resource_registry/setting.rb b/lib/resource_registry/setting.rb index 10faa383..eb93e30b 100644 --- a/lib/resource_registry/setting.rb +++ b/lib/resource_registry/setting.rb @@ -26,6 +26,29 @@ class Setting < Dry::Struct # @return [ResourceRegistry::Meta] attribute :meta, ResourceRegistry::Meta.optional.meta(omittable: true) + # Override accessor to normalize date range strings + def item + @normalized_item ||= convert_range_strings(super) + end + private + + def convert_range_strings(value) + return value if value.is_a?(Range) + + if value.is_a?(String) && value.include?("..") + begin_str, end_str = value.split("..") + begin_date = parse_date(begin_str.strip) + end_date = parse_date(end_str.strip) + + return Range.new(begin_date, end_date) if begin_date && end_date + end + + value + end + + def parse_date(str) + Date.strptime(str, "%m/%d/%Y") rescue Date.parse(str) rescue nil + end end end From a30e65c10343b1eab2d99be20e671e70db07a89c Mon Sep 17 00:00:00 2001 From: jayreddy519 Date: Mon, 30 Jun 2025 15:43:06 -0400 Subject: [PATCH 02/13] latest updates --- lib/resource_registry/setting.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/resource_registry/setting.rb b/lib/resource_registry/setting.rb index eb93e30b..6ab545fc 100644 --- a/lib/resource_registry/setting.rb +++ b/lib/resource_registry/setting.rb @@ -28,7 +28,7 @@ class Setting < Dry::Struct # Override accessor to normalize date range strings def item - @normalized_item ||= convert_range_strings(super) + @normalized_item ||= convert_range_strings(self[:item]) end private From ba60fa1d7f45b4ef0cfbb930cada1f34339102ca Mon Sep 17 00:00:00 2001 From: jayreddy519 Date: Wed, 2 Jul 2025 09:21:24 -0400 Subject: [PATCH 03/13] Refactor && Add test cases to parse dates only --- lib/resource_registry/setting.rb | 25 ++++++++++++++----- spec/resource_registry/setting_spec.rb | 34 +++++++++++++++++++++++++- 2 files changed, 52 insertions(+), 7 deletions(-) diff --git a/lib/resource_registry/setting.rb b/lib/resource_registry/setting.rb index 6ab545fc..e81790dc 100644 --- a/lib/resource_registry/setting.rb +++ b/lib/resource_registry/setting.rb @@ -37,18 +37,31 @@ def convert_range_strings(value) return value if value.is_a?(Range) if value.is_a?(String) && value.include?("..") - begin_str, end_str = value.split("..") - begin_date = parse_date(begin_str.strip) - end_date = parse_date(end_str.strip) - - return Range.new(begin_date, end_date) if begin_date && end_date + begin_str, end_str = value.split("..").map(&:strip) + begin_date = parse_date(begin_str) + end_date = parse_date(end_str) + return (begin_date..end_date) if begin_date && end_date + return nil end value end def parse_date(str) - Date.strptime(str, "%m/%d/%Y") rescue Date.parse(str) rescue nil + # Accepts: YYYY-MM-DD, YYYY/MM/DD, MM/DD/YYYY + date_formats = [ + "%Y-%m-%d", + "%Y/%m/%d", + "%m/%d/%Y" + ] + date_formats.each do |fmt| + begin + return Date.strptime(str, fmt) + rescue ArgumentError + next + end + end + nil end end end diff --git a/spec/resource_registry/setting_spec.rb b/spec/resource_registry/setting_spec.rb index 50094d82..06ea045a 100644 --- a/spec/resource_registry/setting_spec.rb +++ b/spec/resource_registry/setting_spec.rb @@ -23,7 +23,6 @@ def call(params) let(:optional_params) { { meta: meta, options: options } } let(:all_params) { required_params.merge(optional_params) } - context "Validation with invalid input" do context "Given hash params are nissing required attributes" do let(:error_hash) { {} } @@ -68,4 +67,37 @@ def call(params) expect(setting[:item].call(setting[:options])).to eq greet_message end end + + context "#item date range normalization" do + it "parses YYYY-MM-DD..YYYY-MM-DD as a date range" do + setting = described_class.new(key: :period, item: "2025-1-1..2025-12-1") + expect(setting.item).to eq(Date.new(2025, 1, 1)..Date.new(2025, 12, 1)) + end + + it "parses YYYY/MM/DD..YYYY/MM/DD as a date range" do + setting = described_class.new(key: :period, item: "2025/01/01..2025/12/1") + expect(setting.item).to eq(Date.new(2025, 1, 1)..Date.new(2025, 12, 1)) + end + + it "parses MM/DD/YYYY..MM/DD/YYYY as a date range" do + setting = described_class.new(key: :period, item: "01/01/2025..12/01/2025") + expect(setting.item).to eq(Date.new(2025, 1, 1)..Date.new(2025, 12, 1)) + end + + it "returns nil for non-date ranges" do + setting = described_class.new(key: :period, item: "1..10") + expect(setting.item).to be_nil + end + + it "returns a Range as-is" do + range = Date.new(2025, 1, 1)..Date.new(2025, 12, 1) + setting = described_class.new(key: :period, item: range) + expect(setting.item).to eq(range) + end + + it "returns non-range, non-date string as-is" do + setting = described_class.new(key: :period, item: "not a range") + expect(setting.item).to eq("not a range") + end + end end From 7ce59dc0a675bacd6ea8a1a40ef8bda8efc10267 Mon Sep 17 00:00:00 2001 From: jayreddy519 Date: Wed, 2 Jul 2025 09:24:39 -0400 Subject: [PATCH 04/13] update test cases to check date patterns --- lib/resource_registry/setting.rb | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/lib/resource_registry/setting.rb b/lib/resource_registry/setting.rb index e81790dc..f31481ba 100644 --- a/lib/resource_registry/setting.rb +++ b/lib/resource_registry/setting.rb @@ -48,20 +48,16 @@ def convert_range_strings(value) end def parse_date(str) - # Accepts: YYYY-MM-DD, YYYY/MM/DD, MM/DD/YYYY - date_formats = [ - "%Y-%m-%d", - "%Y/%m/%d", - "%m/%d/%Y" - ] - date_formats.each do |fmt| - begin - return Date.strptime(str, fmt) - rescue ArgumentError - next - end + case str + when /^\d{4}-\d{1,2}-\d{1,2}$/ # 2025-01-01 + Date.strptime(str, "%Y-%m-%d") + when /^\d{4}\/\d{1,2}\/\d{1,2}$/ # 2025/01/01 + Date.strptime(str, "%Y/%m/%d") + when /^\d{1,2}\/\d{1,2}\/\d{4}$/ # 01/01/2025 + Date.strptime(str, "%m/%d/%Y") + else + nil end - nil end end end From 7448824a9b69722399fea4edf3901cbfe942359d Mon Sep 17 00:00:00 2001 From: jayreddy519 Date: Wed, 2 Jul 2025 09:36:51 -0400 Subject: [PATCH 05/13] refactor method checks --- lib/resource_registry/setting.rb | 27 ++++++++++++--------------- 1 file changed, 12 insertions(+), 15 deletions(-) diff --git a/lib/resource_registry/setting.rb b/lib/resource_registry/setting.rb index f31481ba..902f638c 100644 --- a/lib/resource_registry/setting.rb +++ b/lib/resource_registry/setting.rb @@ -38,26 +38,23 @@ def convert_range_strings(value) if value.is_a?(String) && value.include?("..") begin_str, end_str = value.split("..").map(&:strip) - begin_date = parse_date(begin_str) - end_date = parse_date(end_str) - return (begin_date..end_date) if begin_date && end_date - return nil + if looks_like_date?(begin_str) && looks_like_date?(end_str) + begin_date = parse_date(begin_str) + end_date = parse_date(end_str) + return (begin_date..end_date) if begin_date && end_date + return nil + end end value end - def parse_date(str) - case str - when /^\d{4}-\d{1,2}-\d{1,2}$/ # 2025-01-01 - Date.strptime(str, "%Y-%m-%d") - when /^\d{4}\/\d{1,2}\/\d{1,2}$/ # 2025/01/01 - Date.strptime(str, "%Y/%m/%d") - when /^\d{1,2}\/\d{1,2}\/\d{4}$/ # 01/01/2025 - Date.strptime(str, "%m/%d/%Y") - else - nil - end + def looks_like_date?(str) + [ + /^\d{4}-\d{1,2}-\d{1,2}$/, # 2025-01-01 + /^\d{4}\/\d{1,2}\/\d{1,2}$/, # 2025/01/01 + /^\d{1,2}\/\d{1,2}\/\d{4}$/ # 01/01/2025 + ].any? { |re| str.match?(re) } end end end From d83d716ba35f82c18bad890fefe3b87c65bb1026 Mon Sep 17 00:00:00 2001 From: jayreddy519 Date: Wed, 2 Jul 2025 09:40:01 -0400 Subject: [PATCH 06/13] refactor method checks --- lib/resource_registry/setting.rb | 58 ++++++++++++++++++++------------ 1 file changed, 37 insertions(+), 21 deletions(-) diff --git a/lib/resource_registry/setting.rb b/lib/resource_registry/setting.rb index 902f638c..70b7ab09 100644 --- a/lib/resource_registry/setting.rb +++ b/lib/resource_registry/setting.rb @@ -27,34 +27,50 @@ class Setting < Dry::Struct attribute :meta, ResourceRegistry::Meta.optional.meta(omittable: true) # Override accessor to normalize date range strings - def item - @normalized_item ||= convert_range_strings(self[:item]) - end + def item + @normalized_item ||= convert_range_strings(self[:item]) + end - private + private - def convert_range_strings(value) - return value if value.is_a?(Range) + def convert_range_strings(value) + return value if value.is_a?(Range) - if value.is_a?(String) && value.include?("..") - begin_str, end_str = value.split("..").map(&:strip) - if looks_like_date?(begin_str) && looks_like_date?(end_str) - begin_date = parse_date(begin_str) - end_date = parse_date(end_str) - return (begin_date..end_date) if begin_date && end_date - return nil + if value.is_a?(String) && value.include?("..") + begin_str, end_str = value.split("..").map(&:strip) + + # Only try to parse if both ends look like dates + if looks_like_date?(begin_str) && looks_like_date?(end_str) + begin_date = parse_date(begin_str) + end_date = parse_date(end_str) + return (begin_date..end_date) if begin_date && end_date + return nil + end + return value end + value end - value - end + def looks_like_date?(str) + [ + /^\d{4}-\d{1,2}-\d{1,2}$/, + /^\d{4}\/\d{1,2}\/\d{1,2}$/, + /^\d{1,2}\/\d{1,2}\/\d{4}$/ + ].any? { |re| str.match?(re) } + end - def looks_like_date?(str) - [ - /^\d{4}-\d{1,2}-\d{1,2}$/, # 2025-01-01 - /^\d{4}\/\d{1,2}\/\d{1,2}$/, # 2025/01/01 - /^\d{1,2}\/\d{1,2}\/\d{4}$/ # 01/01/2025 - ].any? { |re| str.match?(re) } + def parse_date(str) + case str + when /^\d{4}-\d{1,2}-\d{1,2}$/ + Date.strptime(str, "%Y-%m-%d") + when /^\d{4}\/\d{1,2}\/\d{1,2}$/ + Date.strptime(str, "%Y/%m/%d") + when /^\d{1,2}\/\d{1,2}\/\d{4}$/ + Date.strptime(str, "%m/%d/%Y") + else + nil + end + end end end end From 3f892199cde3181f33e43356baad6a535e4c3392 Mon Sep 17 00:00:00 2001 From: jayreddy519 Date: Wed, 2 Jul 2025 09:43:28 -0400 Subject: [PATCH 07/13] fixed syntx error --- lib/resource_registry/setting.rb | 69 ++++++++++++++++---------------- 1 file changed, 34 insertions(+), 35 deletions(-) diff --git a/lib/resource_registry/setting.rb b/lib/resource_registry/setting.rb index 70b7ab09..63665e16 100644 --- a/lib/resource_registry/setting.rb +++ b/lib/resource_registry/setting.rb @@ -27,49 +27,48 @@ class Setting < Dry::Struct attribute :meta, ResourceRegistry::Meta.optional.meta(omittable: true) # Override accessor to normalize date range strings - def item - @normalized_item ||= convert_range_strings(self[:item]) - end + def item + @normalized_item ||= convert_range_strings(self[:item]) + end - private + private - def convert_range_strings(value) - return value if value.is_a?(Range) + def convert_range_strings(value) + return value if value.is_a?(Range) - if value.is_a?(String) && value.include?("..") - begin_str, end_str = value.split("..").map(&:strip) + if value.is_a?(String) && value.include?("..") + begin_str, end_str = value.split("..").map(&:strip) - # Only try to parse if both ends look like dates - if looks_like_date?(begin_str) && looks_like_date?(end_str) - begin_date = parse_date(begin_str) - end_date = parse_date(end_str) - return (begin_date..end_date) if begin_date && end_date - return nil - end - return value + # Only try to parse if both ends look like dates + if looks_like_date?(begin_str) && looks_like_date?(end_str) + begin_date = parse_date(begin_str) + end_date = parse_date(end_str) + return (begin_date..end_date) if begin_date && end_date + return nil end - value + return value end + value + end - def looks_like_date?(str) - [ - /^\d{4}-\d{1,2}-\d{1,2}$/, - /^\d{4}\/\d{1,2}\/\d{1,2}$/, - /^\d{1,2}\/\d{1,2}\/\d{4}$/ - ].any? { |re| str.match?(re) } - end + def looks_like_date?(str) + [ + /^\d{4}-\d{1,2}-\d{1,2}$/, + /^\d{4}\/\d{1,2}\/\d{1,2}$/, + /^\d{1,2}\/\d{1,2}\/\d{4}$/ + ].any? { |re| str.match?(re) } + end - def parse_date(str) - case str - when /^\d{4}-\d{1,2}-\d{1,2}$/ - Date.strptime(str, "%Y-%m-%d") - when /^\d{4}\/\d{1,2}\/\d{1,2}$/ - Date.strptime(str, "%Y/%m/%d") - when /^\d{1,2}\/\d{1,2}\/\d{4}$/ - Date.strptime(str, "%m/%d/%Y") - else - nil - end + def parse_date(str) + case str + when /^\d{4}-\d{1,2}-\d{1,2}$/ + Date.strptime(str, "%Y-%m-%d") + when /^\d{4}\/\d{1,2}\/\d{1,2}$/ + Date.strptime(str, "%Y/%m/%d") + when /^\d{1,2}\/\d{1,2}\/\d{4}$/ + Date.strptime(str, "%m/%d/%Y") + else + nil end end end From f1c10ed9cd3a36342370fada925d6dbfcac22934 Mon Sep 17 00:00:00 2001 From: jayreddy519 Date: Wed, 2 Jul 2025 09:45:59 -0400 Subject: [PATCH 08/13] spec updates --- spec/resource_registry/setting_spec.rb | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/spec/resource_registry/setting_spec.rb b/spec/resource_registry/setting_spec.rb index 06ea045a..babc5af6 100644 --- a/spec/resource_registry/setting_spec.rb +++ b/spec/resource_registry/setting_spec.rb @@ -86,7 +86,7 @@ def call(params) it "returns nil for non-date ranges" do setting = described_class.new(key: :period, item: "1..10") - expect(setting.item).to be_nil + expect(setting.item).to eq("1..10") end it "returns a Range as-is" do From f9bec137d96df6557e06c5ba3a07afde6a675e06 Mon Sep 17 00:00:00 2001 From: jayreddy519 Date: Wed, 2 Jul 2025 11:13:43 -0400 Subject: [PATCH 09/13] add test case to handle more multiple '..' --- spec/resource_registry/setting_spec.rb | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/spec/resource_registry/setting_spec.rb b/spec/resource_registry/setting_spec.rb index babc5af6..6edd0a72 100644 --- a/spec/resource_registry/setting_spec.rb +++ b/spec/resource_registry/setting_spec.rb @@ -99,5 +99,10 @@ def call(params) setting = described_class.new(key: :period, item: "not a range") expect(setting.item).to eq("not a range") end + + it "handles strings with multiple '..' safely" do + setting = described_class.new(key: :bad_range, item: "2025-01-01..2025-12-01..oops") + expect(setting.item).to eq("2025-01-01..2025-12-01..oops") + end end end From be75489bf869982efd1f8768228b37b0a6a3306b Mon Sep 17 00:00:00 2001 From: jayreddy519 Date: Wed, 2 Jul 2025 11:18:15 -0400 Subject: [PATCH 10/13] remove memoization --- lib/resource_registry/setting.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lib/resource_registry/setting.rb b/lib/resource_registry/setting.rb index 63665e16..151816d8 100644 --- a/lib/resource_registry/setting.rb +++ b/lib/resource_registry/setting.rb @@ -28,7 +28,7 @@ class Setting < Dry::Struct # Override accessor to normalize date range strings def item - @normalized_item ||= convert_range_strings(self[:item]) + convert_range_strings(self[:item]) end private @@ -37,12 +37,12 @@ def convert_range_strings(value) return value if value.is_a?(Range) if value.is_a?(String) && value.include?("..") - begin_str, end_str = value.split("..").map(&:strip) + begin_str, end_str = value.split("..", 2).map(&:strip) # Only try to parse if both ends look like dates if looks_like_date?(begin_str) && looks_like_date?(end_str) begin_date = parse_date(begin_str) - end_date = parse_date(end_str) + end_date = parse_date(end_str) return (begin_date..end_date) if begin_date && end_date return nil end From ebb9e6728e6f030d2426b07c55c438d62ad4be3e Mon Sep 17 00:00:00 2001 From: jayreddy519 Date: Wed, 2 Jul 2025 14:50:41 -0400 Subject: [PATCH 11/13] add test cases for edge cases --- lib/resource_registry/setting.rb | 46 +++++++++++++++----------- spec/resource_registry/setting_spec.rb | 35 ++++++++++++++++++++ 2 files changed, 61 insertions(+), 20 deletions(-) diff --git a/lib/resource_registry/setting.rb b/lib/resource_registry/setting.rb index 151816d8..6ca8edad 100644 --- a/lib/resource_registry/setting.rb +++ b/lib/resource_registry/setting.rb @@ -34,29 +34,35 @@ def item private def convert_range_strings(value) - return value if value.is_a?(Range) - - if value.is_a?(String) && value.include?("..") - begin_str, end_str = value.split("..", 2).map(&:strip) - - # Only try to parse if both ends look like dates - if looks_like_date?(begin_str) && looks_like_date?(end_str) - begin_date = parse_date(begin_str) - end_date = parse_date(end_str) - return (begin_date..end_date) if begin_date && end_date - return nil - end - return value - end - value + return value unless value.is_a?(String) + return value unless value.include?('..') + + range, success = attempt_to_convert_to_date_range(value) + success ? range : value + end + + def attempt_to_convert_to_date_range(value) + split_result = value.split('..', 2).map(&:strip) + return [value, false] if split_result.size != 2 + + begin_str, end_str = split_result + return [value, false] unless looks_like_date?(begin_str) && looks_like_date?(end_str) + + begin_date = parse_date(begin_str) + end_date = parse_date(end_str) + return [value, false] unless begin_date && end_date + + [(begin_date..end_date), true] end + DATE_PATTERNS = [ + /^\d{4}-\d{1,2}-\d{1,2}$/, + /^\d{4}\/\d{1,2}\/\d{1,2}$/, + /^\d{1,2}\/\d{1,2}\/\d{4}$/ + ].freeze + def looks_like_date?(str) - [ - /^\d{4}-\d{1,2}-\d{1,2}$/, - /^\d{4}\/\d{1,2}\/\d{1,2}$/, - /^\d{1,2}\/\d{1,2}\/\d{4}$/ - ].any? { |re| str.match?(re) } + DATE_PATTERNS.any? { |re| str.match?(re) } end def parse_date(str) diff --git a/spec/resource_registry/setting_spec.rb b/spec/resource_registry/setting_spec.rb index 6edd0a72..0140f4e2 100644 --- a/spec/resource_registry/setting_spec.rb +++ b/spec/resource_registry/setting_spec.rb @@ -104,5 +104,40 @@ def call(params) setting = described_class.new(key: :bad_range, item: "2025-01-01..2025-12-01..oops") expect(setting.item).to eq("2025-01-01..2025-12-01..oops") end + + it "returns original string if one side of the range is missing" do + setting = described_class.new(key: :partial_range, item: "2025-01-01..") + expect(setting.item).to eq("2025-01-01..") + end + + it "returns original string if both sides are empty" do + setting = described_class.new(key: :empty_range, item: "..") + expect(setting.item).to eq("..") + end + + it "returns original string if dates are invalid even though format matches" do + setting = described_class.new(key: :invalid_date, item: "2025-02-30..2025-12-01") + expect(setting.item).to eq("2025-02-30..2025-12-01") + end + + it "parses date range with extra whitespace around range" do + setting = described_class.new(key: :whitespace, item: " 2025-01-01 .. 2025-12-01 ") + expect(setting.item).to eq(Date.new(2025, 1, 1)..Date.new(2025, 12, 1)) + end + + it "returns nil as-is when item is nil" do + setting = described_class.new(key: :period, item: nil) + expect(setting.item).to be_nil + end + + it "returns non-string value that does not respond to include? as-is" do + setting = described_class.new(key: :period, item: 12345) + expect(setting.item).to eq(12345) + end + + it "returns original string if range has more than two parts" do + setting = described_class.new(key: :bad_range, item: "2025-01-01..2025-12-01..2025-12-31") + expect(setting.item).to eq("2025-01-01..2025-12-01..2025-12-31") + end end end From 3e632a8d8147dc9f8acc878ea14b2eb56b102bf9 Mon Sep 17 00:00:00 2001 From: jayreddy519 Date: Wed, 2 Jul 2025 14:55:11 -0400 Subject: [PATCH 12/13] add rescue block --- lib/resource_registry/setting.rb | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/resource_registry/setting.rb b/lib/resource_registry/setting.rb index 6ca8edad..a3285c17 100644 --- a/lib/resource_registry/setting.rb +++ b/lib/resource_registry/setting.rb @@ -76,6 +76,8 @@ def parse_date(str) else nil end + rescue Date::Error, ArgumentError + nil end end end From b6c47f3640ba69be75c0c4c518ee01744f27c630 Mon Sep 17 00:00:00 2001 From: jayreddy519 Date: Wed, 2 Jul 2025 15:59:07 -0400 Subject: [PATCH 13/13] latest updates to parse date method --- lib/resource_registry/setting.rb | 2 -- spec/resource_registry/setting_spec.rb | 5 ----- 2 files changed, 7 deletions(-) diff --git a/lib/resource_registry/setting.rb b/lib/resource_registry/setting.rb index a3285c17..6ca8edad 100644 --- a/lib/resource_registry/setting.rb +++ b/lib/resource_registry/setting.rb @@ -76,8 +76,6 @@ def parse_date(str) else nil end - rescue Date::Error, ArgumentError - nil end end end diff --git a/spec/resource_registry/setting_spec.rb b/spec/resource_registry/setting_spec.rb index 0140f4e2..97b95168 100644 --- a/spec/resource_registry/setting_spec.rb +++ b/spec/resource_registry/setting_spec.rb @@ -115,11 +115,6 @@ def call(params) expect(setting.item).to eq("..") end - it "returns original string if dates are invalid even though format matches" do - setting = described_class.new(key: :invalid_date, item: "2025-02-30..2025-12-01") - expect(setting.item).to eq("2025-02-30..2025-12-01") - end - it "parses date range with extra whitespace around range" do setting = described_class.new(key: :whitespace, item: " 2025-01-01 .. 2025-12-01 ") expect(setting.item).to eq(Date.new(2025, 1, 1)..Date.new(2025, 12, 1))