jsi 0.0.4 → 0.4.0
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 +4 -4
- data/.simplecov +3 -1
- data/CHANGELOG.md +48 -0
- data/LICENSE.md +613 -0
- data/README.md +84 -45
- data/jsi.gemspec +11 -14
- data/lib/jsi.rb +31 -12
- data/lib/jsi/base.rb +310 -344
- data/lib/jsi/base/to_rb.rb +2 -0
- data/lib/jsi/jsi_coder.rb +91 -0
- data/lib/jsi/json-schema-fragments.rb +3 -135
- data/lib/jsi/json.rb +3 -0
- data/lib/jsi/json/node.rb +72 -197
- data/lib/jsi/json/pointer.rb +419 -0
- data/lib/jsi/metaschema.rb +7 -0
- data/lib/jsi/metaschema_node.rb +218 -0
- data/lib/jsi/pathed_node.rb +118 -0
- data/lib/jsi/schema.rb +168 -223
- data/lib/jsi/schema_classes.rb +158 -0
- data/lib/jsi/simple_wrap.rb +12 -0
- data/lib/jsi/typelike_modules.rb +71 -45
- data/lib/jsi/util.rb +47 -57
- data/lib/jsi/version.rb +1 -1
- data/lib/schemas/json-schema.org/draft-04/schema.rb +7 -0
- data/lib/schemas/json-schema.org/draft-06/schema.rb +7 -0
- data/resources/icons/AGPL-3.0.png +0 -0
- data/test/base_array_test.rb +210 -84
- data/test/base_hash_test.rb +201 -58
- data/test/base_test.rb +212 -121
- data/test/jsi_coder_test.rb +85 -0
- data/test/jsi_json_arraynode_test.rb +26 -25
- data/test/jsi_json_hashnode_test.rb +40 -39
- data/test/jsi_json_node_test.rb +95 -126
- data/test/jsi_json_pointer_test.rb +102 -0
- data/test/jsi_typelike_as_json_test.rb +53 -0
- data/test/metaschema_node_test.rb +19 -0
- data/test/schema_module_test.rb +21 -0
- data/test/schema_test.rb +109 -97
- data/test/spreedly_openapi_test.rb +8 -0
- data/test/test_helper.rb +42 -8
- data/test/util_test.rb +14 -14
- metadata +54 -25
- data/LICENSE.txt +0 -21
- data/lib/jsi/schema_instance_json_coder.rb +0 -83
- data/lib/jsi/struct_json_coder.rb +0 -30
- data/test/schema_instance_json_coder_test.rb +0 -121
- data/test/struct_json_coder_test.rb +0 -130
    
        data/test/base_test.rb
    CHANGED
    
    | @@ -1,57 +1,54 @@ | |
| 1 1 | 
             
            require_relative 'test_helper'
         | 
| 2 2 |  | 
| 3 | 
            -
            NamedSchemaInstance = JSI. | 
| 3 | 
            +
            NamedSchemaInstance = JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/base/named_schema'}).jsi_schema_class
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            # hitting .tap(&:name) causes JSI to assign a constant name from the ID,
         | 
| 6 | 
            +
            # meaning the name NamedSchemaInstanceTwo is not known.
         | 
| 7 | 
            +
            NamedSchemaInstanceTwo = JSI::Schema.new({id: 'https://schemas.jsi.unth.net/test/base/named_schema_two'}).jsi_schema_class.tap(&:name)
         | 
| 4 8 |  | 
| 5 9 | 
             
            describe JSI::Base do
         | 
| 6 | 
            -
              let(:document) { {} }
         | 
| 7 | 
            -
              let(:path) { [] }
         | 
| 8 | 
            -
              let(:instance) { JSI::JSON::Node.new_by_type(document, path) }
         | 
| 9 10 | 
             
              let(:schema_content) { {} }
         | 
| 10 11 | 
             
              let(:schema) { JSI::Schema.new(schema_content) }
         | 
| 11 | 
            -
              let(: | 
| 12 | 
            -
               | 
| 12 | 
            +
              let(:instance) { {} }
         | 
| 13 | 
            +
              let(:subject) { schema.new_jsi(instance) }
         | 
| 14 | 
            +
              describe 'class .inspect' do
         | 
| 13 15 | 
             
                it 'is the same as Class#inspect on the base' do
         | 
| 14 16 | 
             
                  assert_equal('JSI::Base', JSI::Base.inspect)
         | 
| 15 | 
            -
                  assert_equal('JSI::Base', JSI::Base.to_s)
         | 
| 16 17 | 
             
                end
         | 
| 17 | 
            -
                it 'is  | 
| 18 | 
            -
                   | 
| 19 | 
            -
                  assert_match(%r(\AJSI::SchemaClasses\["[a-f0-9\-]+#"\]\z), subject.class.to_s)
         | 
| 18 | 
            +
                it 'is (JSI Schema Class) for generated subclass without id' do
         | 
| 19 | 
            +
                  assert_equal("(JSI Schema Class: #)", subject.class.inspect)
         | 
| 20 20 | 
             
                end
         | 
| 21 21 | 
             
                describe 'with schema id' do
         | 
| 22 22 | 
             
                  let(:schema_content) { {'id' => 'https://jsi/foo'} }
         | 
| 23 | 
            -
                  it 'is  | 
| 24 | 
            -
                    assert_equal( | 
| 25 | 
            -
                    assert_equal(%q(JSI::SchemaClasses["https://jsi/foo#"]), subject.class.to_s)
         | 
| 23 | 
            +
                  it 'is (JSI Schema Class: ...) for generated subclass with id' do
         | 
| 24 | 
            +
                    assert_equal("(JSI Schema Class: https://jsi/foo#)", subject.class.inspect)
         | 
| 26 25 | 
             
                  end
         | 
| 27 26 | 
             
                end
         | 
| 28 | 
            -
                it 'is the constant name  | 
| 27 | 
            +
                it 'is the constant name plus id for a class assigned to a constant' do
         | 
| 29 28 | 
             
                  assert_equal(%q(NamedSchemaInstance (https://schemas.jsi.unth.net/test/base/named_schema#)), NamedSchemaInstance.inspect)
         | 
| 30 | 
            -
             | 
| 29 | 
            +
                end
         | 
| 30 | 
            +
                it 'is not the constant name when the constant name has been generated from the schema_id' do
         | 
| 31 | 
            +
                  assert_equal("JSI::SchemaClasses::Xhttps___schemas_jsi_unth_net_test_base_named_schema_two_", NamedSchemaInstanceTwo.name)
         | 
| 32 | 
            +
                  assert_equal("(JSI Schema Class: https://schemas.jsi.unth.net/test/base/named_schema_two#)", NamedSchemaInstanceTwo.inspect)
         | 
| 31 33 | 
             
                end
         | 
| 32 34 | 
             
              end
         | 
| 33 35 | 
             
              describe 'class name' do
         | 
| 34 36 | 
             
                let(:schema_content) { {'id' => 'https://jsi/BaseTest'} }
         | 
| 35 37 | 
             
                it 'generates a class name from schema_id' do
         | 
| 36 | 
            -
                  assert_equal('JSI::SchemaClasses:: | 
| 38 | 
            +
                  assert_equal('JSI::SchemaClasses::Xhttps___jsi_BaseTest_', subject.class.name)
         | 
| 37 39 | 
             
                end
         | 
| 38 40 | 
             
                it 'uses an existing name' do
         | 
| 39 41 | 
             
                  assert_equal('NamedSchemaInstance', NamedSchemaInstance.name)
         | 
| 40 42 | 
             
                end
         | 
| 41 43 | 
             
              end
         | 
| 42 | 
            -
              describe 'class for schema . | 
| 43 | 
            -
                it '. | 
| 44 | 
            -
                  assert_equal(schema,  | 
| 45 | 
            -
                end
         | 
| 46 | 
            -
              end
         | 
| 47 | 
            -
              describe 'class for schema .schema_id' do
         | 
| 48 | 
            -
                it '.schema_id' do
         | 
| 49 | 
            -
                  assert_equal(schema.schema_id, JSI.class_for_schema(schema).schema_id)
         | 
| 44 | 
            +
              describe 'class for schema .jsi_class_schemas' do
         | 
| 45 | 
            +
                it '.jsi_class_schemas' do
         | 
| 46 | 
            +
                  assert_equal(Set.new << schema, schema.jsi_schema_class.jsi_class_schemas)
         | 
| 50 47 | 
             
                end
         | 
| 51 48 | 
             
              end
         | 
| 52 49 | 
             
              describe 'module for schema .inspect' do
         | 
| 53 50 | 
             
                it '.inspect' do
         | 
| 54 | 
            -
                   | 
| 51 | 
            +
                  assert_equal("(JSI Schema Module: #)", JSI::SchemaClasses.module_for_schema(schema).inspect)
         | 
| 55 52 | 
             
                end
         | 
| 56 53 | 
             
              end
         | 
| 57 54 | 
             
              describe 'module for schema .schema' do
         | 
| @@ -59,26 +56,15 @@ describe JSI::Base do | |
| 59 56 | 
             
                  assert_equal(schema, JSI::SchemaClasses.module_for_schema(schema).schema)
         | 
| 60 57 | 
             
                end
         | 
| 61 58 | 
             
              end
         | 
| 62 | 
            -
              describe ' | 
| 63 | 
            -
                it 'stores the class for the schema' do
         | 
| 64 | 
            -
                  assert_equal(JSI.class_for_schema(schema), JSI::SchemaClasses[schema.schema_id])
         | 
| 65 | 
            -
                end
         | 
| 66 | 
            -
              end
         | 
| 67 | 
            -
              describe '.class_for_schema' do
         | 
| 59 | 
            +
              describe '.class_for_schemas' do
         | 
| 68 60 | 
             
                it 'returns a class from a schema' do
         | 
| 69 | 
            -
                  class_for_schema = JSI. | 
| 61 | 
            +
                  class_for_schema = JSI.class_for_schemas([schema])
         | 
| 70 62 | 
             
                  # same class every time
         | 
| 71 | 
            -
                  assert_equal(JSI. | 
| 63 | 
            +
                  assert_equal(JSI.class_for_schemas([schema]), class_for_schema)
         | 
| 72 64 | 
             
                  assert_operator(class_for_schema, :<, JSI::Base)
         | 
| 73 65 | 
             
                end
         | 
| 74 | 
            -
                it 'returns  | 
| 75 | 
            -
                  assert_equal(JSI. | 
| 76 | 
            -
                end
         | 
| 77 | 
            -
                it 'returns a class from a schema node' do
         | 
| 78 | 
            -
                  assert_equal(JSI.class_for_schema(schema), JSI.class_for_schema(schema.schema_node))
         | 
| 79 | 
            -
                end
         | 
| 80 | 
            -
                it 'returns a class from a Base' do
         | 
| 81 | 
            -
                  assert_equal(JSI.class_for_schema(schema), JSI.class_for_schema(JSI.class_for_schema({}).new(schema.schema_node)))
         | 
| 66 | 
            +
                it 'returns the same class from a hash' do
         | 
| 67 | 
            +
                  assert_equal(JSI.class_for_schemas([schema]), JSI.class_for_schemas([schema_content]))
         | 
| 82 68 | 
             
                end
         | 
| 83 69 | 
             
              end
         | 
| 84 70 | 
             
              describe 'JSI::SchemaClasses.module_for_schema' do
         | 
| @@ -88,26 +74,20 @@ describe JSI::Base do | |
| 88 74 | 
             
                  assert_equal(JSI::SchemaClasses.module_for_schema(schema), module_for_schema)
         | 
| 89 75 | 
             
                end
         | 
| 90 76 | 
             
                it 'returns a module from a hash' do
         | 
| 91 | 
            -
                  assert_equal(JSI::SchemaClasses.module_for_schema(schema), JSI::SchemaClasses.module_for_schema(schema. | 
| 92 | 
            -
                end
         | 
| 93 | 
            -
                it 'returns a module from a schema node' do
         | 
| 94 | 
            -
                  assert_equal(JSI::SchemaClasses.module_for_schema(schema), JSI::SchemaClasses.module_for_schema(schema.schema_node))
         | 
| 95 | 
            -
                end
         | 
| 96 | 
            -
                it 'returns a module from a Base' do
         | 
| 97 | 
            -
                  assert_equal(JSI::SchemaClasses.module_for_schema(schema), JSI::SchemaClasses.module_for_schema(JSI.class_for_schema({}).new(schema.schema_node)))
         | 
| 77 | 
            +
                  assert_equal(JSI::SchemaClasses.module_for_schema(schema), JSI::SchemaClasses.module_for_schema(schema.jsi_instance))
         | 
| 98 78 | 
             
                end
         | 
| 99 79 | 
             
              end
         | 
| 100 80 | 
             
              describe 'initialization' do
         | 
| 101 81 | 
             
                describe 'on Base' do
         | 
| 102 82 | 
             
                  it 'errors' do
         | 
| 103 83 | 
             
                    err = assert_raises(TypeError) { JSI::Base.new({}) }
         | 
| 104 | 
            -
                    assert_equal('cannot instantiate JSI::Base which has no method # | 
| 84 | 
            +
                    assert_equal('cannot instantiate JSI::Base which has no method #jsi_schemas. it is recommended to instantiate JSIs from a schema using JSI::Schema#new_jsi.', err.message)
         | 
| 105 85 | 
             
                  end
         | 
| 106 86 | 
             
                end
         | 
| 107 87 | 
             
                describe 'nil' do
         | 
| 108 88 | 
             
                  let(:instance) { nil }
         | 
| 109 89 | 
             
                  it 'initializes with nil instance' do
         | 
| 110 | 
            -
                    assert_equal( | 
| 90 | 
            +
                    assert_equal(nil, subject.jsi_instance)
         | 
| 111 91 | 
             
                    assert(!subject.respond_to?(:to_ary))
         | 
| 112 92 | 
             
                    assert(!subject.respond_to?(:to_hash))
         | 
| 113 93 | 
             
                  end
         | 
| @@ -115,7 +95,7 @@ describe JSI::Base do | |
| 115 95 | 
             
                describe 'arbitrary instance' do
         | 
| 116 96 | 
             
                  let(:instance) { Object.new }
         | 
| 117 97 | 
             
                  it 'initializes' do
         | 
| 118 | 
            -
                    assert_equal( | 
| 98 | 
            +
                    assert_equal(instance, subject.jsi_instance)
         | 
| 119 99 | 
             
                    assert(!subject.respond_to?(:to_ary))
         | 
| 120 100 | 
             
                    assert(!subject.respond_to?(:to_hash))
         | 
| 121 101 | 
             
                  end
         | 
| @@ -124,16 +104,16 @@ describe JSI::Base do | |
| 124 104 | 
             
                  let(:instance) { {'foo' => 'bar'} }
         | 
| 125 105 | 
             
                  let(:schema_content) { {'type' => 'object'} }
         | 
| 126 106 | 
             
                  it 'initializes' do
         | 
| 127 | 
            -
                    assert_equal( | 
| 107 | 
            +
                    assert_equal({'foo' => 'bar'}, subject.jsi_instance)
         | 
| 128 108 | 
             
                    assert(!subject.respond_to?(:to_ary))
         | 
| 129 109 | 
             
                    assert(subject.respond_to?(:to_hash))
         | 
| 130 110 | 
             
                  end
         | 
| 131 111 | 
             
                end
         | 
| 132 | 
            -
                describe 'JSI::JSON:: | 
| 133 | 
            -
                  let(: | 
| 112 | 
            +
                describe 'JSI::JSON::HashNode' do
         | 
| 113 | 
            +
                  let(:instance) { JSI::JSON::HashNode.new({'foo' => 'bar'}, JSI::JSON::Pointer.new([])) }
         | 
| 134 114 | 
             
                  let(:schema_content) { {'type' => 'object'} }
         | 
| 135 115 | 
             
                  it 'initializes' do
         | 
| 136 | 
            -
                    assert_equal(JSI::JSON::HashNode.new({'foo' => 'bar'}, []), subject. | 
| 116 | 
            +
                    assert_equal(JSI::JSON::HashNode.new({'foo' => 'bar'}, JSI::JSON::Pointer.new([])), subject.jsi_instance)
         | 
| 137 117 | 
             
                    assert(!subject.respond_to?(:to_ary))
         | 
| 138 118 | 
             
                    assert(subject.respond_to?(:to_hash))
         | 
| 139 119 | 
             
                  end
         | 
| @@ -142,69 +122,93 @@ describe JSI::Base do | |
| 142 122 | 
             
                  let(:instance) { ['foo'] }
         | 
| 143 123 | 
             
                  let(:schema_content) { {'type' => 'array'} }
         | 
| 144 124 | 
             
                  it 'initializes' do
         | 
| 145 | 
            -
                    assert_equal( | 
| 125 | 
            +
                    assert_equal(['foo'], subject.jsi_instance)
         | 
| 146 126 | 
             
                    assert(subject.respond_to?(:to_ary))
         | 
| 147 127 | 
             
                    assert(!subject.respond_to?(:to_hash))
         | 
| 148 128 | 
             
                  end
         | 
| 149 129 | 
             
                end
         | 
| 150 | 
            -
                describe 'JSI::JSON:: | 
| 151 | 
            -
                  let(: | 
| 130 | 
            +
                describe 'JSI::JSON::ArrayNode' do
         | 
| 131 | 
            +
                  let(:instance) { JSI::JSON::ArrayNode.new(['foo'], JSI::JSON::Pointer.new([])) }
         | 
| 152 132 | 
             
                  let(:schema_content) { {'type' => 'array'} }
         | 
| 153 133 | 
             
                  it 'initializes' do
         | 
| 154 | 
            -
                    assert_equal(JSI::JSON::ArrayNode.new(['foo'], []), subject. | 
| 134 | 
            +
                    assert_equal(JSI::JSON::ArrayNode.new(['foo'], JSI::JSON::Pointer.new([])), subject.jsi_instance)
         | 
| 155 135 | 
             
                    assert(subject.respond_to?(:to_ary))
         | 
| 156 136 | 
             
                    assert(!subject.respond_to?(:to_hash))
         | 
| 157 137 | 
             
                  end
         | 
| 158 138 | 
             
                end
         | 
| 159 | 
            -
                describe 'another Base' do
         | 
| 139 | 
            +
                describe 'another JSI::Base invalid' do
         | 
| 160 140 | 
             
                  let(:schema_content) { {'type' => 'object'} }
         | 
| 161 | 
            -
                  let(:instance) {  | 
| 162 | 
            -
                  it 'initializes with  | 
| 163 | 
            -
                     | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 141 | 
            +
                  let(:instance) { schema.new_jsi({'foo' => 'bar'}) }
         | 
| 142 | 
            +
                  it 'initializes with an error' do
         | 
| 143 | 
            +
                    err = assert_raises(TypeError) { subject }
         | 
| 144 | 
            +
                    assert_equal("assigning another JSI::Base instance to a (JSI Schema Class: #) instance is incorrect. received: \#{<JSI> \"foo\" => \"bar\"}", err.message)
         | 
| 145 | 
            +
                  end
         | 
| 146 | 
            +
                end
         | 
| 147 | 
            +
                describe 'Schema invalid' do
         | 
| 148 | 
            +
                  let(:instance) { JSI::Schema.new({}) }
         | 
| 149 | 
            +
                  it 'initializes with an error' do
         | 
| 150 | 
            +
                    err = assert_raises(TypeError) { subject }
         | 
| 151 | 
            +
                    assert_equal("assigning a schema to a (JSI Schema Class: #) instance is incorrect. received: \#{<JSI (JSI::JSONSchemaOrgDraft06) Schema>}", err.message)
         | 
| 167 152 | 
             
                  end
         | 
| 168 153 | 
             
                end
         | 
| 169 154 | 
             
              end
         | 
| 170 | 
            -
              describe '# | 
| 155 | 
            +
              describe '#parent_jsis, #parent_jsi' do
         | 
| 171 156 | 
             
                let(:schema_content) { {'properties' => {'foo' => {'properties' => {'bar' => {'properties' => {'baz' => {}}}}}}} }
         | 
| 172 | 
            -
                let(: | 
| 173 | 
            -
                describe 'no  | 
| 157 | 
            +
                let(:instance) { {'foo' => {'bar' => {'baz' => {}}}} }
         | 
| 158 | 
            +
                describe 'no parent_jsis' do
         | 
| 174 159 | 
             
                  it 'has none' do
         | 
| 175 160 | 
             
                    assert_equal([], subject.parents)
         | 
| 161 | 
            +
                    assert_equal([], subject.parent_jsis)
         | 
| 176 162 | 
             
                    assert_equal(nil, subject.parent)
         | 
| 163 | 
            +
                    assert_equal(nil, subject.parent_jsi)
         | 
| 177 164 | 
             
                  end
         | 
| 178 165 | 
             
                end
         | 
| 179 | 
            -
                describe 'one  | 
| 166 | 
            +
                describe 'one parent_jsi' do
         | 
| 180 167 | 
             
                  it 'has one' do
         | 
| 181 168 | 
             
                    assert_equal([subject], subject.foo.parents)
         | 
| 169 | 
            +
                    assert_equal([subject], subject.foo.parent_jsis)
         | 
| 182 170 | 
             
                    assert_equal(subject, subject.foo.parent)
         | 
| 171 | 
            +
                    assert_equal(subject, subject.foo.parent_jsi)
         | 
| 183 172 | 
             
                  end
         | 
| 184 173 | 
             
                end
         | 
| 185 | 
            -
                describe 'more  | 
| 174 | 
            +
                describe 'more parent_jsis' do
         | 
| 186 175 | 
             
                  it 'has more' do
         | 
| 187 176 | 
             
                    assert_equal([subject.foo.bar, subject.foo, subject], subject.foo.bar.baz.parents)
         | 
| 177 | 
            +
                    assert_equal([subject.foo.bar, subject.foo, subject], subject.foo.bar.baz.parent_jsis)
         | 
| 188 178 | 
             
                    assert_equal(subject.foo.bar, subject.foo.bar.baz.parent)
         | 
| 179 | 
            +
                    assert_equal(subject.foo.bar, subject.foo.bar.baz.parent_jsi)
         | 
| 189 180 | 
             
                  end
         | 
| 190 181 | 
             
                end
         | 
| 191 182 | 
             
              end
         | 
| 192 183 | 
             
              describe '#each, Enumerable methods' do
         | 
| 193 | 
            -
                let(: | 
| 184 | 
            +
                let(:instance) { 'a string' }
         | 
| 194 185 | 
             
                it "raises NoMethodError calling each or Enumerable methods" do
         | 
| 195 186 | 
             
                  assert_raises(NoMethodError) { subject.each { nil } }
         | 
| 196 187 | 
             
                  assert_raises(NoMethodError) { subject.map { nil } }
         | 
| 197 188 | 
             
                end
         | 
| 198 189 | 
             
              end
         | 
| 199 190 | 
             
              describe '#modified_copy' do
         | 
| 191 | 
            +
                describe 'with an instance that does not have #modified_copy' do
         | 
| 192 | 
            +
                  let(:instance) { Object.new }
         | 
| 193 | 
            +
                  it 'yields the instance to modify' do
         | 
| 194 | 
            +
                    new_instance = Object.new
         | 
| 195 | 
            +
                    modified = subject.modified_copy do |o|
         | 
| 196 | 
            +
                      assert_equal(instance, o)
         | 
| 197 | 
            +
                      new_instance
         | 
| 198 | 
            +
                    end
         | 
| 199 | 
            +
                    assert_equal(new_instance, modified.jsi_instance)
         | 
| 200 | 
            +
                    assert_equal(instance, subject.jsi_instance)
         | 
| 201 | 
            +
                    refute_equal(instance, modified)
         | 
| 202 | 
            +
                  end
         | 
| 203 | 
            +
                end
         | 
| 200 204 | 
             
                describe 'with an instance that does have #modified_copy' do
         | 
| 201 205 | 
             
                  it 'yields the instance to modify' do
         | 
| 202 206 | 
             
                    modified = subject.modified_copy do |o|
         | 
| 203 207 | 
             
                      assert_equal({}, o)
         | 
| 204 208 | 
             
                      {'a' => 'b'}
         | 
| 205 209 | 
             
                    end
         | 
| 206 | 
            -
                    assert_equal({'a' => 'b'}, modified. | 
| 207 | 
            -
                    assert_equal({}, subject. | 
| 210 | 
            +
                    assert_equal({'a' => 'b'}, modified.jsi_instance)
         | 
| 211 | 
            +
                    assert_equal({}, subject.jsi_instance)
         | 
| 208 212 | 
             
                    refute_equal(instance, modified)
         | 
| 209 213 | 
             
                  end
         | 
| 210 214 | 
             
                end
         | 
| @@ -212,7 +216,7 @@ describe JSI::Base do | |
| 212 216 | 
             
                  it 'yields the instance to modify' do
         | 
| 213 217 | 
             
                    modified = subject.modified_copy { |o| o }
         | 
| 214 218 | 
             
                    # this doesn't really need to be tested but ... whatever
         | 
| 215 | 
            -
                    assert_equal(subject. | 
| 219 | 
            +
                    assert_equal(subject.jsi_instance.object_id, modified.jsi_instance.object_id)
         | 
| 216 220 | 
             
                    assert_equal(subject, modified)
         | 
| 217 221 | 
             
                    refute_equal(subject.object_id, modified.object_id)
         | 
| 218 222 | 
             
                  end
         | 
| @@ -224,18 +228,15 @@ describe JSI::Base do | |
| 224 228 | 
             
                    modified = subject.modified_copy do |o|
         | 
| 225 229 | 
             
                      o.to_s
         | 
| 226 230 | 
             
                    end
         | 
| 227 | 
            -
                    assert_equal('{}', modified. | 
| 228 | 
            -
                    assert_equal({}, subject. | 
| 231 | 
            +
                    assert_equal('{}', modified.jsi_instance)
         | 
| 232 | 
            +
                    assert_equal({}, subject.jsi_instance)
         | 
| 229 233 | 
             
                    refute_equal(instance, modified)
         | 
| 230 234 | 
             
                    # interesting side effect
         | 
| 231 235 | 
             
                    assert(subject.respond_to?(:to_hash))
         | 
| 232 236 | 
             
                    assert(!modified.respond_to?(:to_hash))
         | 
| 233 | 
            -
                    assert_equal(JSI::JSON::HashNode, subject.instance.class)
         | 
| 234 | 
            -
                    assert_equal(JSI::JSON::Node, modified.instance.class)
         | 
| 235 237 | 
             
                  end
         | 
| 236 238 | 
             
                end
         | 
| 237 239 | 
             
              end
         | 
| 238 | 
            -
              it('#fragment') { assert_equal('#', subject.fragment) }
         | 
| 239 240 | 
             
              describe 'validation' do
         | 
| 240 241 | 
             
                describe 'without errors' do
         | 
| 241 242 | 
             
                  it '#fully_validate' do
         | 
| @@ -248,6 +249,94 @@ describe JSI::Base do | |
| 248 249 | 
             
                    assert_equal(true, subject.validate!)
         | 
| 249 250 | 
             
                  end
         | 
| 250 251 | 
             
                end
         | 
| 252 | 
            +
                describe 'with errors' do
         | 
| 253 | 
            +
                  let(:schema_content) {
         | 
| 254 | 
            +
                    {
         | 
| 255 | 
            +
                      'id' => 'https://schemas.jsi.unth.net/test/JSI::Base::validation::with errors',
         | 
| 256 | 
            +
                      'type' => 'object',
         | 
| 257 | 
            +
                      'properties' => {
         | 
| 258 | 
            +
                        'some_number' => {
         | 
| 259 | 
            +
                          'type' => 'number'
         | 
| 260 | 
            +
                        },
         | 
| 261 | 
            +
                        'a_required_property' => {
         | 
| 262 | 
            +
                          'type' => 'string'
         | 
| 263 | 
            +
                        }
         | 
| 264 | 
            +
                      }
         | 
| 265 | 
            +
                    }
         | 
| 266 | 
            +
                  }
         | 
| 267 | 
            +
                  let(:instance) { "this is a string" }
         | 
| 268 | 
            +
             | 
| 269 | 
            +
                  it '#validate' do
         | 
| 270 | 
            +
                    assert_equal(false, subject.validate)
         | 
| 271 | 
            +
                  end
         | 
| 272 | 
            +
                  it '#validate!' do
         | 
| 273 | 
            +
                    assert_raises JSON::Schema::ValidationError do
         | 
| 274 | 
            +
                      subject.validate!
         | 
| 275 | 
            +
                    end
         | 
| 276 | 
            +
                  end
         | 
| 277 | 
            +
                  describe 'fully_validate' do
         | 
| 278 | 
            +
                    it '#fully_validate ' do
         | 
| 279 | 
            +
                      assert_equal(["The property '#/' of type string did not match the following type: object in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::with errors"], subject.fully_validate)
         | 
| 280 | 
            +
                    end
         | 
| 281 | 
            +
                    it '#fully_validate :errors_as_objects' do
         | 
| 282 | 
            +
                      expected = [
         | 
| 283 | 
            +
                        {
         | 
| 284 | 
            +
                          :schema => Addressable::URI.parse('https://schemas.jsi.unth.net/test/JSI::Base::validation::with errors'),
         | 
| 285 | 
            +
                          :fragment => "#/",
         | 
| 286 | 
            +
                          :message => "The property '#/' of type string did not match the following type: object in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::with errors",
         | 
| 287 | 
            +
                          :failed_attribute=>"TypeV4"
         | 
| 288 | 
            +
                        }
         | 
| 289 | 
            +
                      ]
         | 
| 290 | 
            +
                      assert_equal(expected, subject.fully_validate(:errors_as_objects => true))
         | 
| 291 | 
            +
                    end
         | 
| 292 | 
            +
                  end
         | 
| 293 | 
            +
                end
         | 
| 294 | 
            +
                describe 'at a depth' do
         | 
| 295 | 
            +
                  let(:schema_content) do
         | 
| 296 | 
            +
                    {
         | 
| 297 | 
            +
                      'id' => 'https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth',
         | 
| 298 | 
            +
                      'description' => 'hash schema',
         | 
| 299 | 
            +
                      'type' => 'object',
         | 
| 300 | 
            +
                      'properties' => {
         | 
| 301 | 
            +
                        'foo' => {'type' => 'object'},
         | 
| 302 | 
            +
                        'bar' => {},
         | 
| 303 | 
            +
                        'baz' => {'type' => 'array'},
         | 
| 304 | 
            +
                      },
         | 
| 305 | 
            +
                      'additionalProperties' => {'not' => {}},
         | 
| 306 | 
            +
                    }
         | 
| 307 | 
            +
                  end
         | 
| 308 | 
            +
             | 
| 309 | 
            +
                  describe 'without errors' do
         | 
| 310 | 
            +
                    let(:instance) { {'foo' => {'x' => 'y'}, 'bar' => [9], 'baz' => [true]} }
         | 
| 311 | 
            +
             | 
| 312 | 
            +
                    it '#fully_validate' do
         | 
| 313 | 
            +
                      assert_equal([], subject.foo.fully_validate)
         | 
| 314 | 
            +
                      assert_equal([], subject.bar.fully_validate)
         | 
| 315 | 
            +
                    end
         | 
| 316 | 
            +
                    it '#validate' do
         | 
| 317 | 
            +
                      assert_equal(true, subject.foo.validate)
         | 
| 318 | 
            +
                      assert_equal(true, subject.bar.validate)
         | 
| 319 | 
            +
                    end
         | 
| 320 | 
            +
                  end
         | 
| 321 | 
            +
                  describe 'with errors' do
         | 
| 322 | 
            +
                    let(:instance) { {'foo' => [true], 'bar' => [9], 'baz' => {'x' => 'y'}, 'more' => {}} }
         | 
| 323 | 
            +
             | 
| 324 | 
            +
                    it '#fully_validate' do
         | 
| 325 | 
            +
                      assert_equal(["The property '#/' of type array did not match the following type: object in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth"], subject.foo.fully_validate)
         | 
| 326 | 
            +
                      assert_equal([], subject.bar.fully_validate)
         | 
| 327 | 
            +
                      assert_equal(["The property '#/' of type object did not match the following type: array in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth"], subject.baz.fully_validate)
         | 
| 328 | 
            +
                      assert_equal(["The property '#/' of type object matched the disallowed schema in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth"], subject['more'].fully_validate)
         | 
| 329 | 
            +
                      assert_equal(["The property '#/foo' of type array did not match the following type: object in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth", "The property '#/baz' of type object did not match the following type: array in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth", "The property '#/more' of type object matched the disallowed schema in schema https://schemas.jsi.unth.net/test/JSI::Base::validation::at a depth"], subject.fully_validate)
         | 
| 330 | 
            +
                    end
         | 
| 331 | 
            +
                    it '#validate' do
         | 
| 332 | 
            +
                      assert_equal(false, subject.foo.validate)
         | 
| 333 | 
            +
                      assert_equal(true, subject.bar.validate)
         | 
| 334 | 
            +
                      assert_equal(false, subject.baz.validate)
         | 
| 335 | 
            +
                      assert_equal(false, subject['more'].validate)
         | 
| 336 | 
            +
                      assert_equal(false, subject.validate)
         | 
| 337 | 
            +
                    end
         | 
| 338 | 
            +
                  end
         | 
| 339 | 
            +
                end
         | 
| 251 340 | 
             
              end
         | 
| 252 341 | 
             
              describe 'property accessors' do
         | 
| 253 342 | 
             
                let(:schema_content) do
         | 
| @@ -260,17 +349,17 @@ describe JSI::Base do | |
| 260 349 | 
             
                    },
         | 
| 261 350 | 
             
                  }
         | 
| 262 351 | 
             
                end
         | 
| 263 | 
            -
                let(: | 
| 352 | 
            +
                let(:instance) do
         | 
| 264 353 | 
             
                  {'foo' => {'x' => 'y'}, 'bar' => [3.14159], 'baz' => true, 'qux' => []}
         | 
| 265 354 | 
             
                end
         | 
| 266 355 | 
             
                describe 'readers' do
         | 
| 267 356 | 
             
                  it 'reads attributes described as properties' do
         | 
| 268 357 | 
             
                    assert_equal({'x' => 'y'}, subject.foo.as_json)
         | 
| 269 | 
            -
                     | 
| 358 | 
            +
                    assert_is_a(schema.properties['foo'].jsi_schema_module, subject.foo)
         | 
| 270 359 | 
             
                    assert_respond_to(subject.foo, :to_hash)
         | 
| 271 360 | 
             
                    refute_respond_to(subject.foo, :to_ary)
         | 
| 272 361 | 
             
                    assert_equal([3.14159], subject.bar.as_json)
         | 
| 273 | 
            -
                     | 
| 362 | 
            +
                    assert_is_a(schema.properties['bar'].jsi_schema_module, subject.bar)
         | 
| 274 363 | 
             
                    refute_respond_to(subject.bar, :to_hash)
         | 
| 275 364 | 
             
                    assert_respond_to(subject.bar, :to_ary)
         | 
| 276 365 | 
             
                    assert_equal(true, subject.baz)
         | 
| @@ -281,8 +370,8 @@ describe JSI::Base do | |
| 281 370 | 
             
                  describe 'when the instance is not hashlike' do
         | 
| 282 371 | 
             
                    let(:instance) { nil }
         | 
| 283 372 | 
             
                    it 'errors' do
         | 
| 284 | 
            -
                      err = assert_raises( | 
| 285 | 
            -
                       | 
| 373 | 
            +
                      err = assert_raises(JSI::Base::CannotSubscriptError) { subject.foo }
         | 
| 374 | 
            +
                      assert_equal(%q(cannot subcript (using token: "foo") from instance: nil), err.message)
         | 
| 286 375 | 
             
                    end
         | 
| 287 376 | 
             
                  end
         | 
| 288 377 | 
             
                  describe 'properties with the same names as instance methods' do
         | 
| @@ -295,14 +384,14 @@ describe JSI::Base do | |
| 295 384 | 
             
                          'inspect' => {},        # Base
         | 
| 296 385 | 
             
                          'pretty_inspect' => {}, # Kernel
         | 
| 297 386 | 
             
                          'as_json' => {},        # Base::OverrideFromExtensions, extended on initialization
         | 
| 298 | 
            -
                          'each' => {},           #  | 
| 387 | 
            +
                          'each' => {},           # PathedHashNode / PathedArrayNode
         | 
| 299 388 | 
             
                          'instance_exec' => {},  # BasicObject
         | 
| 300 | 
            -
                          ' | 
| 301 | 
            -
                          ' | 
| 389 | 
            +
                          'jsi_instance' => {},   # Base
         | 
| 390 | 
            +
                          'jsi_schemas' => {},    # module_for_schema singleton definition
         | 
| 302 391 | 
             
                        },
         | 
| 303 392 | 
             
                      }
         | 
| 304 393 | 
             
                    end
         | 
| 305 | 
            -
                    let(: | 
| 394 | 
            +
                    let(:instance) do
         | 
| 306 395 | 
             
                      {
         | 
| 307 396 | 
             
                        'foo' => 'bar',
         | 
| 308 397 | 
             
                        'initialize' => 'hi',
         | 
| @@ -311,24 +400,23 @@ describe JSI::Base do | |
| 311 400 | 
             
                        'as_json' => 'hi',
         | 
| 312 401 | 
             
                        'each' => 'hi',
         | 
| 313 402 | 
             
                        'instance_exec' => 'hi',
         | 
| 314 | 
            -
                        ' | 
| 315 | 
            -
                        ' | 
| 403 | 
            +
                        'jsi_instance' => 'hi',
         | 
| 404 | 
            +
                        'jsi_schemas' => 'hi',
         | 
| 316 405 | 
             
                      }
         | 
| 317 406 | 
             
                    end
         | 
| 318 407 | 
             
                    it 'does not define readers' do
         | 
| 319 | 
            -
                      assert_equal('bar', subject.foo)
         | 
| 320 | 
            -
                      assert_equal(JSI::SchemaClasses.module_for_schema(subject.schema), subject.method(:foo).owner)
         | 
| 408 | 
            +
                      assert_equal('bar', subject.foo) # this one is defined
         | 
| 321 409 |  | 
| 322 410 | 
             
                      assert_equal(JSI::Base, subject.method(:initialize).owner)
         | 
| 323 411 | 
             
                      assert_equal('hi', subject['initialize'])
         | 
| 324 | 
            -
                       | 
| 412 | 
            +
                      assert_equal(%q(#{<JSI> "foo" => "bar", "initialize" => "hi", "inspect" => "hi", "pretty_inspect" => "hi", "as_json" => "hi", "each" => "hi", "instance_exec" => "hi", "jsi_instance" => "hi", "jsi_schemas" => "hi"}), subject.inspect)
         | 
| 325 413 | 
             
                      assert_equal('hi', subject['inspect'])
         | 
| 326 | 
            -
                       | 
| 327 | 
            -
                      assert_equal( | 
| 414 | 
            +
                      assert_equal(%Q(\#{<JSI>\n  "foo" => "bar",\n  "initialize" => "hi",\n  "inspect" => "hi",\n  "pretty_inspect" => "hi",\n  "as_json" => "hi",\n  "each" => "hi",\n  "instance_exec" => "hi",\n  "jsi_instance" => "hi",\n  "jsi_schemas" => "hi"\n}\n), subject.pretty_inspect)
         | 
| 415 | 
            +
                      assert_equal(instance, subject.as_json)
         | 
| 328 416 | 
             
                      assert_equal(subject, subject.each { })
         | 
| 329 417 | 
             
                      assert_equal(2, subject.instance_exec { 2 })
         | 
| 330 | 
            -
                      assert_equal(instance, subject. | 
| 331 | 
            -
                      assert_equal(schema, subject. | 
| 418 | 
            +
                      assert_equal(instance, subject.jsi_instance)
         | 
| 419 | 
            +
                      assert_equal(Set.new << schema, subject.jsi_schemas)
         | 
| 332 420 | 
             
                    end
         | 
| 333 421 | 
             
                  end
         | 
| 334 422 | 
             
                end
         | 
| @@ -339,57 +427,60 @@ describe JSI::Base do | |
| 339 427 | 
             
                    subject.foo = {'y' => 'z'}
         | 
| 340 428 |  | 
| 341 429 | 
             
                    assert_equal({'y' => 'z'}, subject.foo.as_json)
         | 
| 342 | 
            -
                     | 
| 343 | 
            -
                     | 
| 430 | 
            +
                    assert_is_a(schema.properties['foo'].jsi_schema_module, orig_foo)
         | 
| 431 | 
            +
                    assert_is_a(schema.properties['foo'].jsi_schema_module, subject.foo)
         | 
| 344 432 | 
             
                  end
         | 
| 345 433 | 
             
                  it 'modifies the instance, visible to other references to the same instance' do
         | 
| 346 | 
            -
                    orig_instance = subject. | 
| 434 | 
            +
                    orig_instance = subject.jsi_instance
         | 
| 347 435 |  | 
| 348 436 | 
             
                    subject.foo = {'y' => 'z'}
         | 
| 349 437 |  | 
| 350 | 
            -
                    assert_equal(orig_instance, subject. | 
| 351 | 
            -
                    assert_equal({'y' => 'z'}, orig_instance['foo'] | 
| 352 | 
            -
                    assert_equal({'y' => 'z'}, subject. | 
| 353 | 
            -
                    assert_equal(orig_instance.class, subject. | 
| 438 | 
            +
                    assert_equal(orig_instance, subject.jsi_instance)
         | 
| 439 | 
            +
                    assert_equal({'y' => 'z'}, orig_instance['foo'])
         | 
| 440 | 
            +
                    assert_equal({'y' => 'z'}, subject.jsi_instance['foo'])
         | 
| 441 | 
            +
                    assert_equal(orig_instance.class, subject.jsi_instance.class)
         | 
| 354 442 | 
             
                  end
         | 
| 355 443 | 
             
                  describe 'when the instance is not hashlike' do
         | 
| 356 444 | 
             
                    let(:instance) { nil }
         | 
| 357 445 | 
             
                    it 'errors' do
         | 
| 358 446 | 
             
                      err = assert_raises(NoMethodError) { subject.foo = 0 }
         | 
| 359 | 
            -
                       | 
| 447 | 
            +
                      assert_equal('cannot assign subcript (using token: "foo") to instance: nil', err.message)
         | 
| 360 448 | 
             
                    end
         | 
| 361 449 | 
             
                  end
         | 
| 362 450 | 
             
                end
         | 
| 363 451 | 
             
              end
         | 
| 364 452 | 
             
              describe '#inspect' do
         | 
| 365 453 | 
             
                # if the instance is hash-like, #inspect gets overridden
         | 
| 366 | 
            -
                let(: | 
| 454 | 
            +
                let(:instance) { Object.new }
         | 
| 367 455 | 
             
                it 'inspects' do
         | 
| 368 | 
            -
                  assert_match(%r(\A | 
| 456 | 
            +
                  assert_match(%r(\A\#<JSI\ \#<Object:[^<>]*>>\z), subject.inspect)
         | 
| 369 457 | 
             
                end
         | 
| 370 458 | 
             
              end
         | 
| 371 459 | 
             
              describe '#pretty_print' do
         | 
| 372 460 | 
             
                # if the instance is hash-like, #pretty_print gets overridden
         | 
| 373 | 
            -
                let(: | 
| 461 | 
            +
                let(:instance) { Object.new }
         | 
| 374 462 | 
             
                it 'pretty_prints' do
         | 
| 375 | 
            -
                  assert_match(%r(\A | 
| 463 | 
            +
                  assert_match(%r(\A\#<JSI\ \#<Object:[^<>]*>>\z), subject.pretty_inspect.chomp)
         | 
| 376 464 | 
             
                end
         | 
| 377 465 | 
             
              end
         | 
| 378 466 | 
             
              describe '#as_json' do
         | 
| 379 467 | 
             
                it '#as_json' do
         | 
| 380 | 
            -
                  assert_equal({'a' => 'b'}, JSI. | 
| 381 | 
            -
                  assert_equal({'a' => 'b'}, JSI. | 
| 382 | 
            -
                  assert_equal( | 
| 383 | 
            -
                  assert_equal(['a'], JSI. | 
| 468 | 
            +
                  assert_equal({'a' => 'b'}, JSI::Schema.new({}).new_jsi({'a' => 'b'}).as_json)
         | 
| 469 | 
            +
                  assert_equal({'a' => 'b'}, JSI::Schema.new({}).new_jsi(JSI::JSON::Node.new_doc({'a' => 'b'})).as_json)
         | 
| 470 | 
            +
                  assert_equal({'a' => 'b'}, JSI::Schema.new({'type' => 'object'}).new_jsi(JSI::JSON::Node.new_doc({'a' => 'b'})).as_json)
         | 
| 471 | 
            +
                  assert_equal(['a', 'b'], JSI::Schema.new({'type' => 'array'}).new_jsi(JSI::JSON::Node.new_doc(['a', 'b'])).as_json)
         | 
| 472 | 
            +
                  assert_equal(['a'], JSI::Schema.new({}).new_jsi(['a']).as_json(some_option: true))
         | 
| 384 473 | 
             
                end
         | 
| 385 474 | 
             
              end
         | 
| 386 | 
            -
              describe ' | 
| 387 | 
            -
                 | 
| 388 | 
            -
             | 
| 389 | 
            -
                 | 
| 390 | 
            -
             | 
| 391 | 
            -
                   | 
| 392 | 
            -
                   | 
| 475 | 
            +
              describe 'equality between different classes of JSI::Base subclasses' do
         | 
| 476 | 
            +
                let(:subject_subclass) { Class.new(schema.jsi_schema_class).new(instance) }
         | 
| 477 | 
            +
             | 
| 478 | 
            +
                it 'considers a Base subclass (class_for_schema) and subsubclass to be equal with the same instance' do
         | 
| 479 | 
            +
                  assert_equal(subject.hash, subject_subclass.hash)
         | 
| 480 | 
            +
                  assert(subject == subject_subclass)
         | 
| 481 | 
            +
                  assert(subject_subclass == subject)
         | 
| 482 | 
            +
                  assert(subject.eql?(subject_subclass))
         | 
| 483 | 
            +
                  assert(subject_subclass.eql?(subject))
         | 
| 393 484 | 
             
                end
         | 
| 394 485 | 
             
              end
         | 
| 395 486 | 
             
            end
         |