Skip to content

Commit

Permalink
feat: Add DateCoercer
Browse files Browse the repository at this point in the history
  • Loading branch information
maxveldink committed Mar 21, 2024
1 parent 6005e14 commit ef8c1db
Show file tree
Hide file tree
Showing 5 changed files with 64 additions and 3 deletions.
1 change: 1 addition & 0 deletions lib/typed/coercion/coercer_registry.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ class CoercerRegistry
BooleanCoercer,
IntegerCoercer,
FloatCoercer,
DateCoercer,
EnumCoercer,
StructCoercer,
TypedArrayCoercer
Expand Down
29 changes: 29 additions & 0 deletions lib/typed/coercion/date_coercer.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# typed: strict

require "date"

module Typed
module Coercion
class DateCoercer < Coercer
extend T::Generic

Target = type_member { {fixed: Date} }

sig { override.params(type: T::Types::Base).returns(T::Boolean) }
def used_for_type?(type)
T::Utils.coerce(type) == T::Utils.coerce(Date)
end

sig { override.params(type: T::Types::Base, value: Value).returns(Result[Target, CoercionError]) }
def coerce(type:, value:)
return Failure.new(CoercionError.new("Type must be a Date.")) unless used_for_type?(type)

return Success.new(value) if value.is_a?(Date)

Success.new(Date.parse(value))
rescue Date::Error, TypeError
Failure.new(CoercionError.new("'#{value}' cannot be coerced into Date."))
end
end
end
end
2 changes: 1 addition & 1 deletion test/typed/coercion/coercer_registry_test.rb
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ def test_register_prepends_coercer_so_it_overrides_built_in_ones
end

def test_when_type_doesnt_match_coercer_returns_nil
assert_nil(Typed::Coercion::CoercerRegistry.instance.select_coercer_by(type: T::Utils.coerce(Date)))
assert_nil(Typed::Coercion::CoercerRegistry.instance.select_coercer_by(type: T::Utils.coerce(BigDecimal)))
end
end
31 changes: 31 additions & 0 deletions test/typed/coercion/date_coercer_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
# typed: true

class DateCoercerTest < Minitest::Test
def setup
@coercer = Typed::Coercion::DateCoercer.new
@type = T::Utils.coerce(Date)
end

def test_used_for_type_works
assert(@coercer.used_for_type?(@type))
refute(@coercer.used_for_type?(T::Utils.coerce(Integer)))
end

def test_when_non_date_type_given_returns_failure
result = @coercer.coerce(type: T::Utils.coerce(Integer), value: Date.new(2024, 1, 1))

assert_failure(result)
assert_error(Typed::Coercion::CoercionError.new("Type must be a Date."), result)
end

def test_when_coercable_returns_success
assert_payload(Date.new(2024, 1, 1), @coercer.coerce(type: @type, value: "20240101"))
assert_payload(Date.new(2024, 5, 1), @coercer.coerce(type: @type, value: "1/5/2024"))
assert_payload(Date.new(2024, 5, 1), @coercer.coerce(type: @type, value: Date.new(2024, 5, 1)))
end

def test_when_not_coercable_returns_failure
assert_error(Typed::Coercion::CoercionError.new("'a' cannot be coerced into Date."), @coercer.coerce(type: @type, value: "a"))
assert_error(Typed::Coercion::CoercionError.new("'1' cannot be coerced into Date."), @coercer.coerce(type: @type, value: 1))
end
end
4 changes: 2 additions & 2 deletions test/typed/coercion_test.rb
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# typed: true

require "date"
require "bigdecimal"

class CoercionTest < Minitest::Test
def teardown
Expand All @@ -21,7 +21,7 @@ def test_when_coercer_is_matched_coerce_coerces
end

def test_when_coercer_isnt_matched_coerce_returns_failure
result = Typed::Coercion.coerce(type: T::Utils.coerce(Date), value: "testing")
result = Typed::Coercion.coerce(type: T::Utils.coerce(BigDecimal), value: "testing")

assert_failure(result)
assert_error(Typed::Coercion::CoercionNotSupportedError.new, result)
Expand Down

0 comments on commit ef8c1db

Please sign in to comment.