From 6df87c2bb8aa44363c3a02b0fe719725dbe97cb5 Mon Sep 17 00:00:00 2001 From: Max VelDink Date: Tue, 27 Feb 2024 15:46:43 -0500 Subject: [PATCH] feat: Add Hash and Json conversion methods to `T::Struct` (#20) --- lib/sorbet-schema/struct_ext.rb | 20 ++++++++++++++++++++ lib/typed/hash_serializer.rb | 9 ++++++--- test/struct_ext_test.rb | 26 ++++++++++++++++++++++++++ 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/lib/sorbet-schema/struct_ext.rb b/lib/sorbet-schema/struct_ext.rb index 645b027..cf1693b 100644 --- a/lib/sorbet-schema/struct_ext.rb +++ b/lib/sorbet-schema/struct_ext.rb @@ -13,5 +13,25 @@ def self.create_schema end ) end + + sig { params(hash: Typed::HashSerializer::InputHash).returns(Typed::Serializer::DeserializeResult) } + def self.from_hash(hash) + Typed::HashSerializer.new(schema: create_schema).deserialize(hash) + end + + sig { params(json: String).returns(Typed::Serializer::DeserializeResult) } + def self.from_json(json) + Typed::JSONSerializer.new(schema: create_schema).deserialize(json) + end + + sig { returns(Typed::HashSerializer::OutputHash) } + def to_hash + Typed::HashSerializer.new(schema: self.class.create_schema).serialize(self) + end + + sig { returns(String) } + def to_json + Typed::JSONSerializer.new(schema: self.class.create_schema).serialize(self) + end end end diff --git a/lib/typed/hash_serializer.rb b/lib/typed/hash_serializer.rb index 042f2d1..e0d81d0 100644 --- a/lib/typed/hash_serializer.rb +++ b/lib/typed/hash_serializer.rb @@ -2,8 +2,11 @@ module Typed class HashSerializer < Serializer - Input = type_member { {fixed: T::Hash[T.any(Symbol, String), T.untyped]} } - Output = type_member { {fixed: T::Hash[Symbol, T.untyped]} } + InputHash = T.type_alias { T::Hash[T.any(Symbol, String), T.untyped] } + OutputHash = T.type_alias { Params } + + Input = type_member { {fixed: InputHash} } + Output = type_member { {fixed: OutputHash} } sig { override.params(source: Input).returns(Result[T::Struct, DeserializeError]) } def deserialize(source) @@ -17,7 +20,7 @@ def serialize(struct) private - sig { params(hash: T::Hash[T.any(String, Symbol), T.untyped]).returns(T::Hash[Symbol, T.untyped]) } + sig { params(hash: InputHash).returns(OutputHash) } def symbolize_keys(hash) hash.each_with_object({}) { |(k, v), h| h[k.intern] = v } end diff --git a/test/struct_ext_test.rb b/test/struct_ext_test.rb index 75cf75b..f4a39cb 100644 --- a/test/struct_ext_test.rb +++ b/test/struct_ext_test.rb @@ -1,7 +1,33 @@ # typed: true class StructExtTest < Minitest::Test + def setup + @person = Person.new(name: "Max", age: 29) + end + def test_create_schema_is_available assert_equal(PersonSchema, Person.create_schema) end + + def test_from_hash_works + result = Person.from_hash({name: "Max", age: 29}) + + assert_success(result) + assert_payload(@person, result) + end + + def test_from_json_works + result = Person.from_json('{"name": "Max", "age": 29}') + + assert_success(result) + assert_payload(@person, result) + end + + def test_to_hash_works + assert_equal({name: "Max", age: 29}, @person.to_hash) + end + + def test_to_json_works + assert_equal('{"name":"Max","age":29}', @person.to_json) + end end