-
-
Notifications
You must be signed in to change notification settings - Fork 243
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #175 from pd/schema-loader
JSON::Schema::Reader
- Loading branch information
Showing
8 changed files
with
333 additions
and
30 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,113 @@ | ||
require 'open-uri' | ||
require 'addressable/uri' | ||
require 'pathname' | ||
|
||
module JSON | ||
class Schema | ||
# Raised by {JSON::Schema::Reader} when one of its settings indicate | ||
# a schema should not be readed. | ||
class ReadRefused < StandardError | ||
# @return [String] the requested schema location which was refused | ||
attr_reader :location | ||
|
||
# @return [Symbol] either +:uri+ or +:file+ | ||
attr_reader :type | ||
|
||
def initialize(location, type) | ||
@location = location | ||
@type = type | ||
super("Read of #{type == :uri ? 'URI' : type} at #{location} refused!") | ||
end | ||
end | ||
|
||
# When an unregistered schema is encountered, the {JSON::Schema::Reader} is | ||
# used to fetch its contents and register it with the {JSON::Validator}. | ||
# | ||
# This default reader will read schemas from the filesystem or from a URI. | ||
class Reader | ||
# The behavior of the schema reader can be controlled by providing | ||
# callbacks to determine whether to permit reading referenced schemas. | ||
# The options +accept_uri+ and +accept_file+ should be procs which | ||
# accept a +URI+ or +Pathname+ object, and return a boolean value | ||
# indicating whether to read the referenced schema. | ||
# | ||
# URIs using the +file+ scheme will be normalized into +Pathname+ objects | ||
# and passed to the +accept_file+ callback. | ||
# | ||
# @param options [Hash] | ||
# @option options [Boolean, #call] accept_uri (true) | ||
# @option options [Boolean, #call] accept_file (true) | ||
# | ||
# @example Reject all unregistered schemas | ||
# JSON::Validator.schema_reader = JSON::Schema::Reader.new( | ||
# :accept_uri => false, | ||
# :accept_file => false | ||
# ) | ||
# | ||
# @example Only permit URIs from certain hosts | ||
# JSON::Validator.schema_reader = JSON::Schema::Reader.new( | ||
# :accept_file => false, | ||
# :accept_uri => proc { |uri| ['mycompany.com', 'json-schema.org'].include?(uri.host) } | ||
# ) | ||
def initialize(options = {}) | ||
@accept_uri = options.fetch(:accept_uri, true) | ||
@accept_file = options.fetch(:accept_file, true) | ||
end | ||
|
||
# @param location [#to_s] The location from which to read the schema | ||
# @return [JSON::Schema] | ||
# @raise [JSON::Schema::ReadRefused] if +accept_uri+ or +accept_file+ | ||
# indicated the schema should not be readed | ||
# @raise [JSON::ParserError] if the schema was not a valid JSON object | ||
def read(location) | ||
uri = Addressable::URI.parse(location.to_s) | ||
body = if uri.scheme.nil? || uri.scheme == 'file' | ||
uri = Addressable::URI.convert_path(uri.path) | ||
read_file(Pathname.new(uri.path).expand_path) | ||
else | ||
read_uri(uri) | ||
end | ||
|
||
JSON::Schema.new(JSON::Validator.parse(body), uri) | ||
end | ||
|
||
# @param uri [Addressable::URI] | ||
# @return [Boolean] | ||
def accept_uri?(uri) | ||
if @accept_uri.respond_to?(:call) | ||
@accept_uri.call(uri) | ||
else | ||
@accept_uri | ||
end | ||
end | ||
|
||
# @param pathname [Pathname] | ||
# @return [Boolean] | ||
def accept_file?(pathname) | ||
if @accept_file.respond_to?(:call) | ||
@accept_file.call(pathname) | ||
else | ||
@accept_file | ||
end | ||
end | ||
|
||
private | ||
|
||
def read_uri(uri) | ||
if accept_uri?(uri) | ||
open(uri.to_s).read | ||
else | ||
raise JSON::Schema::ReadRefused.new(uri.to_s, :uri) | ||
end | ||
end | ||
|
||
def read_file(pathname) | ||
if accept_file?(pathname) | ||
File.read(Addressable::URI.unescape(pathname.to_s)) | ||
else | ||
raise JSON::Schema::ReadRefused.new(pathname.to_s, :file) | ||
end | ||
end | ||
end | ||
end | ||
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
{ | ||
"description": "An Address following the convention of http://microformats.org/wiki/hcard", | ||
"type": "object", | ||
"properties": { | ||
"post-office-box": { "type": "string" }, | ||
"extended-address": { "type": "string" }, | ||
"street-address": { "type": "string" }, | ||
"locality":{ "type": "string" }, | ||
"region": { "type": "string" }, | ||
"postal-code": { "type": "string" }, | ||
"country-name": { "type": "string"} | ||
}, | ||
"required": ["locality", "region", "country-name"], | ||
"dependencies": { | ||
"post-office-box": "street-address", | ||
"extended-address": "street-address" | ||
} | ||
} |
Oops, something went wrong.