Skip to content

Instantly share code, notes, and snippets.

@ayamomiji
Created September 14, 2020 06:05
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save ayamomiji/9783e6294f188e0c714698aeb1591dbc to your computer and use it in GitHub Desktop.
Save ayamomiji/9783e6294f188e0c714698aeb1591dbc to your computer and use it in GitHub Desktop.
class HashSchema
def initialize(schema)
@schema = schema.map { |key, type|
[key, HashSchema.lookup(type)]
}.to_h
end
def cast(params)
params.map { |key, value|
[key, @schema[key] ? @schema[key].cast(value) : value]
}.to_h
end
class << self
def lookup(type)
case type
when Array then ArraySchema.new(type[0])
when Hash then HashSchema.new(type)
when Symbol then ActiveModel::Type.lookup(type)
else type
end
end
end
class ArraySchema
def initialize(type)
@type = HashSchema.lookup(type)
end
def cast(values)
values.map { |value| @type.cast(value) }
end
end
end
require 'rails_helper'
RSpec.describe HashSchema do
it 'casts correctly' do
schema = HashSchema.new(str: :string, int: :integer, bool: :boolean)
expect(schema.cast(str: 100, int: '200', bool: 't', undef: 'wat')).to eq(
str: '100', int: 200, bool: true, undef: 'wat'
)
end
it 'casts recursively' do
schema = HashSchema.new(obj: { str: :string, int: :integer, bool: :boolean })
expect(schema.cast(obj: { str: 100, int: '200', bool: 't', undef: 'wat' })).to eq(
obj: { str: '100', int: 200, bool: true, undef: 'wat' }
)
end
it 'casts for an array' do
schema = HashSchema.new(ints: [:integer])
expect(schema.cast(ints: ['1', '2', 3.1416])).to eq(
ints: [1, 2, 3]
)
end
end
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment