Sha256: c264b79670b059245a532c0e41a1fbced062ebd771571db21208ff595970ef64

Contents?: true

Size: 1.95 KB

Versions: 1

Compression:

Stored size: 1.95 KB

Contents

module DataModel
	module Scanner
		extend self

		def scan(schema, registry = Registry.instance)
			start = { validator: nil, property: nil, state: :start }
			result = schema.each_with_index.reduce(start) do |context, (token, pos)|
				context => {state:, validator:, property:}
				peek = schema[pos + 1]

				# detect named validators, a name could be any type so cannot be detected
				# by ruby type and state. detect name by ensuring we are at the start
				# of scanning, and the next element is a valid type.
				if state == :start && registry.type?(peek)
					context.merge(
						property: token,
						state: :named,
					)
				else
					# with the special case of a name aside, we can detect the meaning
					# of further tokens by their type and scanner state
					case token
					when Symbol
						unless [:start, :named].include?(state)
							raise "got a symbol at pos #{pos}, but validator already defined"
						end

						unless registry.type?(token)
							raise "expected a type in pos #{pos}, but found #{token.inspect} which is not a registered type"
						end

						context.merge(
							validator: registry.type(token, property),
							state: :defined,
						)

					when Hash
						unless state == :defined
							raise "got a hash at pos #{pos}, but state is not :defined (#{state.inspect})"
						end

						context.merge(
							validator: validator.merge(config: token),
							state: :configured,
						)

					when Array
						unless [:defined, :configured].include?(state)
							raise "#{schema.inspect} at pos #{pos}: expected (String | Hash | Symbol | Array), got #{token.class.name}"
						end

						children = token.map { |s| scan(s, registry) }

						context.merge(
							validator: validator.merge(children:),
							state: :complete,
						)
					else
						raise "got token #{token.inspect} at position #{pos} which was unexpected given the scanner was in a state of #{state}"
					end
				end
			end

			result.fetch(:validator)
		end
	end
end

Version data entries

1 entries across 1 versions & 1 rubygems

Version Path
data_model-0.0.1 lib/data_model/scanner.rb