Skip to content

Commit

Permalink
Add Enum::StringConverter(T)
Browse files Browse the repository at this point in the history
  • Loading branch information
caspiano committed Nov 6, 2020
1 parent 7ee04e5 commit 5b3f7d3
Show file tree
Hide file tree
Showing 6 changed files with 95 additions and 0 deletions.
20 changes: 20 additions & 0 deletions spec/std/json/serializable_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -191,6 +191,18 @@ class JSONAttrWithSmallIntegers
property bar : Int8
end

class JSONAttrWithEnumString
include JSON::Serializable

enum Hint
One
Two
end

@[YAML::Field(converter: Enum::StringConverter(JSONAttrWithEnumString::Hint))]
property hint : Hint
end

class JSONAttrWithTimeEpoch
include JSON::Serializable

Expand Down Expand Up @@ -683,6 +695,14 @@ describe "JSON mapping" do
end
end

it "uses Enum::StringConverter(T)" do
string = %({"hint":"One"})
message = JSONAttrWithEnumString.from_json(string)
message.hint.should be_a(JSONAttrWithEnumString::Hint)
message.hint.should eq(JSONAttrWithEnumString::Hint::One)
message.to_json.should eq(string)
end

it "uses Time::EpochConverter" do
string = %({"value":1459859781})
json = JSONAttrWithTimeEpoch.from_json(string)
Expand Down
19 changes: 19 additions & 0 deletions spec/std/yaml/serializable_spec.cr
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,18 @@ class YAMLAttrWithSmallIntegers
property bar : Int8
end

class YAMLAttrWithEnumString
include YAML::Serializable

enum Hint
One
Two
end

@[YAML::Field(converter: Enum::StringConverter(YAMLAttrWithEnumString::Hint))]
property hint : Hint
end

class YAMLAttrWithTimeEpoch
include YAML::Serializable

Expand Down Expand Up @@ -757,6 +769,13 @@ describe "YAML::Serializable" do
end
end

it "uses Enum::StringConverter(T)" do
message = YAMLAttrWithEnumString.from_yaml(%({"hint":"One"}))
message.hint.should be_a(YAMLAttrWithEnumString::Hint)
message.hint.should eq(YAMLAttrWithEnumString::Hint::One)
message.to_yaml.should eq("---\nhint: One\n")
end

it "uses Time::EpochConverter" do
string = %({"value":1459859781})
yaml = YAMLAttrWithTimeEpoch.from_yaml(string)
Expand Down
10 changes: 10 additions & 0 deletions src/json/from_json.cr
Original file line number Diff line number Diff line change
Expand Up @@ -370,3 +370,13 @@ module String::RawConverter
value.read_raw
end
end

module Enum::StringConverter(T)
def self.from_json(pull : JSON::PullParser) : T
if pull.kind.string?
T.parse(pull.read_string)
else
raise "Expecting string in JSON for #{T.class}, not #{pull.kind}"
end
end
end
31 changes: 31 additions & 0 deletions src/json/to_json.cr
Original file line number Diff line number Diff line change
Expand Up @@ -309,3 +309,34 @@ module String::RawConverter
json.raw(value)
end
end

# Converter to be used with `JSON::Serializable` to write and read
# an `Enum` exclusively as a `String`.
#
# This is useful if you wish to serialise to `String`, instead of
# the default of a number representation of the `Enum`.
#
# ```
# require "json"
#
# class EnumStringMessage
# include JSON::Serializable
#
# enum Hint
# Up
# Down
# end
#
# @[JSON::Field(converter: Enum::StringConverter(EnumStringMessage::Hint))]
# getter hint : Hint
# end
#
# message = EnumStringMessage.from_json(%({"hint":"Up"}))
# message.hint # => EnumStringMessage::Hint::Up
# message.to_json # => %({"hint":"Up"})
# ```
module Enum::StringConverter(T)
def self.to_json(value : T, json : JSON::Builder)
json.string(value.to_s)
end
end
9 changes: 9 additions & 0 deletions src/yaml/from_yaml.cr
Original file line number Diff line number Diff line change
Expand Up @@ -322,6 +322,15 @@ module YAML::ArrayConverter(Converter)
end
end

module Enum::StringConverter(T)
def self.from_yaml(ctx : YAML::ParseContext, node : YAML::Nodes::Node) : T
unless node.is_a?(YAML::Nodes::Scalar)
node.raise "Expected scalar, not #{node.class}"
end
T.parse(node.value)
end
end

struct Slice
def self.new(ctx : YAML::ParseContext, node : YAML::Nodes::Node)
{% if T != UInt8 %}
Expand Down
6 changes: 6 additions & 0 deletions src/yaml/to_yaml.cr
Original file line number Diff line number Diff line change
Expand Up @@ -178,6 +178,12 @@ module YAML::ArrayConverter(Converter)
end
end

module Enum::StringConverter(T)
def self.to_yaml(value : T, yaml : YAML::Nodes::Builder)
yaml.scalar value.to_s
end
end

struct Slice
def to_yaml(yaml : YAML::Nodes::Builder)
{% if T != UInt8 %}
Expand Down

0 comments on commit 5b3f7d3

Please sign in to comment.