json-schema_builder 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rspec +2 -0
  4. data/.travis.yml +8 -0
  5. data/Gemfile +2 -0
  6. data/Gemfile.lock +66 -0
  7. data/LICENSE.txt +22 -0
  8. data/README.md +31 -0
  9. data/Rakefile +1 -0
  10. data/json-schema_builder.gemspec +28 -0
  11. data/lib/json/schema_builder.rb +14 -0
  12. data/lib/json/schema_builder/array.rb +29 -0
  13. data/lib/json/schema_builder/boolean.rb +9 -0
  14. data/lib/json/schema_builder/dsl.rb +42 -0
  15. data/lib/json/schema_builder/entity.rb +101 -0
  16. data/lib/json/schema_builder/integer.rb +9 -0
  17. data/lib/json/schema_builder/null.rb +9 -0
  18. data/lib/json/schema_builder/number.rb +9 -0
  19. data/lib/json/schema_builder/numeric.rb +13 -0
  20. data/lib/json/schema_builder/object.rb +36 -0
  21. data/lib/json/schema_builder/schema.rb +16 -0
  22. data/lib/json/schema_builder/string.rb +12 -0
  23. data/lib/json/schema_builder/version.rb +5 -0
  24. data/spec/integration/entity_literals_spec.rb +40 -0
  25. data/spec/integration/mixed_arrays_spec.rb +16 -0
  26. data/spec/integration/schema_builder_spec.rb +19 -0
  27. data/spec/integration/terse_arrays_spec.rb +18 -0
  28. data/spec/integration/terse_objects_spec.rb +30 -0
  29. data/spec/integration/verbose_arrays_spec.rb +18 -0
  30. data/spec/integration/verbose_objects_spec.rb +30 -0
  31. data/spec/spec_helper.rb +13 -0
  32. data/spec/support/.keep +0 -0
  33. data/spec/support/attribute_matcher.rb +17 -0
  34. data/spec/support/examples/entity_literals.rb +33 -0
  35. data/spec/support/examples/mixed_arrays.rb +14 -0
  36. data/spec/support/examples/schema_builder.rb +5 -0
  37. data/spec/support/examples/terse_arrays.rb +11 -0
  38. data/spec/support/examples/terse_objects.rb +16 -0
  39. data/spec/support/examples/verbose_arrays.rb +19 -0
  40. data/spec/support/examples/verbose_objects.rb +24 -0
  41. data/spec/support/integration_helper.rb +12 -0
  42. data/spec/support/shared_contexts_for_entity.rb +24 -0
  43. data/spec/support/shared_examples_for_numeric.rb +10 -0
  44. data/spec/unit/array_spec.rb +55 -0
  45. data/spec/unit/boolean_spec.rb +6 -0
  46. data/spec/unit/dsl_spec.rb +70 -0
  47. data/spec/unit/entity_spec.rb +114 -0
  48. data/spec/unit/integer_spec.rb +7 -0
  49. data/spec/unit/null_spec.rb +6 -0
  50. data/spec/unit/number_spec.rb +7 -0
  51. data/spec/unit/object_spec.rb +28 -0
  52. data/spec/unit/schema_spec.rb +35 -0
  53. data/spec/unit/string_spec.rb +10 -0
  54. 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,12 @@
1
+ require_relative 'entity'
2
+
3
+ module JSON
4
+ module SchemaBuilder
5
+ class String < Entity
6
+ register :string
7
+ attribute :min_length
8
+ attribute :max_length
9
+ attribute :pattern
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,5 @@
1
+ module JSON
2
+ module SchemaBuilder
3
+ VERSION = '0.0.1'
4
+ end
5
+ 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
@@ -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
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,14 @@
1
+ module Examples
2
+ class MixedArrays
3
+ include JSON::SchemaBuilder
4
+
5
+ def example
6
+ array do
7
+ items type: :array do
8
+ items [{ }, { }]
9
+ additional_items false
10
+ end
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,5 @@
1
+ module Examples
2
+ class SchemaBuilder
3
+ include JSON::SchemaBuilder
4
+ end
5
+ end
@@ -0,0 +1,11 @@
1
+ module Examples
2
+ class TerseArrays
3
+ include JSON::SchemaBuilder
4
+
5
+ def example
6
+ array unique_items: true do
7
+ items type: :string, min_length: 1, max_length: 5, pattern: '^test'
8
+ end
9
+ end
10
+ end
11
+ 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,19 @@
1
+ module Examples
2
+ class VerboseArrays
3
+ include JSON::SchemaBuilder
4
+
5
+ def example
6
+ array do
7
+ unique_items true
8
+
9
+ items do
10
+ string do
11
+ min_length 1
12
+ max_length 5
13
+ pattern '^test'
14
+ end
15
+ end
16
+ end
17
+ end
18
+ end
19
+ 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