diff --git a/Gemfile b/Gemfile index 5e2797e3..66a72b34 100644 --- a/Gemfile +++ b/Gemfile @@ -2,9 +2,4 @@ source "https://rubygems.org" gemspec -gem "json", :platforms => :mri_18 - -group :development do - gem "rake" - gem "minitest", '~> 5.0' -end +gem "json", ">= 1.7", :platforms => [:mri_18, :mri_19] diff --git a/README.textile b/README.textile index 43208826..5c0de191 100644 --- a/README.textile +++ b/README.textile @@ -278,6 +278,32 @@ data = { JSON::Validator.validate(schema, data, :version => :draft2) +h3. Explicitly specifying the type of the data + +By default, json-schema accepts a variety of different types for the data parameter, and it will try to work out what to do with it dynamically. You can pass it a string uri (in which case it will download the json from that location before validating), a string of JSON text, or simply a ruby object (such as an array or hash representing parsed json). However, sometimes the nature of the data is ambiguous (for example, is "http://github.com" just a string, or is it a uri?). In other situations, you have already parsed your JSON, and you don't need to re-parse it. + +If you want to be explict about what kind of data is being parsed, JSON schema supports a number of options: + +
+require 'rubygems' +require 'json-schema' + +schema = { + "type" => "string" +} + +# examines the data, determines it's a uri, then tries to load data from it +JSON::Validator.validate(schema, 'https://api.github.com') # returns false + +# data is already parsed json - just accept it as-is +JSON::Validator.validate(schema, 'https://api.github.com', :parse_data => false) # returns true + +# data is parsed to a json string +JSON::Validator.validate(schema, '"https://api.github.com"', :json => true) # returns true + +# loads data from the uri +JSON::Validator.validate(schema, 'https://api.github.com', :uri => true) # returns false +h3. Extend an existing schema and validate against it diff --git a/gemfiles/Gemfile.multi_json.x b/gemfiles/Gemfile.multi_json.x index e9d7839e..349d18d8 100644 --- a/gemfiles/Gemfile.multi_json.x +++ b/gemfiles/Gemfile.multi_json.x @@ -3,7 +3,3 @@ source "https://rubygems.org" gemspec :path => "../" gem "multi_json" - -group :development do - gem "rake" -end diff --git a/gemfiles/Gemfile.uuidtools.x b/gemfiles/Gemfile.uuidtools.x index 27f466c4..e3f30e93 100644 --- a/gemfiles/Gemfile.uuidtools.x +++ b/gemfiles/Gemfile.uuidtools.x @@ -3,7 +3,3 @@ source "https://rubygems.org" gemspec :path => "../" gem "uuidtools" - -group :development do - gem "rake" -end diff --git a/gemfiles/Gemfile.yajl-ruby.x b/gemfiles/Gemfile.yajl-ruby.x index 7ba39542..c9f10cca 100644 --- a/gemfiles/Gemfile.yajl-ruby.x +++ b/gemfiles/Gemfile.yajl-ruby.x @@ -3,7 +3,3 @@ source "https://rubygems.org" gemspec :path => "../" gem "yajl-ruby" - -group :development do - gem "rake" -end diff --git a/json-schema.gemspec b/json-schema.gemspec index c63e1d84..33609fc0 100644 --- a/json-schema.gemspec +++ b/json-schema.gemspec @@ -19,6 +19,9 @@ Gem::Specification.new do |s| s.license = "MIT" s.required_rubygems_version = ">= 1.8" + s.add_development_dependency "rake" + s.add_development_dependency "minitest", '~> 5.0' s.add_development_dependency "webmock" + s.add_runtime_dependency "addressable", '~> 2.3' end diff --git a/lib/json-schema/validator.rb b/lib/json-schema/validator.rb index ff17c27e..e991a647 100644 --- a/lib/json-schema/validator.rb +++ b/lib/json-schema/validator.rb @@ -24,7 +24,8 @@ class Validator :errors_as_objects => false, :insert_defaults => false, :clear_cache => true, - :strict => false + :strict => false, + :parse_data => true } @@validators = {} @@default_validator = nil @@ -400,7 +401,7 @@ def parse(s) else case @@json_backend.to_s when 'json' - JSON.parse(s) + JSON.parse(s, :quirks_mode => true) when 'yajl' json = StringIO.new(s) parser = Yajl::Parser.new @@ -550,20 +551,22 @@ def initialize_schema(schema) def initialize_data(data) - if @options[:json] - data = JSON::Validator.parse(data) - elsif @options[:uri] - json_uri = normalized_uri(data) - data = JSON::Validator.parse(custom_open(json_uri)) - elsif data.is_a?(String) - begin + if @options[:parse_data] + if @options[:json] data = JSON::Validator.parse(data) - rescue + elsif @options[:uri] + json_uri = normalized_uri(data) + data = JSON::Validator.parse(custom_open(json_uri)) + elsif data.is_a?(String) begin - json_uri = normalized_uri(data) - data = JSON::Validator.parse(custom_open(json_uri)) + data = JSON::Validator.parse(data) rescue - # Silently discard the error - the data will not change + begin + json_uri = normalized_uri(data) + data = JSON::Validator.parse(custom_open(json_uri)) + rescue + # Silently discard the error - the data will not change + end end end end diff --git a/test/test_bad_schema_ref.rb b/test/test_bad_schema_ref.rb index 920c8dd8..ef4d9761 100644 --- a/test/test_bad_schema_ref.rb +++ b/test/test_bad_schema_ref.rb @@ -1,5 +1,4 @@ require File.expand_path('../test_helper', __FILE__) -require 'webmock' require 'socket' diff --git a/test/test_common_test_suite.rb b/test/test_common_test_suite.rb index adcd40bb..3c9d3aff 100644 --- a/test/test_common_test_suite.rb +++ b/test/test_common_test_suite.rb @@ -1,5 +1,4 @@ require File.expand_path('../test_helper', __FILE__) -require 'webmock' require 'json' class CommonTestSuiteTest < Minitest::Test @@ -26,11 +25,7 @@ class CommonTestSuiteTest < Minitest::Test ] }) - include WebMock::API - def setup - WebMock.enable! - Dir["#{TEST_DIR}/../remotes/**/*.json"].each do |path| schema = path.sub(%r{^.*/remotes/}, '') stub_request(:get, "http://localhost:1234/#{schema}"). @@ -38,11 +33,6 @@ def setup end end - def teardown - WebMock.disable! - WebMock.reset! - end - Dir["#{TEST_DIR}/*"].each do |suite| version = File.basename(suite).to_sym Dir["#{suite}/**/*.json"].each do |tfile| @@ -63,6 +53,7 @@ def teardown define_method("test_#{err_id}") do errors = JSON::Validator.fully_validate(schema, t["data"], + :parse_data => false, :validate_schema => true, :version => version ) diff --git a/test/test_helper.rb b/test/test_helper.rb index 962eeb38..14510863 100644 --- a/test/test_helper.rb +++ b/test/test_helper.rb @@ -1,4 +1,5 @@ require 'minitest/autorun' +require 'webmock/minitest' $:.unshift(File.expand_path('../../lib', __FILE__)) require 'json-schema' diff --git a/test/test_initialize_data.rb b/test/test_initialize_data.rb new file mode 100644 index 00000000..452830b7 --- /dev/null +++ b/test/test_initialize_data.rb @@ -0,0 +1,135 @@ +require File.expand_path('../test_helper', __FILE__) + +class InitializeDataTest < Minitest::Test + + def refute_block(&blk) + result = blk.call + refute(result) + end + + def test_parse_character_string + schema = {'type' => 'string'} + data = 'hello world' + + assert(JSON::Validator.validate(schema, data)) + + assert(JSON::Validator.validate(schema, data, :parse_data => false)) + + refute_block do + begin + JSON::Validator.validate(schema, data, :json => true) + rescue + false + end + end + + assert_raises(Errno::ENOENT) { JSON::Validator.validate(schema, data, :uri => true) } + end + + def test_parse_integer_string + schema = {'type' => 'integer'} + data = '42' + + assert(JSON::Validator.validate(schema, data)) + + refute(JSON::Validator.validate(schema, data, :parse_data => false)) + + assert(JSON::Validator.validate(schema, data, :json => true)) + + assert_raises(Errno::ENOENT) { JSON::Validator.validate(schema, data, :uri => true) } + end + + def test_parse_hash_string + schema = { 'type' => 'object', 'properties' => { 'a' => { 'type' => 'string' } } } + data = '{"a": "b"}' + + assert(JSON::Validator.validate(schema, data)) + + refute(JSON::Validator.validate(schema, data, :parse_data => false)) + + assert(JSON::Validator.validate(schema, data, :json => true)) + + assert_raises(Errno::ENOENT) { JSON::Validator.validate(schema, data, :uri => true) } + end + + def test_parse_json_string + schema = {'type' => 'string'} + data = '"hello world"' + + assert(JSON::Validator.validate(schema, data)) + + assert(JSON::Validator.validate(schema, data, :parse_data => false)) + + assert(JSON::Validator.validate(schema, data, :json => true)) + + assert_raises(Errno::ENOENT) { JSON::Validator.validate(schema, data, :uri => true) } + end + + def test_parse_valid_uri_string + schema = {'type' => 'string'} + data = 'http://foo.bar/' + + stub_request(:get, "foo.bar").to_return(:body => '"hello world"', :status => 200) + + assert(JSON::Validator.validate(schema, data)) + + assert(JSON::Validator.validate(schema, data, :parse_data => false)) + + refute_block do + begin + JSON::Validator.validate(schema, data, :json => true) + rescue + false + end + end + + assert(JSON::Validator.validate(schema, data, :uri => true)) + end + + def test_parse_invalid_uri_string + schema = {'type' => 'string'} + data = 'http://foo.bar/' + + stub_request(:get, "foo.bar").to_timeout + + assert(JSON::Validator.validate(schema, data)) + + assert(JSON::Validator.validate(schema, data, :parse_data => false)) + + refute_block do + begin + JSON::Validator.validate(schema, data, :json => true) + rescue + false + end + end + + assert_raises(Timeout::Error) { JSON::Validator.validate(schema, data, :uri => true) } + end + + def test_parse_integer + schema = {'type' => 'integer'} + data = 42 + + assert(JSON::Validator.validate(schema, data)) + + assert(JSON::Validator.validate(schema, data, :parse_data => false)) + + assert_raises(TypeError) { JSON::Validator.validate(schema, data, :json => true) } + + assert_raises(TypeError) { JSON::Validator.validate(schema, data, :uri => true) } + end + + def test_parse_hash + schema = { 'type' => 'object', 'properties' => { 'a' => { 'type' => 'string' } } } + data = { 'a' => 'b' } + + assert(JSON::Validator.validate(schema, data)) + + assert(JSON::Validator.validate(schema, data, :parse_data => false)) + + assert_raises(TypeError) { JSON::Validator.validate(schema, data, :json => true) } + + assert_raises(TypeError) { JSON::Validator.validate(schema, data, :uri => true) } + end +end