jimmy 0.5.5 → 2.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (69) hide show
  1. checksums.yaml +5 -5
  2. data/.circleci/config.yml +35 -0
  3. data/.gitignore +4 -3
  4. data/.rspec +3 -0
  5. data/.rubocop.yml +61 -0
  6. data/.ruby-version +1 -1
  7. data/.travis.yml +6 -0
  8. data/CODE_OF_CONDUCT.md +74 -0
  9. data/Gemfile +13 -0
  10. data/LICENSE +1 -1
  11. data/README.md +22 -134
  12. data/Rakefile +91 -1
  13. data/bin/console +15 -0
  14. data/bin/setup +8 -0
  15. data/jimmy.gemspec +25 -21
  16. data/lib/jimmy.rb +23 -15
  17. data/lib/jimmy/declaration.rb +150 -0
  18. data/lib/jimmy/declaration/assertion.rb +81 -0
  19. data/lib/jimmy/declaration/casting.rb +34 -0
  20. data/lib/jimmy/declaration/composites.rb +41 -0
  21. data/lib/jimmy/declaration/number.rb +27 -0
  22. data/lib/jimmy/declaration/object.rb +11 -0
  23. data/lib/jimmy/declaration/string.rb +100 -0
  24. data/lib/jimmy/declaration/types.rb +57 -0
  25. data/lib/jimmy/error.rb +9 -0
  26. data/lib/jimmy/file_map.rb +166 -0
  27. data/lib/jimmy/index.rb +78 -0
  28. data/lib/jimmy/json/array.rb +93 -0
  29. data/lib/jimmy/json/collection.rb +90 -0
  30. data/lib/jimmy/json/hash.rb +118 -0
  31. data/lib/jimmy/json/pointer.rb +119 -0
  32. data/lib/jimmy/json/uri.rb +144 -0
  33. data/lib/jimmy/loaders/base.rb +30 -0
  34. data/lib/jimmy/loaders/json.rb +15 -0
  35. data/lib/jimmy/loaders/ruby.rb +21 -0
  36. data/lib/jimmy/macros.rb +37 -0
  37. data/lib/jimmy/schema.rb +106 -87
  38. data/lib/jimmy/schema/array.rb +95 -0
  39. data/lib/jimmy/schema/casting.rb +17 -0
  40. data/lib/jimmy/schema/json.rb +40 -0
  41. data/lib/jimmy/schema/number.rb +47 -0
  42. data/lib/jimmy/schema/object.rb +108 -0
  43. data/lib/jimmy/schema/operators.rb +96 -0
  44. data/lib/jimmy/schema/string.rb +44 -0
  45. data/lib/jimmy/schema_with_uri.rb +53 -0
  46. data/lib/jimmy/schemer_factory.rb +65 -0
  47. data/lib/jimmy/version.rb +3 -1
  48. data/schema07.json +172 -0
  49. metadata +50 -101
  50. data/circle.yml +0 -11
  51. data/lib/jimmy/combination.rb +0 -34
  52. data/lib/jimmy/definitions.rb +0 -38
  53. data/lib/jimmy/domain.rb +0 -111
  54. data/lib/jimmy/link.rb +0 -93
  55. data/lib/jimmy/reference.rb +0 -39
  56. data/lib/jimmy/schema_creation.rb +0 -121
  57. data/lib/jimmy/schema_type.rb +0 -100
  58. data/lib/jimmy/schema_types.rb +0 -42
  59. data/lib/jimmy/schema_types/array.rb +0 -30
  60. data/lib/jimmy/schema_types/boolean.rb +0 -6
  61. data/lib/jimmy/schema_types/integer.rb +0 -8
  62. data/lib/jimmy/schema_types/null.rb +0 -6
  63. data/lib/jimmy/schema_types/number.rb +0 -34
  64. data/lib/jimmy/schema_types/object.rb +0 -45
  65. data/lib/jimmy/schema_types/string.rb +0 -40
  66. data/lib/jimmy/symbol_array.rb +0 -17
  67. data/lib/jimmy/transform_keys.rb +0 -39
  68. data/lib/jimmy/type_reference.rb +0 -14
  69. data/lib/jimmy/validation_error.rb +0 -20
@@ -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
@@ -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
@@ -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,6 +0,0 @@
1
- module Jimmy
2
- class SchemaTypes::Boolean < SchemaType
3
- register!
4
-
5
- end
6
- end
@@ -1,8 +0,0 @@
1
- require_relative 'number'
2
-
3
- module Jimmy
4
- class SchemaTypes::Integer < SchemaTypes::Number
5
- register!
6
-
7
- end
8
- end
@@ -1,6 +0,0 @@
1
- module Jimmy
2
- class SchemaTypes::Null < SchemaType
3
- register!
4
-
5
- end
6
- 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