smart_schema 0.2.0 → 0.3.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/.rubocop.yml +1 -0
- data/CHANGELOG.md +14 -0
- data/Gemfile.lock +4 -4
- data/README.md +53 -7
- data/lib/smart_core/schema/checker.rb +28 -0
- data/lib/smart_core/schema/checker/reconciler.rb +32 -2
- data/lib/smart_core/schema/checker/reconciler/constructor.rb +32 -0
- data/lib/smart_core/schema/checker/reconciler/matcher.rb +15 -6
- data/lib/smart_core/schema/checker/reconciler/matcher/options.rb +33 -0
- data/lib/smart_core/schema/checker/reconciler/matcher/result_finalizer.rb +51 -14
- data/lib/smart_core/schema/checker/rules/base.rb +19 -3
- data/lib/smart_core/schema/checker/rules/extra_keys.rb +11 -2
- data/lib/smart_core/schema/checker/rules/extra_keys/failure.rb +17 -29
- data/lib/smart_core/schema/checker/rules/extra_keys/result.rb +37 -0
- data/lib/smart_core/schema/checker/rules/extra_keys/success.rb +23 -14
- data/lib/smart_core/schema/checker/rules/optional.rb +5 -2
- data/lib/smart_core/schema/checker/rules/options/filled.rb +3 -3
- data/lib/smart_core/schema/checker/rules/options/type.rb +2 -2
- data/lib/smart_core/schema/checker/rules/required.rb +5 -2
- data/lib/smart_core/schema/checker/rules/verifier.rb +4 -1
- data/lib/smart_core/schema/dsl.rb +26 -2
- data/lib/smart_core/schema/result.rb +13 -1
- data/lib/smart_core/schema/version.rb +2 -2
- metadata +5 -3
    
        checksums.yaml
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            ---
         | 
| 2 2 | 
             
            SHA256:
         | 
| 3 | 
            -
              metadata.gz:  | 
| 4 | 
            -
              data.tar.gz:  | 
| 3 | 
            +
              metadata.gz: ad6ef4371489ef23da9a5b48a6acd744f3b471492407ab5e5b0201b35e5a4d76
         | 
| 4 | 
            +
              data.tar.gz: 05f6c88bb367f406b4d401a5ac2349e17cda800ed46d5be6555b292c8b782d5b
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: 0ec964a29f97595aa11087531ca29872f041c13182edfa6c8766e16472218db0cb9b1a91886a28cc7484761ab5dc5ec9a6dcbc9087d8ed3a35931d927f7582ad
         | 
| 7 | 
            +
              data.tar.gz: 9d64b474fa69b251a0f88abd6c82f01cd6d629c6bee51c113d15481f53df77c296c4e510c5af904bacc5a4be570b080517f6721afd6180e211b9c90e39b5c68e
         | 
    
        data/.rubocop.yml
    CHANGED
    
    
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -1,6 +1,20 @@ | |
| 1 1 | 
             
            # Changelog
         | 
| 2 2 | 
             
            All notable changes to this project will be documented in this file.
         | 
| 3 3 |  | 
| 4 | 
            +
            # [0.3.0] - 2020-12-03
         | 
| 5 | 
            +
            ### Added
         | 
| 6 | 
            +
            - Support for *strict* and *non-strict* schemas;
         | 
| 7 | 
            +
              - `strict!` DSL directive marks your schema as a strict schema (your hash can not have extra keys);
         | 
| 8 | 
            +
              - `non_strict!` DSL directive marks your schema as non-strict schema (your hash can have extra keys);
         | 
| 9 | 
            +
              - use `strict!` in any schema's context place to mark your current schema context as a strict;
         | 
| 10 | 
            +
              - use `non_strict` in any schema's context place to mark your current schema context as a strict;
         | 
| 11 | 
            +
              - use `schema(:strict)` to globally define strict schema (default behavior);
         | 
| 12 | 
            +
              - use `schema(:non_strict)` to globally define non-strict schema;
         | 
| 13 | 
            +
              - nested schemas inherits strict behavior from outer schemas;
         | 
| 14 | 
            +
              - root schema is `:strict` by default;
         | 
| 15 | 
            +
              - schema reopening without mode attribute does not change original schema mode
         | 
| 16 | 
            +
                (you should manually pass a mode attribute to redefine already defined schema mode);
         | 
| 17 | 
            +
             | 
| 4 18 | 
             
            # [0.2.0] - 2020-11-09
         | 
| 5 19 | 
             
            ### Added
         | 
| 6 20 | 
             
            - `#errors` now includes `#extra_keys` too (`:extra_key` error code for each extra key);
         | 
    
        data/Gemfile.lock
    CHANGED
    
    | @@ -1,7 +1,7 @@ | |
| 1 1 | 
             
            PATH
         | 
| 2 2 | 
             
              remote: .
         | 
| 3 3 | 
             
              specs:
         | 
| 4 | 
            -
                smart_schema (0. | 
| 4 | 
            +
                smart_schema (0.3.0)
         | 
| 5 5 | 
             
                  smart_engine (~> 0.8)
         | 
| 6 6 | 
             
                  smart_types (~> 0.1)
         | 
| 7 7 |  | 
| @@ -82,8 +82,8 @@ GEM | |
| 82 82 | 
             
                  simplecov-html (~> 0.11)
         | 
| 83 83 | 
             
                simplecov-html (0.12.3)
         | 
| 84 84 | 
             
                smart_engine (0.8.0)
         | 
| 85 | 
            -
                smart_types (0. | 
| 86 | 
            -
                  smart_engine (~> 0. | 
| 85 | 
            +
                smart_types (0.2.0)
         | 
| 86 | 
            +
                  smart_engine (~> 0.7)
         | 
| 87 87 | 
             
                thread_safe (0.3.6)
         | 
| 88 88 | 
             
                tzinfo (1.2.8)
         | 
| 89 89 | 
             
                  thread_safe (~> 0.1)
         | 
| @@ -103,4 +103,4 @@ DEPENDENCIES | |
| 103 103 | 
             
              smart_schema!
         | 
| 104 104 |  | 
| 105 105 | 
             
            BUNDLED WITH
         | 
| 106 | 
            -
               2.1 | 
| 106 | 
            +
               2.2.0.rc.1
         | 
    
        data/README.md
    CHANGED
    
    | @@ -4,7 +4,7 @@ | |
| 4 4 |  | 
| 5 5 | 
             
            Provides convenient and concise DSL to define complex schemas in easiest way and public validation interface to achieve a comfortable work with detailed validation result.
         | 
| 6 6 |  | 
| 7 | 
            -
            Supports nested structures, type validation (via `smart_types`), required- and optional- schema keys, schema value presence validation, schema inheritance (soon), schema extending (soon) and schema composition (soon).
         | 
| 7 | 
            +
            Supports nested structures, type validation (via `smart_types`), required- and optional- schema keys, *strict* and *non-strict* schemas, schema value presence validation, schema inheritance (soon), schema extending (soon) and schema composition (soon).
         | 
| 8 8 |  | 
| 9 9 | 
             
            Works in predicate style and in OOP/Monadic result object style. Enjoy :)
         | 
| 10 10 |  | 
| @@ -33,18 +33,36 @@ require 'smart_core/schema' | |
| 33 33 | 
             
            - `nil` control: `filled`;
         | 
| 34 34 | 
             
            - nested definitions: `do ... end`;
         | 
| 35 35 | 
             
            - supported types: see `smart_types` gem;
         | 
| 36 | 
            +
            - strict modes and strict behavior: `strict!`, `non_strict!`, `schema(:strict)`, `schema(:non_strict)`;
         | 
| 37 | 
            +
            - `:strict` is used by default (in first `schema` invokation);
         | 
| 38 | 
            +
            - you can make non-strict inner schemas inside strict schemas (and vise-versa);
         | 
| 39 | 
            +
            - inner schemas inherits their's mode from their's nearest outer schema (and can have own mode too);
         | 
| 36 40 |  | 
| 37 41 | 
             
            ```ruby
         | 
| 38 42 | 
             
            class MySchema < SmartCore::Schema
         | 
| 39 | 
            -
              schema  | 
| 43 | 
            +
              # you can mark strict mode in root schema here:
         | 
| 44 | 
            +
              #
         | 
| 45 | 
            +
              # non_strict!
         | 
| 46 | 
            +
              #
         | 
| 47 | 
            +
              # -- or --
         | 
| 48 | 
            +
              #
         | 
| 49 | 
            +
              # strict!
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              schema do # or here with `schema(:strict)` (default in first time) or `schema(:non_strict)`
         | 
| 40 52 | 
             
                required(:key) do
         | 
| 53 | 
            +
                  # inherits `:strict`
         | 
| 41 54 | 
             
                  optional(:data).type(:string).filled
         | 
| 42 55 | 
             
                  optional(:value).type(:numeric)
         | 
| 43 56 | 
             
                  required(:name).type(:string)
         | 
| 44 57 |  | 
| 45 58 | 
             
                  required(:nested) do
         | 
| 59 | 
            +
                    # inherits `:strict`
         | 
| 46 60 | 
             
                    optional(:version).filled
         | 
| 47 61 | 
             
                  end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                  optional(:another_nested) do
         | 
| 64 | 
            +
                    non_strict! # marks current nested schema as `:non_strict`
         | 
| 65 | 
            +
                  end
         | 
| 48 66 | 
             
                end
         | 
| 49 67 |  | 
| 50 68 | 
             
                required(:another_key).filled
         | 
| @@ -55,6 +73,30 @@ class MySchema < SmartCore::Schema | |
| 55 73 | 
             
              # schema do
         | 
| 56 74 | 
             
              #   required(:third_key).filled.type(:string)
         | 
| 57 75 | 
             
              # end
         | 
| 76 | 
            +
             | 
| 77 | 
            +
              # you can redefine strict behavior of already defined schema:
         | 
| 78 | 
            +
              #
         | 
| 79 | 
            +
              # schema(:non_strict) do
         | 
| 80 | 
            +
              #   ...
         | 
| 81 | 
            +
              # end
         | 
| 82 | 
            +
              #
         | 
| 83 | 
            +
              # -- or --
         | 
| 84 | 
            +
              #
         | 
| 85 | 
            +
              # schema do
         | 
| 86 | 
            +
              #   non_strict!
         | 
| 87 | 
            +
              # end
         | 
| 88 | 
            +
              #
         | 
| 89 | 
            +
              # -- or --
         | 
| 90 | 
            +
              #
         | 
| 91 | 
            +
              # non_strict!
         | 
| 92 | 
            +
              
         | 
| 93 | 
            +
              # you can redefine nested schema behavior:
         | 
| 94 | 
            +
              #
         | 
| 95 | 
            +
              # schema do
         | 
| 96 | 
            +
              #   optional(:another_nested) do
         | 
| 97 | 
            +
              #     strict! # change from :non_strict to :strict
         | 
| 98 | 
            +
              #   end
         | 
| 99 | 
            +
              # end
         | 
| 58 100 | 
             
            end
         | 
| 59 101 | 
             
            ```
         | 
| 60 102 |  | 
| @@ -90,9 +132,11 @@ result = MySchema.new.validate( | |
| 90 132 | 
             
            #  #<SmartCore::Schema::Result:0x00007ffcd8926990
         | 
| 91 133 | 
             
            #  @errors={"key.data"=>[:non_filled], "key.value"=>[:invalid_type], "key.nested"=>[:required_key_not_found], "another_key"=>[:non_filled], "third_key"=>[:extra_key]},
         | 
| 92 134 | 
             
            #  @extra_keys=#<Set: {"third_key"}>,
         | 
| 135 | 
            +
            #  @spread_keys=#<Set: {}>, (coming soon (spread keys of non-strict schemas))
         | 
| 93 136 | 
             
            #  @source={:key=>{:data=>nil, :value=>"1", :name=>"D@iVeR"}, :another_key=>nil, :third_key=>"test"}>
         | 
| 94 137 |  | 
| 95 138 | 
             
            result.success? # => false
         | 
| 139 | 
            +
            result.spread_keys # => <Set: {}> (coming soon (spread keys of non-strict schemas))
         | 
| 96 140 | 
             
            result.extra_keys # => <Set: {"third_key"}>
         | 
| 97 141 | 
             
            result.errors # =>
         | 
| 98 142 | 
             
            {
         | 
| @@ -108,16 +152,18 @@ Possible errors: | |
| 108 152 | 
             
              - `:non_filled` (existing key has nil value);
         | 
| 109 153 | 
             
              - `:invalid_type` (existing key has invalid type);
         | 
| 110 154 | 
             
              - `:required_key_not_found` (required key does not exist);
         | 
| 111 | 
            -
              - `:extra_key` ( | 
| 155 | 
            +
              - `:extra_key` (concrete key does not exist in schema);
         | 
| 112 156 |  | 
| 113 157 | 
             
            ---
         | 
| 114 158 |  | 
| 115 159 | 
             
            ## Roadmap
         | 
| 116 160 |  | 
| 117 | 
            -
            - **(0. | 
| 118 | 
            -
            - **(0. | 
| 119 | 
            -
            - **(0.4.0)** -  | 
| 120 | 
            -
            - **(0.5.0)** -  | 
| 161 | 
            +
            - **(0.x.0)** - value-validation layer;
         | 
| 162 | 
            +
            - **(0.x.0)** - error messages (that are consistent with error codes), with a support for error-code-auto-mappings for error messages via explicit hashes or via file (yaml, json and other formats);
         | 
| 163 | 
            +
            - **(0.4.0)** - spread keys of non-strict schemas in validation result;
         | 
| 164 | 
            +
            - **(0.5.0)** - schema inheritance;
         | 
| 165 | 
            +
            - **(0.5.0)** - schema composition (`required(:key).schema(SchemaClass)`) (`compose_with(AnotherSchema)`);
         | 
| 166 | 
            +
            - **(0.5.0)** - dependable schema checking (sample: if one key exist (or not) we should check another (or not), and vice verca) (mb `if(:_key_)` rule);
         | 
| 121 167 | 
             
            - **(0.6.0)** - `smart_type-system` integration;
         | 
| 122 168 | 
             
            - **(0.7.0)** - support for another data structures (such as YAML strings, JSON strings, `Struct`, `OpenStruct`s, custom `Object`s  and etc);
         | 
| 123 169 | 
             
            - **(0.8.0)** - think about pattern matching;
         | 
| @@ -2,6 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            # @api private
         | 
| 4 4 | 
             
            # @since 0.1.0
         | 
| 5 | 
            +
            # @version 0.3.0
         | 
| 5 6 | 
             
            class SmartCore::Schema::Checker
         | 
| 6 7 | 
             
              require_relative 'checker/verifiable_hash'
         | 
| 7 8 | 
             
              require_relative 'checker/rules'
         | 
| @@ -31,6 +32,24 @@ class SmartCore::Schema::Checker | |
| 31 32 | 
             
                end
         | 
| 32 33 | 
             
              end
         | 
| 33 34 |  | 
| 35 | 
            +
              # @param checker_invokations [Block]
         | 
| 36 | 
            +
              # @return [void]
         | 
| 37 | 
            +
              #
         | 
| 38 | 
            +
              # @api private
         | 
| 39 | 
            +
              # @since 0.3.0
         | 
| 40 | 
            +
              def invoke_in_pipe(&checker_invokations)
         | 
| 41 | 
            +
                thread_safe { instance_eval(&checker_invokations) }
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
             | 
| 44 | 
            +
              # @param strict_mode [NilClass, String, Symbol]
         | 
| 45 | 
            +
              # @return [void]
         | 
| 46 | 
            +
              #
         | 
| 47 | 
            +
              # @api private
         | 
| 48 | 
            +
              # @since 0.3.0
         | 
| 49 | 
            +
              def set_strict_mode(strict_mode)
         | 
| 50 | 
            +
                thread_safe { apply_strict_mode(strict_mode) }
         | 
| 51 | 
            +
              end
         | 
| 52 | 
            +
             | 
| 34 53 | 
             
              # @param definitions [Block]
         | 
| 35 54 | 
             
              # @return [void]
         | 
| 36 55 | 
             
              #
         | 
| @@ -70,6 +89,15 @@ class SmartCore::Schema::Checker | |
| 70 89 | 
             
                Reconciler::Constructor.append_definitions(reconciler, &definitions)
         | 
| 71 90 | 
             
              end
         | 
| 72 91 |  | 
| 92 | 
            +
              # @param strict_mode [NilClass, String, Symbol]
         | 
| 93 | 
            +
              # @return [void]
         | 
| 94 | 
            +
              #
         | 
| 95 | 
            +
              # @api private
         | 
| 96 | 
            +
              # @since 0.3.0
         | 
| 97 | 
            +
              def apply_strict_mode(strict_mode)
         | 
| 98 | 
            +
                Reconciler::Constructor.set_strict_mode(reconciler, strict_mode)
         | 
| 99 | 
            +
              end
         | 
| 100 | 
            +
             | 
| 73 101 | 
             
              # @param block [Block]
         | 
| 74 102 | 
             
              # @return [Any]
         | 
| 75 103 | 
             
              #
         | 
| @@ -2,6 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            # @api private
         | 
| 4 4 | 
             
            # @since 0.1.0
         | 
| 5 | 
            +
            # @version 0.3.0
         | 
| 5 6 | 
             
            class SmartCore::Schema::Checker::Reconciler
         | 
| 6 7 | 
             
              require_relative 'reconciler/constructor'
         | 
| 7 8 | 
             
              require_relative 'reconciler/matcher'
         | 
| @@ -10,8 +11,10 @@ class SmartCore::Schema::Checker::Reconciler | |
| 10 11 | 
             
              #
         | 
| 11 12 | 
             
              # @api private
         | 
| 12 13 | 
             
              # @since 0.1.0
         | 
| 14 | 
            +
              # @version 0.3.0
         | 
| 13 15 | 
             
              def initialize
         | 
| 14 16 | 
             
                @rules = SmartCore::Schema::Checker::Rules.new
         | 
| 17 | 
            +
                @strict = Constructor::DEFAULT_STRICT_BEHAVIOR
         | 
| 15 18 | 
             
                @lock = SmartCore::Engine::Lock.new
         | 
| 16 19 | 
             
              end
         | 
| 17 20 |  | 
| @@ -40,15 +43,24 @@ class SmartCore::Schema::Checker::Reconciler | |
| 40 43 | 
             
                thread_safe { rules }
         | 
| 41 44 | 
             
              end
         | 
| 42 45 |  | 
| 46 | 
            +
              # @return [Boolean]
         | 
| 47 | 
            +
              #
         | 
| 48 | 
            +
              # @api private
         | 
| 49 | 
            +
              # @since 0.3.0
         | 
| 50 | 
            +
              def __strict?
         | 
| 51 | 
            +
                thread_safe { @strict }
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
             | 
| 43 54 | 
             
              # @param schema_key [String, Symbol]
         | 
| 44 55 | 
             
              # @param nested_definitions [Block]
         | 
| 45 56 | 
             
              # @return [SmartCore::Schema::Checker::Rules::Required]
         | 
| 46 57 | 
             
              #
         | 
| 47 58 | 
             
              # @api public
         | 
| 48 59 | 
             
              # @since 0.1.0
         | 
| 60 | 
            +
              # @version 0.3.0
         | 
| 49 61 | 
             
              def required(schema_key, &nested_definitions)
         | 
| 50 62 | 
             
                thread_safe do
         | 
| 51 | 
            -
                  rule = SmartCore::Schema::Checker::Rules::Required.new(schema_key, &nested_definitions)
         | 
| 63 | 
            +
                  rule = SmartCore::Schema::Checker::Rules::Required.new(self, schema_key, &nested_definitions)
         | 
| 52 64 | 
             
                  rule.tap { rules[rule.schema_key] = rule }
         | 
| 53 65 | 
             
                end
         | 
| 54 66 | 
             
              end
         | 
| @@ -59,13 +71,31 @@ class SmartCore::Schema::Checker::Reconciler | |
| 59 71 | 
             
              #
         | 
| 60 72 | 
             
              # @api public
         | 
| 61 73 | 
             
              # @since 0.1.0
         | 
| 74 | 
            +
              # @version 0.3.0
         | 
| 62 75 | 
             
              def optional(schema_key, &nested_definitions)
         | 
| 63 76 | 
             
                thread_safe do
         | 
| 64 | 
            -
                  rule = SmartCore::Schema::Checker::Rules::Optional.new(schema_key, &nested_definitions)
         | 
| 77 | 
            +
                  rule = SmartCore::Schema::Checker::Rules::Optional.new(self, schema_key, &nested_definitions)
         | 
| 65 78 | 
             
                  rule.tap { rules[rule.schema_key] = rule }
         | 
| 66 79 | 
             
                end
         | 
| 67 80 | 
             
              end
         | 
| 68 81 |  | 
| 82 | 
            +
              # @param is_strict [Boolean]
         | 
| 83 | 
            +
              # @return [void]
         | 
| 84 | 
            +
              #
         | 
| 85 | 
            +
              # @api public
         | 
| 86 | 
            +
              # @since 0.3.0
         | 
| 87 | 
            +
              def strict!(is_strict = Constructor::DEFAULT_STRICT_BEHAVIOR)
         | 
| 88 | 
            +
                thread_safe { @strict = is_strict }
         | 
| 89 | 
            +
              end
         | 
| 90 | 
            +
             | 
| 91 | 
            +
              # @return [void]
         | 
| 92 | 
            +
              #
         | 
| 93 | 
            +
              # @api public
         | 
| 94 | 
            +
              # @since 0.3.0
         | 
| 95 | 
            +
              def non_strict!
         | 
| 96 | 
            +
                thread_safe { strict!(Constructor::STRICT_MODES[:non_strict]) }
         | 
| 97 | 
            +
              end
         | 
| 98 | 
            +
             | 
| 69 99 | 
             
              private
         | 
| 70 100 |  | 
| 71 101 | 
             
              # @return [SmartCore::Schema::Checker::Rules]
         | 
| @@ -2,7 +2,20 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            # @api private
         | 
| 4 4 | 
             
            # @since 0.1.0
         | 
| 5 | 
            +
            # @version 0.3.0
         | 
| 5 6 | 
             
            module SmartCore::Schema::Checker::Reconciler::Constructor
         | 
| 7 | 
            +
              # @return [Hash<String,Boolean>]
         | 
| 8 | 
            +
              #
         | 
| 9 | 
            +
              # @api private
         | 
| 10 | 
            +
              # @since 0.3.0
         | 
| 11 | 
            +
              STRICT_MODES = { strict: true, 'strict' => true, non_strict: false, 'non_strict' => true }.freeze
         | 
| 12 | 
            +
             | 
| 13 | 
            +
              # @return [Boolean]
         | 
| 14 | 
            +
              #
         | 
| 15 | 
            +
              # @pai private
         | 
| 16 | 
            +
              # @since 0.3.0
         | 
| 17 | 
            +
              DEFAULT_STRICT_BEHAVIOR = STRICT_MODES[:strict] # NOTE: means `strict by default`
         | 
| 18 | 
            +
             | 
| 6 19 | 
             
              class << self
         | 
| 7 20 | 
             
                # @param reconciler [SmartCore::Schema::Checker::Reconciler]
         | 
| 8 21 | 
             
                # @param definitions [Proc]
         | 
| @@ -14,6 +27,25 @@ module SmartCore::Schema::Checker::Reconciler::Constructor | |
| 14 27 | 
             
                  reconciler.instance_eval(&definitions)
         | 
| 15 28 | 
             
                end
         | 
| 16 29 |  | 
| 30 | 
            +
                # @param reconciler [SmartCore::Schema::Checker::Reconciler]
         | 
| 31 | 
            +
                # @param strict_mode [NilClass, String, Symbol]
         | 
| 32 | 
            +
                # @return [void]
         | 
| 33 | 
            +
                #
         | 
| 34 | 
            +
                # @api private
         | 
| 35 | 
            +
                # @since 0.3.0
         | 
| 36 | 
            +
                def set_strict_mode(reconciler, strict_mode)
         | 
| 37 | 
            +
                  return if strict_mode == nil
         | 
| 38 | 
            +
             | 
| 39 | 
            +
                  is_strict = STRICT_MODES.fetch(strict_mode) do
         | 
| 40 | 
            +
                    raise(SmartCore::Schema::ArgumentError, <<~ERROR_MESSAGE)
         | 
| 41 | 
            +
                      Unsupported strict mode "#{strict_mode}".
         | 
| 42 | 
            +
                      SmartCore::Schema supports "strict" and "non_strict" modes only.
         | 
| 43 | 
            +
                    ERROR_MESSAGE
         | 
| 44 | 
            +
                  end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                  reconciler.strict!(is_strict)
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 17 49 | 
             
                # @param definitions [Proc, NilClass]
         | 
| 18 50 | 
             
                # @return [SmarCore::Schema::Checker::Reconciler]
         | 
| 19 51 | 
             
                #
         | 
| @@ -2,7 +2,9 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            # @api private
         | 
| 4 4 | 
             
            # @since 0.1.0
         | 
| 5 | 
            +
            # @version 0.3.0
         | 
| 5 6 | 
             
            module SmartCore::Schema::Checker::Reconciler::Matcher
         | 
| 7 | 
            +
              require_relative 'matcher/options'
         | 
| 6 8 | 
             
              require_relative 'matcher/result'
         | 
| 7 9 | 
             
              require_relative 'matcher/result_finalizer'
         | 
| 8 10 |  | 
| @@ -13,39 +15,46 @@ module SmartCore::Schema::Checker::Reconciler::Matcher | |
| 13 15 | 
             
                #
         | 
| 14 16 | 
             
                # @api private
         | 
| 15 17 | 
             
                # @since 0.1.0
         | 
| 18 | 
            +
                # @version 0.3.0
         | 
| 16 19 | 
             
                def match(reconciler, verifiable_hash)
         | 
| 20 | 
            +
                  matcher_options = Options.build_from(reconciler)
         | 
| 21 | 
            +
             | 
| 17 22 | 
             
                  Result.new(verifiable_hash).tap do |result|
         | 
| 18 | 
            -
                    match_for_contract_keys(reconciler, verifiable_hash, result)
         | 
| 19 | 
            -
                    match_for_extra_keys(reconciler, verifiable_hash, result)
         | 
| 23 | 
            +
                    match_for_contract_keys(reconciler, matcher_options, verifiable_hash, result)
         | 
| 24 | 
            +
                    match_for_extra_keys(reconciler, matcher_options, verifiable_hash, result)
         | 
| 20 25 | 
             
                  end
         | 
| 21 26 | 
             
                end
         | 
| 22 27 |  | 
| 23 28 | 
             
                private
         | 
| 24 29 |  | 
| 25 30 | 
             
                # @param reconciler [SmartCore::Schema::Checker::Reconciler]
         | 
| 31 | 
            +
                # @param matcher_options [SmartCore::Schema::Checker::Reconciler::Matcher::Options]
         | 
| 26 32 | 
             
                # @param verifiable_hash [SmartCore::Schema::Checker::VerifiableHash]
         | 
| 27 33 | 
             
                # @param result [SmartCore::Schema::Checker::Reconciler::Matcher::Result]
         | 
| 28 34 | 
             
                # @return [void]
         | 
| 29 35 | 
             
                #
         | 
| 30 36 | 
             
                # @api private
         | 
| 31 37 | 
             
                # @since 0.1.0
         | 
| 32 | 
            -
                 | 
| 38 | 
            +
                # @version 0.3.0
         | 
| 39 | 
            +
                def match_for_contract_keys(reconciler, matcher_options, verifiable_hash, result)
         | 
| 33 40 | 
             
                  reconciler.__contract_rules.each_rule do |rule|
         | 
| 34 | 
            -
                    verification_result = rule.__verify!(verifiable_hash)
         | 
| 41 | 
            +
                    verification_result = rule.__verify!(verifiable_hash, matcher_options)
         | 
| 35 42 | 
             
                    result.contract_key_result(verification_result)
         | 
| 36 43 | 
             
                  end
         | 
| 37 44 | 
             
                end
         | 
| 38 45 |  | 
| 39 46 | 
             
                # @param reconciler [SmartCore::Schema::Checker::Reconciler]
         | 
| 47 | 
            +
                # @param matcher_options [SmartCore::Schema::Checker::Reconciler::Matcher::Options]
         | 
| 40 48 | 
             
                # @param verifiable_hash [SmartCore::Schema::Checker::VerifiableHash]
         | 
| 41 49 | 
             
                # @param result [SmartCore::Schema::Checker::Reconciler::Matcher::Result]
         | 
| 42 50 | 
             
                # @return [void]
         | 
| 43 51 | 
             
                #
         | 
| 44 52 | 
             
                # @api private
         | 
| 45 53 | 
             
                # @since 0.1.0
         | 
| 46 | 
            -
                 | 
| 54 | 
            +
                # @version 0.3.0
         | 
| 55 | 
            +
                def match_for_extra_keys(reconciler, matcher_options, verifiable_hash, result)
         | 
| 47 56 | 
             
                  verification_result = reconciler.__extra_keys_contract.__verify!(
         | 
| 48 | 
            -
                    verifiable_hash, reconciler.__contract_rules
         | 
| 57 | 
            +
                    verifiable_hash, reconciler.__contract_rules, matcher_options
         | 
| 49 58 | 
             
                  )
         | 
| 50 59 | 
             
                  result.extra_keys_result(verification_result)
         | 
| 51 60 | 
             
                end
         | 
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # @api private
         | 
| 4 | 
            +
            # @since 0.3.0
         | 
| 5 | 
            +
            class SmartCore::Schema::Checker::Reconciler::Matcher::Options
         | 
| 6 | 
            +
              class << self
         | 
| 7 | 
            +
                # @param reconciler [SmartCore::Schema::Checker::Reconciler]
         | 
| 8 | 
            +
                # @return [SmartCore::Schema::Checker::Reconciler::Matcher::Options]
         | 
| 9 | 
            +
                #
         | 
| 10 | 
            +
                # @api private
         | 
| 11 | 
            +
                # @since 0.3.0
         | 
| 12 | 
            +
                def build_from(reconciler)
         | 
| 13 | 
            +
                  new(reconciler.__strict?)
         | 
| 14 | 
            +
                end
         | 
| 15 | 
            +
              end
         | 
| 16 | 
            +
             | 
| 17 | 
            +
              # @param is_strict_schema [Boolean]
         | 
| 18 | 
            +
              # @return [void]
         | 
| 19 | 
            +
              #
         | 
| 20 | 
            +
              # @api private
         | 
| 21 | 
            +
              # @since 0.3.0
         | 
| 22 | 
            +
              def initialize(is_strict_schema)
         | 
| 23 | 
            +
                @is_strict_schema = is_strict_schema
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              # @return [Boolean]
         | 
| 27 | 
            +
              #
         | 
| 28 | 
            +
              # @api private
         | 
| 29 | 
            +
              # @since 0.3.0
         | 
| 30 | 
            +
              def strict_schema?
         | 
| 31 | 
            +
                @is_strict_schema
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| @@ -1,7 +1,10 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            +
            # TODO: refactor error data propagating (with Value Object)
         | 
| 4 | 
            +
             | 
| 3 5 | 
             
            # @api private
         | 
| 4 6 | 
             
            # @since 0.1.0
         | 
| 7 | 
            +
            # @version 0.3.0
         | 
| 5 8 | 
             
            module SmartCore::Schema::Checker::Reconciler::Matcher::ResultFinalizer
         | 
| 6 9 | 
             
              # @return [Proc]
         | 
| 7 10 | 
             
              #
         | 
| @@ -15,6 +18,12 @@ module SmartCore::Schema::Checker::Reconciler::Matcher::ResultFinalizer | |
| 15 18 | 
             
              # @since 0.1.0
         | 
| 16 19 | 
             
              EXTRA_KEYS_CONTAINER_BUILDER = -> { Set.new }
         | 
| 17 20 |  | 
| 21 | 
            +
              # @return [Proc]
         | 
| 22 | 
            +
              #
         | 
| 23 | 
            +
              # @api private
         | 
| 24 | 
            +
              # @since 0.3.0
         | 
| 25 | 
            +
              SPREAD_KEYS_CONTAINER_BUILDER = -> { Set.new }
         | 
| 26 | 
            +
             | 
| 18 27 | 
             
              # @return [Symbol]
         | 
| 19 28 | 
             
              #
         | 
| 20 29 | 
             
              # @api private
         | 
| @@ -27,26 +36,32 @@ module SmartCore::Schema::Checker::Reconciler::Matcher::ResultFinalizer | |
| 27 36 | 
             
                #
         | 
| 28 37 | 
             
                # @ai privates
         | 
| 29 38 | 
             
                # @since 0.1.0
         | 
| 39 | 
            +
                # @version 0.3.0
         | 
| 40 | 
            +
                # rubocop:disable Layout/LineLength
         | 
| 30 41 | 
             
                def finalize(result)
         | 
| 31 | 
            -
                  schema_errors, extra_keys = aggregate_errors(result)
         | 
| 32 | 
            -
                  schema_errors, extra_keys = compile_errors(schema_errors, extra_keys)
         | 
| 33 | 
            -
                  build_final_result(result, schema_errors, extra_keys)
         | 
| 42 | 
            +
                  schema_errors, extra_keys, spread_keys = aggregate_errors(result)
         | 
| 43 | 
            +
                  schema_errors, extra_keys, spread_keys = compile_errors(schema_errors, extra_keys, spread_keys)
         | 
| 44 | 
            +
                  build_final_result(result, schema_errors, extra_keys, spread_keys)
         | 
| 34 45 | 
             
                end
         | 
| 46 | 
            +
                # rubocop:enable Layout/LineLength
         | 
| 35 47 |  | 
| 36 48 | 
             
                private
         | 
| 37 49 |  | 
| 38 50 | 
             
                # @param result [SmartCore::Schema::Checker::Reconciler::Matcher::Result]
         | 
| 39 51 | 
             
                # @param schema_errors [Hash<String,Array<Symbol>>]
         | 
| 40 52 | 
             
                # @param extra_keys [Set<String>]
         | 
| 53 | 
            +
                # @param spread_keys [Set<String>]
         | 
| 41 54 | 
             
                # @return [SmartCore::Schema::Result]
         | 
| 42 55 | 
             
                #
         | 
| 43 56 | 
             
                # @api private
         | 
| 44 57 | 
             
                # @since 0.1.0
         | 
| 45 | 
            -
                 | 
| 58 | 
            +
                # @version 0.3.0
         | 
| 59 | 
            +
                def build_final_result(result, schema_errors, extra_keys, spread_keys)
         | 
| 46 60 | 
             
                  SmartCore::Schema::Result.new(
         | 
| 47 61 | 
             
                    result.verifiable_hash.source,
         | 
| 48 62 | 
             
                    schema_errors.freeze,
         | 
| 49 | 
            -
                    extra_keys.freeze
         | 
| 63 | 
            +
                    extra_keys.freeze,
         | 
| 64 | 
            +
                    SPREAD_KEYS_CONTAINER_BUILDER.call.freeze # TODO: spread_keys.freeze
         | 
| 50 65 | 
             
                  )
         | 
| 51 66 | 
             
                end
         | 
| 52 67 |  | 
| @@ -58,6 +73,7 @@ module SmartCore::Schema::Checker::Reconciler::Matcher::ResultFinalizer | |
| 58 73 | 
             
                def aggregate_errors(result)
         | 
| 59 74 | 
             
                  schema_errors = ERRORS_CONTAINER_BUILDER.call
         | 
| 60 75 | 
             
                  extra_keys = EXTRA_KEYS_CONTAINER_BUILDER.call
         | 
| 76 | 
            +
                  spread_keys = SPREAD_KEYS_CONTAINER_BUILDER.call
         | 
| 61 77 |  | 
| 62 78 | 
             
                  result.each_result do |concrete_result|
         | 
| 63 79 | 
             
                    case concrete_result
         | 
| @@ -65,15 +81,16 @@ module SmartCore::Schema::Checker::Reconciler::Matcher::ResultFinalizer | |
| 65 81 | 
             
                      aggregate_verifier_errors(concrete_result, schema_errors)
         | 
| 66 82 | 
             
                    when SmartCore::Schema::Checker::Rules::ExtraKeys::Failure
         | 
| 67 83 | 
             
                      aggregate_extra_keys_errors(concrete_result, extra_keys)
         | 
| 84 | 
            +
                    when SmartCore::Schema::Checker::Rules::ExtraKeys::Success
         | 
| 85 | 
            +
                      aggregate_spread_keys_notice(concrete_result, spread_keys)
         | 
| 68 86 | 
             
                    end
         | 
| 69 87 | 
             
                  end
         | 
| 70 88 |  | 
| 71 | 
            -
                  [schema_errors, extra_keys]
         | 
| 89 | 
            +
                  [schema_errors, extra_keys, spread_keys]
         | 
| 72 90 | 
             
                end
         | 
| 73 91 |  | 
| 74 92 | 
             
                # @param result [SmartCore::Schema::Checker::Rules::Verifier::Result]
         | 
| 75 93 | 
             
                # @param errors [Hash<String,Array<String>|Hash<String,Hash>>]
         | 
| 76 | 
            -
                # @param extra_keys [Set<String>]
         | 
| 77 94 | 
             
                # @return [void]
         | 
| 78 95 | 
             
                #
         | 
| 79 96 | 
             
                # @api private
         | 
| @@ -102,23 +119,41 @@ module SmartCore::Schema::Checker::Reconciler::Matcher::ResultFinalizer | |
| 102 119 | 
             
                  extra_keys.merge(result.extra_keys)
         | 
| 103 120 | 
             
                end
         | 
| 104 121 |  | 
| 122 | 
            +
                # @param result [SmartCore::Schema::Checker::Rules::ExtraKeys::Success]
         | 
| 123 | 
            +
                # @param spread_keys [Set<String>]
         | 
| 124 | 
            +
                # @return [void]
         | 
| 125 | 
            +
                #
         | 
| 126 | 
            +
                # @api private
         | 
| 127 | 
            +
                # @since 0.3.0
         | 
| 128 | 
            +
                def aggregate_spread_keys_notice(result, spread_keys)
         | 
| 129 | 
            +
                  spread_keys.merge(result.spread_keys)
         | 
| 130 | 
            +
                end
         | 
| 131 | 
            +
             | 
| 105 132 | 
             
                # @param errors [Hash]
         | 
| 106 133 | 
             
                # @param extra_keys [Set]
         | 
| 134 | 
            +
                # @param spread_keys [Set]
         | 
| 135 | 
            +
                # @param initial_error_key [NilClass, String]
         | 
| 107 136 | 
             
                # @return [Array<Hash<String,Set<Symbol>>,Set<String>]
         | 
| 108 137 | 
             
                #
         | 
| 109 138 | 
             
                # @api private
         | 
| 110 139 | 
             
                # @since 0.1.0
         | 
| 111 | 
            -
                # @version 0. | 
| 112 | 
            -
                # rubocop:disable Metrics/AbcSize
         | 
| 113 | 
            -
                def compile_errors(errors, extra_keys, initial_error_key = nil)
         | 
| 140 | 
            +
                # @version 0.3.0
         | 
| 141 | 
            +
                # rubocop:disable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
         | 
| 142 | 
            +
                def compile_errors(errors, extra_keys, spread_keys, initial_error_key = nil)
         | 
| 114 143 | 
             
                  compiled_errors = ERRORS_CONTAINER_BUILDER.call
         | 
| 115 144 | 
             
                  compiled_extra_keys = EXTRA_KEYS_CONTAINER_BUILDER.call
         | 
| 145 | 
            +
                  compiled_spread_keys = SPREAD_KEYS_CONTAINER_BUILDER.call
         | 
| 116 146 |  | 
| 117 147 | 
             
                  compiled_extra_keys.merge(extra_keys).map! do |key|
         | 
| 118 148 | 
             
                    # dot-notated nested keys
         | 
| 119 149 | 
             
                    initial_error_key ? "#{initial_error_key}.#{key}" : key
         | 
| 120 150 | 
             
                  end
         | 
| 121 151 |  | 
| 152 | 
            +
                  compiled_spread_keys.merge(spread_keys).map! do |key|
         | 
| 153 | 
            +
                    # dot-notated nested keys
         | 
| 154 | 
            +
                    initial_error_key ? "#{initial_error_key}.#{key}" : key
         | 
| 155 | 
            +
                  end
         | 
| 156 | 
            +
             | 
| 122 157 | 
             
                  errors.each_pair do |key, error_set|
         | 
| 123 158 | 
             
                    # dot-notated nested key
         | 
| 124 159 | 
             
                    compiled_key = initial_error_key ? "#{initial_error_key}.#{key}" : key
         | 
| @@ -129,11 +164,13 @@ module SmartCore::Schema::Checker::Reconciler::Matcher::ResultFinalizer | |
| 129 164 | 
             
                        compiled_errors[compiled_key] << error
         | 
| 130 165 | 
             
                      when Array # nested errors
         | 
| 131 166 | 
             
                        sub_errors, sub_extra_keys = error
         | 
| 132 | 
            -
                         | 
| 133 | 
            -
             | 
| 167 | 
            +
                        sub_spread_keys = SPREAD_KEYS_CONTAINER_BUILDER.call
         | 
| 168 | 
            +
                        compiled_sub_errors, compiled_sub_extra_keys, compiled_sub_spread_keys = compile_errors(
         | 
| 169 | 
            +
                          sub_errors, sub_extra_keys, sub_spread_keys, compiled_key
         | 
| 134 170 | 
             
                        )
         | 
| 135 171 | 
             
                        compiled_errors.merge!(compiled_sub_errors)
         | 
| 136 172 | 
             
                        compiled_extra_keys.merge(compiled_sub_extra_keys)
         | 
| 173 | 
            +
                        compiled_spread_keys.merge(compiled_sub_spread_keys)
         | 
| 137 174 | 
             
                      end
         | 
| 138 175 | 
             
                    end
         | 
| 139 176 | 
             
                  end
         | 
| @@ -142,8 +179,8 @@ module SmartCore::Schema::Checker::Reconciler::Matcher::ResultFinalizer | |
| 142 179 | 
             
                    compiled_errors[compiled_extra_key] << EXTRA_KEY_ERROR_CODE
         | 
| 143 180 | 
             
                  end
         | 
| 144 181 |  | 
| 145 | 
            -
                  [compiled_errors, compiled_extra_keys]
         | 
| 182 | 
            +
                  [compiled_errors, compiled_extra_keys, compiled_spread_keys]
         | 
| 146 183 | 
             
                end
         | 
| 147 | 
            -
                # rubocop:enable Metrics/AbcSize
         | 
| 184 | 
            +
                # rubocop:enable Metrics/AbcSize, Metrics/CyclomaticComplexity, Metrics/MethodLength
         | 
| 148 185 | 
             
              end
         | 
| 149 186 | 
             
            end
         | 
| @@ -2,6 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            # @api private
         | 
| 4 4 | 
             
            # @since 0.1.0
         | 
| 5 | 
            +
            # @version 0.3.0
         | 
| 5 6 | 
             
            class SmartCore::Schema::Checker::Rules::Base
         | 
| 6 7 | 
             
              # @return [String]
         | 
| 7 8 | 
             
              #
         | 
| @@ -21,14 +22,23 @@ class SmartCore::Schema::Checker::Rules::Base | |
| 21 22 | 
             
              # @since 0.1.0
         | 
| 22 23 | 
             
              attr_reader :nested_reconciler
         | 
| 23 24 |  | 
| 25 | 
            +
              # @return [SmartCore::Schema::Checker::Reconciler]
         | 
| 26 | 
            +
              #
         | 
| 27 | 
            +
              # @api private
         | 
| 28 | 
            +
              # @since 0.3.0
         | 
| 29 | 
            +
              attr_reader :root_reconciler
         | 
| 30 | 
            +
             | 
| 31 | 
            +
              # @param root_reconciler [SmartCore::Schema::Checker::Reconciler]
         | 
| 24 32 | 
             
              # @param schema_key [String, Symbol]
         | 
| 25 33 | 
             
              # @param nested_definitions [Block]
         | 
| 26 34 | 
             
              # @return [void]
         | 
| 27 35 | 
             
              #
         | 
| 28 36 | 
             
              # @api private
         | 
| 29 37 | 
             
              # @since 0.1.0
         | 
| 30 | 
            -
               | 
| 38 | 
            +
              # @version 0.3.0
         | 
| 39 | 
            +
              def initialize(root_reconciler, schema_key, &nested_definitions)
         | 
| 31 40 | 
             
                @lock = SmartCore::Engine::Lock.new
         | 
| 41 | 
            +
                @root_reconciler = root_reconciler
         | 
| 32 42 | 
             
                @schema_key = SmartCore::Schema::KeyControl.normalize(schema_key)
         | 
| 33 43 | 
             
                @options = SmartCore::Schema::Checker::Rules::Options.new(self)
         | 
| 34 44 | 
             
                @nested_reconciler = nil
         | 
| @@ -40,12 +50,16 @@ class SmartCore::Schema::Checker::Rules::Base | |
| 40 50 | 
             
              #   @return [SmartCore::Schema::Checker::Rules::Requirement::Required]
         | 
| 41 51 |  | 
| 42 52 | 
             
              # @param verifiable_hash [Hash<String|Symbol,Any>]
         | 
| 53 | 
            +
              # @param matcher_options [SmartCore::Schema::Checker::Reconciler::Matcher::Options]
         | 
| 43 54 | 
             
              # @return [SmartCore::Schema::Checker::Rules::Verifier::Result]
         | 
| 44 55 | 
             
              #
         | 
| 45 56 | 
             
              # @api private
         | 
| 46 57 | 
             
              # @since 0.1.0
         | 
| 47 | 
            -
               | 
| 48 | 
            -
             | 
| 58 | 
            +
              # @version 0.3.0
         | 
| 59 | 
            +
              def __verify!(verifiable_hash, matcher_options)
         | 
| 60 | 
            +
                SmartCore::Schema::Checker::Rules::Verifier.verify!(
         | 
| 61 | 
            +
                  self, matcher_options, verifiable_hash
         | 
| 62 | 
            +
                )
         | 
| 49 63 | 
             
              end
         | 
| 50 64 |  | 
| 51 65 | 
             
              # @param required_type [String, Symbol, SmartCore::Types::Primitive]
         | 
| @@ -84,11 +98,13 @@ class SmartCore::Schema::Checker::Rules::Base | |
| 84 98 | 
             
              #
         | 
| 85 99 | 
             
              # @api private
         | 
| 86 100 | 
             
              # @since 0.1.0
         | 
| 101 | 
            +
              # @version 0.3.0
         | 
| 87 102 | 
             
              def define_nested_reconciler(&nested_definitions)
         | 
| 88 103 | 
             
                return unless block_given?
         | 
| 89 104 |  | 
| 90 105 | 
             
                SmartCore::Schema::Checker::Reconciler::Constructor.tap do |constructor|
         | 
| 91 106 | 
             
                  @nested_reconciler = constructor.create if @nested_reconciler == nil
         | 
| 107 | 
            +
                  @nested_reconciler.strict!(root_reconciler.__strict?)
         | 
| 92 108 | 
             
                  constructor.append_definitions(@nested_reconciler, &nested_definitions)
         | 
| 93 109 | 
             
                end
         | 
| 94 110 |  | 
| @@ -2,21 +2,30 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            # @api private
         | 
| 4 4 | 
             
            # @since 0.1.0
         | 
| 5 | 
            +
            # @version 0.3.0
         | 
| 5 6 | 
             
            module SmartCore::Schema::Checker::Rules::ExtraKeys
         | 
| 7 | 
            +
              require_relative 'extra_keys/result'
         | 
| 6 8 | 
             
              require_relative 'extra_keys/success'
         | 
| 7 9 | 
             
              require_relative 'extra_keys/failure'
         | 
| 8 10 |  | 
| 9 11 | 
             
              class << self
         | 
| 10 12 | 
             
                # @param verifiable_hash [SmartCore::Schema::Checker::VerifiableHash]
         | 
| 11 13 | 
             
                # @param rules [SmartCore::Schema::Checker::Rules]
         | 
| 14 | 
            +
                # @param matcher_options [SmartCore::Schema::Checker::Reconciler::Matcher::Options]
         | 
| 12 15 | 
             
                # @return [SmartCore::Schema::Checker::Rules::ExtraKeys::Success]
         | 
| 13 16 | 
             
                # @return [SmartCore::Schema::Checker::Rules::ExtraKeys::Failure]
         | 
| 14 17 | 
             
                #
         | 
| 15 18 | 
             
                # @api private
         | 
| 16 19 | 
             
                # @since 0.1.0
         | 
| 17 | 
            -
                 | 
| 20 | 
            +
                # @version 0.3.0
         | 
| 21 | 
            +
                def __verify!(verifiable_hash, rules, matcher_options)
         | 
| 18 22 | 
             
                  extra_keys = verifiable_hash.keys - rules.keys
         | 
| 19 | 
            -
             | 
| 23 | 
            +
             | 
| 24 | 
            +
                  if extra_keys.empty? || (extra_keys.any? && !matcher_options.strict_schema?)
         | 
| 25 | 
            +
                    Success.new(extra_keys, matcher_options)
         | 
| 26 | 
            +
                  else
         | 
| 27 | 
            +
                    Failure.new(extra_keys, matcher_options)
         | 
| 28 | 
            +
                  end
         | 
| 20 29 | 
             
                end
         | 
| 21 30 | 
             
              end
         | 
| 22 31 | 
             
            end
         | 
| @@ -1,36 +1,24 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
            # @since 0.1.0
         | 
| 5 | 
            -
            class SmartCore::Schema::Checker::Rules::ExtraKeys::Failure
         | 
| 6 | 
            -
              # @return extra_keys [Array<String>]
         | 
| 7 | 
            -
              #
         | 
| 3 | 
            +
            module SmartCore::Schema::Checker::Rules::ExtraKeys
         | 
| 8 4 | 
             
              # @api private
         | 
| 9 5 | 
             
              # @since 0.1.0
         | 
| 10 | 
            -
               | 
| 6 | 
            +
              # @version 0.3.0
         | 
| 7 | 
            +
              class Failure < Result
         | 
| 8 | 
            +
                # @return [Boolean]
         | 
| 9 | 
            +
                #
         | 
| 10 | 
            +
                # @api private
         | 
| 11 | 
            +
                # @since 0.1.0
         | 
| 12 | 
            +
                def success?
         | 
| 13 | 
            +
                  false
         | 
| 14 | 
            +
                end
         | 
| 11 15 |  | 
| 12 | 
            -
             | 
| 13 | 
            -
             | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
                 | 
| 19 | 
            -
              end
         | 
| 20 | 
            -
             | 
| 21 | 
            -
              # @return [Boolean]
         | 
| 22 | 
            -
              #
         | 
| 23 | 
            -
              # @api private
         | 
| 24 | 
            -
              # @since 0.1.0
         | 
| 25 | 
            -
              def success?
         | 
| 26 | 
            -
                false
         | 
| 27 | 
            -
              end
         | 
| 28 | 
            -
             | 
| 29 | 
            -
              # @return [Boolean]
         | 
| 30 | 
            -
              #
         | 
| 31 | 
            -
              # @api private
         | 
| 32 | 
            -
              # @since 0.1.0
         | 
| 33 | 
            -
              def failure?
         | 
| 34 | 
            -
                true
         | 
| 16 | 
            +
                # @return [Boolean]
         | 
| 17 | 
            +
                #
         | 
| 18 | 
            +
                # @api private
         | 
| 19 | 
            +
                # @since 0.1.0
         | 
| 20 | 
            +
                def failure?
         | 
| 21 | 
            +
                  true
         | 
| 22 | 
            +
                end
         | 
| 35 23 | 
             
              end
         | 
| 36 24 | 
             
            end
         | 
| @@ -0,0 +1,37 @@ | |
| 1 | 
            +
            # frozen_string_literal: true
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            # @apbstract
         | 
| 4 | 
            +
            #
         | 
| 5 | 
            +
            # @api private
         | 
| 6 | 
            +
            # @since 0.3.0
         | 
| 7 | 
            +
            class SmartCore::Schema::Checker::Rules::ExtraKeys::Result
         | 
| 8 | 
            +
              # @return [Array<String>]
         | 
| 9 | 
            +
              #
         | 
| 10 | 
            +
              # @api private
         | 
| 11 | 
            +
              # @since 0.3.0
         | 
| 12 | 
            +
              attr_reader :extra_keys
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              # @return [SmartCore::Schema::Checker::Reconciler::Matcher::Options]
         | 
| 15 | 
            +
              #
         | 
| 16 | 
            +
              # @api private
         | 
| 17 | 
            +
              # @since 0.3.0
         | 
| 18 | 
            +
              attr_reader :matcher_options
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              # @param extra_keys [Array<String>]
         | 
| 21 | 
            +
              # @param matcher_options [SmartCore::Schema::Checker::Reconciler::Matcher::Options]
         | 
| 22 | 
            +
              # @return [void]
         | 
| 23 | 
            +
              #
         | 
| 24 | 
            +
              # @api private
         | 
| 25 | 
            +
              # @since 0.1.0
         | 
| 26 | 
            +
              # @version 0.3.0
         | 
| 27 | 
            +
              def initialize(extra_keys, matcher_options)
         | 
| 28 | 
            +
                @extra_keys = extra_keys
         | 
| 29 | 
            +
                @matcher_options = matcher_options
         | 
| 30 | 
            +
              end
         | 
| 31 | 
            +
             | 
| 32 | 
            +
              # @!method success?
         | 
| 33 | 
            +
              #   @return [Boolean]
         | 
| 34 | 
            +
             | 
| 35 | 
            +
              # @!method failure?
         | 
| 36 | 
            +
              #   @return [Boolean]
         | 
| 37 | 
            +
            end
         | 
| @@ -1,21 +1,30 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
             | 
| 4 | 
            -
            # @since 0.1.0
         | 
| 5 | 
            -
            class SmartCore::Schema::Checker::Rules::ExtraKeys::Success
         | 
| 6 | 
            -
              # @return [Boolean]
         | 
| 7 | 
            -
              #
         | 
| 3 | 
            +
            module SmartCore::Schema::Checker::Rules::ExtraKeys
         | 
| 8 4 | 
             
              # @api private
         | 
| 9 5 | 
             
              # @since 0.1.0
         | 
| 10 | 
            -
               | 
| 11 | 
            -
             | 
| 12 | 
            -
             | 
| 6 | 
            +
              # @version 0.3.0
         | 
| 7 | 
            +
              class Success < Result
         | 
| 8 | 
            +
                # @return [Array<String>]
         | 
| 9 | 
            +
                #
         | 
| 10 | 
            +
                # @api private
         | 
| 11 | 
            +
                # @since 0.3.0
         | 
| 12 | 
            +
                alias_method :spread_keys, :extra_keys
         | 
| 13 13 |  | 
| 14 | 
            -
             | 
| 15 | 
            -
             | 
| 16 | 
            -
             | 
| 17 | 
            -
             | 
| 18 | 
            -
             | 
| 19 | 
            -
             | 
| 14 | 
            +
                # @return [Boolean]
         | 
| 15 | 
            +
                #
         | 
| 16 | 
            +
                # @api private
         | 
| 17 | 
            +
                # @since 0.1.0
         | 
| 18 | 
            +
                def success?
         | 
| 19 | 
            +
                  true
         | 
| 20 | 
            +
                end
         | 
| 21 | 
            +
             | 
| 22 | 
            +
                # @return [Boolean]
         | 
| 23 | 
            +
                #
         | 
| 24 | 
            +
                # @api private
         | 
| 25 | 
            +
                # @since 0.1.0
         | 
| 26 | 
            +
                def failure?
         | 
| 27 | 
            +
                  false
         | 
| 28 | 
            +
                end
         | 
| 20 29 | 
             
              end
         | 
| 21 30 | 
             
            end
         | 
| @@ -2,6 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            # @api private
         | 
| 4 4 | 
             
            # @since 0.1.0
         | 
| 5 | 
            +
            # @version 0.3.0
         | 
| 5 6 | 
             
            class SmartCore::Schema::Checker::Rules::Optional < SmartCore::Schema::Checker::Rules::Base
         | 
| 6 7 | 
             
              # @return [SmartCore::Schema::Checker::Rules::Requirement::Optional]
         | 
| 7 8 | 
             
              #
         | 
| @@ -9,14 +10,16 @@ class SmartCore::Schema::Checker::Rules::Optional < SmartCore::Schema::Checker:: | |
| 9 10 | 
             
              # @since 0.1.0
         | 
| 10 11 | 
             
              attr_reader :requirement
         | 
| 11 12 |  | 
| 13 | 
            +
              # @param root_reconciler [SmartCore::Schema::Checker::Reconciler]
         | 
| 12 14 | 
             
              # @param schema_key [String, Symbol]
         | 
| 13 15 | 
             
              # @param nested_definitions [Block]
         | 
| 14 16 | 
             
              # @return [void]
         | 
| 15 17 | 
             
              #
         | 
| 16 18 | 
             
              # @api private
         | 
| 17 19 | 
             
              # @since 0.1.0
         | 
| 18 | 
            -
               | 
| 19 | 
            -
             | 
| 20 | 
            +
              # @version 0.3.0
         | 
| 21 | 
            +
              def initialize(root_reconciler, schema_key, &nested_definitions)
         | 
| 22 | 
            +
                super(root_reconciler, schema_key, &nested_definitions)
         | 
| 20 23 | 
             
                @requirement = SmartCore::Schema::Checker::Rules::Requirement::Optional.new(self)
         | 
| 21 24 | 
             
              end
         | 
| 22 25 | 
             
            end
         | 
| @@ -1,10 +1,10 @@ | |
| 1 1 | 
             
            # frozen_string_literal: true
         | 
| 2 2 |  | 
| 3 | 
            -
            # @api private
         | 
| 4 | 
            -
            # @since 0.1.0
         | 
| 5 3 | 
             
            class SmartCore::Schema::Checker::Rules::Options
         | 
| 4 | 
            +
              # @api private
         | 
| 5 | 
            +
              # @since 0.1.0
         | 
| 6 6 | 
             
              class Filled < Empty
         | 
| 7 | 
            -
                # @note Constant is used only for  | 
| 7 | 
            +
                # @note Constant is used only for other developers.
         | 
| 8 8 | 
             
                # @return [Symbol]
         | 
| 9 9 | 
             
                #
         | 
| 10 10 | 
             
                # @api private
         | 
| @@ -2,6 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            # @api private
         | 
| 4 4 | 
             
            # @since 0.1.0
         | 
| 5 | 
            +
            # @version 0.3.0
         | 
| 5 6 | 
             
            class SmartCore::Schema::Checker::Rules::Required < SmartCore::Schema::Checker::Rules::Base
         | 
| 6 7 | 
             
              # @return [SmartCore::Schema::Checker::Rules::Requirement::Required]
         | 
| 7 8 | 
             
              #
         | 
| @@ -9,14 +10,16 @@ class SmartCore::Schema::Checker::Rules::Required < SmartCore::Schema::Checker:: | |
| 9 10 | 
             
              # @since 0.1.0
         | 
| 10 11 | 
             
              attr_reader :requirement
         | 
| 11 12 |  | 
| 13 | 
            +
              # @param root_reconciler [SmartCore::Schema::Checker::Reconciler]
         | 
| 12 14 | 
             
              # @param schema_key [String, Symbol]
         | 
| 13 15 | 
             
              # @param nested_definitions [Block]
         | 
| 14 16 | 
             
              # @return [void]
         | 
| 15 17 | 
             
              #
         | 
| 16 18 | 
             
              # @api private
         | 
| 17 19 | 
             
              # @since 0.1.0
         | 
| 18 | 
            -
               | 
| 19 | 
            -
             | 
| 20 | 
            +
              # @version 0.3.0
         | 
| 21 | 
            +
              def initialize(root_reconciler, schema_key, &nested_definitions)
         | 
| 22 | 
            +
                super(root_reconciler, schema_key, &nested_definitions)
         | 
| 20 23 | 
             
                @requirement = SmartCore::Schema::Checker::Rules::Requirement::Required.new(self)
         | 
| 21 24 | 
             
              end
         | 
| 22 25 | 
             
            end
         | 
| @@ -2,17 +2,20 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            # @api private
         | 
| 4 4 | 
             
            # @since 0.1.0
         | 
| 5 | 
            +
            # @version 0.3.0
         | 
| 5 6 | 
             
            module SmartCore::Schema::Checker::Rules::Verifier
         | 
| 6 7 | 
             
              require_relative 'verifier/result'
         | 
| 7 8 |  | 
| 8 9 | 
             
              class << self
         | 
| 9 10 | 
             
                # @param rule [SmartCore::Schema::Checker::Rules::Base]
         | 
| 11 | 
            +
                # @param matcher_options [SmartCore::Schema::Checker::Reconciler::Matcher::Options]
         | 
| 10 12 | 
             
                # @param verifiable_hash [SmartCore::Schema::Checker::VerifiableHash]
         | 
| 11 13 | 
             
                # @return [SmartCore::Schema::Checker::Rules::Verifier::Result]
         | 
| 12 14 | 
             
                #
         | 
| 13 15 | 
             
                # @api private
         | 
| 14 16 | 
             
                # @since 0.1.0
         | 
| 15 | 
            -
                 | 
| 17 | 
            +
                # @version 0.3.0
         | 
| 18 | 
            +
                def verify!(rule, matcher_options, verifiable_hash)
         | 
| 16 19 | 
             
                  SmartCore::Schema::Checker::Rules::Verifier::Result.new(rule).tap do |result|
         | 
| 17 20 | 
             
                    requirement = result << check_requirement(rule, verifiable_hash)
         | 
| 18 21 | 
             
                    next result if requirement.required? && requirement.failure?
         | 
| @@ -36,6 +36,7 @@ module SmartCore::Schema::DSL | |
| 36 36 |  | 
| 37 37 | 
             
              # @api private
         | 
| 38 38 | 
             
              # @since 0.1.0
         | 
| 39 | 
            +
              # @version 0.3.0
         | 
| 39 40 | 
             
              module ClassMethods
         | 
| 40 41 | 
             
                # @return [SmartCore::Schema::Checker]
         | 
| 41 42 | 
             
                #
         | 
| @@ -45,13 +46,36 @@ module SmartCore::Schema::DSL | |
| 45 46 | 
             
                  @__schema_checker__
         | 
| 46 47 | 
             
                end
         | 
| 47 48 |  | 
| 49 | 
            +
                # @param strict_mode [NilClass, String, Symbol]
         | 
| 48 50 | 
             
                # @param definitions [Block]
         | 
| 49 51 | 
             
                # @return [void]
         | 
| 50 52 | 
             
                #
         | 
| 53 | 
            +
                # @note nil strict mode means `do not change current mode`
         | 
| 54 | 
            +
                #
         | 
| 51 55 | 
             
                # @api public
         | 
| 52 56 | 
             
                # @since 0.1.0
         | 
| 53 | 
            -
                 | 
| 54 | 
            -
             | 
| 57 | 
            +
                # @version 0.3.0
         | 
| 58 | 
            +
                def schema(strict_mode = nil, &definitions)
         | 
| 59 | 
            +
                  __schema_checker__.invoke_in_pipe do
         | 
| 60 | 
            +
                    set_strict_mode(strict_mode)
         | 
| 61 | 
            +
                    append_schema_definitions(&definitions)
         | 
| 62 | 
            +
                  end
         | 
| 63 | 
            +
                end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                # @return [void]
         | 
| 66 | 
            +
                #
         | 
| 67 | 
            +
                # @api public
         | 
| 68 | 
            +
                # @since 0.3.0
         | 
| 69 | 
            +
                def strict!
         | 
| 70 | 
            +
                  __schema_checker__.set_strict_mode(:strict)
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                # @return [void]
         | 
| 74 | 
            +
                #
         | 
| 75 | 
            +
                # @api public
         | 
| 76 | 
            +
                # @since 0.3.0
         | 
| 77 | 
            +
                def non_strict!
         | 
| 78 | 
            +
                  __schema_checker__.set_strict_mode(:non_strict)
         | 
| 55 79 | 
             
                end
         | 
| 56 80 | 
             
              end
         | 
| 57 81 | 
             
            end
         | 
| @@ -2,6 +2,7 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            # @api private
         | 
| 4 4 | 
             
            # @since 0.1.0
         | 
| 5 | 
            +
            # @version 0.3.0
         | 
| 5 6 | 
             
            class SmartCore::Schema::Result
         | 
| 6 7 | 
             
              # @return [Hash<String,Any>]
         | 
| 7 8 | 
             
              #
         | 
| @@ -21,15 +22,26 @@ class SmartCore::Schema::Result | |
| 21 22 | 
             
              # @since 0.1.0
         | 
| 22 23 | 
             
              attr_reader :extra_keys
         | 
| 23 24 |  | 
| 25 | 
            +
              # @return [Set<String>]
         | 
| 26 | 
            +
              #
         | 
| 27 | 
            +
              # @api public
         | 
| 28 | 
            +
              # @since 0.3.0
         | 
| 29 | 
            +
              attr_reader :spread_keys
         | 
| 30 | 
            +
             | 
| 24 31 | 
             
              # @param source [Hash<String|Symbol,Any>]
         | 
| 32 | 
            +
              # @param errors [Hash<String,Array<Symbol>]
         | 
| 33 | 
            +
              # @param extra_keys [Set<String>]
         | 
| 34 | 
            +
              # @param spread_keys [Set<String>]
         | 
| 25 35 | 
             
              # @return [void]
         | 
| 26 36 | 
             
              #
         | 
| 27 37 | 
             
              # @api private
         | 
| 28 38 | 
             
              # @since 0.1.0
         | 
| 29 | 
            -
               | 
| 39 | 
            +
              # @version 0.3.0
         | 
| 40 | 
            +
              def initialize(source, errors, extra_keys, spread_keys)
         | 
| 30 41 | 
             
                @source = source
         | 
| 31 42 | 
             
                @errors = errors
         | 
| 32 43 | 
             
                @extra_keys = extra_keys
         | 
| 44 | 
            +
                @spread_keys = spread_keys
         | 
| 33 45 | 
             
              end
         | 
| 34 46 |  | 
| 35 47 | 
             
              # @return [Boolean]
         | 
    
        metadata
    CHANGED
    
    | @@ -1,14 +1,14 @@ | |
| 1 1 | 
             
            --- !ruby/object:Gem::Specification
         | 
| 2 2 | 
             
            name: smart_schema
         | 
| 3 3 | 
             
            version: !ruby/object:Gem::Version
         | 
| 4 | 
            -
              version: 0. | 
| 4 | 
            +
              version: 0.3.0
         | 
| 5 5 | 
             
            platform: ruby
         | 
| 6 6 | 
             
            authors:
         | 
| 7 7 | 
             
            - Rustam Ibragimov
         | 
| 8 8 | 
             
            autorequire:
         | 
| 9 9 | 
             
            bindir: exe
         | 
| 10 10 | 
             
            cert_chain: []
         | 
| 11 | 
            -
            date: 2020- | 
| 11 | 
            +
            date: 2020-12-03 00:00:00.000000000 Z
         | 
| 12 12 | 
             
            dependencies:
         | 
| 13 13 | 
             
            - !ruby/object:Gem::Dependency
         | 
| 14 14 | 
             
              name: smart_engine
         | 
| @@ -147,12 +147,14 @@ files: | |
| 147 147 | 
             
            - lib/smart_core/schema/checker/reconciler.rb
         | 
| 148 148 | 
             
            - lib/smart_core/schema/checker/reconciler/constructor.rb
         | 
| 149 149 | 
             
            - lib/smart_core/schema/checker/reconciler/matcher.rb
         | 
| 150 | 
            +
            - lib/smart_core/schema/checker/reconciler/matcher/options.rb
         | 
| 150 151 | 
             
            - lib/smart_core/schema/checker/reconciler/matcher/result.rb
         | 
| 151 152 | 
             
            - lib/smart_core/schema/checker/reconciler/matcher/result_finalizer.rb
         | 
| 152 153 | 
             
            - lib/smart_core/schema/checker/rules.rb
         | 
| 153 154 | 
             
            - lib/smart_core/schema/checker/rules/base.rb
         | 
| 154 155 | 
             
            - lib/smart_core/schema/checker/rules/extra_keys.rb
         | 
| 155 156 | 
             
            - lib/smart_core/schema/checker/rules/extra_keys/failure.rb
         | 
| 157 | 
            +
            - lib/smart_core/schema/checker/rules/extra_keys/result.rb
         | 
| 156 158 | 
             
            - lib/smart_core/schema/checker/rules/extra_keys/success.rb
         | 
| 157 159 | 
             
            - lib/smart_core/schema/checker/rules/optional.rb
         | 
| 158 160 | 
             
            - lib/smart_core/schema/checker/rules/options.rb
         | 
| @@ -200,7 +202,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement | |
| 200 202 | 
             
                - !ruby/object:Gem::Version
         | 
| 201 203 | 
             
                  version: '0'
         | 
| 202 204 | 
             
            requirements: []
         | 
| 203 | 
            -
            rubygems_version: 3.1 | 
| 205 | 
            +
            rubygems_version: 3.2.0.rc.1
         | 
| 204 206 | 
             
            signing_key:
         | 
| 205 207 | 
             
            specification_version: 4
         | 
| 206 208 | 
             
            summary: SmartCore::Schema is a schema validator for Hash-like data structures
         |