Given this JSON file:
{
"id": 42,
"name": "bew",
"is_bot": false
}
The corresponding mapping would be:
class User
JSON.mapping(
id: Int32,
name: String,
bot: {type: Bool, key: "is_bot"},
)
end
This would allow us to write:
user = User.from_json some_json
p user.name # => bew
p user.bot # => false
The issue here is the bot which is not really crystal-ish.. I want my method to be bot? not just bot
Maybe we could do something like:
JSON.mapping(
bot: {type: Bool, getter?: true}, # note the ? on getter
)
This would result in a getter with ? (should be the default for Bool ?)
p user.bot? # => false
What do you think ?
I would say that
class User
JSON.mapping(
id: Int32,
name: String,
bot?: {type: Bool, key: "is_bot"},
)
end
Would be the expected way to declare the ?-ended getter.
The challenge is that the expression "bot?".id which is used in both: define the method and define the ivar, preserves the ?. Although it is what we want on the method name, it is not what is wanted in the ivar (it does not compile, ivars can't end with ?)
Making the snippet that use bot? as key work will simplify probably to reuse the logic to other mappings in the future.
@bcardiff you idea is good, I like it too!
So I think in the JSON.mapping macro, all for key, value in properties blocks will need a few lines to detect and remove the ?, and all usage of {{key.id}} will need to be replaced by {{%key.id}}.
Did I miss something ?
Not sure what should replace the @{{key.id}}, but yes. I would vouch for something simple.
If it is too common maybe extending the macro interpreter with key.to_var or something that will be safe for instance variable identifiers.
Or maybe .id is fine and should remove ?, but there should be other what to interpolate the method names.
Since there are like 7 occurrences in JSON mapping of @{{key.id}} we can start with a local solutions and see how it goes/others think of.
I forgot that {{ %key.id }} is not possible as %local variables are not macro variables, and cannot be used in {{ }} macro expansions..
So I think we'll need something like you suggested @bcardiff: {{key.to_var}}, or {{key.var_id}} to extract a valid variable name from the key argument.
Or maybe .id is fine and should remove
?, but there should be other what to interpolate the method names.
I think we should keep .id as generic as possible, and add specific id extractor like .var_id for variable
Maybe remove ?, and if a collision is found, add _s to the end of the name until the collision is resolved?
class Test
JSON.mapping({
bot: Bool,
bot?: {type: Bool, key: "is_bot"}
})
end
x = Bot.from_json(%<{"bot":true,"is_bot":false}>)
puts x.@bot #=> true
puts x.@bot_ #=> false
Passing the type info to to_var could probably get annoying, though, so maybe it could be a method on the type? @type.to_var(name)
Bump
Most helpful comment
I would say that
Would be the expected way to declare the ?-ended getter.
The challenge is that the expression
"bot?".idwhich is used in both: define the method and define the ivar, preserves the?. Although it is what we want on the method name, it is not what is wanted in the ivar (it does not compile, ivars can't end with?)Making the snippet that use
bot?as key work will simplify probably to reuse the logic to other mappings in the future.