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,26 +1,73 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
       4 
     | 
    
         
            -
            	# Hash type has a concept of "child types"
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# Hash type has a concept of "child types". They can either be specified
         
     | 
| 
      
 3 
     | 
    
         
            +
            	# as params of nested child arrays, or in a hash notation if specific
         
     | 
| 
      
 4 
     | 
    
         
            +
            	# keys are not being specified
         
     | 
| 
      
 5 
     | 
    
         
            +
            	#
         
     | 
| 
      
 6 
     | 
    
         
            +
            	# This is by far the most complex built-in type
         
     | 
| 
      
 7 
     | 
    
         
            +
            	#
         
     | 
| 
      
 8 
     | 
    
         
            +
            	# Example:
         
     | 
| 
      
 9 
     | 
    
         
            +
            	# 	[:hash, [:name, :string], [:email, :string]] # must have two specific keys
         
     | 
| 
      
 10 
     | 
    
         
            +
            	# 	[:hash, [symbol: :string] # key and values must be according to type
         
     | 
| 
      
 11 
     | 
    
         
            +
            	# 	[:hash, [symbol: [:string, {optional: true}]]] # types can be specified long hand
         
     | 
| 
       5 
12 
     | 
    
         
             
            	class Builtin::Hash < Type
         
     | 
| 
       6 
13 
     | 
    
         
             
            		include Errors
         
     | 
| 
       7 
14 
     | 
    
         
             
            		include Logging
         
     | 
| 
       8 
15 
     | 
    
         | 
| 
       9 
     | 
    
         
            -
            		class Arguments <  
     | 
| 
       10 
     | 
    
         
            -
            			prop :optional,  
     | 
| 
       11 
     | 
    
         
            -
            			prop :open,  
     | 
| 
      
 16 
     | 
    
         
            +
            		class Arguments < Struct
         
     | 
| 
      
 17 
     | 
    
         
            +
            			prop :optional, :boolean, default: false
         
     | 
| 
      
 18 
     | 
    
         
            +
            			prop :open, :boolean, default: true
         
     | 
| 
       12 
19 
     | 
    
         
             
            		end
         
     | 
| 
       13 
20 
     | 
    
         | 
| 
       14 
21 
     | 
    
         
             
            		## Children
         
     | 
| 
       15 
22 
     | 
    
         | 
| 
       16 
     | 
    
         
            -
            		 
     | 
| 
      
 23 
     | 
    
         
            +
            		# configure how hash children will be read
         
     | 
| 
      
 24 
     | 
    
         
            +
            		# @param params [Array] the params to configure
         
     | 
| 
      
 25 
     | 
    
         
            +
            		# @return [void]
         
     | 
| 
       17 
26 
     | 
    
         
             
            		def configure(params)
         
     | 
| 
       18 
     | 
    
         
            -
            			result =  
     | 
| 
       19 
     | 
    
         
            -
            			@ 
     | 
| 
       20 
     | 
    
         
            -
             
     | 
| 
      
 27 
     | 
    
         
            +
            			result = @children = {}
         
     | 
| 
      
 28 
     | 
    
         
            +
            			@key_value = false
         
     | 
| 
       21 
29 
     | 
    
         
             
            			log.debug("configuring hash children")
         
     | 
| 
       22 
30 
     | 
    
         | 
| 
       23 
     | 
    
         
            -
            			 
     | 
| 
      
 31 
     | 
    
         
            +
            			if params.length == 1 && params.first.length == 1 && params.first.first.is_a?(Hash)
         
     | 
| 
      
 32 
     | 
    
         
            +
            				@key_value = true
         
     | 
| 
      
 33 
     | 
    
         
            +
            				log.debug("configuring hash children with {key => value} notation")
         
     | 
| 
      
 34 
     | 
    
         
            +
            				params = params.first.first
         
     | 
| 
      
 35 
     | 
    
         
            +
             
     | 
| 
      
 36 
     | 
    
         
            +
            				if params.length != 1
         
     | 
| 
      
 37 
     | 
    
         
            +
            					raise "expected only one key in the {key => value} notation, got #{params.length} for #{params.inspect}"
         
     | 
| 
      
 38 
     | 
    
         
            +
            				end
         
     | 
| 
      
 39 
     | 
    
         
            +
             
     | 
| 
      
 40 
     | 
    
         
            +
            				key = params.keys.first
         
     | 
| 
      
 41 
     | 
    
         
            +
            				value = params.values.first
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            				if key.nil?
         
     | 
| 
      
 44 
     | 
    
         
            +
            					raise "schema for key is missing"
         
     | 
| 
      
 45 
     | 
    
         
            +
            				end
         
     | 
| 
      
 46 
     | 
    
         
            +
             
     | 
| 
      
 47 
     | 
    
         
            +
            				if value.nil?
         
     | 
| 
      
 48 
     | 
    
         
            +
            					raise "schema for value is missing"
         
     | 
| 
      
 49 
     | 
    
         
            +
            				end
         
     | 
| 
      
 50 
     | 
    
         
            +
             
     | 
| 
      
 51 
     | 
    
         
            +
            				key_node = Scanner.scan(Array(key), type_registry)
         
     | 
| 
      
 52 
     | 
    
         
            +
            				value_node = Scanner.scan(Array(value), type_registry)
         
     | 
| 
      
 53 
     | 
    
         
            +
             
     | 
| 
      
 54 
     | 
    
         
            +
            				result[:key] = type_registry.type(
         
     | 
| 
      
 55 
     | 
    
         
            +
            					key_node.type,
         
     | 
| 
      
 56 
     | 
    
         
            +
            					args: key_node.args,
         
     | 
| 
      
 57 
     | 
    
         
            +
            					params: key_node.params,
         
     | 
| 
      
 58 
     | 
    
         
            +
            				)
         
     | 
| 
      
 59 
     | 
    
         
            +
             
     | 
| 
      
 60 
     | 
    
         
            +
            				result[:value] = type_registry.type(
         
     | 
| 
      
 61 
     | 
    
         
            +
            					value_node.type,
         
     | 
| 
      
 62 
     | 
    
         
            +
            					args: value_node.args,
         
     | 
| 
      
 63 
     | 
    
         
            +
            					params: value_node.params,
         
     | 
| 
      
 64 
     | 
    
         
            +
            				)
         
     | 
| 
      
 65 
     | 
    
         
            +
             
     | 
| 
      
 66 
     | 
    
         
            +
            				return
         
     | 
| 
      
 67 
     | 
    
         
            +
            			end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            			log.debug("configuring hash children with array notation")
         
     | 
| 
      
 70 
     | 
    
         
            +
            			for child in params
         
     | 
| 
       24 
71 
     | 
    
         
             
            				name, *schema = child
         
     | 
| 
       25 
72 
     | 
    
         
             
            				if !name.is_a?(Symbol)
         
     | 
| 
       26 
73 
     | 
    
         
             
            					raise "expected name as a symbol for the first element of child schemas, got #{name.inspect} for #{child.inspect}"
         
     | 
| 
         @@ -31,13 +78,14 @@ module DataModel 
     | 
|
| 
       31 
78 
     | 
    
         
             
            				end
         
     | 
| 
       32 
79 
     | 
    
         | 
| 
       33 
80 
     | 
    
         
             
            				node = Scanner.scan(schema)
         
     | 
| 
       34 
     | 
    
         
            -
            				log.debug("adding hash child -> #{name}: #{node. 
     | 
| 
      
 81 
     | 
    
         
            +
            				log.debug("adding hash child -> #{name}: #{node.to_h}")
         
     | 
| 
       35 
82 
     | 
    
         | 
| 
       36 
83 
     | 
    
         
             
            				result[name] = instantiate(node.type, args: node.args, params: node.params)
         
     | 
| 
       37 
84 
     | 
    
         
             
            			end
         
     | 
| 
       38 
85 
     | 
    
         
             
            		end
         
     | 
| 
       39 
86 
     | 
    
         | 
| 
       40 
     | 
    
         
            -
            		 
     | 
| 
      
 87 
     | 
    
         
            +
            		# get the children types of this hash
         
     | 
| 
      
 88 
     | 
    
         
            +
            		# @return [Hash] the children types of this hash
         
     | 
| 
       41 
89 
     | 
    
         
             
            		def children
         
     | 
| 
       42 
90 
     | 
    
         
             
            			if @children.nil?
         
     | 
| 
       43 
91 
     | 
    
         
             
            				raise "children not configured"
         
     | 
| 
         @@ -48,7 +96,10 @@ module DataModel 
     | 
|
| 
       48 
96 
     | 
    
         | 
| 
       49 
97 
     | 
    
         
             
            		## Read
         
     | 
| 
       50 
98 
     | 
    
         | 
| 
       51 
     | 
    
         
            -
            		 
     | 
| 
      
 99 
     | 
    
         
            +
            		# read a value, and validate it
         
     | 
| 
      
 100 
     | 
    
         
            +
            		# @param val [Object] the value to read
         
     | 
| 
      
 101 
     | 
    
         
            +
            		# @param coerce [Boolean] whether to coerce the value
         
     | 
| 
      
 102 
     | 
    
         
            +
            		# @return [Array(Object, Error)] the result of reading the value
         
     | 
| 
       52 
103 
     | 
    
         
             
            		def read(val, coerce: false)
         
     | 
| 
       53 
104 
     | 
    
         
             
            			args = Arguments.new(type_args)
         
     | 
| 
       54 
105 
     | 
    
         
             
            			errors = Error.new
         
     | 
| 
         @@ -59,34 +110,32 @@ module DataModel 
     | 
|
| 
       59 
110 
     | 
    
         
             
            			end
         
     | 
| 
       60 
111 
     | 
    
         | 
| 
       61 
112 
     | 
    
         
             
            			if !args.optional && val.nil?
         
     | 
| 
       62 
     | 
    
         
            -
            				errors.add(missing_error( 
     | 
| 
      
 113 
     | 
    
         
            +
            				errors.add(missing_error(type_name))
         
     | 
| 
       63 
114 
     | 
    
         
             
            				return [val, errors]
         
     | 
| 
       64 
115 
     | 
    
         
             
            			end
         
     | 
| 
       65 
116 
     | 
    
         | 
| 
       66 
117 
     | 
    
         
             
            			# type error, early exit
         
     | 
| 
       67 
118 
     | 
    
         
             
            			if !val.is_a?(Hash) && !coerce
         
     | 
| 
       68 
     | 
    
         
            -
            				errors.add(type_error( 
     | 
| 
      
 119 
     | 
    
         
            +
            				errors.add(type_error(type_name, val))
         
     | 
| 
       69 
120 
     | 
    
         
             
            				return [val, errors]
         
     | 
| 
       70 
121 
     | 
    
         
             
            			end
         
     | 
| 
       71 
122 
     | 
    
         | 
| 
       72 
123 
     | 
    
         
             
            			# attempt coercion
         
     | 
| 
       73 
124 
     | 
    
         
             
            			if !val.is_a?(Hash) && coerce
         
     | 
| 
       74 
125 
     | 
    
         
             
            				if val.respond_to?(:to_h)
         
     | 
| 
       75 
     | 
    
         
            -
            					val =  
     | 
| 
      
 126 
     | 
    
         
            +
            					val = val.to_h
         
     | 
| 
       76 
127 
     | 
    
         
             
            				elsif val.respond_to?(:to_hash)
         
     | 
| 
       77 
128 
     | 
    
         
             
            					val = Hash(val)
         
     | 
| 
       78 
129 
     | 
    
         
             
            				else
         
     | 
| 
       79 
     | 
    
         
            -
            					errors.add(coerce_error( 
     | 
| 
      
 130 
     | 
    
         
            +
            					errors.add(coerce_error(type_name, val))
         
     | 
| 
       80 
131 
     | 
    
         
             
            					return [val, errors]
         
     | 
| 
       81 
132 
     | 
    
         
             
            				end
         
     | 
| 
       82 
133 
     | 
    
         
             
            			end
         
     | 
| 
       83 
134 
     | 
    
         | 
| 
       84 
     | 
    
         
            -
            			hash = T.cast(val, T::Hash[Symbol, Object])
         
     | 
| 
       85 
     | 
    
         
            -
             
     | 
| 
       86 
135 
     | 
    
         
             
            			# detect extra keys then what is defined in the schema
         
     | 
| 
       87 
136 
     | 
    
         
             
            			if !args.open
         
     | 
| 
       88 
137 
     | 
    
         
             
            				keys = children.keys
         
     | 
| 
       89 
     | 
    
         
            -
            				extra =  
     | 
| 
      
 138 
     | 
    
         
            +
            				extra = val.keys - keys
         
     | 
| 
       90 
139 
     | 
    
         | 
| 
       91 
140 
     | 
    
         
             
            				if !extra.empty?
         
     | 
| 
       92 
141 
     | 
    
         
             
            					errors.add(extra_keys_error(extra))
         
     | 
| 
         @@ -95,23 +144,39 @@ module DataModel 
     | 
|
| 
       95 
144 
     | 
    
         
             
            			end
         
     | 
| 
       96 
145 
     | 
    
         | 
| 
       97 
146 
     | 
    
         
             
            			# process children
         
     | 
| 
       98 
     | 
    
         
            -
            			 
     | 
| 
       99 
     | 
    
         
            -
             
     | 
| 
       100 
     | 
    
         
            -
            				 
     | 
| 
       101 
     | 
    
         
            -
            				 
     | 
| 
       102 
     | 
    
         
            -
             
     | 
| 
       103 
     | 
    
         
            -
            				 
     | 
| 
       104 
     | 
    
         
            -
            					log.debug(" 
     | 
| 
       105 
     | 
    
         
            -
            					 
     | 
| 
      
 147 
     | 
    
         
            +
            			if @key_value
         
     | 
| 
      
 148 
     | 
    
         
            +
            				log.debug("processing hash children with {key => value} notation")
         
     | 
| 
      
 149 
     | 
    
         
            +
            				key = children[:key]
         
     | 
| 
      
 150 
     | 
    
         
            +
            				value = children[:value]
         
     | 
| 
      
 151 
     | 
    
         
            +
             
     | 
| 
      
 152 
     | 
    
         
            +
            				for (k, v) in val.dup
         
     | 
| 
      
 153 
     | 
    
         
            +
            					log.debug("processing #{k} -> #{v.inspect}")
         
     | 
| 
      
 154 
     | 
    
         
            +
            					k, key_errors = key.read(k, coerce:)
         
     | 
| 
      
 155 
     | 
    
         
            +
            					v, value_errors = value.read(v, coerce:)
         
     | 
| 
      
 156 
     | 
    
         
            +
             
     | 
| 
      
 157 
     | 
    
         
            +
            					if !key_errors.any? && !value_errors.any?
         
     | 
| 
      
 158 
     | 
    
         
            +
            						log.debug("no errors")
         
     | 
| 
      
 159 
     | 
    
         
            +
            						val[k] = v
         
     | 
| 
      
 160 
     | 
    
         
            +
            					end
         
     | 
| 
      
 161 
     | 
    
         
            +
             
     | 
| 
      
 162 
     | 
    
         
            +
            					errors.merge_child(k, key_errors)
         
     | 
| 
      
 163 
     | 
    
         
            +
            					errors.merge_child(k, value_errors)
         
     | 
| 
      
 164 
     | 
    
         
            +
            				end
         
     | 
| 
      
 165 
     | 
    
         
            +
            			else
         
     | 
| 
      
 166 
     | 
    
         
            +
            				log.debug("processing hash children with array notation")
         
     | 
| 
      
 167 
     | 
    
         
            +
            				for (name, child) in children
         
     | 
| 
      
 168 
     | 
    
         
            +
            					val[name], child_errors = child.read(val[name], coerce:)
         
     | 
| 
      
 169 
     | 
    
         
            +
            					log.debug("child #{name} -> #{val[name].inspect} #{child_errors.inspect}")
         
     | 
| 
      
 170 
     | 
    
         
            +
             
     | 
| 
      
 171 
     | 
    
         
            +
            					if !child_errors.any?
         
     | 
| 
      
 172 
     | 
    
         
            +
            						log.debug("no errors, skipping")
         
     | 
| 
      
 173 
     | 
    
         
            +
            						next
         
     | 
| 
      
 174 
     | 
    
         
            +
            					end
         
     | 
| 
      
 175 
     | 
    
         
            +
             
     | 
| 
      
 176 
     | 
    
         
            +
            					errors.merge_child(name, child_errors)
         
     | 
| 
       106 
177 
     | 
    
         
             
            				end
         
     | 
| 
       107 
     | 
    
         
            -
             
     | 
| 
       108 
     | 
    
         
            -
            				errors.merge_child(name, child_errors)
         
     | 
| 
       109 
     | 
    
         
            -
             
     | 
| 
       110 
     | 
    
         
            -
            				return [val, errors]
         
     | 
| 
       111 
178 
     | 
    
         
             
            			end
         
     | 
| 
       112 
179 
     | 
    
         | 
| 
       113 
     | 
    
         
            -
            			log.debug("hash check successful")
         
     | 
| 
       114 
     | 
    
         
            -
             
     | 
| 
       115 
180 
     | 
    
         
             
            			# done
         
     | 
| 
       116 
181 
     | 
    
         
             
            			return [val, errors]
         
     | 
| 
       117 
182 
     | 
    
         
             
            		end
         
     | 
| 
         @@ -1,16 +1,19 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# Integer type
         
     | 
| 
       4 
3 
     | 
    
         
             
            	class Builtin::Integer < Type
         
     | 
| 
       5 
4 
     | 
    
         
             
            		include Errors
         
     | 
| 
       6 
5 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
            		 
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
            			prop : 
     | 
| 
       10 
     | 
    
         
            -
            			prop : 
     | 
| 
      
 6 
     | 
    
         
            +
            		# Arguments for Array type.
         
     | 
| 
      
 7 
     | 
    
         
            +
            		class Arguments < Struct
         
     | 
| 
      
 8 
     | 
    
         
            +
            			prop :optional, :boolean, default: false
         
     | 
| 
      
 9 
     | 
    
         
            +
            			prop :min, :numeric, default: nil
         
     | 
| 
      
 10 
     | 
    
         
            +
            			prop :max, :numeric, default: nil
         
     | 
| 
       11 
11 
     | 
    
         
             
            		end
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
            		 
     | 
| 
      
 13 
     | 
    
         
            +
            		# read a value, and validate it
         
     | 
| 
      
 14 
     | 
    
         
            +
            		# @param val [Object] the value to read
         
     | 
| 
      
 15 
     | 
    
         
            +
            		# @param coerce [Boolean] whether to coerce the value
         
     | 
| 
      
 16 
     | 
    
         
            +
            		# @return [Array(Object, Error)] the result of reading the value
         
     | 
| 
       14 
17 
     | 
    
         
             
            		def read(val, coerce: false)
         
     | 
| 
       15 
18 
     | 
    
         
             
            			err = Error.new
         
     | 
| 
       16 
19 
     | 
    
         
             
            			args = Arguments.new(type_args)
         
     | 
| 
         @@ -20,12 +23,12 @@ module DataModel 
     | 
|
| 
       20 
23 
     | 
    
         
             
            			end
         
     | 
| 
       21 
24 
     | 
    
         | 
| 
       22 
25 
     | 
    
         
             
            			if !args.optional && val.nil?
         
     | 
| 
       23 
     | 
    
         
            -
            				err.add(missing_error( 
     | 
| 
      
 26 
     | 
    
         
            +
            				err.add(missing_error(type_name))
         
     | 
| 
       24 
27 
     | 
    
         
             
            				return [val, err]
         
     | 
| 
       25 
28 
     | 
    
         
             
            			end
         
     | 
| 
       26 
29 
     | 
    
         | 
| 
       27 
30 
     | 
    
         
             
            			if !val.is_a?(Integer) && !coerce
         
     | 
| 
       28 
     | 
    
         
            -
            				err.add(type_error( 
     | 
| 
      
 31 
     | 
    
         
            +
            				err.add(type_error(type_name, val))
         
     | 
| 
       29 
32 
     | 
    
         
             
            				return [val, err]
         
     | 
| 
       30 
33 
     | 
    
         
             
            			end
         
     | 
| 
       31 
34 
     | 
    
         | 
| 
         @@ -33,17 +36,15 @@ module DataModel 
     | 
|
| 
       33 
36 
     | 
    
         
             
            				if val.is_a?(String) || val.is_a?(Numeric)
         
     | 
| 
       34 
37 
     | 
    
         
             
            					val = Integer(val)
         
     | 
| 
       35 
38 
     | 
    
         
             
            				elsif val.respond_to?(:to_i)
         
     | 
| 
       36 
     | 
    
         
            -
            					val =  
     | 
| 
      
 39 
     | 
    
         
            +
            					val = val.to_i
         
     | 
| 
       37 
40 
     | 
    
         
             
            				end
         
     | 
| 
       38 
41 
     | 
    
         | 
| 
       39 
42 
     | 
    
         
             
            				if !val.is_a?(Integer)
         
     | 
| 
       40 
     | 
    
         
            -
            					err.add(coerce_error( 
     | 
| 
      
 43 
     | 
    
         
            +
            					err.add(coerce_error(type_name, val))
         
     | 
| 
       41 
44 
     | 
    
         
             
            					return [val, err]
         
     | 
| 
       42 
45 
     | 
    
         
             
            				end
         
     | 
| 
       43 
46 
     | 
    
         
             
            			end
         
     | 
| 
       44 
47 
     | 
    
         | 
| 
       45 
     | 
    
         
            -
            			val = T.cast(val, Integer)
         
     | 
| 
       46 
     | 
    
         
            -
             
     | 
| 
       47 
48 
     | 
    
         
             
            			min = args.min
         
     | 
| 
       48 
49 
     | 
    
         
             
            			if min && val <= min
         
     | 
| 
       49 
50 
     | 
    
         
             
            				err.add(min_error(min, val))
         
     | 
| 
         @@ -0,0 +1,35 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# Numeric type is :integer | :float | :decimal
         
     | 
| 
      
 3 
     | 
    
         
            +
            	class Builtin::Numeric < Type
         
     | 
| 
      
 4 
     | 
    
         
            +
            		include Errors
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            		# Arguments for this type
         
     | 
| 
      
 7 
     | 
    
         
            +
            		class Arguments < Struct
         
     | 
| 
      
 8 
     | 
    
         
            +
            			prop :optional, :boolean, default: false
         
     | 
| 
      
 9 
     | 
    
         
            +
            		end
         
     | 
| 
      
 10 
     | 
    
         
            +
             
     | 
| 
      
 11 
     | 
    
         
            +
            		# read a value, and validate it
         
     | 
| 
      
 12 
     | 
    
         
            +
            		# @param val [Object] the value to read
         
     | 
| 
      
 13 
     | 
    
         
            +
            		# @param coerce [Boolean] whether to coerce the value
         
     | 
| 
      
 14 
     | 
    
         
            +
            		# @return [Array(Object, Error)] the result of reading the value
         
     | 
| 
      
 15 
     | 
    
         
            +
            		def read(val, coerce: false)
         
     | 
| 
      
 16 
     | 
    
         
            +
            			args = Arguments.new(type_args)
         
     | 
| 
      
 17 
     | 
    
         
            +
            			err = Error.new
         
     | 
| 
      
 18 
     | 
    
         
            +
             
     | 
| 
      
 19 
     | 
    
         
            +
            			# optional and missing
         
     | 
| 
      
 20 
     | 
    
         
            +
            			if !args.optional && val.nil?
         
     | 
| 
      
 21 
     | 
    
         
            +
            				err.add(missing_error(type_name))
         
     | 
| 
      
 22 
     | 
    
         
            +
            			end
         
     | 
| 
      
 23 
     | 
    
         
            +
             
     | 
| 
      
 24 
     | 
    
         
            +
            			# when missing, return early
         
     | 
| 
      
 25 
     | 
    
         
            +
            			if val.nil?
         
     | 
| 
      
 26 
     | 
    
         
            +
            				return [val, err]
         
     | 
| 
      
 27 
     | 
    
         
            +
            			end
         
     | 
| 
      
 28 
     | 
    
         
            +
             
     | 
| 
      
 29 
     | 
    
         
            +
            			val, err = invoke(:or, val, params: [:integer, :float, :decimal], coerce:)
         
     | 
| 
      
 30 
     | 
    
         
            +
             
     | 
| 
      
 31 
     | 
    
         
            +
            			# done
         
     | 
| 
      
 32 
     | 
    
         
            +
            			return [val, err]
         
     | 
| 
      
 33 
     | 
    
         
            +
            		end
         
     | 
| 
      
 34 
     | 
    
         
            +
            	end
         
     | 
| 
      
 35 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,28 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# acts as any type, the only way to fail validation is if it is nil and not present
         
     | 
| 
      
 3 
     | 
    
         
            +
            	class Builtin::Object < Type
         
     | 
| 
      
 4 
     | 
    
         
            +
            		include Errors
         
     | 
| 
      
 5 
     | 
    
         
            +
             
     | 
| 
      
 6 
     | 
    
         
            +
            		# Object arguments
         
     | 
| 
      
 7 
     | 
    
         
            +
            		class Arguments < Struct
         
     | 
| 
      
 8 
     | 
    
         
            +
            			# @!attribute optional
         
     | 
| 
      
 9 
     | 
    
         
            +
            			# 	@return [Boolean] whether or not this type is optional
         
     | 
| 
      
 10 
     | 
    
         
            +
            			prop :optional, :boolean, default: false
         
     | 
| 
      
 11 
     | 
    
         
            +
            		end
         
     | 
| 
      
 12 
     | 
    
         
            +
             
     | 
| 
      
 13 
     | 
    
         
            +
            		# read a value, and validate it
         
     | 
| 
      
 14 
     | 
    
         
            +
            		# @param val [Object] the value to read
         
     | 
| 
      
 15 
     | 
    
         
            +
            		# @param coerce [Boolean] whether to coerce the value
         
     | 
| 
      
 16 
     | 
    
         
            +
            		# @return [Array(Object, Error)] the result of reading the value
         
     | 
| 
      
 17 
     | 
    
         
            +
            		def read(val, coerce: false)
         
     | 
| 
      
 18 
     | 
    
         
            +
            			args = Arguments.new(type_args)
         
     | 
| 
      
 19 
     | 
    
         
            +
            			err = Error.new
         
     | 
| 
      
 20 
     | 
    
         
            +
             
     | 
| 
      
 21 
     | 
    
         
            +
            			if val.nil? && !args.optional
         
     | 
| 
      
 22 
     | 
    
         
            +
            				err.add(missing_error(type_name))
         
     | 
| 
      
 23 
     | 
    
         
            +
            			end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            			return [val, err]
         
     | 
| 
      
 26 
     | 
    
         
            +
            		end
         
     | 
| 
      
 27 
     | 
    
         
            +
            	end
         
     | 
| 
      
 28 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -0,0 +1,73 @@ 
     | 
|
| 
      
 1 
     | 
    
         
            +
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# Or type, allows for value to be one of several types
         
     | 
| 
      
 3 
     | 
    
         
            +
            	# Types will be tried in order. The first type to succeed will be used.
         
     | 
| 
      
 4 
     | 
    
         
            +
            	# If all types fail, the or type fails
         
     | 
| 
      
 5 
     | 
    
         
            +
            	#
         
     | 
| 
      
 6 
     | 
    
         
            +
            	# @example
         
     | 
| 
      
 7 
     | 
    
         
            +
            	#   [:or, :string, [:array, :string]]
         
     | 
| 
      
 8 
     | 
    
         
            +
            	class Builtin::Or < Type
         
     | 
| 
      
 9 
     | 
    
         
            +
            		include Errors
         
     | 
| 
      
 10 
     | 
    
         
            +
            		include Logging
         
     | 
| 
      
 11 
     | 
    
         
            +
             
     | 
| 
      
 12 
     | 
    
         
            +
            		# Arguments for this type
         
     | 
| 
      
 13 
     | 
    
         
            +
            		class Arguments < Struct
         
     | 
| 
      
 14 
     | 
    
         
            +
            			prop :optional, :boolean, default: false
         
     | 
| 
      
 15 
     | 
    
         
            +
            		end
         
     | 
| 
      
 16 
     | 
    
         
            +
             
     | 
| 
      
 17 
     | 
    
         
            +
            		# support either :string shorthand or [:string, {optional: true}]
         
     | 
| 
      
 18 
     | 
    
         
            +
            		# @param params [Array<untyped>] the params to configure this type
         
     | 
| 
      
 19 
     | 
    
         
            +
            		# @return [void]
         
     | 
| 
      
 20 
     | 
    
         
            +
            		def configure(params)
         
     | 
| 
      
 21 
     | 
    
         
            +
            			if params.first.is_a?(Array)
         
     | 
| 
      
 22 
     | 
    
         
            +
            				params = params.first
         
     | 
| 
      
 23 
     | 
    
         
            +
            			end
         
     | 
| 
      
 24 
     | 
    
         
            +
             
     | 
| 
      
 25 
     | 
    
         
            +
            			@child_types = []
         
     | 
| 
      
 26 
     | 
    
         
            +
             
     | 
| 
      
 27 
     | 
    
         
            +
            			nodes = params.map { |p| Scanner.scan(Array(p)) }
         
     | 
| 
      
 28 
     | 
    
         
            +
            			for node in nodes
         
     | 
| 
      
 29 
     | 
    
         
            +
            				type = instantiate(node.type, args: node.args, params: node.params)
         
     | 
| 
      
 30 
     | 
    
         
            +
            				@child_types << type
         
     | 
| 
      
 31 
     | 
    
         
            +
            			end
         
     | 
| 
      
 32 
     | 
    
         
            +
            		end
         
     | 
| 
      
 33 
     | 
    
         
            +
             
     | 
| 
      
 34 
     | 
    
         
            +
            		# read a value, and validate it
         
     | 
| 
      
 35 
     | 
    
         
            +
            		# @param val [Object] the value to read
         
     | 
| 
      
 36 
     | 
    
         
            +
            		# @param coerce [Boolean] whether to coerce the value
         
     | 
| 
      
 37 
     | 
    
         
            +
            		# @return [Array(Object, Error)] the result of reading the value
         
     | 
| 
      
 38 
     | 
    
         
            +
            		def read(val, coerce: false)
         
     | 
| 
      
 39 
     | 
    
         
            +
            			args = Arguments.new(type_args)
         
     | 
| 
      
 40 
     | 
    
         
            +
            			err = Error.new
         
     | 
| 
      
 41 
     | 
    
         
            +
            			child_names = @child_types.map(&:type_name)
         
     | 
| 
      
 42 
     | 
    
         
            +
             
     | 
| 
      
 43 
     | 
    
         
            +
            			log.debug("coerce: #{coerce} or type #{child_names} with value #{val}")
         
     | 
| 
      
 44 
     | 
    
         
            +
             
     | 
| 
      
 45 
     | 
    
         
            +
            			# optional and missing
         
     | 
| 
      
 46 
     | 
    
         
            +
            			if !args.optional && val.nil?
         
     | 
| 
      
 47 
     | 
    
         
            +
            				err.add(missing_error(child_names))
         
     | 
| 
      
 48 
     | 
    
         
            +
            			end
         
     | 
| 
      
 49 
     | 
    
         
            +
             
     | 
| 
      
 50 
     | 
    
         
            +
            			# when missing, return early
         
     | 
| 
      
 51 
     | 
    
         
            +
            			if val.nil?
         
     | 
| 
      
 52 
     | 
    
         
            +
            				return [val, err]
         
     | 
| 
      
 53 
     | 
    
         
            +
            			end
         
     | 
| 
      
 54 
     | 
    
         
            +
             
     | 
| 
      
 55 
     | 
    
         
            +
            			valid = false
         
     | 
| 
      
 56 
     | 
    
         
            +
             
     | 
| 
      
 57 
     | 
    
         
            +
            			for type in @child_types
         
     | 
| 
      
 58 
     | 
    
         
            +
            				val, err = type.read(val, coerce: coerce)
         
     | 
| 
      
 59 
     | 
    
         
            +
            				if err.empty?
         
     | 
| 
      
 60 
     | 
    
         
            +
            					valid = true
         
     | 
| 
      
 61 
     | 
    
         
            +
            					break
         
     | 
| 
      
 62 
     | 
    
         
            +
            				end
         
     | 
| 
      
 63 
     | 
    
         
            +
            			end
         
     | 
| 
      
 64 
     | 
    
         
            +
             
     | 
| 
      
 65 
     | 
    
         
            +
            			if !valid
         
     | 
| 
      
 66 
     | 
    
         
            +
            				err.add(type_error(child_names, val))
         
     | 
| 
      
 67 
     | 
    
         
            +
            			end
         
     | 
| 
      
 68 
     | 
    
         
            +
             
     | 
| 
      
 69 
     | 
    
         
            +
            			# done
         
     | 
| 
      
 70 
     | 
    
         
            +
            			return [val, err]
         
     | 
| 
      
 71 
     | 
    
         
            +
            		end
         
     | 
| 
      
 72 
     | 
    
         
            +
            	end
         
     | 
| 
      
 73 
     | 
    
         
            +
            end
         
     | 
| 
         @@ -1,20 +1,21 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# Built-in type for String
         
     | 
| 
       4 
3 
     | 
    
         
             
            	class Builtin::String < Type
         
     | 
| 
       5 
4 
     | 
    
         
             
            		include Errors
         
     | 
| 
       6 
5 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
            		 
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
             
     | 
| 
       10 
     | 
    
         
            -
            			prop : 
     | 
| 
       11 
     | 
    
         
            -
            			prop : 
     | 
| 
       12 
     | 
    
         
            -
            			prop : 
     | 
| 
       13 
     | 
    
         
            -
            			prop : 
     | 
| 
       14 
     | 
    
         
            -
            			prop :excluded, T::Array[String], default: []
         
     | 
| 
      
 6 
     | 
    
         
            +
            		# Arguments for this type
         
     | 
| 
      
 7 
     | 
    
         
            +
            		class Arguments < Struct
         
     | 
| 
      
 8 
     | 
    
         
            +
            			prop :optional, :boolean, default: false
         
     | 
| 
      
 9 
     | 
    
         
            +
            			prop :allow_blank, :boolean, default: true
         
     | 
| 
      
 10 
     | 
    
         
            +
            			prop :format, :string, default: nil
         
     | 
| 
      
 11 
     | 
    
         
            +
            			prop :included, [:array, :string], default: []
         
     | 
| 
      
 12 
     | 
    
         
            +
            			prop :excluded, [:array, :string], default: []
         
     | 
| 
       15 
13 
     | 
    
         
             
            		end
         
     | 
| 
       16 
14 
     | 
    
         | 
| 
       17 
     | 
    
         
            -
            		 
     | 
| 
      
 15 
     | 
    
         
            +
            		# read a value, and validate it
         
     | 
| 
      
 16 
     | 
    
         
            +
            		# @param val [Object] the value to read
         
     | 
| 
      
 17 
     | 
    
         
            +
            		# @param coerce [Boolean] whether to coerce the value
         
     | 
| 
      
 18 
     | 
    
         
            +
            		# @return [Array(Object, Error)] the result of reading the value
         
     | 
| 
       18 
19 
     | 
    
         
             
            		def read(val, coerce: false)
         
     | 
| 
       19 
20 
     | 
    
         
             
            			args = Arguments.new(type_args)
         
     | 
| 
       20 
21 
     | 
    
         
             
            			err = Error.new
         
     | 
| 
         @@ -25,13 +26,13 @@ module DataModel 
     | 
|
| 
       25 
26 
     | 
    
         
             
            			end
         
     | 
| 
       26 
27 
     | 
    
         | 
| 
       27 
28 
     | 
    
         
             
            			if !args.optional && val.nil?
         
     | 
| 
       28 
     | 
    
         
            -
            				err.add(missing_error( 
     | 
| 
      
 29 
     | 
    
         
            +
            				err.add(missing_error(type_name))
         
     | 
| 
       29 
30 
     | 
    
         
             
            				return [val, err]
         
     | 
| 
       30 
31 
     | 
    
         
             
            			end
         
     | 
| 
       31 
32 
     | 
    
         | 
| 
       32 
33 
     | 
    
         
             
            			# type error
         
     | 
| 
       33 
34 
     | 
    
         
             
            			if !val.is_a?(String) && !coerce
         
     | 
| 
       34 
     | 
    
         
            -
            				err.add(type_error( 
     | 
| 
      
 35 
     | 
    
         
            +
            				err.add(type_error(type_name, val))
         
     | 
| 
       35 
36 
     | 
    
         
             
            				return [val, err]
         
     | 
| 
       36 
37 
     | 
    
         
             
            			end
         
     | 
| 
       37 
38 
     | 
    
         | 
| 
         @@ -40,13 +41,11 @@ module DataModel 
     | 
|
| 
       40 
41 
     | 
    
         
             
            				begin
         
     | 
| 
       41 
42 
     | 
    
         
             
            					val = String(val)
         
     | 
| 
       42 
43 
     | 
    
         
             
            				rescue TypeError
         
     | 
| 
       43 
     | 
    
         
            -
            					err.add(coerce_error( 
     | 
| 
      
 44 
     | 
    
         
            +
            					err.add(coerce_error(type_name, val))
         
     | 
| 
       44 
45 
     | 
    
         
             
            					return [val, err]
         
     | 
| 
       45 
46 
     | 
    
         
             
            				end
         
     | 
| 
       46 
47 
     | 
    
         
             
            			end
         
     | 
| 
       47 
48 
     | 
    
         | 
| 
       48 
     | 
    
         
            -
            			val = T.cast(val, String)
         
     | 
| 
       49 
     | 
    
         
            -
             
     | 
| 
       50 
49 
     | 
    
         
             
            			# format
         
     | 
| 
       51 
50 
     | 
    
         
             
            			fmt = args.format
         
     | 
| 
       52 
51 
     | 
    
         
             
            			if fmt
         
     | 
| 
         @@ -1,16 +1,19 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# Symbol type
         
     | 
| 
       4 
3 
     | 
    
         
             
            	class Builtin::Symbol < Type
         
     | 
| 
       5 
4 
     | 
    
         
             
            		include Errors
         
     | 
| 
       6 
5 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
            		 
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
            			prop : 
     | 
| 
       10 
     | 
    
         
            -
            			prop : 
     | 
| 
      
 6 
     | 
    
         
            +
            		# Arguments for this type
         
     | 
| 
      
 7 
     | 
    
         
            +
            		class Arguments < Struct
         
     | 
| 
      
 8 
     | 
    
         
            +
            			prop :optional, :boolean, default: false
         
     | 
| 
      
 9 
     | 
    
         
            +
            			prop :included, [:array, :symbol], default: []
         
     | 
| 
      
 10 
     | 
    
         
            +
            			prop :excluded, [:array, :symbol], default: []
         
     | 
| 
       11 
11 
     | 
    
         
             
            		end
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
            		 
     | 
| 
      
 13 
     | 
    
         
            +
            		# read a value, and validate it
         
     | 
| 
      
 14 
     | 
    
         
            +
            		# @param val [Object] the value to read
         
     | 
| 
      
 15 
     | 
    
         
            +
            		# @param coerce [Boolean] whether to coerce the value
         
     | 
| 
      
 16 
     | 
    
         
            +
            		# @return [Array(Object, Error)] the result of reading the value
         
     | 
| 
       14 
17 
     | 
    
         
             
            		def read(val, coerce: false)
         
     | 
| 
       15 
18 
     | 
    
         
             
            			args = Arguments.new(type_args)
         
     | 
| 
       16 
19 
     | 
    
         
             
            			err = Error.new
         
     | 
| 
         @@ -21,13 +24,13 @@ module DataModel 
     | 
|
| 
       21 
24 
     | 
    
         
             
            			end
         
     | 
| 
       22 
25 
     | 
    
         | 
| 
       23 
26 
     | 
    
         
             
            			if !args.optional && val.nil?
         
     | 
| 
       24 
     | 
    
         
            -
            				err.add(missing_error( 
     | 
| 
      
 27 
     | 
    
         
            +
            				err.add(missing_error(type_name))
         
     | 
| 
       25 
28 
     | 
    
         
             
            				return [val, err]
         
     | 
| 
       26 
29 
     | 
    
         
             
            			end
         
     | 
| 
       27 
30 
     | 
    
         | 
| 
       28 
31 
     | 
    
         
             
            			# type error
         
     | 
| 
       29 
32 
     | 
    
         
             
            			if !val.is_a?(Symbol) && !coerce
         
     | 
| 
       30 
     | 
    
         
            -
            				err.add(type_error( 
     | 
| 
      
 33 
     | 
    
         
            +
            				err.add(type_error(type_name, val))
         
     | 
| 
       31 
34 
     | 
    
         
             
            				return [val, err]
         
     | 
| 
       32 
35 
     | 
    
         
             
            			end
         
     | 
| 
       33 
36 
     | 
    
         | 
| 
         @@ -36,15 +39,13 @@ module DataModel 
     | 
|
| 
       36 
39 
     | 
    
         
             
            				if val.is_a?(String)
         
     | 
| 
       37 
40 
     | 
    
         
             
            					val = val.intern
         
     | 
| 
       38 
41 
     | 
    
         
             
            				elsif val.respond_to?(:to_sym)
         
     | 
| 
       39 
     | 
    
         
            -
            					val =  
     | 
| 
      
 42 
     | 
    
         
            +
            					val = val.to_sym
         
     | 
| 
       40 
43 
     | 
    
         
             
            				else
         
     | 
| 
       41 
     | 
    
         
            -
            					err.add(coerce_error( 
     | 
| 
      
 44 
     | 
    
         
            +
            					err.add(coerce_error(type_name, val))
         
     | 
| 
       42 
45 
     | 
    
         
             
            					return [val, err]
         
     | 
| 
       43 
46 
     | 
    
         
             
            				end
         
     | 
| 
       44 
47 
     | 
    
         
             
            			end
         
     | 
| 
       45 
48 
     | 
    
         | 
| 
       46 
     | 
    
         
            -
            			val = T.cast(val, Symbol)
         
     | 
| 
       47 
     | 
    
         
            -
             
     | 
| 
       48 
49 
     | 
    
         
             
            			# inclusion
         
     | 
| 
       49 
50 
     | 
    
         
             
            			if args.included.any? && !args.included.include?(val)
         
     | 
| 
       50 
51 
     | 
    
         
             
            				err.add(inclusion_error(args.included))
         
     | 
| 
         @@ -1,16 +1,19 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
      
 2 
     | 
    
         
            +
            	# A time type
         
     | 
| 
       4 
3 
     | 
    
         
             
            	class Builtin::Time < Type
         
     | 
| 
       5 
4 
     | 
    
         
             
            		include Errors
         
     | 
| 
       6 
5 
     | 
    
         | 
| 
       7 
     | 
    
         
            -
            		 
     | 
| 
       8 
     | 
    
         
            -
             
     | 
| 
       9 
     | 
    
         
            -
            			prop : 
     | 
| 
       10 
     | 
    
         
            -
            			prop : 
     | 
| 
      
 6 
     | 
    
         
            +
            		# Arguments for this type
         
     | 
| 
      
 7 
     | 
    
         
            +
            		class Arguments < Struct
         
     | 
| 
      
 8 
     | 
    
         
            +
            			prop :optional, :boolean, default: false
         
     | 
| 
      
 9 
     | 
    
         
            +
            			prop :earliest, [:time, { optional: true }], default: nil
         
     | 
| 
      
 10 
     | 
    
         
            +
            			prop :latest, [:time, { optional: true }], default: nil
         
     | 
| 
       11 
11 
     | 
    
         
             
            		end
         
     | 
| 
       12 
12 
     | 
    
         | 
| 
       13 
     | 
    
         
            -
            		 
     | 
| 
      
 13 
     | 
    
         
            +
            		# read a value, and validate it
         
     | 
| 
      
 14 
     | 
    
         
            +
            		# @param val [Object] the value to read
         
     | 
| 
      
 15 
     | 
    
         
            +
            		# @param coerce [Boolean] whether to coerce the value
         
     | 
| 
      
 16 
     | 
    
         
            +
            		# @return [Array(Object, Error)] the result of reading the value
         
     | 
| 
       14 
17 
     | 
    
         
             
            		def read(val, coerce: false)
         
     | 
| 
       15 
18 
     | 
    
         
             
            			args = Arguments.new(type_args)
         
     | 
| 
       16 
19 
     | 
    
         
             
            			err = Error.new
         
     | 
| 
         @@ -22,7 +25,7 @@ module DataModel 
     | 
|
| 
       22 
25 
     | 
    
         | 
| 
       23 
26 
     | 
    
         
             
            			# missing, but not allowed, don't do any more checks
         
     | 
| 
       24 
27 
     | 
    
         
             
            			if val.nil?
         
     | 
| 
       25 
     | 
    
         
            -
            				err.add(missing_error( 
     | 
| 
      
 28 
     | 
    
         
            +
            				err.add(missing_error(type_name))
         
     | 
| 
       26 
29 
     | 
    
         
             
            				return [val, err]
         
     | 
| 
       27 
30 
     | 
    
         
             
            			end
         
     | 
| 
       28 
31 
     | 
    
         | 
| 
         @@ -31,26 +34,26 @@ module DataModel 
     | 
|
| 
       31 
34 
     | 
    
         
             
            				begin
         
     | 
| 
       32 
35 
     | 
    
         
             
            					val = Time.parse(val)
         
     | 
| 
       33 
36 
     | 
    
         
             
            				rescue ArgumentError
         
     | 
| 
       34 
     | 
    
         
            -
            					err.add(type_error( 
     | 
| 
      
 37 
     | 
    
         
            +
            					err.add(type_error(type_name, val))
         
     | 
| 
       35 
38 
     | 
    
         
             
            					return [val, err]
         
     | 
| 
       36 
39 
     | 
    
         
             
            				end
         
     | 
| 
       37 
40 
     | 
    
         
             
            			end
         
     | 
| 
       38 
41 
     | 
    
         | 
| 
       39 
42 
     | 
    
         
             
            			# not a date, don't do any more checks
         
     | 
| 
       40 
43 
     | 
    
         
             
            			if !val.is_a?(Time)
         
     | 
| 
       41 
     | 
    
         
            -
            				err.add(type_error( 
     | 
| 
      
 44 
     | 
    
         
            +
            				err.add(type_error(type_name, val))
         
     | 
| 
       42 
45 
     | 
    
         
             
            				return [val, err]
         
     | 
| 
       43 
46 
     | 
    
         
             
            			end
         
     | 
| 
       44 
47 
     | 
    
         | 
| 
       45 
48 
     | 
    
         
             
            			# date is before the earliest point allowed
         
     | 
| 
       46 
     | 
    
         
            -
            			if args.earliest && (val <  
     | 
| 
       47 
     | 
    
         
            -
            				error = earliest_error( 
     | 
| 
      
 49 
     | 
    
         
            +
            			if args.earliest && (val < args.earliest)
         
     | 
| 
      
 50 
     | 
    
         
            +
            				error = earliest_error(args.earliest, val)
         
     | 
| 
       48 
51 
     | 
    
         
             
            				err.add(error)
         
     | 
| 
       49 
52 
     | 
    
         
             
            			end
         
     | 
| 
       50 
53 
     | 
    
         | 
| 
       51 
54 
     | 
    
         
             
            			# date is after the latest point allowed
         
     | 
| 
       52 
     | 
    
         
            -
            			if args.latest && (val >  
     | 
| 
       53 
     | 
    
         
            -
            				error = latest_error( 
     | 
| 
      
 55 
     | 
    
         
            +
            			if args.latest && (val > args.latest)
         
     | 
| 
      
 56 
     | 
    
         
            +
            				error = latest_error(args.latest, val)
         
     | 
| 
       54 
57 
     | 
    
         
             
            				err.add(error)
         
     | 
| 
       55 
58 
     | 
    
         
             
            			end
         
     | 
| 
       56 
59 
     | 
    
         | 
    
        data/lib/data_model/builtin.rb
    CHANGED
    
    | 
         @@ -1,22 +1,22 @@ 
     | 
|
| 
       1 
     | 
    
         
            -
            # typed: strict
         
     | 
| 
       2 
     | 
    
         
            -
             
     | 
| 
       3 
1 
     | 
    
         
             
            module DataModel
         
     | 
| 
       4 
2 
     | 
    
         
             
            	module Builtin
         
     | 
| 
       5 
     | 
    
         
            -
            		 
     | 
| 
       6 
     | 
    
         
            -
             
     | 
| 
       7 
     | 
    
         
            -
            		sig { returns(TTypeMap) }
         
     | 
| 
      
 3 
     | 
    
         
            +
            		# Hash of all builtin types, useful when instanciating a Registry
         
     | 
| 
      
 4 
     | 
    
         
            +
            		# @return [Hash{Symbol => Type}] the builtin types
         
     | 
| 
       8 
5 
     | 
    
         
             
            		def self.types
         
     | 
| 
       9 
6 
     | 
    
         
             
            			{
         
     | 
| 
       10 
7 
     | 
    
         
             
            				hash: Builtin::Hash,
         
     | 
| 
      
 8 
     | 
    
         
            +
            				array: Builtin::Array,
         
     | 
| 
      
 9 
     | 
    
         
            +
            				or: Builtin::Or,
         
     | 
| 
      
 10 
     | 
    
         
            +
            				object: Builtin::Object,
         
     | 
| 
      
 11 
     | 
    
         
            +
            				boolean: Builtin::Boolean,
         
     | 
| 
      
 12 
     | 
    
         
            +
            				date: Builtin::Date,
         
     | 
| 
      
 13 
     | 
    
         
            +
            				time: Builtin::Time,
         
     | 
| 
       11 
14 
     | 
    
         
             
            				string: Builtin::String,
         
     | 
| 
       12 
15 
     | 
    
         
             
            				symbol: Builtin::Symbol,
         
     | 
| 
       13 
16 
     | 
    
         
             
            				integer: Builtin::Integer,
         
     | 
| 
       14 
17 
     | 
    
         
             
            				decimal: Builtin::BigDecimal,
         
     | 
| 
       15 
18 
     | 
    
         
             
            				float: Builtin::Float,
         
     | 
| 
       16 
     | 
    
         
            -
            				 
     | 
| 
       17 
     | 
    
         
            -
            				array: Builtin::Array,
         
     | 
| 
       18 
     | 
    
         
            -
            				date: Builtin::Date,
         
     | 
| 
       19 
     | 
    
         
            -
            				time: Builtin::Time
         
     | 
| 
      
 19 
     | 
    
         
            +
            				numeric: Builtin::Numeric
         
     | 
| 
       20 
20 
     | 
    
         
             
            			}
         
     | 
| 
       21 
21 
     | 
    
         
             
            		end
         
     | 
| 
       22 
22 
     | 
    
         
             
            	end
         
     |