Skip to content

Instantly share code, notes, and snippets.

@thiagoa
Last active December 22, 2017 16:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save thiagoa/e496b072e756ff80ff59b963d7637a8a to your computer and use it in GitHub Desktop.
Save thiagoa/e496b072e756ff80ff59b963d7637a8a to your computer and use it in GitHub Desktop.
module Coercible
module Types
BOOL_MAP = { 'true' => true, 'false' => false, true => true, false => false }
BOOL = proc { |v| BOOL_MAP[v] }
INTEGER = proc { |v| v.to_i }
ARRAY = proc { |v, rule| Array(v).map(&ARRAY_MAP[rule[:of]]) }
ARRAY_MAP = { Integer => :to_i, String => :to_s, nil => proc { |v| v } }
module_function
def boolean(default: nil)
{ default: default, fn: BOOL }
end
def integer(default: nil)
{ default: default, fn: INTEGER }
end
def array(of: nil, default: nil)
{ of: of, default: default, fn: ARRAY }
end
def self.apply(value, rule)
return rule[:default] if value.nil?
value = rule[:fn].(value, rule)
value.nil? ? rule[:default] : value
rescue TypeError, NoMethodError
rule[:default]
end
end
def self.call(input, rules)
rules.map { |key, rule| [key, Types.apply(input[key], rule)] }.to_h
end
end
##################
# Standalone use #
##################
input = {
questionable: 'true',
turns: nil,
collection: ['1', '2']
}
rules = {
questionable: Coercible::Types.boolean,
turns: Coercible::Types.integer(default: 0),
collection: Coercible::Types.array(of: Integer, default: [])
}
Coercible.call(input, rules)
#=> { questionable: true, turns: 0, collection: [1, 2] }
##################
# Use in a class #
##################
class MyClass
extend Coercible::Types
RULES = {
questionable: boolean,
turns: integer(default: 0),
collection: array(of: Integer, default: [])
}
def initialize(input)
@input = Coercible.call(input, RULES)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment