data_model 0.4.0 → 0.5.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 +8 -2
 - data/.solargraph.yml +22 -0
 - data/Gemfile.lock +36 -3
 - data/Rakefile +0 -6
 - data/Steepfile +27 -0
 - data/data_model.gemspec +1 -2
 - data/lib/data_model/boolean.rb +0 -2
 - data/lib/data_model/builtin/array.rb +32 -25
 - data/lib/data_model/builtin/big_decimal.rb +15 -14
 - data/lib/data_model/builtin/boolean.rb +10 -7
 - data/lib/data_model/builtin/date.rb +15 -12
 - data/lib/data_model/builtin/float.rb +14 -13
 - data/lib/data_model/builtin/hash.rb +100 -35
 - data/lib/data_model/builtin/integer.rb +14 -13
 - data/lib/data_model/builtin/numeric.rb +35 -0
 - data/lib/data_model/builtin/object.rb +28 -0
 - data/lib/data_model/builtin/or.rb +73 -0
 - data/lib/data_model/builtin/string.rb +15 -16
 - data/lib/data_model/builtin/symbol.rb +14 -13
 - data/lib/data_model/builtin/time.rb +17 -14
 - data/lib/data_model/builtin.rb +9 -9
 - data/lib/data_model/error.rb +30 -18
 - data/lib/data_model/errors.rb +79 -55
 - data/lib/data_model/fixtures/array.rb +22 -9
 - data/lib/data_model/fixtures/big_decimal.rb +9 -7
 - data/lib/data_model/fixtures/boolean.rb +5 -5
 - data/lib/data_model/fixtures/date.rb +13 -11
 - data/lib/data_model/fixtures/example.rb +7 -7
 - data/lib/data_model/fixtures/float.rb +9 -7
 - data/lib/data_model/fixtures/hash.rb +22 -10
 - data/lib/data_model/fixtures/integer.rb +9 -7
 - data/lib/data_model/fixtures/numeric.rb +31 -0
 - data/lib/data_model/fixtures/object.rb +27 -0
 - data/lib/data_model/fixtures/or.rb +29 -0
 - data/lib/data_model/fixtures/string.rb +15 -32
 - data/lib/data_model/fixtures/symbol.rb +9 -7
 - data/lib/data_model/fixtures/time.rb +13 -11
 - data/lib/data_model/logging.rb +5 -8
 - data/lib/data_model/model.rb +11 -8
 - data/lib/data_model/registry.rb +37 -22
 - data/lib/data_model/scanner.rb +23 -28
 - data/lib/data_model/struct.rb +112 -0
 - data/lib/data_model/testing/minitest.rb +33 -9
 - data/lib/data_model/testing.rb +0 -2
 - data/lib/data_model/type.rb +38 -22
 - data/lib/data_model/version.rb +1 -3
 - data/lib/data_model.rb +8 -17
 - metadata +12 -25
 - data/sorbet/config +0 -4
 - data/sorbet/rbi/annotations/rainbow.rbi +0 -269
 - data/sorbet/rbi/gems/minitest@5.18.0.rbi +0 -1491
 - data/sorbet/rbi/gems/zeitwerk.rbi +0 -196
 - data/sorbet/rbi/gems/zeitwerk@2.6.7.rbi +0 -966
 - data/sorbet/rbi/todo.rbi +0 -5
 - data/sorbet/tapioca/config.yml +0 -13
 - data/sorbet/tapioca/require.rb +0 -4
 
| 
         @@ -1,12 +1,11 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# Test data for float schemas
         
     | 
| 
       4 
3 
     | 
    
         
             
            	module Fixtures::Float
         
     | 
| 
       5 
4 
     | 
    
         
             
            		include Fixtures
         
     | 
| 
       6 
     | 
    
         
            -
            		extend T::Sig
         
     | 
| 
       7 
5 
     | 
    
         
             
            		extend self
         
     | 
| 
       8 
6 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            		 
     | 
| 
      
 7 
     | 
    
         
            +
            		# a simple float example
         
     | 
| 
      
 8 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       10 
9 
     | 
    
         
             
            		def simple
         
     | 
| 
       11 
10 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       12 
11 
     | 
    
         
             
            				[:float],
         
     | 
| 
         @@ -18,7 +17,8 @@ module DataModel 
     | 
|
| 
       18 
17 
     | 
    
         
             
            			)
         
     | 
| 
       19 
18 
     | 
    
         
             
            		end
         
     | 
| 
       20 
19 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
            		 
     | 
| 
      
 20 
     | 
    
         
            +
            		# a float example that is optional
         
     | 
| 
      
 21 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       22 
22 
     | 
    
         
             
            		def optional
         
     | 
| 
       23 
23 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       24 
24 
     | 
    
         
             
            				[:float, { optional: true }],
         
     | 
| 
         @@ -28,7 +28,8 @@ module DataModel 
     | 
|
| 
       28 
28 
     | 
    
         
             
            			)
         
     | 
| 
       29 
29 
     | 
    
         
             
            		end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
            		 
     | 
| 
      
 31 
     | 
    
         
            +
            		# a float example where the minimum value is 5
         
     | 
| 
      
 32 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       32 
33 
     | 
    
         
             
            		def min
         
     | 
| 
       33 
34 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       34 
35 
     | 
    
         
             
            				[:float, { min: 5 }],
         
     | 
| 
         @@ -39,7 +40,8 @@ module DataModel 
     | 
|
| 
       39 
40 
     | 
    
         
             
            			)
         
     | 
| 
       40 
41 
     | 
    
         
             
            		end
         
     | 
| 
       41 
42 
     | 
    
         | 
| 
       42 
     | 
    
         
            -
            		 
     | 
| 
      
 43 
     | 
    
         
            +
            		# a float example where the maximum value is 5
         
     | 
| 
      
 44 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       43 
45 
     | 
    
         
             
            		def max
         
     | 
| 
       44 
46 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       45 
47 
     | 
    
         
             
            				[:float, { max: 5.0 }],
         
     | 
| 
         @@ -1,14 +1,11 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# Test data for hash schemas
         
     | 
| 
       4 
3 
     | 
    
         
             
            	module Fixtures::Hash
         
     | 
| 
       5 
4 
     | 
    
         
             
            		include Fixtures
         
     | 
| 
       6 
     | 
    
         
            -
            		extend T::Sig
         
     | 
| 
       7 
5 
     | 
    
         
             
            		extend self
         
     | 
| 
       8 
6 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            		 
     | 
| 
       10 
     | 
    
         
            -
             
     | 
| 
       11 
     | 
    
         
            -
            		sig { returns(TContact) }
         
     | 
| 
      
 7 
     | 
    
         
            +
            		# hash data conforming to the contact schema
         
     | 
| 
      
 8 
     | 
    
         
            +
            		# @return [Hash{Symbol => String}] the hash
         
     | 
| 
       12 
9 
     | 
    
         
             
            		def example_contact
         
     | 
| 
       13 
10 
     | 
    
         
             
            			{
         
     | 
| 
       14 
11 
     | 
    
         
             
            				first_name: "foo",
         
     | 
| 
         @@ -17,7 +14,20 @@ module DataModel 
     | 
|
| 
       17 
14 
     | 
    
         
             
            			}
         
     | 
| 
       18 
15 
     | 
    
         
             
            		end
         
     | 
| 
       19 
16 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
            		 
     | 
| 
      
 17 
     | 
    
         
            +
            		# alternate hash syntax for when you want to type keys and values
         
     | 
| 
      
 18 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
      
 19 
     | 
    
         
            +
            		def dictionary
         
     | 
| 
      
 20 
     | 
    
         
            +
            			Example.new(
         
     | 
| 
      
 21 
     | 
    
         
            +
            				[:hash, [symbol: :string]],
         
     | 
| 
      
 22 
     | 
    
         
            +
            				variants: {
         
     | 
| 
      
 23 
     | 
    
         
            +
            					valid: { foo: "bar" },
         
     | 
| 
      
 24 
     | 
    
         
            +
            					invalid: { foo: 123 }
         
     | 
| 
      
 25 
     | 
    
         
            +
            				},
         
     | 
| 
      
 26 
     | 
    
         
            +
            			)
         
     | 
| 
      
 27 
     | 
    
         
            +
            		end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            		# hash contact example
         
     | 
| 
      
 30 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       21 
31 
     | 
    
         
             
            		def contact
         
     | 
| 
       22 
32 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       23 
33 
     | 
    
         
             
            				[:hash,
         
     | 
| 
         @@ -28,14 +38,15 @@ module DataModel 
     | 
|
| 
       28 
38 
     | 
    
         
             
            					valid: example_contact,
         
     | 
| 
       29 
39 
     | 
    
         
             
            					missing: nil,
         
     | 
| 
       30 
40 
     | 
    
         
             
            					coercible: example_contact.to_a,
         
     | 
| 
       31 
     | 
    
         
            -
            					missing_email: example_contact.tap { |h|  
     | 
| 
      
 41 
     | 
    
         
            +
            					missing_email: example_contact.tap { |h| h.delete(:email) },
         
     | 
| 
       32 
42 
     | 
    
         
             
            					invalid_field: example_contact.merge(email: 123),
         
     | 
| 
       33 
43 
     | 
    
         
             
            					other_type: []
         
     | 
| 
       34 
44 
     | 
    
         
             
            				},
         
     | 
| 
       35 
45 
     | 
    
         
             
            			)
         
     | 
| 
       36 
46 
     | 
    
         
             
            		end
         
     | 
| 
       37 
47 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
            		 
     | 
| 
      
 48 
     | 
    
         
            +
            		# hash contact example that is optional
         
     | 
| 
      
 49 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       39 
50 
     | 
    
         
             
            		def optional_contact
         
     | 
| 
       40 
51 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       41 
52 
     | 
    
         
             
            				[:hash, { optional: true },
         
     | 
| 
         @@ -49,7 +60,8 @@ module DataModel 
     | 
|
| 
       49 
60 
     | 
    
         
             
            			)
         
     | 
| 
       50 
61 
     | 
    
         
             
            		end
         
     | 
| 
       51 
62 
     | 
    
         | 
| 
       52 
     | 
    
         
            -
            		 
     | 
| 
      
 63 
     | 
    
         
            +
            		# hash contact example that is closed to extra keys
         
     | 
| 
      
 64 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       53 
65 
     | 
    
         
             
            		def closed_contact
         
     | 
| 
       54 
66 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       55 
67 
     | 
    
         
             
            				[:hash, { open: false },
         
     | 
| 
         @@ -1,12 +1,11 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# Test data for integer schemas
         
     | 
| 
       4 
3 
     | 
    
         
             
            	module Fixtures::Integer
         
     | 
| 
       5 
4 
     | 
    
         
             
            		include Fixtures
         
     | 
| 
       6 
     | 
    
         
            -
            		extend T::Sig
         
     | 
| 
       7 
5 
     | 
    
         
             
            		extend self
         
     | 
| 
       8 
6 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            		 
     | 
| 
      
 7 
     | 
    
         
            +
            		# simple integer example
         
     | 
| 
      
 8 
     | 
    
         
            +
            		# @return [Hash{Symbol => untyped}] the variants used by each example
         
     | 
| 
       10 
9 
     | 
    
         
             
            		def simple
         
     | 
| 
       11 
10 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       12 
11 
     | 
    
         
             
            				[:integer],
         
     | 
| 
         @@ -18,7 +17,8 @@ module DataModel 
     | 
|
| 
       18 
17 
     | 
    
         
             
            			)
         
     | 
| 
       19 
18 
     | 
    
         
             
            		end
         
     | 
| 
       20 
19 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
            		 
     | 
| 
      
 20 
     | 
    
         
            +
            		# integer example that is optional
         
     | 
| 
      
 21 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       22 
22 
     | 
    
         
             
            		def optional
         
     | 
| 
       23 
23 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       24 
24 
     | 
    
         
             
            				[:integer, { optional: true }],
         
     | 
| 
         @@ -28,7 +28,8 @@ module DataModel 
     | 
|
| 
       28 
28 
     | 
    
         
             
            			)
         
     | 
| 
       29 
29 
     | 
    
         
             
            		end
         
     | 
| 
       30 
30 
     | 
    
         | 
| 
       31 
     | 
    
         
            -
            		 
     | 
| 
      
 31 
     | 
    
         
            +
            		# integer example that has a minimum value
         
     | 
| 
      
 32 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       32 
33 
     | 
    
         
             
            		def min
         
     | 
| 
       33 
34 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       34 
35 
     | 
    
         
             
            				[:integer, { min: 5 }],
         
     | 
| 
         @@ -39,7 +40,8 @@ module DataModel 
     | 
|
| 
       39 
40 
     | 
    
         
             
            			)
         
     | 
| 
       40 
41 
     | 
    
         
             
            		end
         
     | 
| 
       41 
42 
     | 
    
         | 
| 
       42 
     | 
    
         
            -
            		 
     | 
| 
      
 43 
     | 
    
         
            +
            		# integer example that has a maximum value
         
     | 
| 
      
 44 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       43 
45 
     | 
    
         
             
            		def max
         
     | 
| 
       44 
46 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       45 
47 
     | 
    
         
             
            				[:integer, { max: 5 }],
         
     | 
| 
         @@ -0,0 +1,31 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            require "bigdecimal/util"
         
     | 
| 
      
 2 
     | 
    
         
            +
             
     | 
| 
      
 3 
     | 
    
         
            +
            module DataModel
         
     | 
| 
      
 4 
     | 
    
         
            +
            	# test fixtures for object type
         
     | 
| 
      
 5 
     | 
    
         
            +
            	module Fixtures::Numeric
         
     | 
| 
      
 6 
     | 
    
         
            +
            		extend self
         
     | 
| 
      
 7 
     | 
    
         
            +
            		include Fixtures
         
     | 
| 
      
 8 
     | 
    
         
            +
             
     | 
| 
      
 9 
     | 
    
         
            +
            		def variants
         
     | 
| 
      
 10 
     | 
    
         
            +
            			{
         
     | 
| 
      
 11 
     | 
    
         
            +
            				missing: nil,
         
     | 
| 
      
 12 
     | 
    
         
            +
            				integer: 1,
         
     | 
| 
      
 13 
     | 
    
         
            +
            				float: 1.0,
         
     | 
| 
      
 14 
     | 
    
         
            +
            				decimal: 1.0.to_d,
         
     | 
| 
      
 15 
     | 
    
         
            +
            				string: ["1", 1]
         
     | 
| 
      
 16 
     | 
    
         
            +
            			}
         
     | 
| 
      
 17 
     | 
    
         
            +
            		end
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            		# a simple numeric example
         
     | 
| 
      
 20 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
      
 21 
     | 
    
         
            +
            		def simple
         
     | 
| 
      
 22 
     | 
    
         
            +
            			Example.new([:numeric], variants:)
         
     | 
| 
      
 23 
     | 
    
         
            +
            		end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            		# a numeric example that is optional
         
     | 
| 
      
 26 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
      
 27 
     | 
    
         
            +
            		def optional
         
     | 
| 
      
 28 
     | 
    
         
            +
            			Example.new([:numeric, { optional: true }], variants:)
         
     | 
| 
      
 29 
     | 
    
         
            +
            		end
         
     | 
| 
      
 30 
     | 
    
         
            +
            	end
         
     | 
| 
      
 31 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,27 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# test fixtures for object type
         
     | 
| 
      
 3 
     | 
    
         
            +
            	module Fixtures::Object
         
     | 
| 
      
 4 
     | 
    
         
            +
            		extend self
         
     | 
| 
      
 5 
     | 
    
         
            +
            		include Fixtures
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            		def variants
         
     | 
| 
      
 8 
     | 
    
         
            +
            			{
         
     | 
| 
      
 9 
     | 
    
         
            +
            				missing: nil,
         
     | 
| 
      
 10 
     | 
    
         
            +
            				integer: 1,
         
     | 
| 
      
 11 
     | 
    
         
            +
            				string: "string"
         
     | 
| 
      
 12 
     | 
    
         
            +
            			}
         
     | 
| 
      
 13 
     | 
    
         
            +
            		end
         
     | 
| 
      
 14 
     | 
    
         
            +
             
     | 
| 
      
 15 
     | 
    
         
            +
            		# a simple object example
         
     | 
| 
      
 16 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
      
 17 
     | 
    
         
            +
            		def simple
         
     | 
| 
      
 18 
     | 
    
         
            +
            			Example.new([:object], variants:)
         
     | 
| 
      
 19 
     | 
    
         
            +
            		end
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            		# a object example that is optional
         
     | 
| 
      
 22 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
      
 23 
     | 
    
         
            +
            		def optional
         
     | 
| 
      
 24 
     | 
    
         
            +
            			Example.new([:object, { optional: true }], variants:)
         
     | 
| 
      
 25 
     | 
    
         
            +
            		end
         
     | 
| 
      
 26 
     | 
    
         
            +
            	end
         
     | 
| 
      
 27 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,29 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# test fixtures for object type
         
     | 
| 
      
 3 
     | 
    
         
            +
            	module Fixtures::Or
         
     | 
| 
      
 4 
     | 
    
         
            +
            		extend self
         
     | 
| 
      
 5 
     | 
    
         
            +
            		include Fixtures
         
     | 
| 
      
 6 
     | 
    
         
            +
             
     | 
| 
      
 7 
     | 
    
         
            +
            		def variants
         
     | 
| 
      
 8 
     | 
    
         
            +
            			{
         
     | 
| 
      
 9 
     | 
    
         
            +
            				missing: nil,
         
     | 
| 
      
 10 
     | 
    
         
            +
            				integer: 1,
         
     | 
| 
      
 11 
     | 
    
         
            +
            				int_array: [1],
         
     | 
| 
      
 12 
     | 
    
         
            +
            				string: ["1", 1],
         
     | 
| 
      
 13 
     | 
    
         
            +
            				float: 1.0
         
     | 
| 
      
 14 
     | 
    
         
            +
            			}
         
     | 
| 
      
 15 
     | 
    
         
            +
            		end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            		# a simple numeric example, integer or integer array
         
     | 
| 
      
 18 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
      
 19 
     | 
    
         
            +
            		def simple
         
     | 
| 
      
 20 
     | 
    
         
            +
            			Example.new([:or, :integer, [:array, :integer]], variants:)
         
     | 
| 
      
 21 
     | 
    
         
            +
            		end
         
     | 
| 
      
 22 
     | 
    
         
            +
             
     | 
| 
      
 23 
     | 
    
         
            +
            		# a numeric example that is optional
         
     | 
| 
      
 24 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
      
 25 
     | 
    
         
            +
            		def optional
         
     | 
| 
      
 26 
     | 
    
         
            +
            			Example.new([:or, { optional: true }, :integer, [:array, :integer]], variants:)
         
     | 
| 
      
 27 
     | 
    
         
            +
            		end
         
     | 
| 
      
 28 
     | 
    
         
            +
            	end
         
     | 
| 
      
 29 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,12 +1,11 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# Test data for string schemas
         
     | 
| 
       4 
3 
     | 
    
         
             
            	module Fixtures::String
         
     | 
| 
       5 
4 
     | 
    
         
             
            		extend self
         
     | 
| 
       6 
     | 
    
         
            -
            		extend T::Sig
         
     | 
| 
       7 
5 
     | 
    
         
             
            		include Fixtures
         
     | 
| 
       8 
6 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            		 
     | 
| 
      
 7 
     | 
    
         
            +
            		# a simple string example
         
     | 
| 
      
 8 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       10 
9 
     | 
    
         
             
            		def simple
         
     | 
| 
       11 
10 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       12 
11 
     | 
    
         
             
            				[:string],
         
     | 
| 
         @@ -18,7 +17,8 @@ module DataModel 
     | 
|
| 
       18 
17 
     | 
    
         
             
            			)
         
     | 
| 
       19 
18 
     | 
    
         
             
            		end
         
     | 
| 
       20 
19 
     | 
    
         | 
| 
       21 
     | 
    
         
            -
            		 
     | 
| 
      
 20 
     | 
    
         
            +
            		# an email string example
         
     | 
| 
      
 21 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       22 
22 
     | 
    
         
             
            		def email
         
     | 
| 
       23 
23 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       24 
24 
     | 
    
         
             
            				[:string, { format: "@" }],
         
     | 
| 
         @@ -29,29 +29,8 @@ module DataModel 
     | 
|
| 
       29 
29 
     | 
    
         
             
            			)
         
     | 
| 
       30 
30 
     | 
    
         
             
            		end
         
     | 
| 
       31 
31 
     | 
    
         | 
| 
       32 
     | 
    
         
            -
            		 
     | 
| 
       33 
     | 
    
         
            -
            		 
     | 
| 
       34 
     | 
    
         
            -
            			Example.new(
         
     | 
| 
       35 
     | 
    
         
            -
            				[:string, { format: /@/ }],
         
     | 
| 
       36 
     | 
    
         
            -
            				variants: {
         
     | 
| 
       37 
     | 
    
         
            -
            					valid: "foo@bar.com",
         
     | 
| 
       38 
     | 
    
         
            -
            					invalid: "invalid"
         
     | 
| 
       39 
     | 
    
         
            -
            				},
         
     | 
| 
       40 
     | 
    
         
            -
            			)
         
     | 
| 
       41 
     | 
    
         
            -
            		end
         
     | 
| 
       42 
     | 
    
         
            -
             
     | 
| 
       43 
     | 
    
         
            -
            		sig { returns(Example) }
         
     | 
| 
       44 
     | 
    
         
            -
            		def email_proc
         
     | 
| 
       45 
     | 
    
         
            -
            			Example.new(
         
     | 
| 
       46 
     | 
    
         
            -
            				[:string, { format: ->(val) { val.match?(/@/) } }],
         
     | 
| 
       47 
     | 
    
         
            -
            				variants: {
         
     | 
| 
       48 
     | 
    
         
            -
            					valid: "foo@bar.com",
         
     | 
| 
       49 
     | 
    
         
            -
            					invalid: "invalid"
         
     | 
| 
       50 
     | 
    
         
            -
            				},
         
     | 
| 
       51 
     | 
    
         
            -
            			)
         
     | 
| 
       52 
     | 
    
         
            -
            		end
         
     | 
| 
       53 
     | 
    
         
            -
             
     | 
| 
       54 
     | 
    
         
            -
            		sig { returns(Example) }
         
     | 
| 
      
 32 
     | 
    
         
            +
            		# a string example that is optional
         
     | 
| 
      
 33 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       55 
34 
     | 
    
         
             
            		def optional
         
     | 
| 
       56 
35 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       57 
36 
     | 
    
         
             
            				[:string, { optional: true }],
         
     | 
| 
         @@ -63,7 +42,8 @@ module DataModel 
     | 
|
| 
       63 
42 
     | 
    
         
             
            			)
         
     | 
| 
       64 
43 
     | 
    
         
             
            		end
         
     | 
| 
       65 
44 
     | 
    
         | 
| 
       66 
     | 
    
         
            -
            		 
     | 
| 
      
 45 
     | 
    
         
            +
            		# a string example where "valid" is the only allowed String
         
     | 
| 
      
 46 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       67 
47 
     | 
    
         
             
            		def inclusion
         
     | 
| 
       68 
48 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       69 
49 
     | 
    
         
             
            				[:string, { included: ["valid"] }],
         
     | 
| 
         @@ -74,7 +54,8 @@ module DataModel 
     | 
|
| 
       74 
54 
     | 
    
         
             
            			)
         
     | 
| 
       75 
55 
     | 
    
         
             
            		end
         
     | 
| 
       76 
56 
     | 
    
         | 
| 
       77 
     | 
    
         
            -
            		 
     | 
| 
      
 57 
     | 
    
         
            +
            		# a string example where "invalid" is the only disallowed String
         
     | 
| 
      
 58 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       78 
59 
     | 
    
         
             
            		def exclusion
         
     | 
| 
       79 
60 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       80 
61 
     | 
    
         
             
            				[:string, { excluded: ["invalid"] }],
         
     | 
| 
         @@ -85,7 +66,8 @@ module DataModel 
     | 
|
| 
       85 
66 
     | 
    
         
             
            			)
         
     | 
| 
       86 
67 
     | 
    
         
             
            		end
         
     | 
| 
       87 
68 
     | 
    
         | 
| 
       88 
     | 
    
         
            -
            		 
     | 
| 
      
 69 
     | 
    
         
            +
            		# a string example where blank strings are allowed
         
     | 
| 
      
 70 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       89 
71 
     | 
    
         
             
            		def allow_blank
         
     | 
| 
       90 
72 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       91 
73 
     | 
    
         
             
            				[:string, { allow_blank: true }],
         
     | 
| 
         @@ -97,7 +79,8 @@ module DataModel 
     | 
|
| 
       97 
79 
     | 
    
         
             
            			)
         
     | 
| 
       98 
80 
     | 
    
         
             
            		end
         
     | 
| 
       99 
81 
     | 
    
         | 
| 
       100 
     | 
    
         
            -
            		 
     | 
| 
      
 82 
     | 
    
         
            +
            		# a string example where blank strings are not allowed
         
     | 
| 
      
 83 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       101 
84 
     | 
    
         
             
            		def dont_allow_blank
         
     | 
| 
       102 
85 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       103 
86 
     | 
    
         
             
            				[:string, { allow_blank: false }],
         
     | 
| 
         @@ -1,12 +1,11 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# Test data around symbol schemas
         
     | 
| 
       4 
3 
     | 
    
         
             
            	module Fixtures::Symbol
         
     | 
| 
       5 
4 
     | 
    
         
             
            		extend self
         
     | 
| 
       6 
5 
     | 
    
         
             
            		include Fixtures
         
     | 
| 
       7 
     | 
    
         
            -
            		extend T::Sig
         
     | 
| 
       8 
6 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            		 
     | 
| 
      
 7 
     | 
    
         
            +
            		# a simple symbol example
         
     | 
| 
      
 8 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       10 
9 
     | 
    
         
             
            		def simple
         
     | 
| 
       11 
10 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       12 
11 
     | 
    
         
             
            				[:symbol],
         
     | 
| 
         @@ -19,7 +18,8 @@ module DataModel 
     | 
|
| 
       19 
18 
     | 
    
         
             
            			)
         
     | 
| 
       20 
19 
     | 
    
         
             
            		end
         
     | 
| 
       21 
20 
     | 
    
         | 
| 
       22 
     | 
    
         
            -
            		 
     | 
| 
      
 21 
     | 
    
         
            +
            		# a symbol example that is optional
         
     | 
| 
      
 22 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       23 
23 
     | 
    
         
             
            		def optional
         
     | 
| 
       24 
24 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       25 
25 
     | 
    
         
             
            				[:symbol, { optional: true }],
         
     | 
| 
         @@ -31,7 +31,8 @@ module DataModel 
     | 
|
| 
       31 
31 
     | 
    
         
             
            			)
         
     | 
| 
       32 
32 
     | 
    
         
             
            		end
         
     | 
| 
       33 
33 
     | 
    
         | 
| 
       34 
     | 
    
         
            -
            		 
     | 
| 
      
 34 
     | 
    
         
            +
            		# a symbol example where :valid is the only allowed Symbol
         
     | 
| 
      
 35 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       35 
36 
     | 
    
         
             
            		def inclusion
         
     | 
| 
       36 
37 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       37 
38 
     | 
    
         
             
            				[:symbol, { included: [:valid] }],
         
     | 
| 
         @@ -42,7 +43,8 @@ module DataModel 
     | 
|
| 
       42 
43 
     | 
    
         
             
            			)
         
     | 
| 
       43 
44 
     | 
    
         
             
            		end
         
     | 
| 
       44 
45 
     | 
    
         | 
| 
       45 
     | 
    
         
            -
            		 
     | 
| 
      
 46 
     | 
    
         
            +
            		# a symbol example where :invalid is the only disallowed Symbol
         
     | 
| 
      
 47 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       46 
48 
     | 
    
         
             
            		def exclusion
         
     | 
| 
       47 
49 
     | 
    
         
             
            			Example.new(
         
     | 
| 
       48 
50 
     | 
    
         
             
            				[:symbol, { excluded: [:invalid] }],
         
     | 
| 
         @@ -1,22 +1,20 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# Test data around time schemas
         
     | 
| 
       4 
3 
     | 
    
         
             
            	module Fixtures::Time
         
     | 
| 
       5 
     | 
    
         
            -
            		extend T::Sig
         
     | 
| 
       6 
     | 
    
         
            -
            		extend self
         
     | 
| 
       7 
4 
     | 
    
         
             
            		include Fixtures
         
     | 
| 
      
 5 
     | 
    
         
            +
            		extend self
         
     | 
| 
       8 
6 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            		 
     | 
| 
      
 7 
     | 
    
         
            +
            		# @return [Time] a time that is used by the #earliest example
         
     | 
| 
       10 
8 
     | 
    
         
             
            		def earliest_time
         
     | 
| 
       11 
9 
     | 
    
         
             
            			return ::Time.now - 1
         
     | 
| 
       12 
10 
     | 
    
         
             
            		end
         
     | 
| 
       13 
11 
     | 
    
         | 
| 
       14 
     | 
    
         
            -
            		 
     | 
| 
      
 12 
     | 
    
         
            +
            		# @return [Time] a time that is used by the #latest example
         
     | 
| 
       15 
13 
     | 
    
         
             
            		def latest_time
         
     | 
| 
       16 
14 
     | 
    
         
             
            			return ::Time.now + 1
         
     | 
| 
       17 
15 
     | 
    
         
             
            		end
         
     | 
| 
       18 
16 
     | 
    
         | 
| 
       19 
     | 
    
         
            -
            		 
     | 
| 
      
 17 
     | 
    
         
            +
            		# @return [Hash{Symbol => untyped}] the variants used by each example
         
     | 
| 
       20 
18 
     | 
    
         
             
            		def variants
         
     | 
| 
       21 
19 
     | 
    
         
             
            			now = ::Time.now
         
     | 
| 
       22 
20 
     | 
    
         | 
| 
         @@ -30,22 +28,26 @@ module DataModel 
     | 
|
| 
       30 
28 
     | 
    
         
             
            			}
         
     | 
| 
       31 
29 
     | 
    
         
             
            		end
         
     | 
| 
       32 
30 
     | 
    
         | 
| 
       33 
     | 
    
         
            -
            		 
     | 
| 
      
 31 
     | 
    
         
            +
            		# A simple time schema
         
     | 
| 
      
 32 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       34 
33 
     | 
    
         
             
            		def simple
         
     | 
| 
       35 
34 
     | 
    
         
             
            			Example.new([:time], variants:)
         
     | 
| 
       36 
35 
     | 
    
         
             
            		end
         
     | 
| 
       37 
36 
     | 
    
         | 
| 
       38 
     | 
    
         
            -
            		 
     | 
| 
      
 37 
     | 
    
         
            +
            		# A time schema that is optional
         
     | 
| 
      
 38 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       39 
39 
     | 
    
         
             
            		def optional
         
     | 
| 
       40 
40 
     | 
    
         
             
            			Example.new([:time, { optional: true }], variants:)
         
     | 
| 
       41 
41 
     | 
    
         
             
            		end
         
     | 
| 
       42 
42 
     | 
    
         | 
| 
       43 
     | 
    
         
            -
            		 
     | 
| 
      
 43 
     | 
    
         
            +
            		# A time schema that has a restriction on the earliest time
         
     | 
| 
      
 44 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       44 
45 
     | 
    
         
             
            		def earliest
         
     | 
| 
       45 
46 
     | 
    
         
             
            			Example.new([:time, { earliest: earliest_time }], variants:)
         
     | 
| 
       46 
47 
     | 
    
         
             
            		end
         
     | 
| 
       47 
48 
     | 
    
         | 
| 
       48 
     | 
    
         
            -
            		 
     | 
| 
      
 49 
     | 
    
         
            +
            		# A time schema that has a restriction on the latest time
         
     | 
| 
      
 50 
     | 
    
         
            +
            		# @return [Example] the example
         
     | 
| 
       49 
51 
     | 
    
         
             
            		def latest
         
     | 
| 
       50 
52 
     | 
    
         
             
            			Example.new([:time, { latest: latest_time }], variants:)
         
     | 
| 
       51 
53 
     | 
    
         
             
            		end
         
     | 
    
        data/lib/data_model/logging.rb
    CHANGED
    
    | 
         @@ -1,15 +1,12 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            require "logger"
         
     | 
| 
       4 
2 
     | 
    
         | 
| 
       5 
3 
     | 
    
         
             
            module DataModel
         
     | 
| 
      
 4 
     | 
    
         
            +
            	# Provides a logger for classes that include it
         
     | 
| 
       6 
5 
     | 
    
         
             
            	module Logging
         
     | 
| 
       7 
     | 
    
         
            -
            		 
     | 
| 
       8 
     | 
    
         
            -
            		 
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
            		sig { returns(Logger) }
         
     | 
| 
      
 6 
     | 
    
         
            +
            		# Get a logger
         
     | 
| 
      
 7 
     | 
    
         
            +
            		# @return [Logger] the logger for this class
         
     | 
| 
       11 
8 
     | 
    
         
             
            		def log
         
     | 
| 
       12 
     | 
    
         
            -
            			target =  
     | 
| 
      
 9 
     | 
    
         
            +
            			target = respond_to?(:name) ? self : self.class
         
     | 
| 
       13 
10 
     | 
    
         | 
| 
       14 
11 
     | 
    
         
             
            			logger = Logger.new(
         
     | 
| 
       15 
12 
     | 
    
         
             
            				STDERR,
         
     | 
| 
         @@ -17,7 +14,7 @@ module DataModel 
     | 
|
| 
       17 
14 
     | 
    
         
             
            				progname: target.name,
         
     | 
| 
       18 
15 
     | 
    
         
             
            			)
         
     | 
| 
       19 
16 
     | 
    
         | 
| 
       20 
     | 
    
         
            -
            			return @log ||=  
     | 
| 
      
 17 
     | 
    
         
            +
            			return @log ||= logger
         
     | 
| 
       21 
18 
     | 
    
         
             
            		end
         
     | 
| 
       22 
19 
     | 
    
         
             
            	end
         
     | 
| 
       23 
20 
     | 
    
         
             
            end
         
     | 
    
        data/lib/data_model/model.rb
    CHANGED
    
    | 
         @@ -1,28 +1,31 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# A model is a schema and a type. It is the primary interface for interacting
         
     | 
| 
      
 3 
     | 
    
         
            +
            	# with the data_model gem.
         
     | 
| 
       4 
4 
     | 
    
         
             
            	class Model
         
     | 
| 
       5 
     | 
    
         
            -
            		 
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
            		 
     | 
| 
      
 5 
     | 
    
         
            +
            		# Create a new model.
         
     | 
| 
      
 6 
     | 
    
         
            +
            		# @param schema [Array] the schema to define
         
     | 
| 
      
 7 
     | 
    
         
            +
            		# @param type [Type] the type to use
         
     | 
| 
      
 8 
     | 
    
         
            +
            		# @return [void]
         
     | 
| 
       8 
9 
     | 
    
         
             
            		def initialize(schema, type)
         
     | 
| 
       9 
10 
     | 
    
         
             
            			@schema = schema
         
     | 
| 
       10 
11 
     | 
    
         
             
            			@type = type
         
     | 
| 
       11 
12 
     | 
    
         
             
            		end
         
     | 
| 
       12 
13 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
            		 
     | 
| 
      
 14 
     | 
    
         
            +
            		# @return [Array] the schema configured
         
     | 
| 
       14 
15 
     | 
    
         
             
            		attr_reader :schema
         
     | 
| 
       15 
16 
     | 
    
         | 
| 
       16 
17 
     | 
    
         
             
            		# Validate data against the model. This will return true if the data is valid,
         
     | 
| 
       17 
18 
     | 
    
         
             
            		# or false if it is not. If it is not valid, it will raise an exception.
         
     | 
| 
       18 
     | 
    
         
            -
            		 
     | 
| 
      
 19 
     | 
    
         
            +
            		# @param data [Hash] the data to validate
         
     | 
| 
      
 20 
     | 
    
         
            +
            		# @return [Boolean] true if the data is valid, false if it is not
         
     | 
| 
       19 
21 
     | 
    
         
             
            		def validate(data)
         
     | 
| 
       20 
22 
     | 
    
         
             
            			_, err = @type.read(data)
         
     | 
| 
       21 
23 
     | 
    
         
             
            			return err
         
     | 
| 
       22 
24 
     | 
    
         
             
            		end
         
     | 
| 
       23 
25 
     | 
    
         | 
| 
       24 
26 
     | 
    
         
             
            		# Read data with the model. This will return a tuple of [data, error]
         
     | 
| 
       25 
     | 
    
         
            -
            		 
     | 
| 
      
 27 
     | 
    
         
            +
            		# @param data [Hash] the data to read
         
     | 
| 
      
 28 
     | 
    
         
            +
            		# @return [Array] a tuple of [data, error]
         
     | 
| 
       26 
29 
     | 
    
         
             
            		def coerce(data)
         
     | 
| 
       27 
30 
     | 
    
         
             
            			result = @type.read(data, coerce: true)
         
     | 
| 
       28 
31 
     | 
    
         
             
            			return result
         
     | 
    
        data/lib/data_model/registry.rb
    CHANGED
    
    | 
         @@ -1,61 +1,71 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
       4 
2 
     | 
    
         
             
            	# Registry allows for different type implementations to be used by the scanner.
         
     | 
| 
       5 
3 
     | 
    
         
             
            	# It also acts as an error message registry, mostly for pragmatic reasons.
         
     | 
| 
       6 
4 
     | 
    
         
             
            	class Registry
         
     | 
| 
       7 
     | 
    
         
            -
            		extend T::Sig
         
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
5 
     | 
    
         
             
            		# Default types that will be used if alternative type map is not given
         
     | 
| 
       10 
     | 
    
         
            -
            		 
     | 
| 
      
 6 
     | 
    
         
            +
            		# @return [Hash] the default type map
         
     | 
| 
       11 
7 
     | 
    
         
             
            		def self.default_types
         
     | 
| 
       12 
8 
     | 
    
         
             
            			Builtin.types
         
     | 
| 
       13 
9 
     | 
    
         
             
            		end
         
     | 
| 
       14 
10 
     | 
    
         | 
| 
       15 
     | 
    
         
            -
            		 
     | 
| 
      
 11 
     | 
    
         
            +
            		# Default error messages that will be used if alternative error messages are not given
         
     | 
| 
      
 12 
     | 
    
         
            +
            		# @return [Hash] the default error messages
         
     | 
| 
       16 
13 
     | 
    
         
             
            		def self.default_error_messages
         
     | 
| 
       17 
14 
     | 
    
         
             
            			Errors.error_messages
         
     | 
| 
       18 
15 
     | 
    
         
             
            		end
         
     | 
| 
       19 
16 
     | 
    
         | 
| 
       20 
17 
     | 
    
         
             
            		# Singleton instance that will be used globally unless instances given
         
     | 
| 
       21 
     | 
    
         
            -
            		 
     | 
| 
      
 18 
     | 
    
         
            +
            		# @param types [Hash] the type map to use
         
     | 
| 
      
 19 
     | 
    
         
            +
            		# @param errors [Hash] the error message map to use
         
     | 
| 
      
 20 
     | 
    
         
            +
            		# @return [Registry] the singleton instance
         
     | 
| 
       22 
21 
     | 
    
         
             
            		def self.instance(types: default_types, errors: default_error_messages)
         
     | 
| 
       23 
     | 
    
         
            -
            			@instance ||=  
     | 
| 
      
 22 
     | 
    
         
            +
            			@instance ||= new(types:, errors:)
         
     | 
| 
       24 
23 
     | 
    
         
             
            		end
         
     | 
| 
       25 
24 
     | 
    
         | 
| 
       26 
25 
     | 
    
         
             
            		# Register a type on the global instance
         
     | 
| 
       27 
     | 
    
         
            -
            		 
     | 
| 
      
 26 
     | 
    
         
            +
            		# @param name [Symbol] the name of the type
         
     | 
| 
      
 27 
     | 
    
         
            +
            		# @param type [Type] the type to register
         
     | 
| 
      
 28 
     | 
    
         
            +
            		# @return [void]
         
     | 
| 
       28 
29 
     | 
    
         
             
            		def self.register(name, type)
         
     | 
| 
       29 
30 
     | 
    
         
             
            			instance.register(name, type)
         
     | 
| 
       30 
31 
     | 
    
         
             
            		end
         
     | 
| 
       31 
32 
     | 
    
         | 
| 
       32 
33 
     | 
    
         
             
            		# Instanciate a new type registry. Default errors will always be used, but additional
         
     | 
| 
       33 
34 
     | 
    
         
             
            		# errors can be registered.
         
     | 
| 
       34 
     | 
    
         
            -
            		 
     | 
| 
      
 35 
     | 
    
         
            +
            		# @param types [Hash] the type map to use
         
     | 
| 
      
 36 
     | 
    
         
            +
            		# @param errors [Hash] the error message map to use
         
     | 
| 
      
 37 
     | 
    
         
            +
            		# @return [Registry] the new instance
         
     | 
| 
       35 
38 
     | 
    
         
             
            		def initialize(types: self.class.default_types, errors: self.class.default_error_messages)
         
     | 
| 
       36 
     | 
    
         
            -
            			@error_messages =  
     | 
| 
      
 39 
     | 
    
         
            +
            			@error_messages = nil
         
     | 
| 
      
 40 
     | 
    
         
            +
             
     | 
| 
       37 
41 
     | 
    
         
             
            			if errors
         
     | 
| 
       38 
42 
     | 
    
         
             
            				errors.each { |type, builder| register_error_message(type, &builder) }
         
     | 
| 
       39 
43 
     | 
    
         
             
            			end
         
     | 
| 
       40 
44 
     | 
    
         | 
| 
       41 
     | 
    
         
            -
            			@types =  
     | 
| 
      
 45 
     | 
    
         
            +
            			@types = {}
         
     | 
| 
       42 
46 
     | 
    
         
             
            			types.each { |(name, type)| register(name, type) }
         
     | 
| 
       43 
47 
     | 
    
         
             
            		end
         
     | 
| 
       44 
48 
     | 
    
         | 
| 
       45 
49 
     | 
    
         
             
            		# Register a type on this instance
         
     | 
| 
       46 
     | 
    
         
            -
            		 
     | 
| 
      
 50 
     | 
    
         
            +
            		# @param name [Symbol] the name of the Type
         
     | 
| 
      
 51 
     | 
    
         
            +
            		# @param type [Type] the type to register
         
     | 
| 
      
 52 
     | 
    
         
            +
            		# @return [void]
         
     | 
| 
       47 
53 
     | 
    
         
             
            		def register(name, type)
         
     | 
| 
       48 
54 
     | 
    
         
             
            			@types[name] = type
         
     | 
| 
       49 
55 
     | 
    
         
             
            		end
         
     | 
| 
       50 
56 
     | 
    
         | 
| 
       51 
57 
     | 
    
         
             
            		# Check if a type is registered
         
     | 
| 
       52 
     | 
    
         
            -
            		 
     | 
| 
      
 58 
     | 
    
         
            +
            		# @param name [Symbol] the name of the type
         
     | 
| 
      
 59 
     | 
    
         
            +
            		# @return [Boolean] whether the type is registered
         
     | 
| 
       53 
60 
     | 
    
         
             
            		def type?(name)
         
     | 
| 
       54 
61 
     | 
    
         
             
            			@types.key?(name)
         
     | 
| 
       55 
62 
     | 
    
         
             
            		end
         
     | 
| 
       56 
63 
     | 
    
         | 
| 
       57 
64 
     | 
    
         
             
            		# Access and configure registered type
         
     | 
| 
       58 
     | 
    
         
            -
            		 
     | 
| 
      
 65 
     | 
    
         
            +
            		# @param name [Symbol] the name of the Type
         
     | 
| 
      
 66 
     | 
    
         
            +
            		# @param args [Hash] the arguments to pass to the Type
         
     | 
| 
      
 67 
     | 
    
         
            +
            		# @param params [Array] the parameters to configure the Type with
         
     | 
| 
      
 68 
     | 
    
         
            +
            		# @return [Type] the configured type
         
     | 
| 
       59 
69 
     | 
    
         
             
            		def type(name, args: {}, params: nil)
         
     | 
| 
       60 
70 
     | 
    
         
             
            			if !type?(name)
         
     | 
| 
       61 
71 
     | 
    
         
             
            				raise "#{name} is not registered as a type"
         
     | 
| 
         @@ -73,26 +83,30 @@ module DataModel 
     | 
|
| 
       73 
83 
     | 
    
         
             
            		## API
         
     | 
| 
       74 
84 
     | 
    
         | 
| 
       75 
85 
     | 
    
         
             
            		# Register a custom error message for use with custom errors
         
     | 
| 
       76 
     | 
    
         
            -
            		 
     | 
| 
      
 86 
     | 
    
         
            +
            		# @param type [Symbol] the type of error to register
         
     | 
| 
      
 87 
     | 
    
         
            +
            		# @param block [Proc] the block to use to build the error message, shoudl take the error context and return a string
         
     | 
| 
      
 88 
     | 
    
         
            +
            		# @return [void]
         
     | 
| 
       77 
89 
     | 
    
         
             
            		def register_error_message(type, &block)
         
     | 
| 
       78 
90 
     | 
    
         
             
            			error_message_builders[type] = block
         
     | 
| 
       79 
91 
     | 
    
         
             
            		end
         
     | 
| 
       80 
92 
     | 
    
         | 
| 
       81 
93 
     | 
    
         
             
            		# Get the error message builders
         
     | 
| 
       82 
     | 
    
         
            -
            		 
     | 
| 
      
 94 
     | 
    
         
            +
            		# @return [Hash] the error message builders
         
     | 
| 
       83 
95 
     | 
    
         
             
            		def error_message_builders
         
     | 
| 
       84 
96 
     | 
    
         
             
            			if @error_messages.nil?
         
     | 
| 
       85 
     | 
    
         
            -
            				@error_messages ||=  
     | 
| 
      
 97 
     | 
    
         
            +
            				@error_messages ||= {}
         
     | 
| 
       86 
98 
     | 
    
         
             
            			end
         
     | 
| 
       87 
99 
     | 
    
         | 
| 
       88 
100 
     | 
    
         
             
            			@error_messages
         
     | 
| 
       89 
101 
     | 
    
         
             
            		end
         
     | 
| 
       90 
102 
     | 
    
         | 
| 
       91 
103 
     | 
    
         
             
            		# Build the error message for a given error
         
     | 
| 
       92 
     | 
    
         
            -
            		 
     | 
| 
      
 104 
     | 
    
         
            +
            		# @param error [Error] the error to build the message for
         
     | 
| 
      
 105 
     | 
    
         
            +
            		# @return [String] the error message
         
     | 
| 
      
 106 
     | 
    
         
            +
            		# @raise [RuntimeError] if no error message builder is registered for the error type
         
     | 
| 
       93 
107 
     | 
    
         
             
            		def error_message(error)
         
     | 
| 
       94 
     | 
    
         
            -
            			type =  
     | 
| 
       95 
     | 
    
         
            -
            			ctx =  
     | 
| 
      
 108 
     | 
    
         
            +
            			type = error[0]
         
     | 
| 
      
 109 
     | 
    
         
            +
            			ctx = error[1]
         
     | 
| 
       96 
110 
     | 
    
         | 
| 
       97 
111 
     | 
    
         
             
            			builder = error_message_builders[type]
         
     | 
| 
       98 
112 
     | 
    
         | 
| 
         @@ -104,7 +118,8 @@ module DataModel 
     | 
|
| 
       104 
118 
     | 
    
         
             
            		end
         
     | 
| 
       105 
119 
     | 
    
         | 
| 
       106 
120 
     | 
    
         
             
            		# Build error messages from error object
         
     | 
| 
       107 
     | 
    
         
            -
            		 
     | 
| 
      
 121 
     | 
    
         
            +
            		# @param error [Error] the error to build the messages for
         
     | 
| 
      
 122 
     | 
    
         
            +
            		# @return [Hash] the error messages
         
     | 
| 
       108 
123 
     | 
    
         
             
            		def error_messages(error)
         
     | 
| 
       109 
124 
     | 
    
         
             
            			error.to_h.transform_values do |error_list|
         
     | 
| 
       110 
125 
     | 
    
         
             
            				error_list.map { |e| error_message(e) }
         
     |