Open iMacTia opened 3 weeks ago
Thanks @iMacTia! This is great. I had something very similar in mind, down to the Grape::TypedEntity
name :)
Having to declare the generic type twice is annoying, but probably inevitable due to how Grape is designed and Sorbet's own limitations with generics.
If we're going to introduce this generic class, I would also seize the opportunity to replace the expose
method with 3 different aliases, to address the issue that was discussed on the Sorbet Slack:
expose
: default one, same as what you have here but without the block argument to force the use of one of the following when passing a blockexpose_nested
: block variant for nested exposure (block takes no argument and is evaluated in the class context)expose_runtime
: block variant for runtime exposure (block takes 1 or 2 arguments and is evaluated in the instance context)I will try to take a stab at this next week.
That sounds great, I like the idea of the aliases and it seems perfectly fine to "enforce" them because Grape::TypedEntity
is opt-in anyway 😄
Keep me posted and please do let me know when it's ready to test as I'm sure I could help with that
Problem summary
Sharing this little "hack" that we recently implemented in our codebase. There's only that much we can achieve by adding signatures to
Grape::Entity
, especially because of the awful signature ofexpose
that makes use the splat (*
) operator for its arguments.The other "issue" we wanted to address what that there's no way to know what the
object
in a serialiser is, especially in a big codebase with tens of people working on it. It would be great ifGrape::Entity
could be defined as generic (likeGrape::Entity[ObjectType]
, but sorbet doesn't allow you to re-define an existing class as generic without forcing you to define theObjectType
on ALL the existing entities. This was just not viable for us due to the huge amount of existing entities.Solution
In order to achieve the goals above and make this process "opt-in", we therefore introduced a
Grape::TypedEntity
wrapper. The current version, which I'm sure can be improved, looks like this (it's split into an.rb
and.rbi
file due to sorbet's limits):Usage
When defining a
TypedEntity
you need to specify the two generic members:Known issues
The signature for
expose
is not perfect yet. Options that take aproc
will not type-checkobject
andoptions
correctly (this is a sorbet limitations onproc
s). Moreover, theexpose
method sig only accepts ablock
without parameters (for nesting), soas
should be used for defining complex fields