Class Kwalify::MetaValidator
In: kwalify/meta-validator.rb
Parent: Validator

ex.

  meta_validator = Kwalify::MetaValidator.instance()
  schema = File.load_file('schema.yaml')
  errors = meta_validator.validate(schema)
  if !errors.empty?
    errors.each do |error|
      puts "[#{error.path}] #{error.message}"
    end
  end

Methods

instance   new   validate_hook  

Constants

META_SCHEMA = <<'END' name: MAIN type: map required: yes mapping: &main-rule "name": type: str "desc": type: str "classname": type: str "type": type: str #required: yes enum: - seq #- sequence #- list - map #- mapping #- hash - str #- string - int #- integer - float - number #- numeric - bool #- boolean - text - date - time - timestamp #- object - any - scalar #- collection "required": type: bool "enum": type: seq sequence: - type: scalar unique: yes "pattern": type: str "assert": type: str pattern: /\bval\b/ "range": type: map mapping: "max": type: scalar "min": type: scalar "max-ex": type: scalar "min-ex": type: scalar "length": type: map mapping: "max": type: int "min": type: int "max-ex": type: int "min-ex": type: int "ident": type: bool "unique": type: bool "sequence": name: SEQUENCE type: seq sequence: - type: map mapping: *main-rule name: MAIN #required: yes "mapping": name: MAPPING type: map mapping: =: type: map mapping: *main-rule name: MAIN #required: yes END

Public Class methods

[Source]

# File kwalify/meta-validator.rb, line 342
      def self.instance()
         return @instance
      end

[Source]

# File kwalify/meta-validator.rb, line 125
      def initialize(schema, &block)
         super
      end

Public Instance methods

[Source]

# File kwalify/meta-validator.rb, line 129
      def validate_hook(value, rule, path, errors)
         return if value == nil     ## realy?
         return unless rule.name == "MAIN"
         #
         hash = value
         type = hash['type']
         type = Types::DEFAULT_TYPE if type == nil
         klass = Types.type_class(type)
         #unless klass
         #   errors << validate_error(:type_unknown, rule, "#{path}/type", type)
         #end
         #
         if hash.key?('classname')
            val = hash['classname']
            unless val.nil? || type == 'map'
               errors << validate_error(:classname_notmap, rule, "#{path}/classname", 'classname:')
            end
         end
         #
         if hash.key?('pattern')
            val = hash['pattern']
            pat = (val =~ /\A\/(.*)\/([mi]?[mi]?)\z/ ? $1 : val)
            begin
               Regexp.compile(pat)
            rescue RegexpError => ex
               errors << validate_error(:pattern_syntaxerr, rule, "#{path}/pattern", val)
            end
         end
         #
         if hash.key?('enum')
            if Types.collection_type?(type)
               errors << validate_error(:enum_notscalar, rule, path, 'enum:')
            else
               #elem_table = {}
               hash['enum'].each do |elem|
                  #if elem_table[elem]
                  #   errors << validate_error(:enum_duplicate, rule, "#{path}/enum", elem.to_s)
                  #end
                  #elem_table[elem] = true
                  unless elem.is_a?(klass)
                     errors << validate_error(:enum_type_unmatch, rule, "#{path}/enum", elem, [Kwalify.word(type)])
                  end
               end
            end
         end
         #
         if hash.key?('assert')
            val =  hash['assert']
            #val =~ /\bval\b/ or errors << validate_error(:assert_noval, rule, "#{path}/assert", val)
            begin
               eval "proc { |val| #{val} }"
            rescue SyntaxError => ex
               errors << validate_error(:assert_syntaxerr, rule, "#{path}/assert", val)
            end
         end
         #
         if hash.key?('range')
            val = hash['range']
            curr_path = path + "/range"
            #if ! val.is_a?(Hash)
            #   errors << validate_error(:range_notmap, rule, curr_path, val)
            #elsif ...
            if Types.collection_type?(type) || type == 'bool' || type == 'any'
               errors << validate_error(:range_notscalar, rule, path, 'range:')
            else
               val.each do |rkey, rval|
                  #case rkey
                  #when 'max', 'min', 'max-ex', 'min-ex'
                     unless rval.is_a?(klass)
                        typename = Kwalify.word(type) || type
                        errors << validate_error(:range_type_unmatch, rule, "#{curr_path}/#{rkey}", rval, [typename])
                     end
                  #else
                  #   errors << validate_error(:range_undefined, rule, curr_path, "#{rkey}:")
                  #end
               end
            end
            if val.key?('max') && val.key?('max-ex')
               errors << validate_error(:range_twomax, rule, curr_path, nil)
            end
            if val.key?('min') && val.key?('min-ex')
               errors << validate_error(:range_twomin, rule, curr_path, nil)
            end
            max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
            if max
               if min && max < min
                  errors << validate_error(:range_maxltmin, rule, curr_path, nil, [max, min])
               elsif min_ex && max <= min_ex
                  errors << validate_error(:range_maxleminex, rule, curr_path, nil, [max, min_ex])
               end
            elsif max_ex
               if min && max_ex <= min
                  errors << validate_error(:range_maxexlemin, rule, curr_path, nil, [max_ex, min])
               elsif min_ex && max_ex <= min_ex
                  errors << validate_error(:range_maxexleminex, rule, curr_path, nil, [max_ex, min_ex])
               end
            end
         end
         #
         if hash.key?('length')
            val = hash['length']
            curr_path = path + "/length"
            #val.is_a?(Hash) or errors << validate_error(:length_notmap, rule, curr_path, val)
            unless type == 'str' || type == 'text'
               errors << validate_error(:length_nottext, rule, path, 'length:')
            end
            #val.each do |lkey, lval|
            #   #case lkey
            #   #when 'max', 'min', 'max-ex', 'min-ex'
            #      unless lval.is_a?(Integer)
            #         errors << validate_error(:length_notint, rule, "#{curr_path}/#{lkey}", lval)
            #      end
            #   #else
            #   #   errors << validate_error(:length_undefined, rule, curr_path, "#{lkey}:")
            #   #end
            #end
            if val.key?('max') && val.key?('max-ex')
               errors << validate_error(:length_twomax, rule, curr_path, nil)
            end
            if val.key?('min') && val.key?('min-ex')
               errors << validate_error(:length_twomin, rule, curr_path, nil)
            end
            max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
            if max
               if min && max < min
                  errors << validate_error(:length_maxltmin, rule, curr_path, nil, [max, min])
               elsif min_ex && max <= min_ex
                  errors << validate_error(:length_maxleminex, rule, curr_path, nil, [max, min_ex])
               end
            elsif max_ex
               if min && max_ex <= min
                  errors << validate_error(:length_maxexlemin, rule, curr_path, nil, [max_ex, min])
               elsif min_ex && max_ex <= min_ex
                  errors << validate_error(:length_maxexleminex, rule, curr_path, nil, [max_ex, min_ex])
               end
            end
         end
         #
         if hash.key?('unique')
            if hash['unique'] && Types.collection_type?(type)
               errors << validate_error(:unique_notscalar, rule, path, "unique:")
            end
            if path.empty?
               errors << validate_error(:unique_onroot, rule, "/", "unique:")
            end
         end
         #
         if hash.key?('ident')
            if hash['ident'] && Types.collection_type?(type)
               errors << validate_error(:ident_notscalar, rule, path, "ident:")
            end
            if path.empty?
               errors << validate_error(:ident_onroot, rule, "/", "ident:")
            end
         end
         #
         if hash.key?('sequence')
            val = hash['sequence']
            #if val != nil && !val.is_a?(Array)
            #   errors << validate_error(:sequence_notseq,  rule, "#{path}/sequence", val)
            #elsif ...
            if val == nil || val.empty?
               errors << validate_error(:sequence_noelem,  rule, "#{path}/sequence", val)
            elsif val.length > 1
               errors << validate_error(:sequence_toomany, rule, "#{path}/sequence", val)
            else
               elem = val[0]
               assert_error("elem.class=#{elem.class}") unless elem.is_a?(Hash)
               if elem['ident'] && elem['type'] != 'map'
                  errors << validate_error(:ident_notmap, nil, "#{path}/sequence/0", 'ident:')
               end
            end
         end
         #
         if hash.key?('mapping')
            val = hash['mapping']
            if val != nil && !val.is_a?(Hash)
               errors << validate_error(:mapping_notmap, rule, "#{path}/mapping", val)
            elsif val == nil || (val.empty? && !val.default)
               errors << validate_error(:mapping_noelem, rule, "#{path}/mapping", val)
            end
         end
         #
         if type == 'seq'
            errors << validate_error(:seq_nosequence, rule, path, nil)      unless hash.key?('sequence')
            #errors << validate_error(:seq_conflict, rule, path, 'enum:')        if hash.key?('enum')
            errors << validate_error(:seq_conflict, rule, path, 'pattern:')     if hash.key?('pattern')
            errors << validate_error(:seq_conflict, rule, path, 'mapping:')     if hash.key?('mapping')
            #errors << validate_error(:seq_conflict, rule, path, 'range:')       if hash.key?('range')
            #errors << validate_error(:seq_conflict, rule, path, 'length:')      if hash.key?('length')
         elsif type == 'map'
            errors << validate_error(:map_nomapping, rule, path, nil)       unless hash.key?('mapping')
            #errors << validate_error(:map_conflict, rule, path, 'enum:')        if hash.key?('enum')
            errors << validate_error(:map_conflict, rule, path, 'pattern:')     if hash.key?('pattern')
            errors << validate_error(:map_conflict, rule, path, 'sequence:')    if hash.key?('sequence')
            #errors << validate_error(:map_conflict, rule, path, 'range:')       if hash.key?('range')
            #errors << validate_error(:map_conflict, rule, path, 'length:')      if hash.key?('length')
         else
            errors << validate_error(:scalar_conflict, rule, path, 'sequence:') if hash.key?('sequence')
            errors << validate_error(:scalar_conflict, rule, path, 'mapping:')  if hash.key?('mapping')
            if hash.key?('enum')
               errors << validate_error(:enum_conflict, rule, path, 'range:')   if hash.key?('range')
               errors << validate_error(:enum_conflict, rule, path, 'length:')  if hash.key?('length')
               errors << validate_error(:enum_conflict, rule, path, 'pattern:') if hash.key?('pattern')
            end
         end

      end

[Validate]