Skip to content

Commit

Permalink
feat: add coercion support for DateTime
Browse files Browse the repository at this point in the history
  • Loading branch information
maxveldink committed Jul 11, 2024
1 parent 00998e7 commit 9cfa84b
Show file tree
Hide file tree
Showing 4 changed files with 65 additions and 0 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 @@ -19,6 +19,7 @@ class CoercerRegistry
IntegerCoercer,
FloatCoercer,
DateCoercer,
DateTimeCoercer,
EnumCoercer,
StructCoercer,
TypedArrayCoercer,
Expand Down
29 changes: 29 additions & 0 deletions lib/typed/coercion/date_time_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 DateTimeCoercer < Coercer
extend T::Generic

Target = type_member { {fixed: DateTime} }

sig { override.params(type: T::Types::Base).returns(T::Boolean) }
def used_for_type?(type)
T::Utils.coerce(type) == T::Utils.coerce(DateTime)
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 DateTime.")) unless used_for_type?(type)

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

Success.new(DateTime.parse(value))
rescue Date::Error, TypeError
Failure.new(CoercionError.new("'#{value}' cannot be coerced into DateTime."))
end
end
end
end
2 changes: 2 additions & 0 deletions test/typed/coercion/date_coercer_test.rb
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
# typed: true

require "test_helper"

class DateCoercerTest < Minitest::Test
def setup
@coercer = Typed::Coercion::DateCoercer.new
Expand Down
33 changes: 33 additions & 0 deletions test/typed/coercion/date_time_coercer_test.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
# typed: true

require "test_helper"

class DateTimeCoercerTest < Minitest::Test
def setup
@coercer = Typed::Coercion::DateTimeCoercer.new
@type = T::Utils.coerce(DateTime)
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: DateTime.now)

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

def test_when_coercable_returns_success
assert_payload(DateTime.new(2024, 7, 11, 19, 31, 30), @coercer.coerce(type: @type, value: "2024-07-11T19:31:30Z"))
assert_payload(DateTime.new(2024, 7, 11, 19, 31, 30), @coercer.coerce(type: @type, value: "2024-07-11T19:31:30"))
assert_payload(DateTime.new(2024, 7, 11), @coercer.coerce(type: @type, value: "2024-07-11"))
end

def test_when_not_coercable_returns_failure
assert_error(Typed::Coercion::CoercionError.new("'a' cannot be coerced into DateTime."), @coercer.coerce(type: @type, value: "a"))
assert_error(Typed::Coercion::CoercionError.new("'1' cannot be coerced into DateTime."), @coercer.coerce(type: @type, value: 1))
end
end

0 comments on commit 9cfa84b

Please sign in to comment.