Proposal to add coersion or proc types
At the moment I use following patch to support custom coersion:
JsonApiClient::Schema::Property.prepend(
Module.new do
def cast(value)
return super unless proc_coercion?
type.call(value)
end
private
def proc_coercion?
type.is_a?(Proc)
end
end
)
Used as:
property :names, type: -> (data) { data.to_s.split('#,') }
property :interval, type: -> (data) { data[:begin]..data[:end] }
Do you have any plans to have something similar?
Would you be open to opening up a PR with an idea of how that would work?
Hi @gaorlov, I don't work with JsonApiClient anymore. Code which does the job is all included in this particular issue. I used coercion mainly to create ruby range objects and arrays.
@senid231 what do you think about a callable type? Have you seen people use the types much?
@gaorlov If we talk about object with one method I've prefer call here.
but we should keep backward compatibility - if object doesn't respond to call we should use cast instead
@senid231 I guess my question is more: does this belong in the client gem or is this a higher level concern? This feels like parser logic rather than a cast/field validation. Should this be a separate option? Like a
property :names, parser: (data) -> { data.to_s.split('#,') }
property :value, type: :double, parser: ValueParser
property :range, parser_name: "RangeParser"
Where the parcer classes look like
class Parser
attr_reader :field
def initialize( field )
@field = field
end
end
def ArrayParser < Parser
def parse
field.split( ", " )
end
end
def RangeParser < Parser
def parse
start, end = field.split( "-to-" )
( start ... end )
end
end
But again, I'm not sure if this belong in this gem. What do you think?
@gaorlov I think we should keep it simple
currently we have property which can be class with method cast
we should keep that logic to not break code for people who already implementing types in this way
we should extend property logic by allowing :type option to be any object that has method call
after that we will be able do like this:
class OptionsType
def self.call(value)
OpenStruct.new(value) if value
end
end
class Person < JsonApiClient::Resource
property :names, type: ->(value) { value.split(',') }
property :options, type: OptionsType
end