json-schema_builder 0.0.1
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 +7 -0
- data/.gitignore +2 -0
- data/.rspec +2 -0
- data/.travis.yml +8 -0
- data/Gemfile +2 -0
- data/Gemfile.lock +66 -0
- data/LICENSE.txt +22 -0
- data/README.md +31 -0
- data/Rakefile +1 -0
- data/json-schema_builder.gemspec +28 -0
- data/lib/json/schema_builder.rb +14 -0
- data/lib/json/schema_builder/array.rb +29 -0
- data/lib/json/schema_builder/boolean.rb +9 -0
- data/lib/json/schema_builder/dsl.rb +42 -0
- data/lib/json/schema_builder/entity.rb +101 -0
- data/lib/json/schema_builder/integer.rb +9 -0
- data/lib/json/schema_builder/null.rb +9 -0
- data/lib/json/schema_builder/number.rb +9 -0
- data/lib/json/schema_builder/numeric.rb +13 -0
- data/lib/json/schema_builder/object.rb +36 -0
- data/lib/json/schema_builder/schema.rb +16 -0
- data/lib/json/schema_builder/string.rb +12 -0
- data/lib/json/schema_builder/version.rb +5 -0
- data/spec/integration/entity_literals_spec.rb +40 -0
- data/spec/integration/mixed_arrays_spec.rb +16 -0
- data/spec/integration/schema_builder_spec.rb +19 -0
- data/spec/integration/terse_arrays_spec.rb +18 -0
- data/spec/integration/terse_objects_spec.rb +30 -0
- data/spec/integration/verbose_arrays_spec.rb +18 -0
- data/spec/integration/verbose_objects_spec.rb +30 -0
- data/spec/spec_helper.rb +13 -0
- data/spec/support/.keep +0 -0
- data/spec/support/attribute_matcher.rb +17 -0
- data/spec/support/examples/entity_literals.rb +33 -0
- data/spec/support/examples/mixed_arrays.rb +14 -0
- data/spec/support/examples/schema_builder.rb +5 -0
- data/spec/support/examples/terse_arrays.rb +11 -0
- data/spec/support/examples/terse_objects.rb +16 -0
- data/spec/support/examples/verbose_arrays.rb +19 -0
- data/spec/support/examples/verbose_objects.rb +24 -0
- data/spec/support/integration_helper.rb +12 -0
- data/spec/support/shared_contexts_for_entity.rb +24 -0
- data/spec/support/shared_examples_for_numeric.rb +10 -0
- data/spec/unit/array_spec.rb +55 -0
- data/spec/unit/boolean_spec.rb +6 -0
- data/spec/unit/dsl_spec.rb +70 -0
- data/spec/unit/entity_spec.rb +114 -0
- data/spec/unit/integer_spec.rb +7 -0
- data/spec/unit/null_spec.rb +6 -0
- data/spec/unit/number_spec.rb +7 -0
- data/spec/unit/object_spec.rb +28 -0
- data/spec/unit/schema_spec.rb +35 -0
- data/spec/unit/string_spec.rb +10 -0
- metadata +230 -0
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'ostruct'
|
2
|
+
|
3
|
+
module JSON
|
4
|
+
module SchemaBuilder
|
5
|
+
class Schema < OpenStruct
|
6
|
+
def merge(schema)
|
7
|
+
self.class.new to_h.deep_merge schema.to_h
|
8
|
+
end
|
9
|
+
|
10
|
+
def merge!(schema)
|
11
|
+
@table = to_h.deep_merge schema.to_h
|
12
|
+
self
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Examples::EntityLiterals, type: :integration do
|
4
|
+
it_behaves_like 'a builder' do
|
5
|
+
let(:expected_json) do
|
6
|
+
{
|
7
|
+
type: :object,
|
8
|
+
required: [:one],
|
9
|
+
properties: {
|
10
|
+
one: {
|
11
|
+
enum: [:string, :null]
|
12
|
+
},
|
13
|
+
two: {
|
14
|
+
allOf: [
|
15
|
+
{ type: :integer, minimum: 1 },
|
16
|
+
{ type: :string }
|
17
|
+
]
|
18
|
+
},
|
19
|
+
three: {
|
20
|
+
anyOf: [
|
21
|
+
{ type: :integer, minimum: 1 },
|
22
|
+
{ type: :null }
|
23
|
+
]
|
24
|
+
},
|
25
|
+
four: {
|
26
|
+
not: {
|
27
|
+
type: :null
|
28
|
+
}
|
29
|
+
},
|
30
|
+
five: {
|
31
|
+
oneOf: [
|
32
|
+
{ type: :string },
|
33
|
+
{ type: :number }
|
34
|
+
]
|
35
|
+
}
|
36
|
+
}
|
37
|
+
}
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Examples::MixedArrays, type: :integration do
|
4
|
+
it_behaves_like 'a builder' do
|
5
|
+
let(:expected_json) do
|
6
|
+
{
|
7
|
+
type: :array,
|
8
|
+
items: {
|
9
|
+
type: :array,
|
10
|
+
items: [{ }, { }],
|
11
|
+
additionalItems: false
|
12
|
+
}
|
13
|
+
}
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Examples::SchemaBuilder, type: :integration do
|
4
|
+
types = %w(array boolean integer null number object string)
|
5
|
+
|
6
|
+
types.each do |type|
|
7
|
+
describe "##{ type }" do
|
8
|
+
let(:klass){ "JSON::SchemaBuilder::#{ type.classify }".constantize }
|
9
|
+
|
10
|
+
it "should register #{ type } type" do
|
11
|
+
expect(subject.types[type.to_sym]).to be klass
|
12
|
+
end
|
13
|
+
|
14
|
+
it "should define a #{ type } method" do
|
15
|
+
expect(subject).to respond_to type.to_sym
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Examples::TerseArrays, type: :integration do
|
4
|
+
it_behaves_like 'a builder' do
|
5
|
+
let(:expected_json) do
|
6
|
+
{
|
7
|
+
type: :array,
|
8
|
+
uniqueItems: true,
|
9
|
+
items: {
|
10
|
+
type: :string,
|
11
|
+
minLength: 1,
|
12
|
+
maxLength: 5,
|
13
|
+
pattern: '^test'
|
14
|
+
}
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Examples::TerseObjects, type: :integration do
|
4
|
+
it_behaves_like 'a builder' do
|
5
|
+
let(:expected_json) do
|
6
|
+
{
|
7
|
+
type: :object,
|
8
|
+
properties: {
|
9
|
+
name: {
|
10
|
+
type: :string,
|
11
|
+
minLength: 1
|
12
|
+
},
|
13
|
+
ids: {
|
14
|
+
type: :array,
|
15
|
+
minItems: 1,
|
16
|
+
items: {
|
17
|
+
type: :object,
|
18
|
+
required: [:id],
|
19
|
+
properties: {
|
20
|
+
id: {
|
21
|
+
type: :integer
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Examples::VerboseArrays, type: :integration do
|
4
|
+
it_behaves_like 'a builder' do
|
5
|
+
let(:expected_json) do
|
6
|
+
{
|
7
|
+
type: :array,
|
8
|
+
uniqueItems: true,
|
9
|
+
items: {
|
10
|
+
type: :string,
|
11
|
+
minLength: 1,
|
12
|
+
maxLength: 5,
|
13
|
+
pattern: '^test'
|
14
|
+
}
|
15
|
+
}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe Examples::VerboseObjects, type: :integration do
|
4
|
+
it_behaves_like 'a builder' do
|
5
|
+
let(:expected_json) do
|
6
|
+
{
|
7
|
+
type: :object,
|
8
|
+
properties: {
|
9
|
+
name: {
|
10
|
+
type: :string,
|
11
|
+
minLength: 1
|
12
|
+
},
|
13
|
+
ids: {
|
14
|
+
type: :array,
|
15
|
+
minItems: 1,
|
16
|
+
items: {
|
17
|
+
type: :object,
|
18
|
+
required: [:id],
|
19
|
+
properties: {
|
20
|
+
id: {
|
21
|
+
type: :integer
|
22
|
+
}
|
23
|
+
}
|
24
|
+
}
|
25
|
+
}
|
26
|
+
}
|
27
|
+
}
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'pry'
|
2
|
+
%w(lib spec/support).each do |path|
|
3
|
+
Dir["./#{ path }/**/*.rb"].sort.each{ |file| require file }
|
4
|
+
end
|
5
|
+
|
6
|
+
require 'codeclimate-test-reporter'
|
7
|
+
CodeClimate::TestReporter.start
|
8
|
+
|
9
|
+
require 'rspec/its'
|
10
|
+
RSpec.configure do |config|
|
11
|
+
config.disable_monkey_patching!
|
12
|
+
config.include IntegrationHelper, type: :integration
|
13
|
+
end
|
data/spec/support/.keep
ADDED
File without changes
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec::Matchers.define :define_attribute do |attribute|
|
4
|
+
match do |entity_klass|
|
5
|
+
entity = entity_klass.new 'entity'
|
6
|
+
entity.respond_to?(attribute) &&
|
7
|
+
entity.respond_to?("#{ attribute }=")
|
8
|
+
end
|
9
|
+
|
10
|
+
failure_message do |entity_klass|
|
11
|
+
"#{ entity_klass.class } does not define attribute #{ attribute.inspect }"
|
12
|
+
end
|
13
|
+
|
14
|
+
failure_message_when_negated do |entity_klass|
|
15
|
+
"#{ entity_klass.class } does define attribute #{ attribute.inspect }"
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
module Examples
|
2
|
+
class EntityLiterals
|
3
|
+
include JSON::SchemaBuilder
|
4
|
+
|
5
|
+
def example
|
6
|
+
object do
|
7
|
+
entity 'one', required: true do
|
8
|
+
enum [:string, :null]
|
9
|
+
end
|
10
|
+
|
11
|
+
entity 'two' do
|
12
|
+
all_of positive_int, string
|
13
|
+
end
|
14
|
+
|
15
|
+
entity 'three' do
|
16
|
+
any_of [positive_int, null]
|
17
|
+
end
|
18
|
+
|
19
|
+
entity 'four' do
|
20
|
+
not_a null
|
21
|
+
end
|
22
|
+
|
23
|
+
entity 'five' do
|
24
|
+
one_of string, number
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def positive_int
|
30
|
+
integer minimum: 1
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
module Examples
|
2
|
+
class TerseObjects
|
3
|
+
include JSON::SchemaBuilder
|
4
|
+
|
5
|
+
def example
|
6
|
+
object do
|
7
|
+
string :name, min_length: 1
|
8
|
+
array :ids, min_items: 1 do
|
9
|
+
items type: :object do
|
10
|
+
integer :id, required: true
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Examples
|
2
|
+
class VerboseObjects
|
3
|
+
include JSON::SchemaBuilder
|
4
|
+
|
5
|
+
def example
|
6
|
+
object do
|
7
|
+
string :name do
|
8
|
+
min_length 1
|
9
|
+
end
|
10
|
+
|
11
|
+
array :ids do
|
12
|
+
min_items 1
|
13
|
+
|
14
|
+
items do
|
15
|
+
object do
|
16
|
+
required :id
|
17
|
+
integer :id
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,12 @@
|
|
1
|
+
module IntegrationHelper
|
2
|
+
extend RSpec::SharedContext
|
3
|
+
let(:schema){ described_class.new.example }
|
4
|
+
let(:json){ schema.as_json }
|
5
|
+
let(:expected_json){ { } }
|
6
|
+
|
7
|
+
RSpec.shared_examples_for 'a builder' do
|
8
|
+
it 'should produce the correct json schema' do
|
9
|
+
expect(json).to eql expected_json.as_json
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.shared_context 'an entity' do
|
4
|
+
let(:klass) do
|
5
|
+
Class.new JSON::SchemaBuilder::Entity do
|
6
|
+
attribute :test
|
7
|
+
attribute :test_name
|
8
|
+
attribute :test_list, array: true
|
9
|
+
attribute :test_as, as: :testOther
|
10
|
+
def initialize(*args); end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
subject{ klass.new }
|
15
|
+
end
|
16
|
+
|
17
|
+
RSpec.shared_context 'an entity with a parent' do
|
18
|
+
let(:parent){ OpenStruct.new children: [], required: [] }
|
19
|
+
subject do
|
20
|
+
JSON::SchemaBuilder::Entity.new 'name', title: 'test', parent: parent do
|
21
|
+
schema.evaluated_block = true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,10 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.shared_examples_for 'a numeric entity' do
|
4
|
+
subject{ described_class }
|
5
|
+
it{ is_expected.to define_attribute :multiple_of }
|
6
|
+
it{ is_expected.to define_attribute :minimum }
|
7
|
+
it{ is_expected.to define_attribute :maximum }
|
8
|
+
it{ is_expected.to define_attribute :exclusive_minimum }
|
9
|
+
it{ is_expected.to define_attribute :exclusive_maximum }
|
10
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
RSpec.describe JSON::SchemaBuilder::Array, type: :unit do
|
4
|
+
subject{ described_class }
|
5
|
+
|
6
|
+
it{ is_expected.to define_attribute :additional_items }
|
7
|
+
it{ is_expected.to define_attribute :min_items }
|
8
|
+
it{ is_expected.to define_attribute :max_items }
|
9
|
+
it{ is_expected.to define_attribute :unique_items }
|
10
|
+
its(:registered_type){ is_expected.to eql :array }
|
11
|
+
|
12
|
+
describe '#items' do
|
13
|
+
context 'with a simple array' do
|
14
|
+
let(:array) do
|
15
|
+
described_class.new 'name' do
|
16
|
+
min_items 2
|
17
|
+
items type: :string do
|
18
|
+
min_length 3
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
subject{ array.as_json }
|
24
|
+
its(['type']){ is_expected.to eql 'array' }
|
25
|
+
its(['minItems']){ is_expected.to eql 2 }
|
26
|
+
its(['items']){ is_expected.to eql 'type' => 'string', 'minLength' => 3 }
|
27
|
+
end
|
28
|
+
|
29
|
+
context 'with nested structure' do
|
30
|
+
let(:array) do
|
31
|
+
described_class.new 'name' do
|
32
|
+
items do
|
33
|
+
object do
|
34
|
+
string :key_name, required: true
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
subject{ array.as_json }
|
41
|
+
its(['type']){ is_expected.to eql 'array' }
|
42
|
+
|
43
|
+
describe 'items' do
|
44
|
+
subject{ array.as_json['items'] }
|
45
|
+
its(['type']){ is_expected.to eql 'object' }
|
46
|
+
its(['required']){ is_expected.to eql ['key_name'] }
|
47
|
+
|
48
|
+
describe "items['properties']" do
|
49
|
+
subject{ array.as_json['items']['properties'] }
|
50
|
+
its(['key_name']){ is_expected.to eql 'type' => 'string' }
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|