schemacop 2.4.7 → 3.0.0.rc0
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/.gitignore +3 -0
 - data/.rubocop.yml +25 -1
 - data/.travis.yml +2 -1
 - data/CHANGELOG.md +8 -0
 - data/README.md +41 -708
 - data/README_V2.md +775 -0
 - data/README_V3.md +683 -0
 - data/Rakefile +8 -12
 - data/VERSION +1 -1
 - data/lib/schemacop.rb +35 -37
 - data/lib/schemacop/base_schema.rb +37 -0
 - data/lib/schemacop/railtie.rb +10 -0
 - data/lib/schemacop/schema.rb +1 -60
 - data/lib/schemacop/schema2.rb +22 -0
 - data/lib/schemacop/schema3.rb +21 -0
 - data/lib/schemacop/scoped_env.rb +25 -13
 - data/lib/schemacop/v2.rb +26 -0
 - data/lib/schemacop/{caster.rb → v2/caster.rb} +16 -2
 - data/lib/schemacop/{collector.rb → v2/collector.rb} +5 -2
 - data/lib/schemacop/{dupper.rb → v2/dupper.rb} +1 -1
 - data/lib/schemacop/{field_node.rb → v2/field_node.rb} +4 -3
 - data/lib/schemacop/v2/node.rb +142 -0
 - data/lib/schemacop/{node_resolver.rb → v2/node_resolver.rb} +1 -1
 - data/lib/schemacop/{node_supporting_field.rb → v2/node_supporting_field.rb} +8 -10
 - data/lib/schemacop/{node_supporting_type.rb → v2/node_supporting_type.rb} +6 -3
 - data/lib/schemacop/{node_with_block.rb → v2/node_with_block.rb} +3 -2
 - data/lib/schemacop/v2/root_node.rb +6 -0
 - data/lib/schemacop/v2/validator/array_validator.rb +32 -0
 - data/lib/schemacop/{validator → v2/validator}/boolean_validator.rb +1 -1
 - data/lib/schemacop/v2/validator/float_validator.rb +7 -0
 - data/lib/schemacop/v2/validator/hash_validator.rb +37 -0
 - data/lib/schemacop/v2/validator/integer_validator.rb +7 -0
 - data/lib/schemacop/{validator → v2/validator}/nil_validator.rb +1 -1
 - data/lib/schemacop/v2/validator/number_validator.rb +21 -0
 - data/lib/schemacop/v2/validator/object_validator.rb +29 -0
 - data/lib/schemacop/v2/validator/string_validator.rb +39 -0
 - data/lib/schemacop/{validator → v2/validator}/symbol_validator.rb +1 -1
 - data/lib/schemacop/v3.rb +45 -0
 - data/lib/schemacop/v3/all_of_node.rb +27 -0
 - data/lib/schemacop/v3/any_of_node.rb +28 -0
 - data/lib/schemacop/v3/array_node.rb +219 -0
 - data/lib/schemacop/v3/boolean_node.rb +16 -0
 - data/lib/schemacop/v3/combination_node.rb +45 -0
 - data/lib/schemacop/v3/context.rb +17 -0
 - data/lib/schemacop/v3/dsl_scope.rb +46 -0
 - data/lib/schemacop/v3/global_context.rb +114 -0
 - data/lib/schemacop/v3/hash_node.rb +217 -0
 - data/lib/schemacop/v3/integer_node.rb +13 -0
 - data/lib/schemacop/v3/is_not_node.rb +32 -0
 - data/lib/schemacop/v3/node.rb +214 -0
 - data/lib/schemacop/v3/node_registry.rb +49 -0
 - data/lib/schemacop/v3/number_node.rb +18 -0
 - data/lib/schemacop/v3/numeric_node.rb +76 -0
 - data/lib/schemacop/v3/object_node.rb +40 -0
 - data/lib/schemacop/v3/one_of_node.rb +28 -0
 - data/lib/schemacop/v3/reference_node.rb +49 -0
 - data/lib/schemacop/v3/result.rb +58 -0
 - data/lib/schemacop/v3/string_node.rb +124 -0
 - data/lib/schemacop/v3/symbol_node.rb +13 -0
 - data/schemacop.gemspec +24 -27
 - data/test/lib/test_helper.rb +152 -0
 - data/test/schemas/nested/group.rb +6 -0
 - data/test/schemas/user.rb +7 -0
 - data/test/unit/schemacop/v2/casting_test.rb +120 -0
 - data/test/unit/schemacop/v2/collector_test.rb +47 -0
 - data/test/unit/schemacop/v2/custom_check_test.rb +95 -0
 - data/test/unit/schemacop/v2/custom_if_test.rb +97 -0
 - data/test/unit/schemacop/v2/defaults_test.rb +95 -0
 - data/test/unit/schemacop/v2/empty_test.rb +16 -0
 - data/test/unit/schemacop/v2/nil_dis_allow_test.rb +43 -0
 - data/test/unit/schemacop/v2/node_resolver_test.rb +28 -0
 - data/test/unit/schemacop/v2/short_forms_test.rb +351 -0
 - data/test/unit/schemacop/v2/types_test.rb +88 -0
 - data/test/unit/schemacop/v2/validator_array_test.rb +99 -0
 - data/test/unit/schemacop/v2/validator_boolean_test.rb +17 -0
 - data/test/unit/schemacop/v2/validator_float_test.rb +59 -0
 - data/test/unit/schemacop/v2/validator_hash_test.rb +95 -0
 - data/test/unit/schemacop/v2/validator_integer_test.rb +48 -0
 - data/test/unit/schemacop/v2/validator_nil_test.rb +15 -0
 - data/test/unit/schemacop/v2/validator_number_test.rb +62 -0
 - data/test/unit/schemacop/v2/validator_object_test.rb +141 -0
 - data/test/unit/schemacop/v2/validator_string_test.rb +78 -0
 - data/test/unit/schemacop/v2/validator_symbol_test.rb +18 -0
 - data/test/unit/schemacop/v3/all_of_node_test.rb +199 -0
 - data/test/unit/schemacop/v3/any_of_node_test.rb +218 -0
 - data/test/unit/schemacop/v3/array_node_test.rb +805 -0
 - data/test/unit/schemacop/v3/boolean_node_test.rb +126 -0
 - data/test/unit/schemacop/v3/global_context_test.rb +164 -0
 - data/test/unit/schemacop/v3/hash_node_test.rb +775 -0
 - data/test/unit/schemacop/v3/integer_node_test.rb +323 -0
 - data/test/unit/schemacop/v3/is_not_node_test.rb +173 -0
 - data/test/unit/schemacop/v3/node_test.rb +148 -0
 - data/test/unit/schemacop/v3/number_node_test.rb +292 -0
 - data/test/unit/schemacop/v3/object_node_test.rb +170 -0
 - data/test/unit/schemacop/v3/one_of_node_test.rb +187 -0
 - data/test/unit/schemacop/v3/reference_node_test.rb +351 -0
 - data/test/unit/schemacop/v3/string_node_test.rb +334 -0
 - data/test/unit/schemacop/v3/symbol_node_test.rb +75 -0
 - metadata +152 -145
 - data/doc/Schemacop.html +0 -146
 - data/doc/Schemacop/ArrayValidator.html +0 -329
 - data/doc/Schemacop/BooleanValidator.html +0 -145
 - data/doc/Schemacop/Caster.html +0 -379
 - data/doc/Schemacop/Collector.html +0 -787
 - data/doc/Schemacop/Dupper.html +0 -214
 - data/doc/Schemacop/Exceptions.html +0 -115
 - data/doc/Schemacop/Exceptions/InvalidSchemaError.html +0 -124
 - data/doc/Schemacop/Exceptions/ValidationError.html +0 -124
 - data/doc/Schemacop/FieldNode.html +0 -421
 - data/doc/Schemacop/FloatValidator.html +0 -158
 - data/doc/Schemacop/HashValidator.html +0 -293
 - data/doc/Schemacop/IntegerValidator.html +0 -158
 - data/doc/Schemacop/NilValidator.html +0 -145
 - data/doc/Schemacop/Node.html +0 -1438
 - data/doc/Schemacop/NodeResolver.html +0 -258
 - data/doc/Schemacop/NodeSupportingField.html +0 -590
 - data/doc/Schemacop/NodeSupportingType.html +0 -612
 - data/doc/Schemacop/NodeWithBlock.html +0 -289
 - data/doc/Schemacop/NumberValidator.html +0 -232
 - data/doc/Schemacop/ObjectValidator.html +0 -298
 - data/doc/Schemacop/RootNode.html +0 -171
 - data/doc/Schemacop/Schema.html +0 -699
 - data/doc/Schemacop/StringValidator.html +0 -295
 - data/doc/Schemacop/SymbolValidator.html +0 -145
 - data/doc/ScopedEnv.html +0 -351
 - data/doc/_index.html +0 -379
 - data/doc/class_list.html +0 -51
 - data/doc/css/common.css +0 -1
 - data/doc/css/full_list.css +0 -58
 - data/doc/css/style.css +0 -496
 - data/doc/file.README.html +0 -833
 - data/doc/file_list.html +0 -56
 - data/doc/frames.html +0 -17
 - data/doc/index.html +0 -833
 - data/doc/inheritance.graphml +0 -524
 - data/doc/inheritance.pdf +0 -825
 - data/doc/js/app.js +0 -303
 - data/doc/js/full_list.js +0 -216
 - data/doc/js/jquery.js +0 -4
 - data/doc/method_list.html +0 -587
 - data/doc/top-level-namespace.html +0 -112
 - data/lib/schemacop/node.rb +0 -139
 - data/lib/schemacop/root_node.rb +0 -4
 - data/lib/schemacop/validator/array_validator.rb +0 -30
 - data/lib/schemacop/validator/float_validator.rb +0 -5
 - data/lib/schemacop/validator/hash_validator.rb +0 -35
 - data/lib/schemacop/validator/integer_validator.rb +0 -5
 - data/lib/schemacop/validator/number_validator.rb +0 -19
 - data/lib/schemacop/validator/object_validator.rb +0 -27
 - data/lib/schemacop/validator/string_validator.rb +0 -37
 - data/test/casting_test.rb +0 -118
 - data/test/collector_test.rb +0 -45
 - data/test/custom_check_test.rb +0 -93
 - data/test/custom_if_test.rb +0 -95
 - data/test/defaults_test.rb +0 -93
 - data/test/empty_test.rb +0 -14
 - data/test/nil_dis_allow_test.rb +0 -41
 - data/test/node_resolver_test.rb +0 -26
 - data/test/short_forms_test.rb +0 -349
 - data/test/test_helper.rb +0 -13
 - data/test/types_test.rb +0 -84
 - data/test/validator_array_test.rb +0 -97
 - data/test/validator_boolean_test.rb +0 -15
 - data/test/validator_float_test.rb +0 -57
 - data/test/validator_hash_test.rb +0 -93
 - data/test/validator_integer_test.rb +0 -46
 - data/test/validator_nil_test.rb +0 -13
 - data/test/validator_number_test.rb +0 -60
 - data/test/validator_object_test.rb +0 -139
 - data/test/validator_string_test.rb +0 -76
 - data/test/validator_symbol_test.rb +0 -16
 
    
        data/lib/schemacop/v3.rb
    ADDED
    
    | 
         @@ -0,0 +1,45 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Schemacop
         
     | 
| 
      
 2 
     | 
    
         
            +
              module V3
         
     | 
| 
      
 3 
     | 
    
         
            +
                def self.register(*args)
         
     | 
| 
      
 4 
     | 
    
         
            +
                  NodeRegistry.register(*args)
         
     | 
| 
      
 5 
     | 
    
         
            +
                end
         
     | 
| 
      
 6 
     | 
    
         
            +
              end
         
     | 
| 
      
 7 
     | 
    
         
            +
            end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            # Require V3 files
         
     | 
| 
      
 10 
     | 
    
         
            +
            require 'schemacop/v3/node_registry'
         
     | 
| 
      
 11 
     | 
    
         
            +
            require 'schemacop/v3/dsl_scope'
         
     | 
| 
      
 12 
     | 
    
         
            +
            require 'schemacop/v3/context'
         
     | 
| 
      
 13 
     | 
    
         
            +
            require 'schemacop/v3/global_context'
         
     | 
| 
      
 14 
     | 
    
         
            +
            require 'schemacop/v3/result'
         
     | 
| 
      
 15 
     | 
    
         
            +
            require 'schemacop/v3/node'
         
     | 
| 
      
 16 
     | 
    
         
            +
            require 'schemacop/v3/combination_node'
         
     | 
| 
      
 17 
     | 
    
         
            +
            require 'schemacop/v3/numeric_node'
         
     | 
| 
      
 18 
     | 
    
         
            +
            require 'schemacop/v3/all_of_node'
         
     | 
| 
      
 19 
     | 
    
         
            +
            require 'schemacop/v3/any_of_node'
         
     | 
| 
      
 20 
     | 
    
         
            +
            require 'schemacop/v3/array_node'
         
     | 
| 
      
 21 
     | 
    
         
            +
            require 'schemacop/v3/boolean_node'
         
     | 
| 
      
 22 
     | 
    
         
            +
            require 'schemacop/v3/hash_node'
         
     | 
| 
      
 23 
     | 
    
         
            +
            require 'schemacop/v3/integer_node'
         
     | 
| 
      
 24 
     | 
    
         
            +
            require 'schemacop/v3/is_not_node'
         
     | 
| 
      
 25 
     | 
    
         
            +
            require 'schemacop/v3/number_node'
         
     | 
| 
      
 26 
     | 
    
         
            +
            require 'schemacop/v3/object_node'
         
     | 
| 
      
 27 
     | 
    
         
            +
            require 'schemacop/v3/one_of_node'
         
     | 
| 
      
 28 
     | 
    
         
            +
            require 'schemacop/v3/reference_node'
         
     | 
| 
      
 29 
     | 
    
         
            +
            require 'schemacop/v3/string_node'
         
     | 
| 
      
 30 
     | 
    
         
            +
            require 'schemacop/v3/symbol_node'
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
            # Register built-in nodes
         
     | 
| 
      
 33 
     | 
    
         
            +
            Schemacop::V3.register :all_of,    :all_of, Schemacop::V3::AllOfNode
         
     | 
| 
      
 34 
     | 
    
         
            +
            Schemacop::V3.register :any_of,    :any_of, Schemacop::V3::AnyOfNode
         
     | 
| 
      
 35 
     | 
    
         
            +
            Schemacop::V3.register :array,     :ary,    Schemacop::V3::ArrayNode
         
     | 
| 
      
 36 
     | 
    
         
            +
            Schemacop::V3.register :boolean,   :boo,    Schemacop::V3::BooleanNode
         
     | 
| 
      
 37 
     | 
    
         
            +
            Schemacop::V3.register :integer,   :int,    Schemacop::V3::IntegerNode
         
     | 
| 
      
 38 
     | 
    
         
            +
            Schemacop::V3.register :is_not,    :is_not, Schemacop::V3::IsNotNode
         
     | 
| 
      
 39 
     | 
    
         
            +
            Schemacop::V3.register :number,    :num,    Schemacop::V3::NumberNode
         
     | 
| 
      
 40 
     | 
    
         
            +
            Schemacop::V3.register :hash,      :hsh,    Schemacop::V3::HashNode
         
     | 
| 
      
 41 
     | 
    
         
            +
            Schemacop::V3.register :one_of,    :one_of, Schemacop::V3::OneOfNode
         
     | 
| 
      
 42 
     | 
    
         
            +
            Schemacop::V3.register :reference, :ref,    Schemacop::V3::ReferenceNode
         
     | 
| 
      
 43 
     | 
    
         
            +
            Schemacop::V3.register :object,    :obj,    Schemacop::V3::ObjectNode
         
     | 
| 
      
 44 
     | 
    
         
            +
            Schemacop::V3.register :string,    :str,    Schemacop::V3::StringNode
         
     | 
| 
      
 45 
     | 
    
         
            +
            Schemacop::V3.register :symbol,    :sym,    Schemacop::V3::SymbolNode
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Schemacop
         
     | 
| 
      
 2 
     | 
    
         
            +
              module V3
         
     | 
| 
      
 3 
     | 
    
         
            +
                class AllOfNode < CombinationNode
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def type
         
     | 
| 
      
 5 
     | 
    
         
            +
                    :allOf
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def _validate(data, result:)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    super_data = super
         
     | 
| 
      
 10 
     | 
    
         
            +
                    return if super_data.nil?
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    if matches(super_data).size != @items.size
         
     | 
| 
      
 13 
     | 
    
         
            +
                      result.error 'Does not match all allOf conditions.'
         
     | 
| 
      
 14 
     | 
    
         
            +
                    end
         
     | 
| 
      
 15 
     | 
    
         
            +
                  end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                  def cast(value)
         
     | 
| 
      
 18 
     | 
    
         
            +
                    items = matches(value)
         
     | 
| 
      
 19 
     | 
    
         
            +
                    return value unless items
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                    casted_value = value.dup
         
     | 
| 
      
 22 
     | 
    
         
            +
                    items.each { |i| casted_value = i.cast(casted_value) }
         
     | 
| 
      
 23 
     | 
    
         
            +
                    return casted_value
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
                end
         
     | 
| 
      
 26 
     | 
    
         
            +
              end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Schemacop
         
     | 
| 
      
 2 
     | 
    
         
            +
              module V3
         
     | 
| 
      
 3 
     | 
    
         
            +
                class AnyOfNode < CombinationNode
         
     | 
| 
      
 4 
     | 
    
         
            +
                  def type
         
     | 
| 
      
 5 
     | 
    
         
            +
                    :anyOf
         
     | 
| 
      
 6 
     | 
    
         
            +
                  end
         
     | 
| 
      
 7 
     | 
    
         
            +
             
     | 
| 
      
 8 
     | 
    
         
            +
                  def _validate(data, result:)
         
     | 
| 
      
 9 
     | 
    
         
            +
                    super_data = super
         
     | 
| 
      
 10 
     | 
    
         
            +
                    return if super_data.nil?
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                    match = match(super_data)
         
     | 
| 
      
 13 
     | 
    
         
            +
             
     | 
| 
      
 14 
     | 
    
         
            +
                    if match
         
     | 
| 
      
 15 
     | 
    
         
            +
                      match._validate(super_data, result: result)
         
     | 
| 
      
 16 
     | 
    
         
            +
                    else
         
     | 
| 
      
 17 
     | 
    
         
            +
                      result.error 'Does not match any anyOf condition.'
         
     | 
| 
      
 18 
     | 
    
         
            +
                    end
         
     | 
| 
      
 19 
     | 
    
         
            +
                  end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
                  def validate_self
         
     | 
| 
      
 22 
     | 
    
         
            +
                    if @items.empty?
         
     | 
| 
      
 23 
     | 
    
         
            +
                      fail 'Node "any_of" makes only sense with at least 1 item.'
         
     | 
| 
      
 24 
     | 
    
         
            +
                    end
         
     | 
| 
      
 25 
     | 
    
         
            +
                  end
         
     | 
| 
      
 26 
     | 
    
         
            +
                end
         
     | 
| 
      
 27 
     | 
    
         
            +
              end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,219 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Schemacop
         
     | 
| 
      
 2 
     | 
    
         
            +
              module V3
         
     | 
| 
      
 3 
     | 
    
         
            +
                class ArrayNode < Node
         
     | 
| 
      
 4 
     | 
    
         
            +
                  ATTRIBUTES = %i[
         
     | 
| 
      
 5 
     | 
    
         
            +
                    min_items
         
     | 
| 
      
 6 
     | 
    
         
            +
                    max_items
         
     | 
| 
      
 7 
     | 
    
         
            +
                    unique_items
         
     | 
| 
      
 8 
     | 
    
         
            +
                  ].freeze
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  supports_children
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
                  def self.allowed_options
         
     | 
| 
      
 13 
     | 
    
         
            +
                    super + ATTRIBUTES + %i[additional_items]
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
             
     | 
| 
      
 16 
     | 
    
         
            +
                  def self.dsl_methods
         
     | 
| 
      
 17 
     | 
    
         
            +
                    super + NodeRegistry.dsl_methods(false) + %i[dsl_add dsl_list dsl_cont]
         
     | 
| 
      
 18 
     | 
    
         
            +
                  end
         
     | 
| 
      
 19 
     | 
    
         
            +
             
     | 
| 
      
 20 
     | 
    
         
            +
                  attr_reader :items
         
     | 
| 
      
 21 
     | 
    
         
            +
                  attr_accessor :list_item
         
     | 
| 
      
 22 
     | 
    
         
            +
                  attr_accessor :cont_item
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
                  def dsl_add(type, **options, &block)
         
     | 
| 
      
 25 
     | 
    
         
            +
                    if @options[:additional_items].is_a?(Node)
         
     | 
| 
      
 26 
     | 
    
         
            +
                      fail Exceptions::InvalidSchemaError, 'You can only use "add" once to specify additional items.'
         
     | 
| 
      
 27 
     | 
    
         
            +
                    end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
                    @options[:additional_items] = create(type, **options, &block)
         
     | 
| 
      
 30 
     | 
    
         
            +
                  end
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  def dsl_list(type, **options, &block)
         
     | 
| 
      
 33 
     | 
    
         
            +
                    if list_item.is_a?(Node)
         
     | 
| 
      
 34 
     | 
    
         
            +
                      fail Exceptions::InvalidSchemaError, 'You can only use "list" once.'
         
     | 
| 
      
 35 
     | 
    
         
            +
                    end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                    @list_item = create(type, **options, &block)
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  def dsl_cont(type, **options, &block)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    if cont_item.is_a?(Node)
         
     | 
| 
      
 42 
     | 
    
         
            +
                      fail Exceptions::InvalidSchemaError, 'You can only use "cont" once.'
         
     | 
| 
      
 43 
     | 
    
         
            +
                    end
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
                    @cont_item = create(type, **options, &block)
         
     | 
| 
      
 46 
     | 
    
         
            +
                  end
         
     | 
| 
      
 47 
     | 
    
         
            +
             
     | 
| 
      
 48 
     | 
    
         
            +
                  def add_child(node)
         
     | 
| 
      
 49 
     | 
    
         
            +
                    @items << node
         
     | 
| 
      
 50 
     | 
    
         
            +
                  end
         
     | 
| 
      
 51 
     | 
    
         
            +
             
     | 
| 
      
 52 
     | 
    
         
            +
                  def as_json
         
     | 
| 
      
 53 
     | 
    
         
            +
                    json = { type: :array }
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
                    if cont_item
         
     | 
| 
      
 56 
     | 
    
         
            +
                      json[:contains] = cont_item.as_json
         
     | 
| 
      
 57 
     | 
    
         
            +
                    end
         
     | 
| 
      
 58 
     | 
    
         
            +
             
     | 
| 
      
 59 
     | 
    
         
            +
                    if list?
         
     | 
| 
      
 60 
     | 
    
         
            +
                      json[:items] = @list_item.as_json
         
     | 
| 
      
 61 
     | 
    
         
            +
                    elsif @items.any?
         
     | 
| 
      
 62 
     | 
    
         
            +
                      json[:items] = @items.map(&:as_json)
         
     | 
| 
      
 63 
     | 
    
         
            +
                      if options[:additional_items] == true
         
     | 
| 
      
 64 
     | 
    
         
            +
                        json[:additionalItems] = true
         
     | 
| 
      
 65 
     | 
    
         
            +
                      elsif options[:additional_items].is_a?(Node)
         
     | 
| 
      
 66 
     | 
    
         
            +
                        json[:additionalItems] = options[:additional_items].as_json
         
     | 
| 
      
 67 
     | 
    
         
            +
                      else
         
     | 
| 
      
 68 
     | 
    
         
            +
                        json[:additionalItems] = false
         
     | 
| 
      
 69 
     | 
    
         
            +
                      end
         
     | 
| 
      
 70 
     | 
    
         
            +
                    end
         
     | 
| 
      
 71 
     | 
    
         
            +
             
     | 
| 
      
 72 
     | 
    
         
            +
                    return process_json(ATTRIBUTES, json)
         
     | 
| 
      
 73 
     | 
    
         
            +
                  end
         
     | 
| 
      
 74 
     | 
    
         
            +
             
     | 
| 
      
 75 
     | 
    
         
            +
                  def allowed_types
         
     | 
| 
      
 76 
     | 
    
         
            +
                    { Array => :array }
         
     | 
| 
      
 77 
     | 
    
         
            +
                  end
         
     | 
| 
      
 78 
     | 
    
         
            +
             
     | 
| 
      
 79 
     | 
    
         
            +
                  def _validate(data, result:)
         
     | 
| 
      
 80 
     | 
    
         
            +
                    super_data = super
         
     | 
| 
      
 81 
     | 
    
         
            +
                    return if super_data.nil?
         
     | 
| 
      
 82 
     | 
    
         
            +
             
     | 
| 
      
 83 
     | 
    
         
            +
                    # Validate length #
         
     | 
| 
      
 84 
     | 
    
         
            +
                    length = super_data.size
         
     | 
| 
      
 85 
     | 
    
         
            +
             
     | 
| 
      
 86 
     | 
    
         
            +
                    if options[:min_items] && length < options[:min_items]
         
     | 
| 
      
 87 
     | 
    
         
            +
                      result.error "Array has #{length} items but needs at least #{options[:min_items]}."
         
     | 
| 
      
 88 
     | 
    
         
            +
                    end
         
     | 
| 
      
 89 
     | 
    
         
            +
             
     | 
| 
      
 90 
     | 
    
         
            +
                    if options[:max_items] && length > options[:max_items]
         
     | 
| 
      
 91 
     | 
    
         
            +
                      result.error "Array has #{length} items but needs at most #{options[:max_items]}."
         
     | 
| 
      
 92 
     | 
    
         
            +
                    end
         
     | 
| 
      
 93 
     | 
    
         
            +
             
     | 
| 
      
 94 
     | 
    
         
            +
                    if list?
         
     | 
| 
      
 95 
     | 
    
         
            +
                      # Validate list
         
     | 
| 
      
 96 
     | 
    
         
            +
                      super_data.each_with_index do |value, index|
         
     | 
| 
      
 97 
     | 
    
         
            +
                        result.in_path :"[#{index}]" do
         
     | 
| 
      
 98 
     | 
    
         
            +
                          list_item._validate(value, result: result)
         
     | 
| 
      
 99 
     | 
    
         
            +
                        end
         
     | 
| 
      
 100 
     | 
    
         
            +
                      end
         
     | 
| 
      
 101 
     | 
    
         
            +
                    elsif items.any?
         
     | 
| 
      
 102 
     | 
    
         
            +
                      # Validate tuple
         
     | 
| 
      
 103 
     | 
    
         
            +
                      if length == items.size || (options[:additional_items] != false && length >= items.size)
         
     | 
| 
      
 104 
     | 
    
         
            +
                        items.each_with_index do |child_node, index|
         
     | 
| 
      
 105 
     | 
    
         
            +
                          value = super_data[index]
         
     | 
| 
      
 106 
     | 
    
         
            +
             
     | 
| 
      
 107 
     | 
    
         
            +
                          result.in_path :"[#{index}]" do
         
     | 
| 
      
 108 
     | 
    
         
            +
                            child_node._validate(value, result: result)
         
     | 
| 
      
 109 
     | 
    
         
            +
                          end
         
     | 
| 
      
 110 
     | 
    
         
            +
                        end
         
     | 
| 
      
 111 
     | 
    
         
            +
             
     | 
| 
      
 112 
     | 
    
         
            +
                        # Validate additional items #
         
     | 
| 
      
 113 
     | 
    
         
            +
                        if options[:additional_items].is_a?(Node)
         
     | 
| 
      
 114 
     | 
    
         
            +
                          (items.size..(length - 1)).each do |index|
         
     | 
| 
      
 115 
     | 
    
         
            +
                            additional_item = super_data[index]
         
     | 
| 
      
 116 
     | 
    
         
            +
                            result.in_path :"[#{index}]" do
         
     | 
| 
      
 117 
     | 
    
         
            +
                              options[:additional_items]._validate(additional_item, result: result)
         
     | 
| 
      
 118 
     | 
    
         
            +
                            end
         
     | 
| 
      
 119 
     | 
    
         
            +
                          end
         
     | 
| 
      
 120 
     | 
    
         
            +
                        end
         
     | 
| 
      
 121 
     | 
    
         
            +
                      else
         
     | 
| 
      
 122 
     | 
    
         
            +
                        result.error "Array has #{length} items but must have exactly #{items.size}."
         
     | 
| 
      
 123 
     | 
    
         
            +
                      end
         
     | 
| 
      
 124 
     | 
    
         
            +
                    end
         
     | 
| 
      
 125 
     | 
    
         
            +
             
     | 
| 
      
 126 
     | 
    
         
            +
                    if cont_item.present? && super_data.none? { |obj| item_matches?(cont_item, obj) }
         
     | 
| 
      
 127 
     | 
    
         
            +
                      result.error "At least one entry must match schema #{cont_item.as_json.inspect}."
         
     | 
| 
      
 128 
     | 
    
         
            +
                    end
         
     | 
| 
      
 129 
     | 
    
         
            +
             
     | 
| 
      
 130 
     | 
    
         
            +
                    # Validate uniqueness #
         
     | 
| 
      
 131 
     | 
    
         
            +
                    if options[:unique_items] && super_data.size != super_data.uniq.size
         
     | 
| 
      
 132 
     | 
    
         
            +
                      result.error 'Array has duplicate items.'
         
     | 
| 
      
 133 
     | 
    
         
            +
                    end
         
     | 
| 
      
 134 
     | 
    
         
            +
                  end
         
     | 
| 
      
 135 
     | 
    
         
            +
             
     | 
| 
      
 136 
     | 
    
         
            +
                  def children
         
     | 
| 
      
 137 
     | 
    
         
            +
                    (@items + [@cont_item]).compact
         
     | 
| 
      
 138 
     | 
    
         
            +
                  end
         
     | 
| 
      
 139 
     | 
    
         
            +
             
     | 
| 
      
 140 
     | 
    
         
            +
                  def cast(value)
         
     | 
| 
      
 141 
     | 
    
         
            +
                    return default unless value
         
     | 
| 
      
 142 
     | 
    
         
            +
             
     | 
| 
      
 143 
     | 
    
         
            +
                    result = []
         
     | 
| 
      
 144 
     | 
    
         
            +
             
     | 
| 
      
 145 
     | 
    
         
            +
                    value.each_with_index do |value_item, index|
         
     | 
| 
      
 146 
     | 
    
         
            +
                      if cont_item.present? && item_matches?(cont_item, value_item)
         
     | 
| 
      
 147 
     | 
    
         
            +
                        result << cont_item.cast(value_item)
         
     | 
| 
      
 148 
     | 
    
         
            +
                      elsif list?
         
     | 
| 
      
 149 
     | 
    
         
            +
                        result << list_item.cast(value_item)
         
     | 
| 
      
 150 
     | 
    
         
            +
                      elsif items.any?
         
     | 
| 
      
 151 
     | 
    
         
            +
                        if options[:additional_items] != false && index >= items.size
         
     | 
| 
      
 152 
     | 
    
         
            +
                          if options[:additional_items].is_a?(Node)
         
     | 
| 
      
 153 
     | 
    
         
            +
                            result << options[:additional_items].cast(value_item)
         
     | 
| 
      
 154 
     | 
    
         
            +
                          else
         
     | 
| 
      
 155 
     | 
    
         
            +
                            result << value_item
         
     | 
| 
      
 156 
     | 
    
         
            +
                          end
         
     | 
| 
      
 157 
     | 
    
         
            +
                        else
         
     | 
| 
      
 158 
     | 
    
         
            +
                          item = item_for_data(value_item)
         
     | 
| 
      
 159 
     | 
    
         
            +
                          result << item.cast(value_item)
         
     | 
| 
      
 160 
     | 
    
         
            +
                        end
         
     | 
| 
      
 161 
     | 
    
         
            +
                      else
         
     | 
| 
      
 162 
     | 
    
         
            +
                        result << value_item
         
     | 
| 
      
 163 
     | 
    
         
            +
                      end
         
     | 
| 
      
 164 
     | 
    
         
            +
                    end
         
     | 
| 
      
 165 
     | 
    
         
            +
             
     | 
| 
      
 166 
     | 
    
         
            +
                    return result
         
     | 
| 
      
 167 
     | 
    
         
            +
                  end
         
     | 
| 
      
 168 
     | 
    
         
            +
             
     | 
| 
      
 169 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
                  def list?
         
     | 
| 
      
 172 
     | 
    
         
            +
                    list_item.present?
         
     | 
| 
      
 173 
     | 
    
         
            +
                  end
         
     | 
| 
      
 174 
     | 
    
         
            +
             
     | 
| 
      
 175 
     | 
    
         
            +
                  def item_for_data(data, force: true)
         
     | 
| 
      
 176 
     | 
    
         
            +
                    item = children.find { |c| item_matches?(c, data) }
         
     | 
| 
      
 177 
     | 
    
         
            +
                    return item if item
         
     | 
| 
      
 178 
     | 
    
         
            +
                    return nil unless force
         
     | 
| 
      
 179 
     | 
    
         
            +
             
     | 
| 
      
 180 
     | 
    
         
            +
                    fail "Could not find specification for item #{data.inspect}."
         
     | 
| 
      
 181 
     | 
    
         
            +
                  end
         
     | 
| 
      
 182 
     | 
    
         
            +
             
     | 
| 
      
 183 
     | 
    
         
            +
                  def init
         
     | 
| 
      
 184 
     | 
    
         
            +
                    @items = []
         
     | 
| 
      
 185 
     | 
    
         
            +
                    @cont_item = nil
         
     | 
| 
      
 186 
     | 
    
         
            +
             
     | 
| 
      
 187 
     | 
    
         
            +
                    if options[:additional_items].nil?
         
     | 
| 
      
 188 
     | 
    
         
            +
                      options[:additional_items] = false
         
     | 
| 
      
 189 
     | 
    
         
            +
                    end
         
     | 
| 
      
 190 
     | 
    
         
            +
                  end
         
     | 
| 
      
 191 
     | 
    
         
            +
             
     | 
| 
      
 192 
     | 
    
         
            +
                  def validate_self
         
     | 
| 
      
 193 
     | 
    
         
            +
                    if list? && items.any?
         
     | 
| 
      
 194 
     | 
    
         
            +
                      fail 'Can\'t use "list" and normal items.'
         
     | 
| 
      
 195 
     | 
    
         
            +
                    end
         
     | 
| 
      
 196 
     | 
    
         
            +
             
     | 
| 
      
 197 
     | 
    
         
            +
                    if list? && @options[:additional_items].is_a?(Node)
         
     | 
| 
      
 198 
     | 
    
         
            +
                      fail 'Can\'t use "list" and additional items.'
         
     | 
| 
      
 199 
     | 
    
         
            +
                    end
         
     | 
| 
      
 200 
     | 
    
         
            +
             
     | 
| 
      
 201 
     | 
    
         
            +
                    unless options[:min_items].nil? || options[:min_items].is_a?(Integer)
         
     | 
| 
      
 202 
     | 
    
         
            +
                      fail 'Option "min_items" must be an "integer"'
         
     | 
| 
      
 203 
     | 
    
         
            +
                    end
         
     | 
| 
      
 204 
     | 
    
         
            +
             
     | 
| 
      
 205 
     | 
    
         
            +
                    unless options[:max_items].nil? || options[:max_items].is_a?(Integer)
         
     | 
| 
      
 206 
     | 
    
         
            +
                      fail 'Option "max_items" must be an "integer"'
         
     | 
| 
      
 207 
     | 
    
         
            +
                    end
         
     | 
| 
      
 208 
     | 
    
         
            +
             
     | 
| 
      
 209 
     | 
    
         
            +
                    unless options[:unique_items].nil? || options[:unique_items].is_a?(TrueClass) || options[:unique_items].is_a?(FalseClass)
         
     | 
| 
      
 210 
     | 
    
         
            +
                      fail 'Option "unique_items" must be a "boolean".'
         
     | 
| 
      
 211 
     | 
    
         
            +
                    end
         
     | 
| 
      
 212 
     | 
    
         
            +
             
     | 
| 
      
 213 
     | 
    
         
            +
                    if options[:min_items] && options[:max_items] && options[:min_items] > options[:max_items]
         
     | 
| 
      
 214 
     | 
    
         
            +
                      fail 'Option "min_items" can\'t be greater than "max_items".'
         
     | 
| 
      
 215 
     | 
    
         
            +
                    end
         
     | 
| 
      
 216 
     | 
    
         
            +
                  end
         
     | 
| 
      
 217 
     | 
    
         
            +
                end
         
     | 
| 
      
 218 
     | 
    
         
            +
              end
         
     | 
| 
      
 219 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,45 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Schemacop
         
     | 
| 
      
 2 
     | 
    
         
            +
              module V3
         
     | 
| 
      
 3 
     | 
    
         
            +
                # @abstract
         
     | 
| 
      
 4 
     | 
    
         
            +
                class CombinationNode < Node
         
     | 
| 
      
 5 
     | 
    
         
            +
                  def self.dsl_methods
         
     | 
| 
      
 6 
     | 
    
         
            +
                    super + NodeRegistry.dsl_methods(false)
         
     | 
| 
      
 7 
     | 
    
         
            +
                  end
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
                  supports_children
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def init
         
     | 
| 
      
 12 
     | 
    
         
            +
                    @items = []
         
     | 
| 
      
 13 
     | 
    
         
            +
                  end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                  def as_json
         
     | 
| 
      
 16 
     | 
    
         
            +
                    process_json([], type => @items.map(&:as_json))
         
     | 
| 
      
 17 
     | 
    
         
            +
                  end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
                  def cast(value)
         
     | 
| 
      
 20 
     | 
    
         
            +
                    item = match(value)
         
     | 
| 
      
 21 
     | 
    
         
            +
                    return value unless item
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    return item.cast(value)
         
     | 
| 
      
 24 
     | 
    
         
            +
                  end
         
     | 
| 
      
 25 
     | 
    
         
            +
             
     | 
| 
      
 26 
     | 
    
         
            +
                  def add_child(node)
         
     | 
| 
      
 27 
     | 
    
         
            +
                    @items << node
         
     | 
| 
      
 28 
     | 
    
         
            +
                  end
         
     | 
| 
      
 29 
     | 
    
         
            +
             
     | 
| 
      
 30 
     | 
    
         
            +
                  protected
         
     | 
| 
      
 31 
     | 
    
         
            +
             
     | 
| 
      
 32 
     | 
    
         
            +
                  def type
         
     | 
| 
      
 33 
     | 
    
         
            +
                    fail NotImplementedError
         
     | 
| 
      
 34 
     | 
    
         
            +
                  end
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
                  def match(data)
         
     | 
| 
      
 37 
     | 
    
         
            +
                    matches(data).first
         
     | 
| 
      
 38 
     | 
    
         
            +
                  end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
                  def matches(data)
         
     | 
| 
      
 41 
     | 
    
         
            +
                    @items.filter { |i| item_matches?(i, data) }
         
     | 
| 
      
 42 
     | 
    
         
            +
                  end
         
     | 
| 
      
 43 
     | 
    
         
            +
                end
         
     | 
| 
      
 44 
     | 
    
         
            +
              end
         
     | 
| 
      
 45 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,17 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Schemacop
         
     | 
| 
      
 2 
     | 
    
         
            +
              module V3
         
     | 
| 
      
 3 
     | 
    
         
            +
                class Context
         
     | 
| 
      
 4 
     | 
    
         
            +
                  attr_accessor :schemas
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @schemas = {}.with_indifferent_access.freeze
         
     | 
| 
      
 8 
     | 
    
         
            +
                  end
         
     | 
| 
      
 9 
     | 
    
         
            +
             
     | 
| 
      
 10 
     | 
    
         
            +
                  def schema(name, type = :hash, **options, &block)
         
     | 
| 
      
 11 
     | 
    
         
            +
                    @schemas = @schemas.merge(
         
     | 
| 
      
 12 
     | 
    
         
            +
                      name => Node.create(type, **options, &block)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    ).freeze
         
     | 
| 
      
 14 
     | 
    
         
            +
                  end
         
     | 
| 
      
 15 
     | 
    
         
            +
                end
         
     | 
| 
      
 16 
     | 
    
         
            +
              end
         
     | 
| 
      
 17 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,46 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module Schemacop
         
     | 
| 
      
 2 
     | 
    
         
            +
              module V3
         
     | 
| 
      
 3 
     | 
    
         
            +
                class DslScope
         
     | 
| 
      
 4 
     | 
    
         
            +
                  EXP_NAME = /^dsl_([a-z_]+)([?!])?$/.freeze
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
                  def initialize(node)
         
     | 
| 
      
 7 
     | 
    
         
            +
                    @node = node
         
     | 
| 
      
 8 
     | 
    
         
            +
                    @with_name = @node.class.supports_children_options[:name]
         
     | 
| 
      
 9 
     | 
    
         
            +
                  end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
                  def method_missing(name, *args, **options, &block)
         
     | 
| 
      
 12 
     | 
    
         
            +
                    match = EXP_NAME.match(name)
         
     | 
| 
      
 13 
     | 
    
         
            +
                    return super unless match
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
                    base_name, req_optional = match.captures
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
                    if req_optional == '!'
         
     | 
| 
      
 18 
     | 
    
         
            +
                      options[:required] = true
         
     | 
| 
      
 19 
     | 
    
         
            +
                    elsif req_optional == '?'
         
     | 
| 
      
 20 
     | 
    
         
            +
                      options[:required] = false
         
     | 
| 
      
 21 
     | 
    
         
            +
                    end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
                    options[:parent] = @node
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
                    if (klass = NodeRegistry.by_short_name(base_name))
         
     | 
| 
      
 26 
     | 
    
         
            +
                      if @with_name
         
     | 
| 
      
 27 
     | 
    
         
            +
                        options[:name] = args.shift
         
     | 
| 
      
 28 
     | 
    
         
            +
                      end
         
     | 
| 
      
 29 
     | 
    
         
            +
                      node = klass.create(*args, **options, &block)
         
     | 
| 
      
 30 
     | 
    
         
            +
                      @node.add_child node
         
     | 
| 
      
 31 
     | 
    
         
            +
                      return node
         
     | 
| 
      
 32 
     | 
    
         
            +
                    else
         
     | 
| 
      
 33 
     | 
    
         
            +
                      return super
         
     | 
| 
      
 34 
     | 
    
         
            +
                    end
         
     | 
| 
      
 35 
     | 
    
         
            +
                  end
         
     | 
| 
      
 36 
     | 
    
         
            +
             
     | 
| 
      
 37 
     | 
    
         
            +
                  def respond_to_missing?(name, *args)
         
     | 
| 
      
 38 
     | 
    
         
            +
                    match = EXP_NAME.match(name)
         
     | 
| 
      
 39 
     | 
    
         
            +
                    return super unless match
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
      
 41 
     | 
    
         
            +
                    base_name, _req_optional = match.captures
         
     | 
| 
      
 42 
     | 
    
         
            +
                    return NodeRegistry.by_short_name(base_name).present? || super
         
     | 
| 
      
 43 
     | 
    
         
            +
                  end
         
     | 
| 
      
 44 
     | 
    
         
            +
                end
         
     | 
| 
      
 45 
     | 
    
         
            +
              end
         
     | 
| 
      
 46 
     | 
    
         
            +
            end
         
     |