I'd like to have the ability to have String based Enums. My current use case is I'm using JSON.mapping to turn JSON output into typed classes, but I'd like the ability to do something like this:
enum EventType : String
Pending = "PENDING"
InProgress = "IN_PROGRESS"
Complete = "COMPLETE"
end
struct Event
JSON.mapping({
name: String,
event_type: EventType
})
end
I'm not sure how a event_type value that doesn't match should work, maybe some sort of catch all EventType::Other like how there's All and None for the integer ones?
Thoughts?
I would suggest using a formatter for converting the string to symbols.
I'd like to be able use types to mitigate errors so I can catch typos easily.
For example:
Event.create(name: "Foo", type: Pending)
The other option is to write my own struct that I can subclass and do that, but Enum seems like a better fit for this.
Enum#new(JSON::PullParser) accepts both an Integer (the enum value) or a String (the enum key), so you may just override the to_json(io) method to output the key instead of the value and you'll have it working as you expect; you'll just have upcased keys:
require "json"
enum EventType
PENDING = 1
IN_PROGRESS = 2
COMPLETE = 3
def to_json(io)
io << '"'
to_s(io)
io << '"'
end
end
struct MyEvent
JSON.mapping({
name: String,
event_type: EventType,
})
end
p event = MyEvent.from_json("{ \"name\": \"blabla\", \"event_type\": \"PENDING\" }")
# => MyEvent(@name="blabla", @event_type=PENDING)
puts event.to_json
# => {"name":"blabla","event_type":"PENDING"}
enum is Value type but String is a Reference so I think that is hard to enum a String?
BTW, if we can provide the convert rules in JSON.mapping (like giving a NamedTuple?) will be better.
Edited: like
struct MyEvent
JSON.mapping({
name: String,
event_type: {PENDING: :foo, IN_PROGRESS: :bar}
})
end
p event = MyEvent.from_json("{ \"name\": \"blabla\", \"event_type\": \"PENDING\" }")
# => MyEvent(@name="blabla", @event_type=:foo)
puts event.to_json
# => {"name":"blabla","event_type":"PENDING"}
I believe that this issue should be closed as "status:wantfix".
The example from @ysbaddaden shows, that the intended result can already be achieved in a different way.
BTW to_json is even simple nowadays: builder.string self
Let's close this. Enums need an integer value. For a string representation the solutions above are good enough.
Most helpful comment
Enum#new(JSON::PullParser)accepts both an Integer (the enum value) or a String (the enum key), so you may just override theto_json(io)method to output the key instead of the value and you'll have it working as you expect; you'll just have upcased keys: