Skip to content

Instantly share code, notes, and snippets.

@burke
Created September 24, 2021 16:44
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 burke/f626393231f54b05937896bb1031682d to your computer and use it in GitHub Desktop.
Save burke/f626393231f54b05937896bb1031682d to your computer and use it in GitHub Desktop.
I'm going to hell for sure.
assert(JSONType.recursively_valid?({'a' => ['neato']}))
refute(JSONType.recursively_valid?({'a' => [:neato]}))
class JSONMetaType < T::Types::Base
def initialize(max_depth: 10)
@max_depth = max_depth
super()
end
def recursively_valid?(obj)
type_for_obj(obj).recursively_valid?(obj)
end
def validate!(obj)
type_for_obj(obj).validate!(obj)
end
private
def type_for_obj(obj)
d = depth(obj)
if d > @max_depth
raise("object too deep: has depth #{d}; max is #{@max_depth}")
end
type_for_depth(d)
end
def type_for_depth(d)
@types ||= [
T.type_alias { T.any(String, Numeric, NilClass, FalseClass, TrueClass) },
]
return @types[d] if @types[d]
prev = type_for_depth(d - 1)
@types[d] = T.type_alias { T.any(prev, T::Hash[String, prev], T::Array[prev]) }
@types[d]
end
def depth(obj)
case obj
when Hash
1 + [*obj.keys, *obj.values].map { |o| depth(o) }.max
when Array
1 + obj.map { |o| depth(o) }.max
when Numeric, String, NilClass, FalseClass, TrueClass
1
else
# bail, but not here: let the validation get it.
1
end
end
end
JSONType = JSONMetaType.new(max_depth: 10)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment