Module: Fend::Plugins::Coercions
- Defined in:
- lib/fend/plugins/coercions.rb
Overview
‘coercions` plugin provides a way to coerce validaiton input. First, the plugin needs to be loaded
plugin :coercions
Because of Fend’s dynamic nature, coercion is separated from validation. As such, coercion needs to be done before the actual validation. In order to make this work, type schema must be passed to ‘coerce` method.
coerce username: :string, age: :integer, admin: :boolean
As you can see, type schema is just a hash containing param names and types to which the values need to be converted. Here are some examples:
# coerce username value to string
coerce(username: :string)
# coerce address value to hash
coerce(address: :hash)
# coerce address value to hash
# coerce address[:city] value to string
# coerce address[:street] value to string
coerce(address: { city: :string, street: :string })
# coerce tags to an array
coerce(tags: :array)
# coerce tags to an array of strings
coerce(tags: [:string])
# coerce tags to an array of hashes, each containing `id` and `name` of the tag
coerce(tags: [{ id: :integer, name: :string }])
Coerced data will also serve as result output:
result = UserValidation.call(username: 1234, age: "18", admin: 0)
result.output #=> { username: "1234", age: 18, admin: false }
## Built-in coercions
General rules:
* If input value **cannot** be coerced to specified type, it is returned
unmodified.
* `nil` is returned if input value is an empty string, except for `:hash`
and `:array` coercions.
:any : Returns input
:string : Returns ‘input.to_s` if input is `Numeric` or `Symbol`
:symbol : Returns ‘input.to_sym` if `input.respond_to?(:to_sym)`
:integer : Uses ‘Kernel.Integer(input)`
:float : Uses ‘Kernel.Float(input)`
:decimal : Uses ‘Kernel.Float(input).to_d`
:date : Uses ‘Date.parse(input)`
:date_time : Uses ‘DateTime.parse(input)`
:time : Uses ‘Time.parse(input)`
:boolean : Returns ‘true` if input is one of: `1, “1”, “t”, “true”, :true “y”,“yes”, “on”` (case insensitive)
: Returns ‘false` if input is one of: `0, “0”, “f”, “false”, :false, “n”, “no”, “off”` (case insensitive)
:array : Returns ‘[]` if input is an empty string.
: Returns input if input is an array
:hash : Returns ‘{}` if input is an empty string.
: Returns input if input is a hash
## Strict coercions
Adding ‘strict_` prefix to type name will cause error to be raised when input is incoercible:
coerce username: :strict_string
UserValidation.call(username: Hash.new)
#=> Fend::Plugins::Coercions::CoercionError: cannot coerce {} to string
Custom error message can be defined by setting ‘:strict_error_message` option when loading the plugin:
plugin :coercions, strict_error_message: "Incoercible input encountered"
# or
plugin :coercions, strict_error_message: ->(value, type) { "#{value.inspect} cannot become #{type}" }
## Defining custom coercions and overriding built-in ones
You can define your own coercion method or override the built-in one by passing a block and using ‘coerce_to` method, when loading the plugin:
plugin :coercions do
# add new
coerce_to(:positive_integer) do |input|
Kernel.Integer(input).abs
end
# override existing
coerce_to(:integer) do |input|
# ...
end
end
### Handling incoercible input
If input value cannot be coerced, either ‘ArgumentError` or `TypeError` should be raised.
class PostValidation < Fend
plugin :coercions do
coerce_to(:user) do |input|
raise ArgumentError unless input.is_a?(Integer)
User.find(input)
end
end
# ...
end
‘ArgumentError` and `TypeError` are rescued on a higher level and input is returned as is.
‘coerce(modified_by: :user)`
result = PostValidation.call(modified_by: "invalid_id")
result.input #=> { modified_by: "invalid_id" }
result.output #=> { modified_by: "invalid_id" }
If strict coercion is specified, errors are re-raised as ‘CoercionError`.
‘coerce(modified_by: :strict_user)`
result = PostValidation.call(modified_by: "invalid_id")
#=> Fend::Plugins::Coercions::CoercionError: cannot coerce invalid_id to user
### Handling empty strings
In order to check if input is an empty string, you can take advantange of ‘empty_string?` helper method. It takes input as an argument:
coerce_to(:user) do |input|
return if empty_string?(input)
# ...
end
Defined Under Namespace
Modules: ClassMethods, InstanceMethods Classes: Coerce, Coercer, CoercionError
Class Method Summary collapse
Class Method Details
.configure(validation, opts = {}, &block) ⇒ Object
188 189 190 191 192 193 194 195 |
# File 'lib/fend/plugins/coercions.rb', line 188 def self.configure(validation, opts = {}, &block) validation.const_set(:Coerce, Class.new(Fend::Plugins::Coercions::Coerce)) unless validation.const_defined?(:Coerce) validation::Coerce.class_eval(&block) if block_given? validation.opts[:coercions_strict_error_message] = opts.fetch(:strict_error_message, validation.opts[:coercions_strict_error_message]) validation::Coerce.fend_class = validation validation.const_set(:Coercer, Coercer) unless validation.const_defined?(:Coercer) end |