Skip to content

Instantly share code, notes, and snippets.

@Kroid
Created March 9, 2017 08:38
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 Kroid/f2fc81c643fcc229ef876d5ea1fb0824 to your computer and use it in GitHub Desktop.
Save Kroid/f2fc81c643fcc229ef876d5ea1fb0824 to your computer and use it in GitHub Desktop.
grape-like params validation
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