jsi 0.8.2 → 0.9.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.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/.yardopts +3 -2
  3. data/CHANGELOG.md +8 -3
  4. data/LICENSE.md +2 -3
  5. data/README.md +68 -31
  6. data/docs/Glossary.md +313 -0
  7. data/jsi.gemspec +1 -0
  8. data/lib/jsi/base/mutability.rb +4 -0
  9. data/lib/jsi/base/node.rb +63 -24
  10. data/lib/jsi/base.rb +556 -173
  11. data/lib/jsi/metaschema_node/bootstrap_schema.rb +106 -56
  12. data/lib/jsi/metaschema_node.rb +227 -160
  13. data/lib/jsi/ptr.rb +32 -15
  14. data/lib/jsi/ref.rb +197 -0
  15. data/lib/jsi/registry.rb +311 -0
  16. data/lib/jsi/schema/cxt/child_application.rb +35 -0
  17. data/lib/jsi/schema/cxt/inplace_application.rb +37 -0
  18. data/lib/jsi/schema/cxt.rb +80 -0
  19. data/lib/jsi/schema/dialect.rb +137 -0
  20. data/lib/jsi/schema/draft04.rb +113 -5
  21. data/lib/jsi/schema/draft06.rb +123 -5
  22. data/lib/jsi/schema/draft07.rb +157 -5
  23. data/lib/jsi/schema/draft202012.rb +303 -0
  24. data/lib/jsi/schema/dynamic_anchor_map.rb +63 -0
  25. data/lib/jsi/schema/element.rb +69 -0
  26. data/lib/jsi/schema/elements/anchor.rb +13 -0
  27. data/lib/jsi/schema/elements/array_validation.rb +82 -0
  28. data/lib/jsi/schema/elements/comment.rb +10 -0
  29. data/lib/jsi/schema/{validation → elements}/const.rb +11 -7
  30. data/lib/jsi/schema/elements/contains.rb +59 -0
  31. data/lib/jsi/schema/elements/contains_minmax.rb +91 -0
  32. data/lib/jsi/schema/elements/content_encoding.rb +10 -0
  33. data/lib/jsi/schema/elements/content_media_type.rb +10 -0
  34. data/lib/jsi/schema/elements/content_schema.rb +16 -0
  35. data/lib/jsi/schema/elements/default.rb +11 -0
  36. data/lib/jsi/schema/elements/definitions.rb +19 -0
  37. data/lib/jsi/schema/elements/dependencies.rb +99 -0
  38. data/lib/jsi/schema/elements/dependent_required.rb +49 -0
  39. data/lib/jsi/schema/elements/dependent_schemas.rb +69 -0
  40. data/lib/jsi/schema/elements/dynamic_ref.rb +69 -0
  41. data/lib/jsi/schema/elements/enum.rb +26 -0
  42. data/lib/jsi/schema/elements/examples.rb +10 -0
  43. data/lib/jsi/schema/elements/format.rb +10 -0
  44. data/lib/jsi/schema/elements/id.rb +30 -0
  45. data/lib/jsi/schema/elements/if_then_else.rb +82 -0
  46. data/lib/jsi/schema/elements/info_bool.rb +10 -0
  47. data/lib/jsi/schema/elements/info_string.rb +10 -0
  48. data/lib/jsi/schema/elements/items.rb +93 -0
  49. data/lib/jsi/schema/elements/items_prefixed.rb +96 -0
  50. data/lib/jsi/schema/elements/not.rb +31 -0
  51. data/lib/jsi/schema/elements/numeric.rb +137 -0
  52. data/lib/jsi/schema/elements/numeric_draft04.rb +77 -0
  53. data/lib/jsi/schema/elements/object_validation.rb +55 -0
  54. data/lib/jsi/schema/elements/pattern.rb +35 -0
  55. data/lib/jsi/schema/elements/properties.rb +145 -0
  56. data/lib/jsi/schema/elements/property_names.rb +48 -0
  57. data/lib/jsi/schema/elements/ref.rb +62 -0
  58. data/lib/jsi/schema/elements/required.rb +34 -0
  59. data/lib/jsi/schema/elements/self.rb +24 -0
  60. data/lib/jsi/schema/elements/some_of.rb +180 -0
  61. data/lib/jsi/schema/elements/string_validation.rb +57 -0
  62. data/lib/jsi/schema/elements/type.rb +43 -0
  63. data/lib/jsi/schema/elements/unevaluated_items.rb +54 -0
  64. data/lib/jsi/schema/elements/unevaluated_properties.rb +54 -0
  65. data/lib/jsi/schema/elements/xschema.rb +10 -0
  66. data/lib/jsi/schema/elements/xvocabulary.rb +10 -0
  67. data/lib/jsi/schema/elements.rb +101 -0
  68. data/lib/jsi/schema/issue.rb +3 -4
  69. data/lib/jsi/schema/schema_ancestor_node.rb +103 -50
  70. data/lib/jsi/schema/vocabulary.rb +36 -0
  71. data/lib/jsi/schema.rb +519 -337
  72. data/lib/jsi/schema_classes.rb +168 -124
  73. data/lib/jsi/schema_set.rb +67 -126
  74. data/lib/jsi/set.rb +23 -0
  75. data/lib/jsi/simple_wrap.rb +13 -16
  76. data/lib/jsi/struct.rb +57 -0
  77. data/lib/jsi/uri.rb +40 -0
  78. data/lib/jsi/util/private/memo_map.rb +9 -13
  79. data/lib/jsi/util/private.rb +57 -12
  80. data/lib/jsi/util/typelike.rb +19 -64
  81. data/lib/jsi/util.rb +52 -34
  82. data/lib/jsi/validation/error.rb +41 -2
  83. data/lib/jsi/validation/result.rb +118 -71
  84. data/lib/jsi/validation.rb +1 -6
  85. data/lib/jsi/version.rb +1 -1
  86. data/lib/jsi.rb +158 -41
  87. data/lib/schemas/json-schema.org/draft/2020-12/schema.rb +67 -0
  88. data/lib/schemas/json-schema.org/draft-04/schema.rb +63 -106
  89. data/lib/schemas/json-schema.org/draft-06/schema.rb +56 -105
  90. data/lib/schemas/json-schema.org/draft-07/schema.rb +67 -124
  91. data/readme.rb +3 -3
  92. data/{resources}/schemas/2020-12_strict.json +19 -0
  93. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/applicator.json +48 -0
  94. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/content.json +17 -0
  95. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/core.json +51 -0
  96. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-annotation.json +14 -0
  97. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-assertion.json +14 -0
  98. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/meta-data.json +37 -0
  99. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/unevaluated.json +15 -0
  100. data/{resources}/schemas/json-schema.org/draft/2020-12/meta/validation.json +98 -0
  101. data/{resources}/schemas/json-schema.org/draft/2020-12/schema.json +58 -0
  102. metadata +69 -47
  103. data/lib/jsi/schema/application/child_application/contains.rb +0 -25
  104. data/lib/jsi/schema/application/child_application/draft04.rb +0 -21
  105. data/lib/jsi/schema/application/child_application/draft06.rb +0 -28
  106. data/lib/jsi/schema/application/child_application/draft07.rb +0 -28
  107. data/lib/jsi/schema/application/child_application/items.rb +0 -18
  108. data/lib/jsi/schema/application/child_application/properties.rb +0 -25
  109. data/lib/jsi/schema/application/child_application.rb +0 -13
  110. data/lib/jsi/schema/application/draft04.rb +0 -8
  111. data/lib/jsi/schema/application/draft06.rb +0 -8
  112. data/lib/jsi/schema/application/draft07.rb +0 -8
  113. data/lib/jsi/schema/application/inplace_application/dependencies.rb +0 -28
  114. data/lib/jsi/schema/application/inplace_application/draft04.rb +0 -25
  115. data/lib/jsi/schema/application/inplace_application/draft06.rb +0 -26
  116. data/lib/jsi/schema/application/inplace_application/draft07.rb +0 -32
  117. data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +0 -20
  118. data/lib/jsi/schema/application/inplace_application/ref.rb +0 -18
  119. data/lib/jsi/schema/application/inplace_application/someof.rb +0 -44
  120. data/lib/jsi/schema/application/inplace_application.rb +0 -14
  121. data/lib/jsi/schema/application.rb +0 -12
  122. data/lib/jsi/schema/ref.rb +0 -186
  123. data/lib/jsi/schema/validation/array.rb +0 -69
  124. data/lib/jsi/schema/validation/contains.rb +0 -25
  125. data/lib/jsi/schema/validation/dependencies.rb +0 -49
  126. data/lib/jsi/schema/validation/draft04/minmax.rb +0 -93
  127. data/lib/jsi/schema/validation/draft04.rb +0 -110
  128. data/lib/jsi/schema/validation/draft06.rb +0 -120
  129. data/lib/jsi/schema/validation/draft07.rb +0 -157
  130. data/lib/jsi/schema/validation/enum.rb +0 -25
  131. data/lib/jsi/schema/validation/ifthenelse.rb +0 -46
  132. data/lib/jsi/schema/validation/items.rb +0 -54
  133. data/lib/jsi/schema/validation/not.rb +0 -20
  134. data/lib/jsi/schema/validation/numeric.rb +0 -121
  135. data/lib/jsi/schema/validation/object.rb +0 -45
  136. data/lib/jsi/schema/validation/pattern.rb +0 -34
  137. data/lib/jsi/schema/validation/properties.rb +0 -101
  138. data/lib/jsi/schema/validation/property_names.rb +0 -32
  139. data/lib/jsi/schema/validation/ref.rb +0 -40
  140. data/lib/jsi/schema/validation/required.rb +0 -27
  141. data/lib/jsi/schema/validation/someof.rb +0 -90
  142. data/lib/jsi/schema/validation/string.rb +0 -47
  143. data/lib/jsi/schema/validation/type.rb +0 -49
  144. data/lib/jsi/schema/validation.rb +0 -49
  145. data/lib/jsi/schema_registry.rb +0 -200
  146. data/lib/jsi/util/private/attr_struct.rb +0 -141
data/lib/jsi/base/node.rb CHANGED
@@ -1,8 +1,10 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module JSI
4
- # module extending a {JSI::Base} object when its instance (its {Base#jsi_node_content})
5
- # is a Hash (or responds to `#to_hash`)
4
+ # Included on {Base} subclasses for instances that are Hash or
5
+ # [#to_hash](https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html#label-Hash-Convertible+Objects).
6
+ #
7
+ # Dynamically defines most methods of Hash to make the JSI duck-type like a Hash.
6
8
  module Base::HashNode
7
9
  # instantiates and yields each property name (hash key) as a JSI described by any `propertyNames` schemas.
8
10
  #
@@ -11,12 +13,8 @@ module JSI
11
13
  def jsi_each_propertyName
12
14
  return to_enum(__method__) { jsi_node_content_hash_pubsend(:size) } unless block_given?
13
15
 
14
- property_schemas = SchemaSet.build do |schemas|
15
- jsi_schemas.each do |s|
16
- if s.keyword?('propertyNames') && s['propertyNames'].is_a?(Schema)
17
- schemas << s['propertyNames']
18
- end
19
- end
16
+ property_schemas = jsi_schemas.each_yield_set do |s, y|
17
+ s.dialect_invoke_each(:propertyNames, &y)
20
18
  end
21
19
  jsi_node_content_hash_pubsend(:each_key) do |key|
22
20
  yield property_schemas.new_jsi(key)
@@ -37,14 +35,14 @@ module JSI
37
35
  nil
38
36
  end
39
37
 
40
- # See {Base#jsi_child_token_in_range?}
41
- def jsi_child_token_in_range?(token)
38
+ # See {Base#jsi_child_token_present?}
39
+ def jsi_child_token_present?(token)
42
40
  jsi_node_content_hash_pubsend(:key?, token)
43
41
  end
44
42
 
45
43
  # See {Base#jsi_node_content_child}
46
44
  def jsi_node_content_child(token)
47
- # I could check token_in_range? and return nil here (as ArrayNode does).
45
+ # I could check token_present? and return nil here (as ArrayNode does).
48
46
  # without that check, if the instance defines Hash#default or #default_proc, that result is returned.
49
47
  # the preferred mechanism for a JSI's default value should be its schema.
50
48
  # but there's no compelling reason not to support both, so I'll return what #[] returns.
@@ -53,6 +51,8 @@ module JSI
53
51
 
54
52
  # See {Base#[]}
55
53
  def [](token, as_jsi: jsi_child_as_jsi_default, use_default: jsi_child_use_default_default)
54
+ raise(BlockGivenError) if block_given?
55
+ token = token.jsi_node_content if token.is_a?(Schema::SchemaAncestorNode)
56
56
  if jsi_node_content_hash_pubsend(:key?, token)
57
57
  jsi_child(token, as_jsi: as_jsi)
58
58
  else
@@ -64,19 +64,45 @@ module JSI
64
64
  end
65
65
  end
66
66
 
67
+ # See [Hash#store](https://ruby-doc.org/current/Hash.html#method-i-store)
68
+ def store(key, value)
69
+ self[key] = value
70
+ end
71
+
72
+ # See {Base#jsi_as_child_default_as_jsi}. true for HashNode.
73
+ def jsi_as_child_default_as_jsi
74
+ true
75
+ end
76
+
67
77
  # yields each Hash key (JSON object property name) and value of this node.
68
78
  #
69
79
  # each yielded key is a key of the instance hash, and each yielded value is the result of {Base#[]}.
70
80
  #
81
+ # @param key_as_jsi (see #each_key)
71
82
  # @param kw keyword arguments are passed to {Base#[]}
72
83
  # @yield [Object, Object] each key and value of this hash node
73
84
  # @return [self, Enumerator] an Enumerator if invoked without a block; otherwise self
74
- def each(**kw, &block)
75
- return to_enum(__method__, **kw) { jsi_node_content_hash_pubsend(:size) } unless block
85
+ def each(key_as_jsi: false, **kw, &block)
86
+ return to_enum(__method__, key_as_jsi: key_as_jsi, **kw) { jsi_node_content_hash_pubsend(:size) } unless block
76
87
  if block.arity > 1
77
- jsi_node_content_hash_pubsend(:each_key) { |k| yield k, self[k, **kw] }
88
+ each_key(key_as_jsi: key_as_jsi) { |k| yield(k, self[k, **kw]) }
78
89
  else
79
- jsi_node_content_hash_pubsend(:each_key) { |k| yield [k, self[k, **kw]] }
90
+ each_key(key_as_jsi: key_as_jsi) { |k| yield([k, self[k, **kw]]) }
91
+ end
92
+ self
93
+ end
94
+
95
+ alias_method(:each_pair, :each)
96
+
97
+ # Yields each key (property name)
98
+ # @param key_as_jsi [Boolean] Yield each key as a JSI instance, per {#jsi_each_propertyName}
99
+ # @yield [String, Base]
100
+ def each_key(key_as_jsi: false, &block)
101
+ return to_enum(__method__, key_as_jsi: key_as_jsi) { size } unless block
102
+ if key_as_jsi
103
+ jsi_each_propertyName(&block)
104
+ else
105
+ jsi_node_content_hash_pubsend(:each_key, &block)
80
106
  end
81
107
  self
82
108
  end
@@ -86,7 +112,7 @@ module JSI
86
112
  # @return [Hash]
87
113
  def to_hash(**kw)
88
114
  hash = {}
89
- jsi_node_content_hash_pubsend(:each_key) { |k| hash[k] = self[k, **kw] }
115
+ each_key { |k| hash[k] = self[k, **kw] }
90
116
  hash.freeze
91
117
  end
92
118
 
@@ -135,7 +161,7 @@ module JSI
135
161
  end
136
162
 
137
163
  # methods that don't look at the value; can skip the overhead of #[] (invoked by #to_hash)
138
- SAFE_KEY_ONLY_METHODS.each do |method_name|
164
+ SAFE_KEY_ONLY_METHODS.reject { |m| instance_method(m).owner == self }.each do |method_name|
139
165
  if Util::LAST_ARGUMENT_AS_KEYWORD_PARAMETERS
140
166
  define_method(method_name) do |*a, &b|
141
167
  jsi_node_content_hash_pubsend(method_name, *a, &b)
@@ -148,8 +174,10 @@ module JSI
148
174
  end
149
175
  end
150
176
 
151
- # module extending a {JSI::Base} object when its instance (its {Base#jsi_node_content})
152
- # is an Array (or responds to `#to_ary`)
177
+ # Included on {Base} subclasses for instances that are Array or
178
+ # [#to_ary](https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html#label-Array-Convertible+Objects).
179
+ #
180
+ # Dynamically defines most methods of Array to make the JSI duck-type like an Array.
153
181
  module Base::ArrayNode
154
182
  # See {Base#jsi_array?}. Always true for ArrayNode.
155
183
  def jsi_array?
@@ -163,16 +191,16 @@ module JSI
163
191
  nil
164
192
  end
165
193
 
166
- # See {Base#jsi_child_token_in_range?}
167
- def jsi_child_token_in_range?(token)
194
+ # See {Base#jsi_child_token_present?}
195
+ def jsi_child_token_present?(token)
168
196
  token.is_a?(Integer) && token >= 0 && token < jsi_node_content_ary_pubsend(:size)
169
197
  end
170
198
 
171
199
  # See {Base#jsi_node_content_child}
172
200
  def jsi_node_content_child(token)
173
- # we check token_in_range? here (unlike HashNode) because we do not want to pass
201
+ # we check token_present? here (unlike HashNode) because we do not want to pass
174
202
  # negative indices, Ranges, or non-Integers to Array#[]
175
- if jsi_child_token_in_range?(token)
203
+ if jsi_child_token_present?(token)
176
204
  jsi_node_content_ary_pubsend(:[], token)
177
205
  else
178
206
  nil
@@ -181,6 +209,8 @@ module JSI
181
209
 
182
210
  # See {Base#[]}
183
211
  def [](token, as_jsi: jsi_child_as_jsi_default, use_default: jsi_child_use_default_default)
212
+ raise(BlockGivenError) if block_given?
213
+ token = token.jsi_node_content if token.is_a?(Schema::SchemaAncestorNode)
184
214
  size = jsi_node_content_ary_pubsend(:size)
185
215
  if token.is_a?(Integer)
186
216
  if token < 0
@@ -240,6 +270,11 @@ module JSI
240
270
  end
241
271
  end
242
272
 
273
+ # See {Base#jsi_as_child_default_as_jsi}. true for ArrayNode.
274
+ def jsi_as_child_default_as_jsi
275
+ true
276
+ end
277
+
243
278
  # yields each array element of this node.
244
279
  #
245
280
  # each yielded element is the result of {Base#[]} for each index of the instance array.
@@ -299,7 +334,7 @@ module JSI
299
334
 
300
335
  # methods that don't look at the value; can skip the overhead of #[] (invoked by #to_a).
301
336
  # we override these methods from Arraylike
302
- SAFE_INDEX_ONLY_METHODS.each do |method_name|
337
+ SAFE_INDEX_ONLY_METHODS.reject { |m| instance_method(m).owner == self }.each do |method_name|
303
338
  if Util::LAST_ARGUMENT_AS_KEYWORD_PARAMETERS
304
339
  define_method(method_name) do |*a, &b|
305
340
  jsi_node_content_ary_pubsend(method_name, *a, &b)
@@ -312,6 +347,10 @@ module JSI
312
347
  end
313
348
  end
314
349
 
350
+ # Included on {Base} subclasses for instances that are String or
351
+ # [#to_str](https://docs.ruby-lang.org/en/master/implicit_conversion_rdoc.html#label-String-Convertible+Objects).
352
+ #
353
+ # Dynamically defines most methods of String to make the JSI duck-type like a String.
315
354
  module Base::StringNode
316
355
  delegate_methods = %w(% * + << =~ [] []=
317
356
  ascii_only? b byteindex byterindex bytes bytesize byteslice bytesplice capitalize capitalize!