nakischema 0.0.1 → 0.1.1

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 (4) hide show
  1. checksums.yaml +4 -4
  2. data/lib/nakischema.rb +84 -18
  3. data/nakischema.gemspec +1 -1
  4. metadata +2 -2
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 66f0fa36c6867bf9d4ae1e6388522a98baa5ce53
4
- data.tar.gz: 3fa3398cecfcb67fa6428e0d69898f3bfc5a5af1
3
+ metadata.gz: 4d78fcac47a9551f79d2a35208246902c1330e71
4
+ data.tar.gz: 9e4f2ac556c22c26669343e44e489808804c56b9
5
5
  SHA512:
6
- metadata.gz: 573bc852f4e8d2af49d856247818d3d7b264fa3aa3df05b306136eb35d72f3979831221bce80859eab539ec591b96a00283d2080a38b0b46495288e947623f78
7
- data.tar.gz: '0504529ee39e1306ec3c5469bb3a2a649f5738a61965ff8613f944581e07a041e32785173ec8c48bcf24beba2b41d2d9a5620e8b87e70cad359db4ee43e490c7'
6
+ metadata.gz: 1b2e80736ba9165d63dba0d13deb6d7286ab0af153c243a82d5826aa9a3cba996d24011e0f573f5b0b6d131ce89300d09bc693afecb34f987beadc273d51cd4f
7
+ data.tar.gz: 0e4204ab10c47f1bdae7856be58acef6a75cf177fc73855e04154cb4aa03c635054b0b3445133082d8ca6503d3dd69484b80ede8aff6f58a7132fdfe2cbb45ae
data/lib/nakischema.rb CHANGED
@@ -1,24 +1,33 @@
1
1
  module Nakischema
2
2
  Error = Class.new RuntimeError
3
+
3
4
  def self.validate object, schema, path = []
4
- raise_with_path = lambda do |msg|
5
- raise Error.new "#{msg}#{" (at #{path})" unless path.empty?}" # TODO: maybe move '(at ...)' to the beginning
5
+ raise_with_path = lambda do |msg, _path = path|
6
+ raise Error.new "#{msg}#{" (at #{_path})" unless _path.empty?}"
6
7
  end
8
+ # TODO: maybe move '(at ...)' to the beginning
7
9
  case schema
10
+ when NilClass, TrueClass, FalseClass, String, Symbol ; raise_with_path.call "expected #{schema.inspect} != #{object.inspect}" unless schema == object
11
+ # TODO: maybe deprecate the NilClass, TrueClass, FalseClass since they can be asserted via the next case branch
12
+ when Class ; raise_with_path.call "expected #{schema } != #{object.class }" unless schema === object
13
+ when Regexp ; raise_with_path.call "expected #{schema } != #{object.inspect}" unless schema === object
14
+ when Range ; raise_with_path.call "expected #{schema } != #{object }" unless schema.include? object
8
15
  when Hash
9
16
  raise_with_path.call "expected Hash != #{object.class}" unless object.is_a? Hash unless (schema.keys & %i{ keys each_key each_value }).empty?
10
17
  raise_with_path.call "expected Array != #{object.class}" unless object.is_a? Array unless (schema.keys & %i{ size }).empty?
11
18
  schema.each do |k, v|
12
19
  case k
13
- # when :keys_sorted ; raise_with_path.call "expected explicit keys #{v} != #{object.keys.sort}" unless v == object.keys.sort
14
20
  when :size ; raise_with_path.call "expected explicit size #{v} != #{object.size}" unless v.include? object.size
15
21
  # when Fixnum
16
22
  # raise_with_path.call "expected Array != #{object.class}" unless object.is_a? Array
17
- # validate object[k], v, [*path, "##{k}"]
23
+ # validate object[k], v, [*path, :"##{k}"]
18
24
  when :keys ; validate object.keys, v, [*path, :keys]
25
+ when :values ; validate object.values, v, [*path, :values]
26
+ when :keys_sorted ; validate object.keys.sort, v, [*path, :keys_sorted]
19
27
  when :hash_opt ; v.each{ |k, v| validate object.fetch(k), v, [*path, k] if object.key? k }
20
28
  when :hash_req ; v.each{ |k, v| validate object.fetch(k), v, [*path, k] }
21
- when :hash ; raise_with_path.call "expected implicit keys #{v.keys} != #{object.keys.sort}" unless v.keys.sort == object.keys.sort
29
+ when :hash ; raise_with_path.call "expected Hash != #{object.class}" unless object.is_a? Hash
30
+ raise_with_path.call "expected implicit keys #{v.keys} != #{object.keys.sort}" unless v.keys.sort == object.keys.sort
22
31
  v.each{ |k, v| validate object.fetch(k), v, [*path, k] }
23
32
  when :each_key ; object.keys.each_with_index{ |k, i| validate k, v, [*path, :"key##{i}"] }
24
33
  when :each_value ; object.values.each_with_index{ |v_, i| validate v_, v, [*path, :"value##{i}"] }
@@ -36,35 +45,92 @@ module Nakischema
36
45
  # validate object, v, [*path, :"case##{i}"]
37
46
  # true
38
47
  # end.none?
39
- when :assertions ; v.each_with_index{ |assertion, i| raise_with_path.call "custom assertion failed" unless assertion.call object, [*path, :"assertion##{i}"] }
40
- else ; raise_with_path.call "unsupported rule #{k.inspect}"
48
+ when :assertions
49
+ v.each_with_index do |assertion, i|
50
+ begin
51
+ raise Error.new "custom assertion failed" unless assertion.call object, [*path, :"assertion##{i}"]
52
+ rescue Error => e
53
+ raise_with_path.call e, [*path, :"assertion##{i}"]
54
+ end
55
+ end
56
+ else
57
+ raise_with_path.call "unsupported rule #{k.inspect}"
41
58
  end
42
59
  end
43
- when NilClass, TrueClass, FalseClass, String, Symbol ; raise_with_path.call "expected #{schema.inspect} != #{object.inspect}" unless schema == object
44
- when Regexp ; raise_with_path.call "expected #{schema } != #{object.inspect}" unless schema === object
45
- when Range ; raise_with_path.call "expected #{schema } != #{object }" unless schema.include? object
46
60
  when Array
47
61
  if schema.map(&:class) == [Array]
48
62
  raise_with_path.call "expected Array != #{object.class}" unless object.is_a? Array
49
- raise_with_path.call "expected implicit size #{schema[0].size} != #{object.size}" unless schema[0].size == object.size
50
- object.zip(schema[0]).each_with_index do |(o, v), i|
51
- validate o, v, [*path, :"##{i}"]
52
- end
63
+ raise_with_path.call "expected implicit size #{schema[0].size} != #{object.size} for #{object.inspect}" unless schema[0].size == object.size
64
+ object.zip(schema[0]).each_with_index{ |(o, v), i| validate o, v, [*path, :"##{i}"] }
53
65
  else
54
66
  results = schema.lazy.with_index.map do |v, i|
55
67
  # raise_with_path.call "unsupported nested Array" if v.is_a? Array
56
68
  begin
57
- validate object, v, [*path, "variant##{i}"]
69
+ validate object, v, [*path, :"variant##{i}"]
70
+ nil
71
+ rescue Error => e
72
+ e
73
+ end
74
+ end
75
+ raise Error.new "expected at least one of #{schema.size} rules to match the #{object.inspect}, errors:\n" +
76
+ results.force.compact.map{ |_| _.to_s.gsub(/^/, " ") }.join("\n") if results.all?
77
+ end
78
+ else
79
+ raise_with_path.call "unsupported rule class #{schema.class}"
80
+ end
81
+ end
82
+
83
+ def self.validate_oga_xml object, schema, path = []
84
+ raise_with_path = lambda do |msg, _path = path|
85
+ raise Error.new "#{msg}#{" (at #{_path})" unless _path.empty?}"
86
+ end
87
+ case schema
88
+ when Hash
89
+ schema.each do |k, v|
90
+ case k
91
+ when :size ; raise_with_path.call "expected explicit size #{v} != #{object.size}" unless v.include? object.size
92
+ when :text ; raise_with_path.call "expected text #{v.inspect} != #{object.text.inspect}" unless v == object.text
93
+ when :each ; raise_with_path.call "expected iterable != #{object.class}" unless object.respond_to? :each_with_index
94
+ object.each_with_index{ |e, i| validate_oga_xml e, v, [*path, :"##{i}"] }
95
+ when :exact ; children = object.xpath "./*"
96
+ names = children.map(&:name).uniq
97
+ raise_with_path.call "expected implicit children #{v.keys} != #{names}" unless v.keys == names
98
+ v.each do |k, v|
99
+ selected = children.select{ |_| _.name == k }
100
+ validate_oga_xml selected, v, [*path, k]
101
+ end
102
+ when :req ; v.each{ |k, v| validate_oga_xml object.xpath(k.start_with?("./") ? k : "./#{k}"), v, [*path, k] }
103
+ when :attr_req ; v.each{ |k, v| raise_with_path.call "expected #{v} != #{object[k]}", [*path, k] unless v === object[k] }
104
+ when :assertions
105
+ v.each_with_index do |assertion, i|
106
+ begin
107
+ raise Error.new "custom assertion failed" unless assertion.call object, [*path, :"assertion##{i}"]
108
+ rescue Error => e
109
+ raise_with_path.call e, [*path, :"assertion##{i}"]
110
+ end
111
+ end
112
+ else
113
+ raise_with_path.call "unsupported rule #{k.inspect}"
114
+ end
115
+ end
116
+ when Array
117
+ if schema.map(&:class) == [Array]
118
+ raise_with_path.call "expected implicit size #{schema[0].size} != #{object.size} for #{object.inspect}" unless schema[0].size == object.size
119
+ object.zip(schema[0]).each_with_index{ |(o, v), i| validate_oga_xml o, v, [*path, :"##{i}"] }
120
+ else
121
+ results = schema.lazy.with_index.map do |v, i|
122
+ begin
123
+ validate_oga_xml object, v, [*path, :"variant##{i}"]
58
124
  nil
59
125
  rescue Error => e
60
126
  e
61
127
  end
62
128
  end
63
- raise_with_path.call \
64
- "expected at least one of #{schema.size} rules to match the #{object.inspect}, errors:\n" +
129
+ raise Error.new "expected at least one of #{schema.size} rules to match the #{object.inspect}, errors:\n" +
65
130
  results.force.compact.map{ |_| _.to_s.gsub(/^/, " ") }.join("\n") if results.all?
66
131
  end
67
- else ; raise_with_path.call "unsupported rule class #{schema.class}"
132
+ else
133
+ raise_with_path.call "unsupported rule class #{schema.class}"
68
134
  end
69
135
  end
70
136
  end
data/nakischema.gemspec CHANGED
@@ -1,6 +1,6 @@
1
1
  Gem::Specification.new do |spec|
2
2
  spec.name = "nakischema"
3
- spec.version = "0.0.1"
3
+ spec.version = "0.1.1"
4
4
  spec.summary = "compact yet powerful arbitrary nested objects validator"
5
5
  spec.description = "The most compact yet powerful arbitrary nested objects validator. Especially handy to validate JSONs."
6
6
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: nakischema
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.1.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Victor Maslov aka Nakilon
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2021-08-14 00:00:00.000000000 Z
11
+ date: 2021-09-11 00:00:00.000000000 Z
12
12
  dependencies: []
13
13
  description: The most compact yet powerful arbitrary nested objects validator. Especially
14
14
  handy to validate JSONs.