jimmy 0.5.3 → 2.0.2

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.
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 +98 -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 +107 -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(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,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(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