jimmy 0.5.5 → 2.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.circleci/config.yml +35 -0
- data/.gitignore +4 -3
- data/.rspec +3 -0
- data/.rubocop.yml +61 -0
- data/.ruby-version +1 -1
- data/.travis.yml +6 -0
- data/CODE_OF_CONDUCT.md +74 -0
- data/Gemfile +13 -0
- data/LICENSE +1 -1
- data/README.md +22 -134
- data/Rakefile +91 -1
- data/bin/console +15 -0
- data/bin/setup +8 -0
- data/jimmy.gemspec +25 -21
- data/lib/jimmy.rb +23 -15
- data/lib/jimmy/declaration.rb +150 -0
- data/lib/jimmy/declaration/assertion.rb +81 -0
- data/lib/jimmy/declaration/casting.rb +34 -0
- data/lib/jimmy/declaration/composites.rb +41 -0
- data/lib/jimmy/declaration/number.rb +27 -0
- data/lib/jimmy/declaration/object.rb +11 -0
- data/lib/jimmy/declaration/string.rb +100 -0
- data/lib/jimmy/declaration/types.rb +57 -0
- data/lib/jimmy/error.rb +9 -0
- data/lib/jimmy/file_map.rb +166 -0
- data/lib/jimmy/index.rb +78 -0
- data/lib/jimmy/json/array.rb +93 -0
- data/lib/jimmy/json/collection.rb +90 -0
- data/lib/jimmy/json/hash.rb +118 -0
- data/lib/jimmy/json/pointer.rb +119 -0
- data/lib/jimmy/json/uri.rb +144 -0
- data/lib/jimmy/loaders/base.rb +30 -0
- data/lib/jimmy/loaders/json.rb +15 -0
- data/lib/jimmy/loaders/ruby.rb +21 -0
- data/lib/jimmy/macros.rb +37 -0
- data/lib/jimmy/schema.rb +106 -87
- data/lib/jimmy/schema/array.rb +95 -0
- data/lib/jimmy/schema/casting.rb +17 -0
- data/lib/jimmy/schema/json.rb +40 -0
- data/lib/jimmy/schema/number.rb +47 -0
- data/lib/jimmy/schema/object.rb +108 -0
- data/lib/jimmy/schema/operators.rb +96 -0
- data/lib/jimmy/schema/string.rb +44 -0
- data/lib/jimmy/schema_with_uri.rb +53 -0
- data/lib/jimmy/schemer_factory.rb +65 -0
- data/lib/jimmy/version.rb +3 -1
- data/schema07.json +172 -0
- metadata +50 -101
- data/circle.yml +0 -11
- data/lib/jimmy/combination.rb +0 -34
- data/lib/jimmy/definitions.rb +0 -38
- data/lib/jimmy/domain.rb +0 -111
- data/lib/jimmy/link.rb +0 -93
- data/lib/jimmy/reference.rb +0 -39
- data/lib/jimmy/schema_creation.rb +0 -121
- data/lib/jimmy/schema_type.rb +0 -100
- data/lib/jimmy/schema_types.rb +0 -42
- data/lib/jimmy/schema_types/array.rb +0 -30
- data/lib/jimmy/schema_types/boolean.rb +0 -6
- data/lib/jimmy/schema_types/integer.rb +0 -8
- data/lib/jimmy/schema_types/null.rb +0 -6
- data/lib/jimmy/schema_types/number.rb +0 -34
- data/lib/jimmy/schema_types/object.rb +0 -45
- data/lib/jimmy/schema_types/string.rb +0 -40
- data/lib/jimmy/symbol_array.rb +0 -17
- data/lib/jimmy/transform_keys.rb +0 -39
- data/lib/jimmy/type_reference.rb +0 -14
- data/lib/jimmy/validation_error.rb +0 -20
data/lib/jimmy/reference.rb
DELETED
@@ -1,39 +0,0 @@
|
|
1
|
-
require_relative './transform_keys'
|
2
|
-
|
3
|
-
module Jimmy
|
4
|
-
class Reference
|
5
|
-
include SchemaCreation::MetadataMethods
|
6
|
-
attr_reader :uri, :data
|
7
|
-
|
8
|
-
def initialize(uri, domain, nullable = false, *args, **opts, &block)
|
9
|
-
@uri = TransformKeys.transformer.transform_ref(uri, domain.options[:transform_keys])
|
10
|
-
@nullable = nullable
|
11
|
-
@data = {}
|
12
|
-
args.each { |arg| __send__ arg }
|
13
|
-
opts.each { |arg| __send__ *arg }
|
14
|
-
instance_exec &block if block
|
15
|
-
end
|
16
|
-
|
17
|
-
def compile
|
18
|
-
data.merge(nullable? ?
|
19
|
-
{
|
20
|
-
'anyOf' => [
|
21
|
-
{'type' => 'null'},
|
22
|
-
ref_hash
|
23
|
-
]
|
24
|
-
} :
|
25
|
-
ref_hash
|
26
|
-
)
|
27
|
-
end
|
28
|
-
|
29
|
-
def nullable?
|
30
|
-
@nullable
|
31
|
-
end
|
32
|
-
|
33
|
-
private
|
34
|
-
|
35
|
-
def ref_hash
|
36
|
-
{'$ref' => uri}
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
@@ -1,121 +0,0 @@
|
|
1
|
-
module Jimmy
|
2
|
-
class SchemaCreation
|
3
|
-
|
4
|
-
@handlers = {}
|
5
|
-
|
6
|
-
class << self
|
7
|
-
|
8
|
-
attr_reader :handlers
|
9
|
-
|
10
|
-
def apply_to(klass, &handler)
|
11
|
-
@handlers[klass] = handler
|
12
|
-
%i(one all any).each do |condition|
|
13
|
-
klass.__send__ :define_method, :"#{condition}_of" do |*args, &inner_block|
|
14
|
-
Combination.new(condition, schema).tap do |combo|
|
15
|
-
combo.with_locals(locals) { combo.evaluate inner_block }
|
16
|
-
instance_exec combo, *args, &handler
|
17
|
-
end
|
18
|
-
end
|
19
|
-
end
|
20
|
-
klass.include DefiningMethods
|
21
|
-
end
|
22
|
-
end
|
23
|
-
|
24
|
-
module MetadataMethods
|
25
|
-
def set(**values)
|
26
|
-
values.each { |k, v| data[k.to_s] = v }
|
27
|
-
end
|
28
|
-
|
29
|
-
%i[title description default].each { |k| define_method(k) { |v| set k => v } }
|
30
|
-
end
|
31
|
-
|
32
|
-
module Referencing
|
33
|
-
def method_missing(name, *args, &block)
|
34
|
-
if schema.definitions[name]
|
35
|
-
ref *args, definition(name), &block
|
36
|
-
else
|
37
|
-
super
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
def respond_to_missing?(name, *)
|
42
|
-
schema.definitions.key?(name) || super
|
43
|
-
end
|
44
|
-
|
45
|
-
def definition(id)
|
46
|
-
"/#{schema.name}#/definitions/#{id}"
|
47
|
-
end
|
48
|
-
|
49
|
-
def ref(*args, uri, &block)
|
50
|
-
handler = SchemaCreation.handlers[self.class]
|
51
|
-
instance_exec(Reference.new(uri, domain, args.delete(:nullable), &block), *args, &handler) if handler
|
52
|
-
end
|
53
|
-
end
|
54
|
-
|
55
|
-
module DefiningMethods
|
56
|
-
include MetadataMethods
|
57
|
-
|
58
|
-
def locals
|
59
|
-
@locals ||= {}
|
60
|
-
end
|
61
|
-
|
62
|
-
def with_locals(**locals)
|
63
|
-
locals.each_key do |key|
|
64
|
-
raise "Local '#{key}' conflicts with an existing DSL method" if reserved? key
|
65
|
-
end
|
66
|
-
original = locals
|
67
|
-
@locals = original.merge(locals)
|
68
|
-
yield.tap { @locals = original }
|
69
|
-
end
|
70
|
-
|
71
|
-
def respond_to_missing?(method, *)
|
72
|
-
locals.key?(method) || reserved?(method, false) || super
|
73
|
-
end
|
74
|
-
|
75
|
-
def method_missing(method, *args, &block)
|
76
|
-
return locals[method] if locals.key?(method)
|
77
|
-
|
78
|
-
if SchemaTypes.key? method
|
79
|
-
handler = SchemaCreation.handlers[self.class]
|
80
|
-
self.class.__send__ :define_method, method do |*inner_args, &inner_block|
|
81
|
-
handler_args = handler && inner_args.shift(handler.arity - 1)
|
82
|
-
child_schema = Schema.new(
|
83
|
-
method,
|
84
|
-
respond_to?(:schema) ? schema : domain
|
85
|
-
)
|
86
|
-
child_schema.name = @schema_name if is_a? Domain
|
87
|
-
child_schema.setup *inner_args, **locals, &inner_block
|
88
|
-
instance_exec child_schema, *handler_args, &handler if handler
|
89
|
-
child_schema.dsl
|
90
|
-
end
|
91
|
-
return __send__ method, *args, &block
|
92
|
-
end
|
93
|
-
|
94
|
-
domain.autoload_type method
|
95
|
-
|
96
|
-
if domain.types.key? method
|
97
|
-
return instance_exec TypeReference.new(method, domain, args.include?(:nullable)), *args, &SchemaCreation.handlers[self.class]
|
98
|
-
end
|
99
|
-
|
100
|
-
if kind_of_array?(method)
|
101
|
-
return array(*args) { __send__ method[0..-7], &block }
|
102
|
-
end
|
103
|
-
|
104
|
-
super method, *args, &block
|
105
|
-
end
|
106
|
-
|
107
|
-
private
|
108
|
-
|
109
|
-
def reserved?(key, all = true)
|
110
|
-
domain.autoload_type key
|
111
|
-
(all && respond_to?(key)) || SchemaTypes.key?(key) || domain.types.key?(key) || kind_of_array?(key)
|
112
|
-
end
|
113
|
-
|
114
|
-
def kind_of_array?(key)
|
115
|
-
key =~ /^(\w+)_array$/ && reserved?($1.to_sym)
|
116
|
-
end
|
117
|
-
|
118
|
-
end
|
119
|
-
|
120
|
-
end
|
121
|
-
end
|
data/lib/jimmy/schema_type.rb
DELETED
@@ -1,100 +0,0 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
|
3
|
-
require_relative 'schema'
|
4
|
-
|
5
|
-
module Jimmy
|
6
|
-
class SchemaType
|
7
|
-
|
8
|
-
class << self
|
9
|
-
|
10
|
-
def register!
|
11
|
-
SchemaTypes.register self
|
12
|
-
end
|
13
|
-
|
14
|
-
def trait(*args, &handler)
|
15
|
-
args.each do |name_or_type|
|
16
|
-
case name_or_type
|
17
|
-
when Symbol
|
18
|
-
handler ||= proc { |value| attrs[name_or_type] = value }
|
19
|
-
self::DSL.__send__ :define_method, name_or_type, handler
|
20
|
-
when Class
|
21
|
-
Schema.set_argument_handler self, name_or_type, handler
|
22
|
-
else
|
23
|
-
raise 'Trait must be a Symbol or a Class'
|
24
|
-
end
|
25
|
-
end
|
26
|
-
end
|
27
|
-
|
28
|
-
def nested(&handler)
|
29
|
-
SchemaTypes.nested_handlers[self] = handler
|
30
|
-
end
|
31
|
-
|
32
|
-
def compile(&handler)
|
33
|
-
SchemaTypes.compilers[self] = handler
|
34
|
-
end
|
35
|
-
|
36
|
-
end
|
37
|
-
|
38
|
-
class DSL
|
39
|
-
extend Forwardable
|
40
|
-
include SchemaCreation::Referencing
|
41
|
-
include SchemaCreation::MetadataMethods
|
42
|
-
|
43
|
-
attr_reader :schema
|
44
|
-
|
45
|
-
delegate %i(attrs domain) => :schema
|
46
|
-
|
47
|
-
def initialize(schema)
|
48
|
-
@schema = schema
|
49
|
-
end
|
50
|
-
|
51
|
-
def evaluate(proc, *args)
|
52
|
-
instance_exec *args, &proc
|
53
|
-
end
|
54
|
-
|
55
|
-
def camelize_attrs(*args)
|
56
|
-
included_args = args.flatten.reject { |arg| attrs[arg].nil? }
|
57
|
-
included_args.map { |arg| [arg.to_s.gsub(/_([a-z])/) { $1.upcase }, attrs[arg]] }.to_h
|
58
|
-
end
|
59
|
-
|
60
|
-
def include(*partial_names, **locals)
|
61
|
-
partial_names.each do |name|
|
62
|
-
with_locals locals do
|
63
|
-
evaluate_partial domain.partials[name.to_s]
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
67
|
-
|
68
|
-
def definitions(&block)
|
69
|
-
schema.definitions.evaluate &block
|
70
|
-
end
|
71
|
-
|
72
|
-
def define(type, *args, &block)
|
73
|
-
definitions { __send__ type, *args, &block }
|
74
|
-
end
|
75
|
-
|
76
|
-
def data
|
77
|
-
schema.data
|
78
|
-
end
|
79
|
-
|
80
|
-
def link(rel_and_href, &block)
|
81
|
-
link = Link.new(schema, *rel_and_href.first)
|
82
|
-
schema.links << link
|
83
|
-
link.dsl.evaluate &block if block
|
84
|
-
end
|
85
|
-
|
86
|
-
def nullable
|
87
|
-
schema.nullable = true
|
88
|
-
end
|
89
|
-
|
90
|
-
private
|
91
|
-
|
92
|
-
# Minimize collisions with local scope (hence the weird name __args)
|
93
|
-
def evaluate_partial(__args)
|
94
|
-
instance_eval *__args
|
95
|
-
end
|
96
|
-
|
97
|
-
end
|
98
|
-
|
99
|
-
end
|
100
|
-
end
|
data/lib/jimmy/schema_types.rb
DELETED
@@ -1,42 +0,0 @@
|
|
1
|
-
require 'forwardable'
|
2
|
-
|
3
|
-
require_relative 'schema_type'
|
4
|
-
require_relative 'schema_creation'
|
5
|
-
|
6
|
-
module Jimmy
|
7
|
-
module SchemaTypes
|
8
|
-
|
9
|
-
@types = {}
|
10
|
-
@dsls = {}
|
11
|
-
@nested_handlers = {}
|
12
|
-
@compilers = {}
|
13
|
-
|
14
|
-
class << self
|
15
|
-
extend Forwardable
|
16
|
-
|
17
|
-
delegate %i[each keys values key?] => :@types
|
18
|
-
|
19
|
-
attr_reader :dsls, :nested_handlers, :compilers
|
20
|
-
|
21
|
-
def [](type_name)
|
22
|
-
@types[type_name]
|
23
|
-
end
|
24
|
-
|
25
|
-
def register(type_class)
|
26
|
-
type_name = type_class.name[/\w+$/].downcase.to_sym
|
27
|
-
dsl_class = Class.new(type_class.superclass::DSL)
|
28
|
-
type_class.const_set :DSL, dsl_class
|
29
|
-
@dsls[type_name] = dsl_class
|
30
|
-
@types[type_name] = type_class
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
Dir[ROOT + 'lib/jimmy/schema_types/*.rb'].each do |path|
|
36
|
-
require path
|
37
|
-
end
|
38
|
-
|
39
|
-
nested_handlers.each { |klass, handler| SchemaCreation.apply_to klass::DSL, &handler }
|
40
|
-
|
41
|
-
end
|
42
|
-
end
|
@@ -1,30 +0,0 @@
|
|
1
|
-
module Jimmy
|
2
|
-
class SchemaTypes::Array < SchemaType
|
3
|
-
register!
|
4
|
-
|
5
|
-
trait :min_items
|
6
|
-
trait :max_items
|
7
|
-
trait(:unique) { attrs[:unique_items] = true }
|
8
|
-
trait Range do |range|
|
9
|
-
min, max = [range.first, range.last].sort
|
10
|
-
min_items min
|
11
|
-
max_items max
|
12
|
-
end
|
13
|
-
trait(Integer) { |value| min_items value; max_items value }
|
14
|
-
|
15
|
-
nested do |schema|
|
16
|
-
(attrs[:items] ||= []) << schema
|
17
|
-
end
|
18
|
-
|
19
|
-
compile do |hash|
|
20
|
-
hash.merge! camelize_attrs(%i[min_items max_items unique_items])
|
21
|
-
items = attrs[:items] || []
|
22
|
-
if items.length > 1
|
23
|
-
hash['items'] = {'anyOf' => items.map(&:compile)}
|
24
|
-
elsif items.length == 1
|
25
|
-
hash['items'] = items.first.compile
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
module Jimmy
|
2
|
-
class SchemaTypes::Number < SchemaType
|
3
|
-
register!
|
4
|
-
|
5
|
-
trait :multiple_of
|
6
|
-
trait :minimum
|
7
|
-
trait :maximum
|
8
|
-
trait(:<) { |value| maximum value; attrs[:exclusive_maximum] = true; self }
|
9
|
-
trait(:<=) { |value| maximum value; attrs[:exclusive_maximum] = nil; self }
|
10
|
-
trait(:>) { |value| minimum value; attrs[:exclusive_minimum] = true; self }
|
11
|
-
trait(:>=) { |value| minimum value; attrs[:exclusive_minimum] = nil; self }
|
12
|
-
trait(:enum) do |*values|
|
13
|
-
attrs[:enum] ||= []
|
14
|
-
attrs[:enum] |= values.flatten
|
15
|
-
end
|
16
|
-
trait(Numeric, Array) { |value| enum value }
|
17
|
-
trait(Range) do |range|
|
18
|
-
if range.first <= range.last
|
19
|
-
minimum range.first
|
20
|
-
maximum range.last
|
21
|
-
attrs[:exclusive_maximum] ||= range.exclude_end? || nil
|
22
|
-
else
|
23
|
-
minimum range.last
|
24
|
-
maximum range.first
|
25
|
-
attrs[:exclusive_minimum] ||= range.exclude_end? || nil
|
26
|
-
end
|
27
|
-
end
|
28
|
-
|
29
|
-
compile do |hash|
|
30
|
-
hash.merge! camelize_attrs(%i[minimum maximum exclusive_minimum exclusive_maximum multiple_of enum])
|
31
|
-
end
|
32
|
-
|
33
|
-
end
|
34
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
require_relative '../transform_keys'
|
2
|
-
|
3
|
-
module Jimmy
|
4
|
-
class SchemaTypes::Object < SchemaType
|
5
|
-
register!
|
6
|
-
|
7
|
-
trait :require do |*required_keys|
|
8
|
-
if required_keys == [0]
|
9
|
-
attrs[:required] = SymbolArray.new
|
10
|
-
else
|
11
|
-
attrs[:required] ||= SymbolArray.new
|
12
|
-
attrs[:required] |= required_keys.flatten.map(&:to_s).uniq
|
13
|
-
end
|
14
|
-
end
|
15
|
-
|
16
|
-
trait :all do
|
17
|
-
SymbolArray.new(attrs[:properties].keys.select { |x| x.is_a? Symbol })
|
18
|
-
end
|
19
|
-
|
20
|
-
trait(:none) { 0 }
|
21
|
-
|
22
|
-
trait(:allow_additional) { attrs[:additional_properties] = true }
|
23
|
-
|
24
|
-
nested do |schema, property_name|
|
25
|
-
(attrs[:properties] ||= {})[TransformKeys.transformer.transform(property_name, domain.options[:transform_keys])] = schema
|
26
|
-
end
|
27
|
-
|
28
|
-
compile do |hash|
|
29
|
-
(attrs[:properties] || {}).each do |key, value|
|
30
|
-
collection, key =
|
31
|
-
if key.is_a? Regexp
|
32
|
-
['patternProperties', key.inspect.gsub(%r`^/|/[a-z]*$`, '')]
|
33
|
-
else
|
34
|
-
['properties', key.to_s]
|
35
|
-
end
|
36
|
-
hash[collection] ||= {}
|
37
|
-
hash[collection][key] = value.compile
|
38
|
-
end
|
39
|
-
required = attrs[:required]
|
40
|
-
hash['required'] = required.to_a if required && !required.empty?
|
41
|
-
hash['additionalProperties'] = !!attrs[:additional_properties]
|
42
|
-
end
|
43
|
-
|
44
|
-
end
|
45
|
-
end
|
@@ -1,40 +0,0 @@
|
|
1
|
-
module Jimmy
|
2
|
-
class SchemaTypes::String < SchemaType
|
3
|
-
register!
|
4
|
-
|
5
|
-
trait :min_length
|
6
|
-
trait :max_length
|
7
|
-
trait(:pattern) { |regex| attrs[:pattern] = regex.is_a?(Regexp) ? regex.inspect.gsub(%r`^/|/[a-z]*$`, '') : regex }
|
8
|
-
trait(:format) { |value| attrs[:format] = value.to_s.gsub('_', '-') }
|
9
|
-
%i[
|
10
|
-
date_time
|
11
|
-
email
|
12
|
-
hostname
|
13
|
-
ipv4
|
14
|
-
ipv6
|
15
|
-
uri
|
16
|
-
].each { |k| trait(k) { format k } }
|
17
|
-
trait(:enum) do |*values|
|
18
|
-
attrs[:enum] ||= []
|
19
|
-
attrs[:enum] |= values.flatten.map(&:to_s)
|
20
|
-
end
|
21
|
-
trait(Regexp) { |regex| pattern regex }
|
22
|
-
trait Range do |value|
|
23
|
-
variation = value.exclude_end? ? 1 : 0
|
24
|
-
if value.first < value.last
|
25
|
-
attrs[:min_length] = value.first
|
26
|
-
attrs[:max_length] = value.last - variation
|
27
|
-
else
|
28
|
-
attrs[:max_length] = value.first
|
29
|
-
attrs[:min_length] = value.last + variation
|
30
|
-
end
|
31
|
-
end
|
32
|
-
trait(Integer) { |value| min_length value; max_length value }
|
33
|
-
trait(Array) { |value| enum value }
|
34
|
-
|
35
|
-
compile do |hash|
|
36
|
-
hash.merge! camelize_attrs(%i[min_length max_length pattern enum format])
|
37
|
-
end
|
38
|
-
|
39
|
-
end
|
40
|
-
end
|