jimmy 0.5.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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 -86
- 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 -10
- 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(Fixnum) { |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(Fixnum) { |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
|