Class: JSONSchemer::Schema
- Inherits:
-
Object
- Object
- JSONSchemer::Schema
- Extended by:
- Forwardable
- Includes:
- Output
- Defined in:
- lib/json_schemer/schema.rb
Defined Under Namespace
Classes: Context
Constant Summary collapse
- SCHEMA_KEYWORD_CLASS =
Draft202012::Vocab::Core::Schema
- VOCABULARY_KEYWORD_CLASS =
Draft202012::Vocab::Core::Vocabulary
- ID_KEYWORD_CLASS =
Draft202012::Vocab::Core::Id
- UNKNOWN_KEYWORD_CLASS =
Draft202012::Vocab::Core::UnknownKeyword
- NOT_KEYWORD_CLASS =
Draft202012::Vocab::Applicator::Not
- PROPERTIES_KEYWORD_CLASS =
Draft202012::Vocab::Applicator::Properties
- NET_HTTP_REF_RESOLVER =
proc { |uri| JSON.parse(Net::HTTP.get(uri)) }
- RUBY_REGEXP_RESOLVER =
proc { |pattern| Regexp.new(pattern) }
- ECMA_REGEXP_RESOLVER =
proc { |pattern| Regexp.new(EcmaRegexp.ruby_equivalent(pattern)) }
- DEFAULT_PROPERTY_DEFAULT_RESOLVER =
proc do |instance, property, results_with_tree_validity| results_with_tree_validity = results_with_tree_validity.select(&:last) unless results_with_tree_validity.size == 1 annotations = results_with_tree_validity.to_set { |result, _tree_valid| result.annotation } if annotations.size == 1 instance[property] = annotations.first.clone true else false end end
- SYMBOL_PROPERTY_DEFAULT_RESOLVER =
proc do |instance, property, results_with_tree_validity| DEFAULT_PROPERTY_DEFAULT_RESOLVER.call(instance, property.to_sym, results_with_tree_validity) end
Constants included from Output
Instance Attribute Summary collapse
-
#base_uri ⇒ Object
Returns the value of attribute base_uri.
-
#configuration ⇒ Object
readonly
Returns the value of attribute configuration.
-
#keyword_order ⇒ Object
Returns the value of attribute keyword_order.
-
#keywords ⇒ Object
Returns the value of attribute keywords.
-
#meta_schema ⇒ Object
Returns the value of attribute meta_schema.
-
#parent ⇒ Object
readonly
Returns the value of attribute parent.
-
#parsed ⇒ Object
readonly
Returns the value of attribute parsed.
-
#root ⇒ Object
readonly
Returns the value of attribute root.
-
#value ⇒ Object
readonly
Returns the value of attribute value.
Attributes included from Output
Instance Method Summary collapse
- #absolute_keyword_location ⇒ Object
- #bundle ⇒ Object
- #defs_keyword ⇒ Object
- #error(formatted_instance_location:, **options) ⇒ Object
- #error_key ⇒ Object
- #fetch(key) ⇒ Object
- #fetch_content_encoding(content_encoding, *args, &block) ⇒ Object
- #fetch_content_media_type(content_media_type, *args, &block) ⇒ Object
- #fetch_format(format, *args, &block) ⇒ Object
- #id_keyword ⇒ Object
-
#initialize(value, parent = nil, root = self, keyword = nil, configuration: JSONSchemer.configuration, base_uri: configuration.base_uri, meta_schema: configuration.meta_schema, vocabulary: configuration.vocabulary, format: configuration.format, formats: configuration.formats, content_encodings: configuration.content_encodings, content_media_types: configuration.content_media_types, keywords: configuration.keywords, before_property_validation: configuration.before_property_validation, after_property_validation: configuration.after_property_validation, insert_property_defaults: configuration.insert_property_defaults, property_default_resolver: configuration.property_default_resolver, ref_resolver: configuration.ref_resolver, regexp_resolver: configuration.regexp_resolver, output_format: configuration.output_format, resolve_enumerators: configuration.resolve_enumerators, access_mode: configuration.access_mode) ⇒ Schema
constructor
A new instance of Schema.
- #inspect ⇒ Object
- #ref(value) ⇒ Object
- #ref_resolver ⇒ Object
- #regexp_resolver ⇒ Object
- #resolve_ref(uri) ⇒ Object
- #resolve_regexp(pattern) ⇒ Object
- #resources ⇒ Object
- #schema_pointer ⇒ Object
- #valid?(instance, **options) ⇒ Boolean
- #valid_schema?(**options) ⇒ Boolean
- #validate(instance, output_format: @configuration.output_format, resolve_enumerators: @configuration.resolve_enumerators, access_mode: @configuration.access_mode) ⇒ Object
- #validate_instance(instance, instance_location, keyword_location, context) ⇒ Object
- #validate_schema(**options) ⇒ Object
Methods included from Output
Constructor Details
permalink #initialize(value, parent = nil, root = self, keyword = nil, configuration: JSONSchemer.configuration, base_uri: configuration.base_uri, meta_schema: configuration.meta_schema, vocabulary: configuration.vocabulary, format: configuration.format, formats: configuration.formats, content_encodings: configuration.content_encodings, content_media_types: configuration.content_media_types, keywords: configuration.keywords, before_property_validation: configuration.before_property_validation, after_property_validation: configuration.after_property_validation, insert_property_defaults: configuration.insert_property_defaults, property_default_resolver: configuration.property_default_resolver, ref_resolver: configuration.ref_resolver, regexp_resolver: configuration.regexp_resolver, output_format: configuration.output_format, resolve_enumerators: configuration.resolve_enumerators, access_mode: configuration.access_mode) ⇒ Schema
Returns a new instance of Schema.
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 |
# File 'lib/json_schemer/schema.rb', line 51 def initialize( value, parent = nil, root = self, keyword = nil, configuration: JSONSchemer.configuration, base_uri: configuration.base_uri, meta_schema: configuration., vocabulary: configuration.vocabulary, format: configuration.format, formats: configuration.formats, content_encodings: configuration.content_encodings, content_media_types: configuration.content_media_types, keywords: configuration.keywords, before_property_validation: configuration.before_property_validation, after_property_validation: configuration.after_property_validation, insert_property_defaults: configuration.insert_property_defaults, property_default_resolver: configuration.property_default_resolver, ref_resolver: configuration.ref_resolver, regexp_resolver: configuration.regexp_resolver, output_format: configuration.output_format, resolve_enumerators: configuration.resolve_enumerators, access_mode: configuration.access_mode ) @value = deep_stringify_keys(value) @parent = parent @root = root @keyword = keyword @schema = self @base_uri = base_uri @meta_schema = @configuration = Configuration.new( :base_uri => base_uri, :meta_schema => , :vocabulary => vocabulary, :format => format, :formats => formats, :content_encodings => content_encodings, :content_media_types => content_media_types, :keywords => keywords, :before_property_validation => Array(before_property_validation), :after_property_validation => Array(after_property_validation), :insert_property_defaults => insert_property_defaults, :property_default_resolver => property_default_resolver, :ref_resolver => ref_resolver, :regexp_resolver => regexp_resolver, :output_format => output_format, :resolve_enumerators => resolve_enumerators, :access_mode => access_mode ) @parsed = parse end |
Instance Attribute Details
permalink #base_uri ⇒ Object
Returns the value of attribute base_uri.
46 47 48 |
# File 'lib/json_schemer/schema.rb', line 46 def base_uri @base_uri end |
permalink #configuration ⇒ Object (readonly)
Returns the value of attribute configuration.
47 48 49 |
# File 'lib/json_schemer/schema.rb', line 47 def configuration @configuration end |
permalink #keyword_order ⇒ Object
Returns the value of attribute keyword_order.
46 47 48 |
# File 'lib/json_schemer/schema.rb', line 46 def keyword_order @keyword_order end |
permalink #keywords ⇒ Object
Returns the value of attribute keywords.
46 47 48 |
# File 'lib/json_schemer/schema.rb', line 46 def keywords @keywords end |
permalink #meta_schema ⇒ Object
Returns the value of attribute meta_schema.
46 47 48 |
# File 'lib/json_schemer/schema.rb', line 46 def @meta_schema end |
permalink #parent ⇒ Object (readonly)
Returns the value of attribute parent.
47 48 49 |
# File 'lib/json_schemer/schema.rb', line 47 def parent @parent end |
permalink #parsed ⇒ Object (readonly)
Returns the value of attribute parsed.
47 48 49 |
# File 'lib/json_schemer/schema.rb', line 47 def parsed @parsed end |
permalink #root ⇒ Object (readonly)
Returns the value of attribute root.
47 48 49 |
# File 'lib/json_schemer/schema.rb', line 47 def root @root end |
permalink #value ⇒ Object (readonly)
Returns the value of attribute value.
47 48 49 |
# File 'lib/json_schemer/schema.rb', line 47 def value @value end |
Instance Method Details
permalink #absolute_keyword_location ⇒ Object
[View source]
272 273 274 275 276 277 278 279 280 281 282 283 |
# File 'lib/json_schemer/schema.rb', line 272 def absolute_keyword_location # using `equal?` because `URI::Generic#==` is slow @absolute_keyword_location ||= if !parent || (!parent.schema.base_uri.equal?(base_uri) && (base_uri.fragment.nil? || base_uri.fragment.empty?)) absolute_keyword_location_uri = base_uri.dup absolute_keyword_location_uri.fragment = '' absolute_keyword_location_uri.to_s elsif keyword "#{parent.absolute_keyword_location}/#{fragment_encode(escaped_keyword)}" else parent.absolute_keyword_location end end |
permalink #bundle ⇒ Object
[View source]
223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 |
# File 'lib/json_schemer/schema.rb', line 223 def bundle return value unless value.is_a?(Hash) id_keyword = .id_keyword defs_keyword = .defs_keyword compound_document = value.dup compound_document[id_keyword] = base_uri.to_s compound_document['$schema'] = .base_uri.to_s = compound_document[defs_keyword] = (compound_document[defs_keyword]&.dup || {}) if compound_document.key?('$ref') && .keywords.fetch('$ref').exclusive? compound_document['allOf'] = (compound_document['allOf']&.dup || []) compound_document['allOf'] << { '$ref' => compound_document.delete('$ref') } end values = [self] while value = values.shift case value when Schema values << value.parsed when Keyword if value.respond_to?(:ref_uri) && value.respond_to?(:ref_schema) ref_uri = value.ref_uri.dup ref_uri.fragment = nil ref_id = ref_uri.to_s ref_schema = value.ref_schema.root next if ref_schema == root || .key?(ref_id) = ref_schema.value.dup [id_keyword] = ref_id ['$schema'] = ref_schema..base_uri.to_s [ref_id] = values << ref_schema else values << value.parsed end when Hash values.concat(value.values) when Array values.concat(value) end end compound_document end |
permalink #defs_keyword ⇒ Object
[View source]
331 332 333 |
# File 'lib/json_schemer/schema.rb', line 331 def defs_keyword @defs_keyword ||= (keywords.key?('$defs') ? '$defs' : 'definitions') end |
permalink #error(formatted_instance_location:, **options) ⇒ Object
[View source]
339 340 341 342 343 344 345 |
# File 'lib/json_schemer/schema.rb', line 339 def error(formatted_instance_location:, **) if value == false && parent&.respond_to?(:false_schema_error) parent.false_schema_error(:formatted_instance_location => formatted_instance_location, **) else "value at #{formatted_instance_location} does not match schema" end end |
permalink #error_key ⇒ Object
[View source]
295 296 297 |
# File 'lib/json_schemer/schema.rb', line 295 def error_key '^' end |
permalink #fetch(key) ⇒ Object
[View source]
299 300 301 |
# File 'lib/json_schemer/schema.rb', line 299 def fetch(key) parsed.fetch(key) end |
permalink #fetch_content_encoding(content_encoding, *args, &block) ⇒ Object
[View source]
311 312 313 314 315 316 317 |
# File 'lib/json_schemer/schema.rb', line 311 def fetch_content_encoding(content_encoding, *args, &block) if == self content_encodings.fetch(content_encoding, *args, &block) else content_encodings.fetch(content_encoding) { .fetch_content_encoding(content_encoding, *args, &block) } end end |
permalink #fetch_content_media_type(content_media_type, *args, &block) ⇒ Object
[View source]
319 320 321 322 323 324 325 |
# File 'lib/json_schemer/schema.rb', line 319 def fetch_content_media_type(content_media_type, *args, &block) if == self content_media_types.fetch(content_media_type, *args, &block) else content_media_types.fetch(content_media_type) { .fetch_content_media_type(content_media_type, *args, &block) } end end |
permalink #fetch_format(format, *args, &block) ⇒ Object
[View source]
303 304 305 306 307 308 309 |
# File 'lib/json_schemer/schema.rb', line 303 def fetch_format(format, *args, &block) if == self formats.fetch(format, *args, &block) else formats.fetch(format) { .fetch_format(format, *args, &block) } end end |
permalink #id_keyword ⇒ Object
[View source]
327 328 329 |
# File 'lib/json_schemer/schema.rb', line 327 def id_keyword @id_keyword ||= (keywords.key?('$id') ? '$id' : 'id') end |
permalink #inspect ⇒ Object
[View source]
362 363 364 |
# File 'lib/json_schemer/schema.rb', line 362 def inspect "#<#{self.class.name} @value=#{@value.inspect} @parent=#{@parent.inspect} @keyword=#{@keyword.inspect}>" end |
permalink #ref(value) ⇒ Object
[View source]
128 129 130 |
# File 'lib/json_schemer/schema.rb', line 128 def ref(value) root.resolve_ref(URI.join(base_uri, value)) end |
permalink #ref_resolver ⇒ Object
[View source]
347 348 349 |
# File 'lib/json_schemer/schema.rb', line 347 def ref_resolver @ref_resolver ||= @configuration.ref_resolver == 'net/http' ? CachedResolver.new(&NET_HTTP_REF_RESOLVER) : @configuration.ref_resolver end |
permalink #regexp_resolver ⇒ Object
[View source]
351 352 353 354 355 356 357 358 359 360 |
# File 'lib/json_schemer/schema.rb', line 351 def regexp_resolver @regexp_resolver ||= case @configuration.regexp_resolver when 'ecma' CachedResolver.new(&ECMA_REGEXP_RESOLVER) when 'ruby' CachedResolver.new(&RUBY_REGEXP_RESOLVER) else @configuration.regexp_resolver end end |
permalink #resolve_ref(uri) ⇒ Object
175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 |
# File 'lib/json_schemer/schema.rb', line 175 def resolve_ref(uri) pointer = '' if Format.valid_json_pointer?(uri.fragment) pointer = URI.decode_www_form_component(uri.fragment) uri.fragment = nil end lexical_resources = resources.fetch(:lexical) schema = lexical_resources[uri] if !schema && uri.fragment.nil? empty_fragment_uri = uri.dup empty_fragment_uri.fragment = '' schema = lexical_resources[empty_fragment_uri] end unless schema location_independent_identifier = uri.fragment uri.fragment = nil remote_schema = JSONSchemer.schema( ref_resolver.call(uri) || raise(InvalidRefResolution, uri.to_s), :configuration => configuration, :base_uri => uri, :meta_schema => , :ref_resolver => ref_resolver, :regexp_resolver => regexp_resolver ) remote_uri = remote_schema.base_uri.dup remote_uri.fragment = location_independent_identifier if location_independent_identifier schema = remote_schema.resources.fetch(:lexical).fetch(remote_uri) end schema = Hana::Pointer.parse(pointer).reduce(schema) do |obj, token| obj.fetch(token) rescue IndexError raise InvalidRefPointer, pointer end schema = schema.parsed_schema if schema.is_a?(Keyword) raise InvalidRefPointer, pointer unless schema.is_a?(Schema) schema end |
permalink #resolve_regexp(pattern) ⇒ Object
[View source]
219 220 221 |
# File 'lib/json_schemer/schema.rb', line 219 def resolve_regexp(pattern) regexp_resolver.call(pattern) || raise(InvalidRegexpResolution, pattern) end |
permalink #resources ⇒ Object
[View source]
335 336 337 |
# File 'lib/json_schemer/schema.rb', line 335 def resources @resources ||= { :lexical => Resources.new, :dynamic => Resources.new } end |
permalink #schema_pointer ⇒ Object
[View source]
285 286 287 288 289 290 291 292 293 |
# File 'lib/json_schemer/schema.rb', line 285 def schema_pointer @schema_pointer ||= if !parent '' elsif keyword "#{parent.schema_pointer}/#{escaped_keyword}" else parent.schema_pointer end end |
permalink #valid?(instance, **options) ⇒ Boolean
104 105 106 |
# File 'lib/json_schemer/schema.rb', line 104 def valid?(instance, **) validate(instance, :output_format => 'flag', **).fetch('valid') end |
permalink #valid_schema?(**options) ⇒ Boolean
120 121 122 |
# File 'lib/json_schemer/schema.rb', line 120 def valid_schema?(**) .valid?(value, **) end |
permalink #validate(instance, output_format: @configuration.output_format, resolve_enumerators: @configuration.resolve_enumerators, access_mode: @configuration.access_mode) ⇒ Object
[View source]
108 109 110 111 112 113 114 115 116 117 118 |
# File 'lib/json_schemer/schema.rb', line 108 def validate(instance, output_format: @configuration.output_format, resolve_enumerators: @configuration.resolve_enumerators, access_mode: @configuration.access_mode) instance_location = Location.root context = Context.new(instance, [], nil, (!insert_property_defaults && output_format == 'flag'), access_mode) result = validate_instance(deep_stringify_keys(instance), instance_location, root_keyword_location, context) if insert_property_defaults && result.insert_property_defaults(context, &property_default_resolver) result = validate_instance(deep_stringify_keys(instance), instance_location, root_keyword_location, context) end output = result.output(output_format) resolve_enumerators!(output) if resolve_enumerators output end |
permalink #validate_instance(instance, instance_location, keyword_location, context) ⇒ Object
[View source]
132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 |
# File 'lib/json_schemer/schema.rb', line 132 def validate_instance(instance, instance_location, keyword_location, context) context.dynamic_scope.push(self) original_adjacent_results = context.adjacent_results adjacent_results = context.adjacent_results = {} short_circuit = context.short_circuit begin return result(instance, instance_location, keyword_location, false) if value == false return result(instance, instance_location, keyword_location, true) if value == true || value.empty? valid = true nested = [] parsed.each do |keyword, keyword_instance| next unless keyword_result = keyword_instance.validate(instance, instance_location, join_location(keyword_location, keyword), context) valid &&= keyword_result.valid return result(instance, instance_location, keyword_location, false) if short_circuit && !valid nested << keyword_result adjacent_results[keyword_instance.class] = keyword_result end if root.custom_keywords.any? resolved_instance_location = Location.resolve(instance_location) root.custom_keywords.each do |custom_keyword, callable| if value.key?(custom_keyword) [*callable.call(instance, value, resolved_instance_location)].each do |custom_keyword_result| custom_keyword_valid = custom_keyword_result == true valid &&= custom_keyword_valid type = custom_keyword_result.is_a?(String) ? custom_keyword_result : custom_keyword details = { 'keyword' => custom_keyword, 'result' => custom_keyword_result } nested << result(instance, instance_location, keyword_location, custom_keyword_valid, :type => type, :details => details) end end end end result(instance, instance_location, keyword_location, valid, nested) ensure context.dynamic_scope.pop context.adjacent_results = original_adjacent_results end end |
permalink #validate_schema(**options) ⇒ Object
[View source]
124 125 126 |
# File 'lib/json_schemer/schema.rb', line 124 def validate_schema(**) .validate(value, **) end |