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.
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