Skip to content

Commit

Permalink
Merge pull request #170 from omkarmoghe/default-config
Browse files Browse the repository at this point in the history
Global configuration options
  • Loading branch information
davishmcclurg committed Mar 2, 2024
2 parents 2eeef77 + 6b536e8 commit 8803d3b
Show file tree
Hide file tree
Showing 9 changed files with 456 additions and 66 deletions.
17 changes: 11 additions & 6 deletions lib/json_schemer.rb
Original file line number Diff line number Diff line change
Expand Up @@ -59,10 +59,10 @@
require 'json_schemer/openapi30/vocab/base'
require 'json_schemer/openapi30/vocab'
require 'json_schemer/openapi'
require 'json_schemer/configuration'
require 'json_schemer/schema'

module JSONSchemer
class UnsupportedMetaSchema < StandardError; end
class UnsupportedOpenAPIVersion < StandardError; end
class UnknownRef < StandardError; end
class UnknownFormat < StandardError; end
Expand Down Expand Up @@ -113,12 +113,9 @@ class InvalidEcmaRegexp < StandardError; end
end

class << self
def schema(schema, meta_schema: draft202012, **options)
def schema(schema, **options)
schema = resolve(schema, options)
unless meta_schema.is_a?(Schema)
meta_schema = META_SCHEMAS_BY_BASE_URI_STR[meta_schema] || raise(UnsupportedMetaSchema, meta_schema)
end
Schema.new(schema, :meta_schema => meta_schema, **options)
Schema.new(schema, **options)
end

def valid_schema?(schema, **options)
Expand Down Expand Up @@ -235,6 +232,14 @@ def openapi(document, **options)
OpenAPI.new(document, **options)
end

def configuration
@configuration ||= Configuration.new
end

def configure
yield configuration
end

private

def resolve(schema, options)
Expand Down
32 changes: 32 additions & 0 deletions lib/json_schemer/configuration.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# frozen_string_literal: true

module JSONSchemer
Configuration = Struct.new(
:base_uri, :meta_schema, :vocabulary, :format, :formats, :content_encodings, :content_media_types, :keywords,
:before_property_validation, :after_property_validation, :insert_property_defaults, :property_default_resolver,
:ref_resolver, :regexp_resolver, :output_format, :resolve_enumerators, :access_mode,
keyword_init: true
) do
def initialize(
base_uri: URI('json-schemer://schema'),
meta_schema: Draft202012::BASE_URI.to_s,
vocabulary: nil,
format: true,
formats: {},
content_encodings: {},
content_media_types: {},
keywords: {},
before_property_validation: [],
after_property_validation: [],
insert_property_defaults: false,
property_default_resolver: nil,
ref_resolver: proc { |uri| raise UnknownRef, uri.to_s },
regexp_resolver: 'ruby',
output_format: 'classic',
resolve_enumerators: false,
access_mode: nil
)
super
end
end
end
3 changes: 3 additions & 0 deletions lib/json_schemer/keyword.rb
Original file line number Diff line number Diff line change
Expand Up @@ -45,8 +45,11 @@ def parse
end

def subschema(value, keyword = nil, **options)
options[:configuration] ||= schema.configuration
options[:base_uri] ||= schema.base_uri
options[:meta_schema] ||= schema.meta_schema
options[:ref_resolver] ||= schema.ref_resolver
options[:regexp_resolver] ||= schema.regexp_resolver
Schema.new(value, self, root, keyword, **options)
end
end
Expand Down
6 changes: 2 additions & 4 deletions lib/json_schemer/openapi.rb
Original file line number Diff line number Diff line change
Expand Up @@ -8,16 +8,14 @@ def initialize(document, **options)
case version
when /\A3\.1\.\d+\z/
@document_schema = JSONSchemer.openapi31_document
json_schema_dialect = document.fetch('jsonSchemaDialect') { OpenAPI31::BASE_URI.to_s }
meta_schema = document.fetch('jsonSchemaDialect') { OpenAPI31::BASE_URI.to_s }
when /\A3\.0\.\d+\z/
@document_schema = JSONSchemer.openapi30_document
json_schema_dialect = OpenAPI30::BASE_URI.to_s
meta_schema = OpenAPI30::BASE_URI.to_s
else
raise UnsupportedOpenAPIVersion, version
end

meta_schema = META_SCHEMAS_BY_BASE_URI_STR[json_schema_dialect] || raise(UnsupportedMetaSchema, json_schema_dialect)

@schema = JSONSchemer.schema(@document, :meta_schema => meta_schema, **options)
end

Expand Down
91 changes: 39 additions & 52 deletions lib/json_schemer/schema.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,21 +17,13 @@ def original_instance(instance_location)

include Output

DEFAULT_SCHEMA = Draft202012::BASE_URI.to_s.freeze
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
DEFAULT_BASE_URI = URI('json-schemer://schema').freeze
DEFAULT_FORMATS = {}.freeze
DEFAULT_CONTENT_ENCODINGS = {}.freeze
DEFAULT_CONTENT_MEDIA_TYPES = {}.freeze
DEFAULT_KEYWORDS = {}.freeze
DEFAULT_BEFORE_PROPERTY_VALIDATION = [].freeze
DEFAULT_AFTER_PROPERTY_VALIDATION = [].freeze
DEFAULT_REF_RESOLVER = proc { |uri| raise UnknownRef, uri.to_s }

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)) }
Expand All @@ -51,37 +43,39 @@ def original_instance(instance_location)
end

attr_accessor :base_uri, :meta_schema, :keywords, :keyword_order
attr_reader :value, :parent, :root, :parsed
attr_reader :value, :parent, :root, :configuration, :parsed
attr_reader :vocabulary, :format, :formats, :content_encodings, :content_media_types, :custom_keywords, :before_property_validation, :after_property_validation, :insert_property_defaults

def initialize(
value,
parent = nil,
root = self,
keyword = nil,
base_uri: DEFAULT_BASE_URI,
meta_schema: nil,
vocabulary: nil,
format: true,
formats: DEFAULT_FORMATS,
content_encodings: DEFAULT_CONTENT_ENCODINGS,
content_media_types: DEFAULT_CONTENT_MEDIA_TYPES,
keywords: DEFAULT_KEYWORDS,
before_property_validation: DEFAULT_BEFORE_PROPERTY_VALIDATION,
after_property_validation: DEFAULT_AFTER_PROPERTY_VALIDATION,
insert_property_defaults: false,
property_default_resolver: nil,
ref_resolver: DEFAULT_REF_RESOLVER,
regexp_resolver: 'ruby',
output_format: 'classic',
resolve_enumerators: false,
access_mode: 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
)
@value = deep_stringify_keys(value)
@parent = parent
@root = root
@keyword = keyword
@schema = self
@configuration = configuration
@base_uri = base_uri
@meta_schema = meta_schema
@vocabulary = vocabulary
Expand Down Expand Up @@ -194,16 +188,9 @@ def resolve_ref(uri)
uri.fragment = nil
remote_schema = JSONSchemer.schema(
ref_resolver.call(uri) || raise(InvalidRefResolution, uri.to_s),
:configuration => configuration,
:base_uri => uri,
:meta_schema => meta_schema,
:format => format,
:formats => formats,
:content_encodings => content_encodings,
:content_media_types => content_media_types,
:keywords => custom_keywords,
:before_property_validation => before_property_validation,
:after_property_validation => after_property_validation,
:property_default_resolver => property_default_resolver,
:ref_resolver => ref_resolver,
:regexp_resolver => regexp_resolver
)
Expand Down Expand Up @@ -352,6 +339,21 @@ def error(formatted_instance_location:, **options)
end
end

def ref_resolver
@ref_resolver ||= @original_ref_resolver == 'net/http' ? CachedResolver.new(&NET_HTTP_REF_RESOLVER) : @original_ref_resolver
end

def regexp_resolver
@regexp_resolver ||= case @original_regexp_resolver
when 'ecma'
CachedResolver.new(&ECMA_REGEXP_RESOLVER)
when 'ruby'
CachedResolver.new(&RUBY_REGEXP_RESOLVER)
else
@original_regexp_resolver
end
end

def inspect
"#<#{self.class.name} @value=#{@value.inspect} @parent=#{@parent.inspect} @keyword=#{@keyword.inspect}>"
end
Expand All @@ -363,8 +365,8 @@ def parse

if value.is_a?(Hash) && value.key?('$schema')
@parsed['$schema'] = SCHEMA_KEYWORD_CLASS.new(value.fetch('$schema'), self, '$schema')
elsif root == self && !meta_schema
SCHEMA_KEYWORD_CLASS.new(DEFAULT_SCHEMA, self, '$schema')
elsif meta_schema.is_a?(String)
SCHEMA_KEYWORD_CLASS.new(meta_schema, self, '$schema')
end

if value.is_a?(Hash) && value.key?('$vocabulary')
Expand Down Expand Up @@ -408,21 +410,6 @@ def property_default_resolver
@property_default_resolver ||= insert_property_defaults == :symbol ? SYMBOL_PROPERTY_DEFAULT_RESOLVER : DEFAULT_PROPERTY_DEFAULT_RESOLVER
end

def ref_resolver
@ref_resolver ||= @original_ref_resolver == 'net/http' ? CachedResolver.new(&NET_HTTP_REF_RESOLVER) : @original_ref_resolver
end

def regexp_resolver
@regexp_resolver ||= case @original_regexp_resolver
when 'ecma'
CachedResolver.new(&ECMA_REGEXP_RESOLVER)
when 'ruby'
CachedResolver.new(&RUBY_REGEXP_RESOLVER)
else
@original_regexp_resolver
end
end

def resolve_enumerators!(output)
case output
when Hash
Expand Down

0 comments on commit 8803d3b

Please sign in to comment.