nxt_schema 0.1.0 → 1.0.2
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/.ruby-version +1 -0
- data/Gemfile +0 -1
- data/Gemfile.lock +40 -42
- data/README.md +267 -121
- data/lib/nxt_schema.rb +60 -51
- data/lib/nxt_schema/callable.rb +21 -55
- data/lib/nxt_schema/dsl.rb +41 -31
- data/lib/nxt_schema/error.rb +4 -0
- data/lib/nxt_schema/errors/{error.rb → coercion_error.rb} +1 -2
- data/lib/nxt_schema/errors/invalid.rb +16 -0
- data/lib/nxt_schema/errors/invalid_options.rb +6 -0
- data/lib/nxt_schema/node/any_of.rb +39 -0
- data/lib/nxt_schema/node/base.rb +66 -267
- data/lib/nxt_schema/node/collection.rb +40 -56
- data/lib/nxt_schema/node/error_store.rb +41 -0
- data/lib/nxt_schema/node/errors/schema_error.rb +15 -0
- data/lib/nxt_schema/node/errors/validation_error.rb +15 -0
- data/lib/nxt_schema/node/leaf.rb +8 -36
- data/lib/nxt_schema/node/schema.rb +70 -103
- data/lib/nxt_schema/registry.rb +12 -74
- data/lib/nxt_schema/registry/proxy.rb +21 -0
- data/lib/nxt_schema/template/any_of.rb +50 -0
- data/lib/nxt_schema/template/base.rb +220 -0
- data/lib/nxt_schema/template/collection.rb +23 -0
- data/lib/nxt_schema/template/has_sub_nodes.rb +87 -0
- data/lib/nxt_schema/template/leaf.rb +13 -0
- data/lib/nxt_schema/template/maybe_evaluator.rb +28 -0
- data/lib/nxt_schema/template/on_evaluator.rb +25 -0
- data/lib/nxt_schema/template/schema.rb +22 -0
- data/lib/nxt_schema/template/sub_nodes.rb +22 -0
- data/lib/nxt_schema/template/type_resolver.rb +39 -0
- data/lib/nxt_schema/template/type_system_resolver.rb +22 -0
- data/lib/nxt_schema/types.rb +7 -4
- data/lib/nxt_schema/undefined.rb +4 -2
- data/lib/nxt_schema/validators/{equality.rb → equal_to.rb} +2 -2
- data/lib/nxt_schema/validators/error_messages.rb +42 -0
- data/lib/nxt_schema/{error_messages → validators/error_messages}/en.yaml +6 -5
- data/lib/nxt_schema/validators/{excluded.rb → excluded_in.rb} +1 -1
- data/lib/nxt_schema/validators/{included.rb → included_in.rb} +1 -1
- data/lib/nxt_schema/validators/includes.rb +1 -1
- data/lib/nxt_schema/validators/optional_node.rb +11 -6
- data/lib/nxt_schema/validators/registry.rb +1 -7
- data/lib/nxt_schema/{node → validators}/validate_with_proxy.rb +3 -3
- data/lib/nxt_schema/validators/validator.rb +2 -2
- data/lib/nxt_schema/version.rb +1 -1
- data/nxt_schema.gemspec +1 -0
- metadata +44 -21
- data/lib/nxt_schema/callable_or_value.rb +0 -72
- data/lib/nxt_schema/error_messages.rb +0 -40
- data/lib/nxt_schema/errors.rb +0 -4
- data/lib/nxt_schema/errors/invalid_options_error.rb +0 -5
- data/lib/nxt_schema/errors/schema_not_applied_error.rb +0 -5
- data/lib/nxt_schema/node/constructor.rb +0 -9
- data/lib/nxt_schema/node/default_value_evaluator.rb +0 -20
- data/lib/nxt_schema/node/error.rb +0 -13
- data/lib/nxt_schema/node/has_subnodes.rb +0 -97
- data/lib/nxt_schema/node/maybe_evaluator.rb +0 -23
- data/lib/nxt_schema/node/template_store.rb +0 -15
- data/lib/nxt_schema/node/type_resolver.rb +0 -24
| @@ -1,72 +0,0 @@ | |
| 1 | 
            -
            module NxtSchema
         | 
| 2 | 
            -
              class CallableOrValue
         | 
| 3 | 
            -
                def initialize(callee)
         | 
| 4 | 
            -
                  @callee = callee
         | 
| 5 | 
            -
             | 
| 6 | 
            -
                  if callee.is_a?(Symbol)
         | 
| 7 | 
            -
                    self.type = :method
         | 
| 8 | 
            -
                  elsif callee.respond_to?(:call)
         | 
| 9 | 
            -
                    self.type = :proc
         | 
| 10 | 
            -
                    self.context = callee.binding
         | 
| 11 | 
            -
                  else
         | 
| 12 | 
            -
                    self.type = :value
         | 
| 13 | 
            -
                  end
         | 
| 14 | 
            -
                end
         | 
| 15 | 
            -
             | 
| 16 | 
            -
                def bind(execution_context = nil)
         | 
| 17 | 
            -
                  self.context = execution_context
         | 
| 18 | 
            -
                  ensure_context_not_missing
         | 
| 19 | 
            -
                  self
         | 
| 20 | 
            -
                end
         | 
| 21 | 
            -
             | 
| 22 | 
            -
                # NOTE: Currently we only allow arguments! Not keyword args or **options
         | 
| 23 | 
            -
                # If we would allow **options and we would pass a hash as the only argument it would
         | 
| 24 | 
            -
                # automatically be parsed as the options!
         | 
| 25 | 
            -
                def call(*args)
         | 
| 26 | 
            -
                  return callee if value?
         | 
| 27 | 
            -
             | 
| 28 | 
            -
                  ensure_context_not_missing
         | 
| 29 | 
            -
             | 
| 30 | 
            -
                  args = args.take(arity)
         | 
| 31 | 
            -
             | 
| 32 | 
            -
                  if method?
         | 
| 33 | 
            -
                    context.send(callee, *args)
         | 
| 34 | 
            -
                  else
         | 
| 35 | 
            -
                    context.instance_exec(*args, &callee)
         | 
| 36 | 
            -
                  end
         | 
| 37 | 
            -
                end
         | 
| 38 | 
            -
             | 
| 39 | 
            -
                def arity
         | 
| 40 | 
            -
                  if proc?
         | 
| 41 | 
            -
                    callee.arity
         | 
| 42 | 
            -
                  elsif method?
         | 
| 43 | 
            -
                    method = context.send(:method, callee)
         | 
| 44 | 
            -
                    method.arity
         | 
| 45 | 
            -
                  else
         | 
| 46 | 
            -
                    raise ArgumentError, "Can't resolve arity from #{callee}"
         | 
| 47 | 
            -
                  end
         | 
| 48 | 
            -
                end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                private
         | 
| 51 | 
            -
             | 
| 52 | 
            -
                def proc?
         | 
| 53 | 
            -
                  type == :proc
         | 
| 54 | 
            -
                end
         | 
| 55 | 
            -
             | 
| 56 | 
            -
                def method?
         | 
| 57 | 
            -
                  type == :method
         | 
| 58 | 
            -
                end
         | 
| 59 | 
            -
             | 
| 60 | 
            -
                def value?
         | 
| 61 | 
            -
                  type == :value
         | 
| 62 | 
            -
                end
         | 
| 63 | 
            -
             | 
| 64 | 
            -
                def ensure_context_not_missing
         | 
| 65 | 
            -
                  return if context
         | 
| 66 | 
            -
             | 
| 67 | 
            -
                  raise ArgumentError, "Missing context: #{context}"
         | 
| 68 | 
            -
                end
         | 
| 69 | 
            -
             | 
| 70 | 
            -
                attr_accessor :context, :callee, :type
         | 
| 71 | 
            -
              end
         | 
| 72 | 
            -
            end
         | 
| @@ -1,40 +0,0 @@ | |
| 1 | 
            -
            module NxtSchema
         | 
| 2 | 
            -
              class ErrorMessages
         | 
| 3 | 
            -
                class << self
         | 
| 4 | 
            -
                  def values
         | 
| 5 | 
            -
                    @values ||= {}
         | 
| 6 | 
            -
                  end
         | 
| 7 | 
            -
             | 
| 8 | 
            -
                  def values=(value)
         | 
| 9 | 
            -
                    @values = value
         | 
| 10 | 
            -
                  end
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                  def load(paths = files)
         | 
| 13 | 
            -
                    Array(paths).each do |path|
         | 
| 14 | 
            -
                      new_values = YAML.load(ERB.new(File.read(path)).result).with_indifferent_access
         | 
| 15 | 
            -
                      self.values = values.deep_merge!(new_values)
         | 
| 16 | 
            -
                    end
         | 
| 17 | 
            -
                  end
         | 
| 18 | 
            -
             | 
| 19 | 
            -
                  def resolve(locale, key, **options)
         | 
| 20 | 
            -
                    message = begin
         | 
| 21 | 
            -
                      values.fetch(locale).fetch(key)
         | 
| 22 | 
            -
                    rescue KeyError
         | 
| 23 | 
            -
                      raise "Could not resolve error message for #{locale}->#{key}"
         | 
| 24 | 
            -
                    end
         | 
| 25 | 
            -
             | 
| 26 | 
            -
                    message % options
         | 
| 27 | 
            -
                  end
         | 
| 28 | 
            -
             | 
| 29 | 
            -
                  def files
         | 
| 30 | 
            -
                    @files ||= begin
         | 
| 31 | 
            -
                      files = Dir.entries(File.expand_path('../error_messages/', __FILE__)).map do |filename|
         | 
| 32 | 
            -
                        File.expand_path("../error_messages/#{filename}", __FILE__)
         | 
| 33 | 
            -
                      end
         | 
| 34 | 
            -
             | 
| 35 | 
            -
                      files.select { |f| !File.directory? f }
         | 
| 36 | 
            -
                    end
         | 
| 37 | 
            -
                  end
         | 
| 38 | 
            -
                end
         | 
| 39 | 
            -
              end
         | 
| 40 | 
            -
            end
         | 
    
        data/lib/nxt_schema/errors.rb
    DELETED
    
    
| @@ -1,20 +0,0 @@ | |
| 1 | 
            -
            module NxtSchema
         | 
| 2 | 
            -
              module Node
         | 
| 3 | 
            -
                class DefaultValueEvaluator
         | 
| 4 | 
            -
                  def initialize(node, evaluator_or_value)
         | 
| 5 | 
            -
                    @node = node
         | 
| 6 | 
            -
                    @evaluator_or_value = evaluator_or_value
         | 
| 7 | 
            -
                  end
         | 
| 8 | 
            -
             | 
| 9 | 
            -
                  attr_reader :node, :evaluator_or_value
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                  def call
         | 
| 12 | 
            -
                    if evaluator_or_value.respond_to?(:call)
         | 
| 13 | 
            -
                      Callable.new(evaluator_or_value).call(node)
         | 
| 14 | 
            -
                    else
         | 
| 15 | 
            -
                      evaluator_or_value
         | 
| 16 | 
            -
                    end
         | 
| 17 | 
            -
                  end
         | 
| 18 | 
            -
                end
         | 
| 19 | 
            -
              end
         | 
| 20 | 
            -
            end
         | 
| @@ -1,97 +0,0 @@ | |
| 1 | 
            -
            require_relative 'schema'
         | 
| 2 | 
            -
            require_relative 'collection'
         | 
| 3 | 
            -
            require_relative 'constructor'
         | 
| 4 | 
            -
            require_relative 'leaf'
         | 
| 5 | 
            -
             | 
| 6 | 
            -
            module NxtSchema
         | 
| 7 | 
            -
              module Node
         | 
| 8 | 
            -
                module HasSubNodes
         | 
| 9 | 
            -
                  attr_accessor :template_store, :value_store
         | 
| 10 | 
            -
             | 
| 11 | 
            -
                  # TODO: Would be cool if we could register custom node types!
         | 
| 12 | 
            -
                  def node(name, type_or_node, **options, &block)
         | 
| 13 | 
            -
                    child_node = case type_or_node.to_s.to_sym
         | 
| 14 | 
            -
                    when :Schema
         | 
| 15 | 
            -
                      NxtSchema::Node::Schema.new(name: name, type: NxtSchema::Types::Strict::Hash, parent_node: self, **options, &block)
         | 
| 16 | 
            -
                    when :Collection
         | 
| 17 | 
            -
                      NxtSchema::Node::Collection.new(name: name, type: NxtSchema::Types::Strict::Array, parent_node: self, **options, &block)
         | 
| 18 | 
            -
                    when :Struct
         | 
| 19 | 
            -
                      NxtSchema::Node::Constructor.new(
         | 
| 20 | 
            -
                        name: name,
         | 
| 21 | 
            -
                        type: NxtSchema::Types::Constructor(::Struct) { |hash| ::Struct.new(*hash.keys).new(*hash.values) },
         | 
| 22 | 
            -
                        parent_node: self,
         | 
| 23 | 
            -
                        **options,
         | 
| 24 | 
            -
                        &block
         | 
| 25 | 
            -
                      )
         | 
| 26 | 
            -
                    when :OpenStruct
         | 
| 27 | 
            -
                      NxtSchema::Node::Constructor.new(
         | 
| 28 | 
            -
                        name: name,
         | 
| 29 | 
            -
                        type: NxtSchema::Types::Constructor(::OpenStruct),
         | 
| 30 | 
            -
                        parent_node: self,
         | 
| 31 | 
            -
                        **options,
         | 
| 32 | 
            -
                        &block
         | 
| 33 | 
            -
                      )
         | 
| 34 | 
            -
                    else
         | 
| 35 | 
            -
                      if type_or_node.is_a?(NxtSchema::Node::Base)
         | 
| 36 | 
            -
                        node = type_or_node.clone
         | 
| 37 | 
            -
                        node.options.merge!(options)
         | 
| 38 | 
            -
                        node.name = name
         | 
| 39 | 
            -
                        node.parent_node = self
         | 
| 40 | 
            -
                        node
         | 
| 41 | 
            -
                      else
         | 
| 42 | 
            -
                        NxtSchema::Node::Leaf.new(name: name, type: type_or_node, parent_node: self, **options)
         | 
| 43 | 
            -
                      end
         | 
| 44 | 
            -
                    end
         | 
| 45 | 
            -
             | 
| 46 | 
            -
                    # TODO: Should we check if there is a
         | 
| 47 | 
            -
                    raise KeyError, "Duplicate registration for key: #{name}" if template_store.key?(name)
         | 
| 48 | 
            -
                    template_store.push(child_node)
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                    child_node
         | 
| 51 | 
            -
                  end
         | 
| 52 | 
            -
             | 
| 53 | 
            -
                  def required(name, type, **options, &block)
         | 
| 54 | 
            -
                    node(name, type, options, &block)
         | 
| 55 | 
            -
                  end
         | 
| 56 | 
            -
             | 
| 57 | 
            -
                  alias_method :requires, :required
         | 
| 58 | 
            -
             | 
| 59 | 
            -
                  def nodes(name, **options, &block)
         | 
| 60 | 
            -
                    node(name, :Collection, options, &block)
         | 
| 61 | 
            -
                  end
         | 
| 62 | 
            -
             | 
| 63 | 
            -
                  alias_method :array, :nodes
         | 
| 64 | 
            -
             | 
| 65 | 
            -
                  def schema(name, **options, &block)
         | 
| 66 | 
            -
                    node(name, :Schema, options, &block)
         | 
| 67 | 
            -
                  end
         | 
| 68 | 
            -
             | 
| 69 | 
            -
                  alias_method :hash, :schema
         | 
| 70 | 
            -
             | 
| 71 | 
            -
                  def struct(name, **options, &block)
         | 
| 72 | 
            -
                    node(name, NxtSchema::Types::Constructor(::OpenStruct), options, &block)
         | 
| 73 | 
            -
                  end
         | 
| 74 | 
            -
             | 
| 75 | 
            -
                  def dup
         | 
| 76 | 
            -
                    result = super
         | 
| 77 | 
            -
                    result.template_store = template_store.deep_dup
         | 
| 78 | 
            -
                    result.options = options.deep_dup
         | 
| 79 | 
            -
                    result
         | 
| 80 | 
            -
                  end
         | 
| 81 | 
            -
             | 
| 82 | 
            -
                  delegate_missing_to :value_store
         | 
| 83 | 
            -
             | 
| 84 | 
            -
                  private
         | 
| 85 | 
            -
             | 
| 86 | 
            -
                  def value_violates_emptiness?(value)
         | 
| 87 | 
            -
                    return true unless value.respond_to?(:empty?)
         | 
| 88 | 
            -
             | 
| 89 | 
            -
                    value.empty?
         | 
| 90 | 
            -
                  end
         | 
| 91 | 
            -
                end
         | 
| 92 | 
            -
              end
         | 
| 93 | 
            -
            end
         | 
| 94 | 
            -
             | 
| 95 | 
            -
            NxtSchema::Node::Schema.include(::NxtSchema::Node::HasSubNodes)
         | 
| 96 | 
            -
            NxtSchema::Node::Collection.include(::NxtSchema::Node::HasSubNodes)
         | 
| 97 | 
            -
            NxtSchema::Node::Constructor.include(::NxtSchema::Node::HasSubNodes)
         | 
| @@ -1,23 +0,0 @@ | |
| 1 | 
            -
            module NxtSchema
         | 
| 2 | 
            -
              module Node
         | 
| 3 | 
            -
                class MaybeEvaluator
         | 
| 4 | 
            -
                  def initialize(node, evaluator, value)
         | 
| 5 | 
            -
                    @node = node
         | 
| 6 | 
            -
                    @evaluator = evaluator
         | 
| 7 | 
            -
                    @value = value
         | 
| 8 | 
            -
                  end
         | 
| 9 | 
            -
             | 
| 10 | 
            -
                  attr_reader :node, :evaluator, :value
         | 
| 11 | 
            -
             | 
| 12 | 
            -
                  def call
         | 
| 13 | 
            -
                    if evaluator.respond_to?(:call)
         | 
| 14 | 
            -
                      Callable.new(evaluator).call(node, value)
         | 
| 15 | 
            -
                    elsif value.is_a?(Symbol) && value.respond_to?(evaluator)
         | 
| 16 | 
            -
                      Callable.new(evaluator).bind(value).call(node, value)
         | 
| 17 | 
            -
                    else
         | 
| 18 | 
            -
                      value == evaluator
         | 
| 19 | 
            -
                    end
         | 
| 20 | 
            -
                  end
         | 
| 21 | 
            -
                end
         | 
| 22 | 
            -
              end
         | 
| 23 | 
            -
            end
         | 
| @@ -1,15 +0,0 @@ | |
| 1 | 
            -
            module NxtSchema
         | 
| 2 | 
            -
              module Node
         | 
| 3 | 
            -
                class TemplateStore < ::Hash
         | 
| 4 | 
            -
                  def push(node)
         | 
| 5 | 
            -
                    node_name = node.name
         | 
| 6 | 
            -
                    raise_key_error(node_name) if key?(node_name)
         | 
| 7 | 
            -
                    self[node_name] = node
         | 
| 8 | 
            -
                  end
         | 
| 9 | 
            -
             | 
| 10 | 
            -
                  def raise_key_error(key)
         | 
| 11 | 
            -
                    raise KeyError, "Node with name '#{key}' already registered! Node names must be unique!"
         | 
| 12 | 
            -
                  end
         | 
| 13 | 
            -
                end
         | 
| 14 | 
            -
              end
         | 
| 15 | 
            -
            end
         | 
| @@ -1,24 +0,0 @@ | |
| 1 | 
            -
            module NxtSchema
         | 
| 2 | 
            -
              module Node
         | 
| 3 | 
            -
                class TypeResolver
         | 
| 4 | 
            -
                  def resolve(type_system, type)
         | 
| 5 | 
            -
                    @resolve ||= {}
         | 
| 6 | 
            -
                    @resolve[type] ||= begin
         | 
| 7 | 
            -
                      if type.is_a?(Dry::Types::Type)
         | 
| 8 | 
            -
                        type
         | 
| 9 | 
            -
                      else
         | 
| 10 | 
            -
                        # Try to resolve in type system
         | 
| 11 | 
            -
                        type = type_system.const_get(type.to_s.classify)
         | 
| 12 | 
            -
             | 
| 13 | 
            -
                        if type.is_a?(Dry::Types::Type)
         | 
| 14 | 
            -
                          type
         | 
| 15 | 
            -
                        else
         | 
| 16 | 
            -
                          # in case it does not exist fallback to Types::Nominal
         | 
| 17 | 
            -
                          "NxtSchema::Types::Nominal::#{type.to_s.classify}".constantize
         | 
| 18 | 
            -
                        end
         | 
| 19 | 
            -
                      end
         | 
| 20 | 
            -
                    end
         | 
| 21 | 
            -
                  end
         | 
| 22 | 
            -
                end
         | 
| 23 | 
            -
              end
         | 
| 24 | 
            -
            end
         |