Created
March 9, 2017 08:38
-
-
Save Kroid/f2fc81c643fcc229ef876d5ea1fb0824 to your computer and use it in GitHub Desktop.
grape-like params validation
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'json' | |
class Hash | |
def try(*a, &b) | |
if a.empty? && block_given? | |
yield self | |
else | |
__send__(*a, &b) | |
end | |
end | |
end | |
PARAMS = {} | |
module ParamsDSL | |
def params(&block) | |
parser = ParamsParser.new | |
parser.instance_eval &block | |
PARAMS[self.name] = parser.attributes | |
end | |
def self.attributes | |
@attributes | |
# @parser.attributes | |
end | |
end | |
class ParamsParser | |
attr_reader :attributes | |
def initialize | |
@attributes = {} | |
@parent = @attributes | |
end | |
def method_missing(name, *args, &block) | |
if ['optional', 'requires'].find(name) | |
attrs = args[1] | |
attrs[:requires] = true if name == :requires | |
name = args[0] | |
old_parent = @parent | |
@parent[name] = attrs | |
if block.nil? | |
@parent = old_parent | |
else | |
@parent[name][:attributes] = {} | |
@parent = @parent[name][:attributes] | |
self.instance_eval &block | |
@parent = old_parent | |
end | |
end | |
end | |
end | |
class BaseAction | |
extend ParamsDSL | |
end | |
class MyAction < BaseAction | |
params do | |
optional :id, type: Integer | |
requires :title, type: String, default: 'demo' | |
optional :user, type: Hash do | |
requires :email, type: String | |
requires :session, type: Hash do | |
optional :id, type: Integer | |
requires :token, type: String | |
end | |
optional :password, type: String | |
end | |
optional :desc, type: String | |
requires :tags, type: Array do | |
requires :id, type: Integer | |
requires :tag, type: String | |
end | |
optional :numbers, type: Array | |
optional :strings, type: Array, default: ['qwe', 'rty'] | |
end | |
end | |
def declared_params(schema, params) | |
result = {} | |
schema.each do |key, value| | |
params_value = params.try(:[], key) | |
params_value = value[:default] if params_value.nil? and !value[:default].nil? | |
if value[:type] == Hash | |
value = declared_params(value[:attributes], params_value) | |
elsif value[:type] == Array | |
if value[:attributes].nil? | |
value = params_value | |
else | |
value = params_value.map do |_params_value| | |
declared_params(value[:attributes], _params_value) | |
end | |
end | |
else | |
value = params_value | |
end | |
result[key] = value unless value.nil? | |
end | |
result | |
end | |
schema = PARAMS[MyAction.name] | |
params = { | |
id: 1, | |
content: 'qweqweqwe', | |
user: { | |
id: 1, | |
phone_number: '79123456789', | |
password: '123123', | |
session: { | |
token: 'hey', | |
qwe: 123, | |
}, | |
}, | |
tags: [ | |
{ id: 1, tag: 'qwe' }, | |
{ id: 2, tag: 'try', abc: 123}, | |
], | |
numbers: [1,2,3,4,5], | |
} | |
declared = declared_params(schema, params) | |
puts JSON.pretty_generate(declared) | |
# output: | |
# | |
# { | |
# "id": 1, | |
# "title": "demo", | |
# "user": { | |
# "session": { | |
# "token": "hey" | |
# }, | |
# "password": "123123" | |
# }, | |
# "tags": [ | |
# { | |
# "id": 1, | |
# "tag": "qwe" | |
# }, | |
# { | |
# "id": 2, | |
# "tag": "try" | |
# } | |
# ], | |
# "numbers": [ | |
# 1, | |
# 2, | |
# 3, | |
# 4, | |
# 5 | |
# ], | |
# "strings": [ | |
# "qwe", | |
# "rty" | |
# ] | |
# } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment