jsi 0.8.1 → 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.
- checksums.yaml +4 -4
- data/.yardopts +3 -2
- data/CHANGELOG.md +9 -0
- data/LICENSE.md +2 -3
- data/README.md +68 -31
- data/docs/Glossary.md +313 -0
- data/jsi.gemspec +1 -0
- data/lib/jsi/base/mutability.rb +4 -0
- data/lib/jsi/base/node.rb +63 -24
- data/lib/jsi/base.rb +556 -173
- data/lib/jsi/metaschema_node/bootstrap_schema.rb +106 -56
- data/lib/jsi/metaschema_node.rb +227 -160
- data/lib/jsi/ptr.rb +32 -15
- data/lib/jsi/ref.rb +197 -0
- data/lib/jsi/registry.rb +311 -0
- data/lib/jsi/schema/cxt/child_application.rb +35 -0
- data/lib/jsi/schema/cxt/inplace_application.rb +37 -0
- data/lib/jsi/schema/cxt.rb +80 -0
- data/lib/jsi/schema/dialect.rb +137 -0
- data/lib/jsi/schema/draft04.rb +113 -5
- data/lib/jsi/schema/draft06.rb +123 -5
- data/lib/jsi/schema/draft07.rb +157 -5
- data/lib/jsi/schema/draft202012.rb +303 -0
- data/lib/jsi/schema/dynamic_anchor_map.rb +63 -0
- data/lib/jsi/schema/element.rb +69 -0
- data/lib/jsi/schema/elements/anchor.rb +13 -0
- data/lib/jsi/schema/elements/array_validation.rb +82 -0
- data/lib/jsi/schema/elements/comment.rb +10 -0
- data/lib/jsi/schema/{validation → elements}/const.rb +11 -7
- data/lib/jsi/schema/elements/contains.rb +59 -0
- data/lib/jsi/schema/elements/contains_minmax.rb +91 -0
- data/lib/jsi/schema/elements/content_encoding.rb +10 -0
- data/lib/jsi/schema/elements/content_media_type.rb +10 -0
- data/lib/jsi/schema/elements/content_schema.rb +16 -0
- data/lib/jsi/schema/elements/default.rb +11 -0
- data/lib/jsi/schema/elements/definitions.rb +19 -0
- data/lib/jsi/schema/elements/dependencies.rb +99 -0
- data/lib/jsi/schema/elements/dependent_required.rb +49 -0
- data/lib/jsi/schema/elements/dependent_schemas.rb +69 -0
- data/lib/jsi/schema/elements/dynamic_ref.rb +69 -0
- data/lib/jsi/schema/elements/enum.rb +26 -0
- data/lib/jsi/schema/elements/examples.rb +10 -0
- data/lib/jsi/schema/elements/format.rb +10 -0
- data/lib/jsi/schema/elements/id.rb +30 -0
- data/lib/jsi/schema/elements/if_then_else.rb +82 -0
- data/lib/jsi/schema/elements/info_bool.rb +10 -0
- data/lib/jsi/schema/elements/info_string.rb +10 -0
- data/lib/jsi/schema/elements/items.rb +93 -0
- data/lib/jsi/schema/elements/items_prefixed.rb +96 -0
- data/lib/jsi/schema/elements/not.rb +31 -0
- data/lib/jsi/schema/elements/numeric.rb +137 -0
- data/lib/jsi/schema/elements/numeric_draft04.rb +77 -0
- data/lib/jsi/schema/elements/object_validation.rb +55 -0
- data/lib/jsi/schema/elements/pattern.rb +35 -0
- data/lib/jsi/schema/elements/properties.rb +145 -0
- data/lib/jsi/schema/elements/property_names.rb +48 -0
- data/lib/jsi/schema/elements/ref.rb +62 -0
- data/lib/jsi/schema/elements/required.rb +34 -0
- data/lib/jsi/schema/elements/self.rb +24 -0
- data/lib/jsi/schema/elements/some_of.rb +180 -0
- data/lib/jsi/schema/elements/string_validation.rb +57 -0
- data/lib/jsi/schema/elements/type.rb +43 -0
- data/lib/jsi/schema/elements/unevaluated_items.rb +54 -0
- data/lib/jsi/schema/elements/unevaluated_properties.rb +54 -0
- data/lib/jsi/schema/elements/xschema.rb +10 -0
- data/lib/jsi/schema/elements/xvocabulary.rb +10 -0
- data/lib/jsi/schema/elements.rb +101 -0
- data/lib/jsi/schema/issue.rb +3 -4
- data/lib/jsi/schema/schema_ancestor_node.rb +103 -50
- data/lib/jsi/schema/vocabulary.rb +36 -0
- data/lib/jsi/schema.rb +520 -338
- data/lib/jsi/schema_classes.rb +168 -124
- data/lib/jsi/schema_set.rb +67 -126
- data/lib/jsi/set.rb +23 -0
- data/lib/jsi/simple_wrap.rb +13 -16
- data/lib/jsi/struct.rb +57 -0
- data/lib/jsi/uri.rb +40 -0
- data/lib/jsi/util/private/memo_map.rb +9 -13
- data/lib/jsi/util/private.rb +57 -12
- data/lib/jsi/util/typelike.rb +19 -64
- data/lib/jsi/util.rb +52 -34
- data/lib/jsi/validation/error.rb +41 -2
- data/lib/jsi/validation/result.rb +118 -71
- data/lib/jsi/validation.rb +1 -6
- data/lib/jsi/version.rb +1 -1
- data/lib/jsi.rb +158 -41
- data/lib/schemas/json-schema.org/draft/2020-12/schema.rb +67 -0
- data/lib/schemas/json-schema.org/draft-04/schema.rb +63 -106
- data/lib/schemas/json-schema.org/draft-06/schema.rb +56 -105
- data/lib/schemas/json-schema.org/draft-07/schema.rb +67 -124
- data/readme.rb +3 -3
- data/{resources}/schemas/2020-12_strict.json +19 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/applicator.json +48 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/content.json +17 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/core.json +51 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-annotation.json +14 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/format-assertion.json +14 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/meta-data.json +37 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/unevaluated.json +15 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/meta/validation.json +98 -0
- data/{resources}/schemas/json-schema.org/draft/2020-12/schema.json +58 -0
- metadata +70 -48
- data/lib/jsi/schema/application/child_application/contains.rb +0 -25
- data/lib/jsi/schema/application/child_application/draft04.rb +0 -21
- data/lib/jsi/schema/application/child_application/draft06.rb +0 -28
- data/lib/jsi/schema/application/child_application/draft07.rb +0 -28
- data/lib/jsi/schema/application/child_application/items.rb +0 -18
- data/lib/jsi/schema/application/child_application/properties.rb +0 -25
- data/lib/jsi/schema/application/child_application.rb +0 -13
- data/lib/jsi/schema/application/draft04.rb +0 -8
- data/lib/jsi/schema/application/draft06.rb +0 -8
- data/lib/jsi/schema/application/draft07.rb +0 -8
- data/lib/jsi/schema/application/inplace_application/dependencies.rb +0 -28
- data/lib/jsi/schema/application/inplace_application/draft04.rb +0 -25
- data/lib/jsi/schema/application/inplace_application/draft06.rb +0 -26
- data/lib/jsi/schema/application/inplace_application/draft07.rb +0 -32
- data/lib/jsi/schema/application/inplace_application/ifthenelse.rb +0 -20
- data/lib/jsi/schema/application/inplace_application/ref.rb +0 -18
- data/lib/jsi/schema/application/inplace_application/someof.rb +0 -44
- data/lib/jsi/schema/application/inplace_application.rb +0 -14
- data/lib/jsi/schema/application.rb +0 -12
- data/lib/jsi/schema/ref.rb +0 -186
- data/lib/jsi/schema/validation/array.rb +0 -69
- data/lib/jsi/schema/validation/contains.rb +0 -25
- data/lib/jsi/schema/validation/dependencies.rb +0 -49
- data/lib/jsi/schema/validation/draft04/minmax.rb +0 -93
- data/lib/jsi/schema/validation/draft04.rb +0 -110
- data/lib/jsi/schema/validation/draft06.rb +0 -120
- data/lib/jsi/schema/validation/draft07.rb +0 -157
- data/lib/jsi/schema/validation/enum.rb +0 -25
- data/lib/jsi/schema/validation/ifthenelse.rb +0 -46
- data/lib/jsi/schema/validation/items.rb +0 -54
- data/lib/jsi/schema/validation/not.rb +0 -20
- data/lib/jsi/schema/validation/numeric.rb +0 -121
- data/lib/jsi/schema/validation/object.rb +0 -45
- data/lib/jsi/schema/validation/pattern.rb +0 -34
- data/lib/jsi/schema/validation/properties.rb +0 -101
- data/lib/jsi/schema/validation/property_names.rb +0 -32
- data/lib/jsi/schema/validation/ref.rb +0 -40
- data/lib/jsi/schema/validation/required.rb +0 -27
- data/lib/jsi/schema/validation/someof.rb +0 -90
- data/lib/jsi/schema/validation/string.rb +0 -47
- data/lib/jsi/schema/validation/type.rb +0 -49
- data/lib/jsi/schema/validation.rb +0 -49
- data/lib/jsi/schema_registry.rb +0 -200
- data/lib/jsi/util/private/attr_struct.rb +0 -141
data/lib/jsi/schema_set.rb
CHANGED
|
@@ -4,7 +4,7 @@ module JSI
|
|
|
4
4
|
# a Set of JSI Schemas. always frozen.
|
|
5
5
|
#
|
|
6
6
|
# any schema instance is described by a set of schemas.
|
|
7
|
-
class SchemaSet <
|
|
7
|
+
class SchemaSet < Set
|
|
8
8
|
class << self
|
|
9
9
|
# Builds a SchemaSet, yielding a yielder to be called with each schema of the SchemaSet.
|
|
10
10
|
#
|
|
@@ -13,21 +13,6 @@ module JSI
|
|
|
13
13
|
def build(&block)
|
|
14
14
|
new(Enumerator.new(&block))
|
|
15
15
|
end
|
|
16
|
-
|
|
17
|
-
# ensures the given param becomes a SchemaSet. returns the param if it is already SchemaSet, otherwise
|
|
18
|
-
# initializes a SchemaSet from it.
|
|
19
|
-
#
|
|
20
|
-
# @param schemas [SchemaSet, Enumerable] the object to ensure becomes a SchemaSet
|
|
21
|
-
# @return [SchemaSet] the given SchemaSet, or a SchemaSet initialized from the given Enumerable
|
|
22
|
-
# @raise [ArgumentError] when the schemas param is not an Enumerable
|
|
23
|
-
# @raise [Schema::NotASchemaError] when the schemas param contains objects which are not Schemas
|
|
24
|
-
def ensure_schema_set(schemas)
|
|
25
|
-
if schemas.is_a?(SchemaSet)
|
|
26
|
-
schemas
|
|
27
|
-
else
|
|
28
|
-
new(schemas)
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
16
|
end
|
|
32
17
|
|
|
33
18
|
# initializes a SchemaSet from the given enum and freezes it.
|
|
@@ -36,7 +21,7 @@ module JSI
|
|
|
36
21
|
# if no block is given, the enum must contain only Schemas.
|
|
37
22
|
#
|
|
38
23
|
# @param enum [#each] the schemas to be included in the SchemaSet, or items to be passed to the block
|
|
39
|
-
# @yieldparam yields each element of enum for preprocessing into a Schema
|
|
24
|
+
# @yieldparam yields each element of `enum` for preprocessing into a Schema
|
|
40
25
|
# @yieldreturn [JSI::Schema]
|
|
41
26
|
# @raise [JSI::Schema::NotASchemaError]
|
|
42
27
|
def initialize(enum, &block)
|
|
@@ -53,7 +38,15 @@ module JSI
|
|
|
53
38
|
raise(ArgumentError, "#{SchemaSet} initialized with non-Enumerable: #{enum.pretty_inspect.chomp}")
|
|
54
39
|
end
|
|
55
40
|
|
|
56
|
-
super
|
|
41
|
+
super(&nil) # note super() does implicitly pass block without &nil
|
|
42
|
+
|
|
43
|
+
compare_by_identity
|
|
44
|
+
|
|
45
|
+
if block
|
|
46
|
+
enum.each_entry { |o| add(block[o]) }
|
|
47
|
+
else
|
|
48
|
+
merge(enum)
|
|
49
|
+
end
|
|
57
50
|
|
|
58
51
|
not_schemas = reject { |s| s.is_a?(Schema) }
|
|
59
52
|
if !not_schemas.empty?
|
|
@@ -67,130 +60,85 @@ module JSI
|
|
|
67
60
|
end
|
|
68
61
|
|
|
69
62
|
# Instantiates a new JSI whose content comes from the given `instance` param.
|
|
70
|
-
#
|
|
63
|
+
#
|
|
64
|
+
# The schemas of the JSI (its {Base#jsi_schemas}) are in-place
|
|
71
65
|
# applicators of this set's schemas which apply to the given instance.
|
|
66
|
+
# The JSI's {Base#jsi_indicated_schemas} set is this set.
|
|
67
|
+
#
|
|
68
|
+
# The resulting JSI is an instance of a number of modules:
|
|
69
|
+
#
|
|
70
|
+
# - The {SchemaModule JSI schema module} of each applicator schema.
|
|
71
|
+
# - {Base::HashNode}, {Base::ArrayNode}, or {Base::StringNode} if the instance is
|
|
72
|
+
# a hash/object, array, or string.
|
|
73
|
+
# - A module defining readers for properties described by applicator schemas.
|
|
74
|
+
# If the instance is mutable, writers as well.
|
|
72
75
|
#
|
|
73
76
|
# @param instance [Object] the instance to be represented as a JSI
|
|
74
|
-
# @param
|
|
77
|
+
# @param base_uri [#to_str, URI, nil]
|
|
78
|
+
# The base URI of the instance document. An absolute URI.
|
|
75
79
|
#
|
|
76
|
-
# It is rare that this needs to be specified
|
|
77
|
-
#
|
|
80
|
+
# It is rare that this needs to be specified. It is useful when the instance contains schemas,
|
|
81
|
+
# and schemas in the document use relative URIs for `$id` or `$ref` without an absolute id
|
|
82
|
+
# in an ancestor schema - those URIs will be resolved relative to `base_uri`.
|
|
83
|
+
#
|
|
84
|
+
# See also {Base::Conf conf} {Base::Conf#root_uri `root_uri`}. `base_uri` is not used to identify
|
|
85
|
+
# any resource, only to resolve relative URIs. `root_uri` does identify the root resource.
|
|
78
86
|
# @param register [Boolean] Whether schema resources in the instantiated JSI will be registered
|
|
79
|
-
# in the
|
|
87
|
+
# in the {Base::Conf configured} {Base::Conf#registry `registry`}.
|
|
80
88
|
# This is only useful when the JSI is a schema or contains schemas.
|
|
81
|
-
# The JSI's root will be registered with the `uri` param, if specified, whether or not the
|
|
82
|
-
# root is a schema.
|
|
83
|
-
# @param schema_registry [SchemaRegistry, nil] The registry to use for references to other schemas and,
|
|
84
|
-
# depending on `register` and `uri` params, to register this JSI and/or any contained schemas with
|
|
85
|
-
# declared URIs.
|
|
86
89
|
# @param stringify_symbol_keys [Boolean] Whether the instance content will have any Symbol keys of Hashes
|
|
87
90
|
# replaced with Strings (recursively through the document).
|
|
88
91
|
# Replacement is done on a copy; the given instance is not modified.
|
|
89
|
-
# @param to_immutable [#call, nil] A proc/callable which takes given instance content
|
|
90
|
-
# and results in an immutable (i.e. deeply frozen) object equal to that.
|
|
91
|
-
# If the instantiated JSI will be mutable, this is not used.
|
|
92
|
-
# Though not recommended, this may be nil with immutable JSIs if the instance content is otherwise
|
|
93
|
-
# guaranteed to be immutable, as well as any modified copies of the instance.
|
|
94
92
|
# @param mutable [Boolean] Whether the instantiated JSI will be mutable.
|
|
95
|
-
# The instance content will be transformed with
|
|
96
|
-
#
|
|
97
|
-
#
|
|
93
|
+
# The instance content will be transformed with the {Base::Conf configured}
|
|
94
|
+
# {Base::Conf#to_immutable `to_immutable`} if the JSI will be immutable.
|
|
95
|
+
# @param conf_kw Additional keyword params are passed to initialize a {Base::Conf}, the JSI's {Base#jsi_conf}.
|
|
96
|
+
# @return [Base] a JSI whose content comes from the given instance and whose schemas are
|
|
97
|
+
# in-place applicators of the schemas in this set.
|
|
98
98
|
def new_jsi(instance,
|
|
99
|
-
|
|
99
|
+
base_uri: nil,
|
|
100
100
|
register: false,
|
|
101
|
-
schema_registry: JSI.schema_registry,
|
|
102
101
|
stringify_symbol_keys: false,
|
|
103
|
-
|
|
104
|
-
|
|
102
|
+
mutable: false,
|
|
103
|
+
**conf_kw
|
|
105
104
|
)
|
|
106
|
-
|
|
105
|
+
raise(BlockGivenError) if block_given?
|
|
107
106
|
|
|
108
|
-
|
|
107
|
+
conf = Base::Conf.new(**conf_kw)
|
|
108
|
+
|
|
109
|
+
instance = Util.deep_stringify_symbol_keys(instance) if stringify_symbol_keys
|
|
109
110
|
|
|
110
|
-
|
|
111
|
+
instance = conf.to_immutable.call(instance) if !mutable && conf.to_immutable
|
|
111
112
|
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
end
|
|
116
|
-
uri = Util.uri(uri)
|
|
117
|
-
unless uri.absolute? && !uri.fragment
|
|
118
|
-
raise(ArgumentError, "uri must be an absolute URI with no fragment; got: #{uri.inspect}")
|
|
119
|
-
end
|
|
113
|
+
applied_schemas = SchemaSet.build do |y|
|
|
114
|
+
c = y.method(:yield) # TODO drop c, just pass y, when all supported Enumerator::Yielder.method_defined?(:to_proc)
|
|
115
|
+
each { |is| is.each_inplace_applicator_schema(instance, &c) }
|
|
120
116
|
end
|
|
121
117
|
|
|
118
|
+
base_uri = Util.uri(base_uri, nnil: false, yabs: true) || conf.root_uri
|
|
119
|
+
|
|
122
120
|
jsi_class = JSI::SchemaClasses.class_for_schemas(applied_schemas,
|
|
123
121
|
includes: SchemaClasses.includes_for(instance),
|
|
124
122
|
mutable: mutable,
|
|
125
123
|
)
|
|
126
|
-
jsi = jsi_class.new(
|
|
124
|
+
jsi = jsi_class.new(
|
|
125
|
+
jsi_document: instance,
|
|
127
126
|
jsi_indicated_schemas: self,
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
)
|
|
127
|
+
jsi_base_uri: base_uri,
|
|
128
|
+
jsi_conf: conf,
|
|
129
|
+
).send(:jsi_initialized)
|
|
132
130
|
|
|
133
|
-
|
|
131
|
+
conf.registry.register(jsi) if register && conf.registry
|
|
134
132
|
|
|
135
133
|
jsi
|
|
136
134
|
end
|
|
137
135
|
|
|
138
|
-
# a set of inplace applicator schemas of each schema in this set which apply to the given instance.
|
|
139
|
-
# (see {Schema#inplace_applicator_schemas})
|
|
140
|
-
#
|
|
141
|
-
# @param instance (see Schema#inplace_applicator_schemas)
|
|
142
|
-
# @return [JSI::SchemaSet]
|
|
143
|
-
def inplace_applicator_schemas(instance)
|
|
144
|
-
SchemaSet.new(each_inplace_applicator_schema(instance))
|
|
145
|
-
end
|
|
146
|
-
|
|
147
|
-
# yields each inplace applicator schema which applies to the given instance.
|
|
148
|
-
#
|
|
149
|
-
# @param instance (see Schema#inplace_applicator_schemas)
|
|
150
|
-
# @yield [JSI::Schema]
|
|
151
|
-
# @return [nil, Enumerator] an Enumerator if invoked without a block; otherwise nil
|
|
152
|
-
def each_inplace_applicator_schema(instance, &block)
|
|
153
|
-
return to_enum(__method__, instance) unless block
|
|
154
|
-
|
|
155
|
-
each do |schema|
|
|
156
|
-
schema.each_inplace_applicator_schema(instance, &block)
|
|
157
|
-
end
|
|
158
|
-
|
|
159
|
-
nil
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
# a set of child applicator subschemas of each schema in this set which apply to the child
|
|
163
|
-
# of the given instance on the given token.
|
|
164
|
-
# (see {Schema#child_applicator_schemas})
|
|
165
|
-
#
|
|
166
|
-
# @param instance (see Schema#child_applicator_schemas)
|
|
167
|
-
# @return [JSI::SchemaSet]
|
|
168
|
-
def child_applicator_schemas(token, instance)
|
|
169
|
-
SchemaSet.new(each_child_applicator_schema(token, instance))
|
|
170
|
-
end
|
|
171
|
-
|
|
172
|
-
# yields each child applicator schema which applies to the child of
|
|
173
|
-
# the given instance on the given token.
|
|
174
|
-
#
|
|
175
|
-
# @param (see Schema#child_applicator_schemas)
|
|
176
|
-
# @yield [JSI::Schema]
|
|
177
|
-
# @return [nil, Enumerator] an Enumerator if invoked without a block; otherwise nil
|
|
178
|
-
def each_child_applicator_schema(token, instance, &block)
|
|
179
|
-
return to_enum(__method__, token, instance) unless block
|
|
180
|
-
|
|
181
|
-
each do |schema|
|
|
182
|
-
schema.each_child_applicator_schema(token, instance, &block)
|
|
183
|
-
end
|
|
184
|
-
|
|
185
|
-
nil
|
|
186
|
-
end
|
|
187
|
-
|
|
188
136
|
# validates the given instance against our schemas
|
|
189
137
|
#
|
|
190
138
|
# @param instance [Object] the instance to validate against our schemas
|
|
191
139
|
# @return [JSI::Validation::Result]
|
|
192
140
|
def instance_validate(instance)
|
|
193
|
-
inject(Validation::
|
|
141
|
+
inject(Validation::Result::Full.new) do |result, schema|
|
|
194
142
|
result.merge(schema.instance_validate(instance))
|
|
195
143
|
end.freeze
|
|
196
144
|
end
|
|
@@ -202,26 +150,19 @@ module JSI
|
|
|
202
150
|
all? { |schema| schema.instance_valid?(instance) }
|
|
203
151
|
end
|
|
204
152
|
|
|
205
|
-
# @return [
|
|
206
|
-
def
|
|
207
|
-
|
|
208
|
-
end
|
|
209
|
-
|
|
210
|
-
def to_s
|
|
211
|
-
inspect
|
|
153
|
+
# @return [Set<SchemaModule>]
|
|
154
|
+
def jsi_schema_modules
|
|
155
|
+
Set.new(self, &:jsi_schema_module).freeze
|
|
212
156
|
end
|
|
213
157
|
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
}
|
|
223
|
-
q.breakable ''
|
|
224
|
-
q.text ']'
|
|
158
|
+
# Builds a SchemaSet, yielding each schema and a callable to be called with each schema of the resulting SchemaSet.
|
|
159
|
+
# @yield [Schema, #to_proc]
|
|
160
|
+
# @return [SchemaSet]
|
|
161
|
+
def each_yield_set(&block)
|
|
162
|
+
self.class.new(Enumerator.new do |y|
|
|
163
|
+
c = y.method(:yield) # TODO drop c, just pass y, when all supported Enumerator::Yielder.method_defined?(:to_proc)
|
|
164
|
+
each { |schema| yield(schema, c) }
|
|
165
|
+
end)
|
|
225
166
|
end
|
|
226
167
|
end
|
|
227
168
|
end
|
data/lib/jsi/set.rb
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JSI
|
|
4
|
+
# @private
|
|
5
|
+
class Set < ::Set
|
|
6
|
+
include(Util::Pretty)
|
|
7
|
+
|
|
8
|
+
def pretty_print(q)
|
|
9
|
+
q.text(self.class.to_s)
|
|
10
|
+
q.text('[')
|
|
11
|
+
q.group do
|
|
12
|
+
q.nest(2) do
|
|
13
|
+
q.breakable('')
|
|
14
|
+
q.seplist(self) do |e|
|
|
15
|
+
q.pp(e)
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
q.breakable('')
|
|
19
|
+
end
|
|
20
|
+
q.text(']')
|
|
21
|
+
end
|
|
22
|
+
end
|
|
23
|
+
end
|
data/lib/jsi/simple_wrap.rb
CHANGED
|
@@ -1,26 +1,23 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module JSI
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
4
|
+
dialect = Schema::Dialect.new(
|
|
5
|
+
vocabularies: [
|
|
6
|
+
Schema::Vocabulary.new(elements: [
|
|
7
|
+
Schema::Element.new do |element|
|
|
8
|
+
element.add_action(:inplace_applicate) { inplace_schema_applicate(schema) }
|
|
9
|
+
element.add_action(:child_applicate) { child_schema_applicate(schema) }
|
|
10
|
+
end,
|
|
11
|
+
]),
|
|
12
|
+
],
|
|
13
|
+
)
|
|
8
14
|
|
|
9
|
-
|
|
10
|
-
yield self
|
|
11
|
-
end
|
|
12
|
-
|
|
13
|
-
def internal_validate_keywords(result_builder)
|
|
14
|
-
end
|
|
15
|
-
end
|
|
16
|
-
|
|
17
|
-
simple_wrap_metaschema = JSI.new_metaschema(nil, schema_implementation_modules: [simple_wrap_implementation])
|
|
15
|
+
simple_wrap_metaschema = JSI.new_metaschema_node(nil, dialect: dialect)
|
|
18
16
|
SimpleWrap = simple_wrap_metaschema.new_schema_module(Util::EMPTY_HASH)
|
|
19
17
|
|
|
20
18
|
# SimpleWrap is a JSI schema module which recursively wraps nested structures
|
|
21
|
-
module SimpleWrap
|
|
22
|
-
end
|
|
19
|
+
module SimpleWrap end
|
|
23
20
|
|
|
24
|
-
SimpleWrap::
|
|
21
|
+
SimpleWrap::DIALECT = dialect
|
|
25
22
|
SimpleWrap::METASCHEMA = simple_wrap_metaschema
|
|
26
23
|
end
|
data/lib/jsi/struct.rb
ADDED
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JSI
|
|
4
|
+
# JSI::Struct adds to Struct:
|
|
5
|
+
#
|
|
6
|
+
# - always initialized by keywords
|
|
7
|
+
# - .subclass enables hierarchical class inheritance with added members
|
|
8
|
+
# - better pretty/inspect
|
|
9
|
+
# @private
|
|
10
|
+
class Struct < ::Struct
|
|
11
|
+
include(Util::Pretty)
|
|
12
|
+
|
|
13
|
+
STRUCT_NEW = Struct.singleton_class.instance_method(:new)
|
|
14
|
+
private_constant(:STRUCT_NEW)
|
|
15
|
+
|
|
16
|
+
HAS_KEYWORD_INIT = Struct.new(:_, keyword_init: true) && true rescue false
|
|
17
|
+
private_constant(:HAS_KEYWORD_INIT)
|
|
18
|
+
|
|
19
|
+
class << self
|
|
20
|
+
# @return [Class]
|
|
21
|
+
def subclass(*members)
|
|
22
|
+
#chkbug fail if !members.all? { |m| m.is_a?(Symbol) }
|
|
23
|
+
self_members = self.members rescue [] # NoMethodError on mri, NameError on truffle
|
|
24
|
+
# Struct does not enable adding members to subclasses of its generated classes,
|
|
25
|
+
# but that is still possible by binding Struct.new to the class and calling
|
|
26
|
+
# that with both existing and new members.
|
|
27
|
+
if HAS_KEYWORD_INIT
|
|
28
|
+
STRUCT_NEW.bind(self).call(*self_members, *members, keyword_init: true)
|
|
29
|
+
else
|
|
30
|
+
STRUCT_NEW.bind(self).call(*self_members, *members)
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
if !HAS_KEYWORD_INIT
|
|
36
|
+
def initialize(h = {})
|
|
37
|
+
super(*members.map { |m| h.key?(m) ? h.delete(m) : nil })
|
|
38
|
+
raise(ArgumentError, "#{self.class} given non-members: #{h}") if !h.empty?
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
# @return [self.class]
|
|
43
|
+
def merge(**h)
|
|
44
|
+
self.class.new(**to_h, **h)
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def pretty_print(q)
|
|
48
|
+
jsi_pp_object_group(q) do
|
|
49
|
+
q.seplist(each_pair) do |k, v|
|
|
50
|
+
q.text(k.to_s)
|
|
51
|
+
q.text(': ')
|
|
52
|
+
q.pp(v)
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
end
|
data/lib/jsi/uri.rb
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
module JSI
|
|
4
|
+
# JSI::URI adds to Addressable::URI:
|
|
5
|
+
#
|
|
6
|
+
# - `JSI::URI["http://x"]` parses, and JSI::URI#inspect shows this form, copy/pastable
|
|
7
|
+
# - Immutable when instantiated with `.[]`, `.parse`, or modified-copy instance methods join, merge, or normalize.
|
|
8
|
+
# However `.new` and `#dup` do not freeze for compatibility with some libraries (Faraday) that dup and mutate URIs.
|
|
9
|
+
# @private
|
|
10
|
+
class URI < Addressable::URI
|
|
11
|
+
class << self
|
|
12
|
+
# @param uri [#to_str]
|
|
13
|
+
# @return [URI]
|
|
14
|
+
def [](uri)
|
|
15
|
+
parse(uri)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def parse(uri)
|
|
19
|
+
super.freeze
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def join(uri)
|
|
24
|
+
super.freeze
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
def merge(hash)
|
|
28
|
+
super.freeze
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def normalize
|
|
32
|
+
super.freeze
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
# @return [String]
|
|
36
|
+
def inspect
|
|
37
|
+
-"#{self.class}[#{to_s.inspect}]"
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
@@ -25,15 +25,6 @@ module JSI
|
|
|
25
25
|
end
|
|
26
26
|
|
|
27
27
|
class MemoMap::Mutable < MemoMap
|
|
28
|
-
Result = AttrStruct[*%w(
|
|
29
|
-
value
|
|
30
|
-
inputs
|
|
31
|
-
inputs_hash
|
|
32
|
-
)]
|
|
33
|
-
|
|
34
|
-
class Result
|
|
35
|
-
end
|
|
36
|
-
|
|
37
28
|
def [](**inputs)
|
|
38
29
|
key = key_for(inputs)
|
|
39
30
|
|
|
@@ -43,11 +34,12 @@ module JSI
|
|
|
43
34
|
|
|
44
35
|
result_mutex.synchronize do
|
|
45
36
|
inputs_hash = inputs.hash
|
|
46
|
-
|
|
47
|
-
|
|
37
|
+
result_value, result_inputs, result_inputs_hash = @results[key]
|
|
38
|
+
if inputs_hash == result_inputs_hash && inputs == result_inputs
|
|
39
|
+
result_value
|
|
48
40
|
else
|
|
49
41
|
value = @block.call(**inputs)
|
|
50
|
-
@results[key] =
|
|
42
|
+
@results[key] = [value, inputs, inputs_hash]
|
|
51
43
|
value
|
|
52
44
|
end
|
|
53
45
|
end
|
|
@@ -58,6 +50,8 @@ module JSI
|
|
|
58
50
|
def [](**inputs)
|
|
59
51
|
key = key_for(inputs)
|
|
60
52
|
|
|
53
|
+
return @results[key] if @results.key?(key)
|
|
54
|
+
|
|
61
55
|
result_mutex = @result_mutexes_mutex.synchronize do
|
|
62
56
|
@result_mutexes[key] ||= Mutex.new
|
|
63
57
|
end
|
|
@@ -66,7 +60,9 @@ module JSI
|
|
|
66
60
|
if @results.key?(key)
|
|
67
61
|
@results[key]
|
|
68
62
|
else
|
|
69
|
-
@results[key] = @block.call(**inputs)
|
|
63
|
+
result = @results[key] = @block.call(**inputs)
|
|
64
|
+
@result_mutexes.delete(key)
|
|
65
|
+
result
|
|
70
66
|
end
|
|
71
67
|
end
|
|
72
68
|
end
|
data/lib/jsi/util/private.rb
CHANGED
|
@@ -5,7 +5,6 @@ module JSI
|
|
|
5
5
|
#
|
|
6
6
|
# @api private
|
|
7
7
|
module Util::Private
|
|
8
|
-
autoload :AttrStruct, 'jsi/util/private/attr_struct'
|
|
9
8
|
autoload :MemoMap, 'jsi/util/private/memo_map'
|
|
10
9
|
|
|
11
10
|
extend self
|
|
@@ -69,10 +68,16 @@ module JSI
|
|
|
69
68
|
end
|
|
70
69
|
|
|
71
70
|
def const_name_from_parts(parts, join: '')
|
|
71
|
+
initAZ = false
|
|
72
72
|
parts = parts.map do |part|
|
|
73
|
-
part = part.dup
|
|
74
|
-
|
|
75
|
-
|
|
73
|
+
part = part.to_str.dup
|
|
74
|
+
if !initAZ
|
|
75
|
+
part[/\A[^a-zA-Z]*/] = ''
|
|
76
|
+
end
|
|
77
|
+
if part[0]
|
|
78
|
+
part[0] = part[0].upcase
|
|
79
|
+
initAZ = true
|
|
80
|
+
end
|
|
76
81
|
part.gsub!(RUBY_REJECT_NAME_RE, '_')
|
|
77
82
|
part
|
|
78
83
|
end
|
|
@@ -83,18 +88,46 @@ module JSI
|
|
|
83
88
|
end
|
|
84
89
|
end
|
|
85
90
|
|
|
91
|
+
if JSON.parse('[]', freeze: true).frozen?
|
|
92
|
+
def json_parse_freeze(json)
|
|
93
|
+
JSON.parse(json, freeze: true)
|
|
94
|
+
end
|
|
95
|
+
else
|
|
96
|
+
def json_parse_freeze(json)
|
|
97
|
+
Util.deep_to_frozen(JSON.parse(json))
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
86
101
|
# string or URI → frozen URI
|
|
87
|
-
# @
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
102
|
+
# @param nnil must not be nil
|
|
103
|
+
# @param yabs must be absolute
|
|
104
|
+
# @param ynorm must be normalized
|
|
105
|
+
# @param tonorm normalize returned URI
|
|
106
|
+
# @return [URI, nil]
|
|
107
|
+
def uri(uri, nnil: false, yabs: false, ynorm: false, tonorm: false)
|
|
108
|
+
return nil if !nnil && uri.nil?
|
|
109
|
+
if uri.is_a?(URI)
|
|
110
|
+
auri = uri
|
|
111
|
+
elsif uri.is_a?(String) || uri.respond_to?(:to_str)
|
|
112
|
+
auri = URI.parse(uri)
|
|
113
|
+
else
|
|
114
|
+
raise(URIError, "URI is not a string: #{uri.inspect}")
|
|
115
|
+
end
|
|
116
|
+
if yabs && !auri.scheme
|
|
117
|
+
raise(URIError, "URI must be an absolute URI. got: #{uri.inspect}")
|
|
118
|
+
end
|
|
119
|
+
if yabs && auri.fragment
|
|
120
|
+
if auri.fragment.empty?
|
|
121
|
+
auri = auri.merge(fragment: nil)
|
|
92
122
|
else
|
|
93
|
-
uri.
|
|
123
|
+
raise(URIError, "URI must have no fragment. got: #{uri.inspect}")
|
|
94
124
|
end
|
|
95
|
-
else
|
|
96
|
-
Addressable::URI.parse(uri).freeze
|
|
97
125
|
end
|
|
126
|
+
if ynorm && uri.to_str != auri.normalize.to_s
|
|
127
|
+
raise(URIError, "URI must be in normalized form. got: #{uri.inspect}; normalized: #{auri.normalize.to_s.inspect}")
|
|
128
|
+
end
|
|
129
|
+
auri = auri.normalize if tonorm
|
|
130
|
+
auri
|
|
98
131
|
end
|
|
99
132
|
|
|
100
133
|
# this is the Y-combinator, which allows anonymous recursive functions. for a simple example,
|
|
@@ -141,6 +174,18 @@ module JSI
|
|
|
141
174
|
nil
|
|
142
175
|
end
|
|
143
176
|
|
|
177
|
+
# @param visited_refs [Array<Schema::Ref>]
|
|
178
|
+
# @param ref [Schema::Ref, nil]
|
|
179
|
+
# @return [Array<Schema::Ref>]
|
|
180
|
+
def add_visited_ref(visited_refs, ref)
|
|
181
|
+
return(visited_refs) if ref.nil?
|
|
182
|
+
#chkbug fail unless ref.is_a?(Schema::Ref) && visited_refs.is_a?(Array) && visited_refs.frozen?
|
|
183
|
+
if visited_refs.include?(ref)
|
|
184
|
+
raise(ResolutionError, "cyclical ref application with refs: #{visited_refs}")
|
|
185
|
+
end
|
|
186
|
+
visited_refs.dup.push(ref).freeze
|
|
187
|
+
end
|
|
188
|
+
|
|
144
189
|
# Defines equality methods and #hash (for Hash / Set), based on a method #jsi_fingerprint
|
|
145
190
|
# implemented by the includer. #jsi_fingerprint is to include the class and any properties
|
|
146
191
|
# of the instance which constitute its identity.
|