lib/kwalify/meta-validator.rb in kwalify-0.1.0 vs lib/kwalify/meta-validator.rb in kwalify-0.2.0

- old
+ new

@@ -1,137 +1,260 @@ ### -### $Rev: 9 $ -### $Release: 0.1.0 $ +### $Rev: 18 $ +### $Release: 0.2.0 $ ### copyright(c) 2005 kuwata-lab all rights reserved. ### require 'kwalify/errors' +require 'kwalify/rule' require 'kwalify/validator' require 'yaml' module Kwalify - META_SCHEMA_DEF = <<'END' - + META_SCHEMA = <<'END' name: MAIN type: map required: yes -mapping: &main-schema +mapping: &main-rule "name": - type: string + type: str "desc": - type: text + type: str "type": - type: string + type: str + #required: yes enum: - seq - - sequence + #- sequence #- list - map - - mapping + #- mapping #- hash - - string - - integer + - str + #- string + - int + #- integer - float - number - - numeric + #- numeric - bool - - boolean + #- boolean - text - date - time - - object + - timestamp + #- object - any + - scalar + #- collection "required": - type: boolean + type: bool "enum": type: seq sequence: - - type: object + - type: scalar "pattern": - type: string + type: str + "assert": + type: str + pattern: /\bval\b/ + "range": + type: map + mapping: + "max": + type: scalar + "min": + type: scalar + "length": + type: map + mapping: + "max": + type: int + "min": + type: int "sequence": name: SEQUENCE type: seq sequence: - type: map - mapping: *main-schema + mapping: *main-rule name: MAIN + #required: yes "mapping": name: MAPPING type: map mapping: - '*': + '*': type: map - mapping: *main-schema + mapping: *main-rule name: MAIN - + #required: yes END - def self.meta_validator() - yaml = YAML.load(META_SCHEMA_DEF) - validator = Kwalify::Validator.new(yaml) - return validator - end + ## + ## ex. + ## meta_validator = Kwalify.meta_validator() + ## 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 + ## + class MetaValidator < Validator + def initialize(schema, &block) + super + end - - def self.meta_validator2() - yaml = YAML.load(META_SCHEMA_DEF) - validator = Kwalify::Validator.new(yaml) { |schema, obj, errors, path| - next if obj == nil ## realy? - if schema.name == "MAIN" - hash = obj - if hash.key?('pattern') - val = hash['pattern'] - pat = (val =~ /\A\/(.*)\/\z/ ? $1 : val) - begin - Regexp.compile(pat) - rescue RegexpError => ex - errors << Kwalify::Errors.validate_error(:regexp_error, schema, path, obj) + def validate_hook(value, rule, path, errors) + return if value == nil ## realy? + return unless rule.name == "MAIN" + # + hash = value + type = hash['type'] + type = Kwalify::DEFAULT_TYPE if type == nil + unless type.is_a?(String) + errors << Kwalify.validate_error(:type_notstr, rule, "#{path}/type", type.to_s) + end + klass = Kwalify.get_type_class(type) + unless klass + errors << Kwalify.validate_error(:type_unknown, rule, "#{path}/type", type.to_s) + end + # + if hash.key?('pattern') + val = hash['pattern'] + pat = (val =~ /\A\/(.*)\/([mi]?[mi]?)\z/ ? $1 : val) + begin + Regexp.compile(pat) + rescue RegexpError => ex + errors << Kwalify.validate_error(:pattern_syntaxerr, rule, "#{path}/pattern", val) + end + end + # + if hash.key?('enum') + if type == 'seq' || type == 'map' # unless Kwalify.scalar_class?(klass) + errors << schema_error(:enum_notscalar, rule, path, 'enum:') + else + elem_table = {} + hash['enum'].each do |elem| + if elem_table[elem] + errors << Kwalify.validate_error(:enum_duplicate, rule, "#{path}/enum", elem.to_s) + end + elem_table[elem] = true + unless elem.is_a?(klass) + errors << schema_error(:enum_type_unmatch, rule, "#{path}/enum", elem, [Kwalify.word(type)]) + end end end - type = hash['type'] - if type == nil - if hash.key?('sequence') - type = 'seq' - elsif hash.key?('mapping') - type = 'map' + end + # + if hash.key?('assert') + val = hash['assert'] + val =~ /\bval\b/ or errors << Kwalify.validate_error(:assert_noval, rule, "#{path}/assert", val) + begin + eval "proc { |val| #{val} }" + rescue SyntaxError => ex + errors << Kwalify.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 << Kwalify.validate_error(:range_notmap, rule, curr_path, val) + elsif type == 'seq' || type == 'map' || type == 'bool' || type == 'any' + errors << Kwalify.validate_error(:range_notscalar, rule, path, 'range:') + else + val.each do |rkey, rval| + case rkey + when 'max', 'min' + unless rval.is_a?(klass) + typename = Kwalify.word(type) || type + errors << Kwalify.validate_error(:range_type_unmatch, rule, "#{curr_path}/#{rkey}", rval, [typename]) + end + else + errors << Kwalify.validate_error(:range_undefined, rule, curr_path, "#{rkey}:") + end + end + end + end + # + if hash.key?('length') + val = hash['length'] + curr_path = path + "/length" + val.is_a?(Hash) or errors << Kwalify.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' + unless lval.is_a?(Integer) + errors << Kwalify.validate_error(:length_notint, rule, "#{curr_path}/#{lkey}", lval) + end else - type = Kwalify::DEFAULT_TYPE + errors << validate_error(:length_undefined, rule, curr_path, "#{lkey}:") end end - klass = Kwalify.type_table[type] - if klass == nil - errors << Kwalify::Errors.validate_error(:invalid_type, schema, path, obj) - elsif klass == Array - errors << Kwalify::Errors.validate_error(:seq_has_enum, schema, path, obj) if hash.key?('enum') - errors << Kwalify::Errors.validate_error(:seq_has_pattern, schema, path, obj) if hash.key?('pattern') - errors << Kwalify::Errors.validate_error(:seq_has_mapping, schema, path, obj) if hash.key?('mapping') - elsif klass == Hash - errors << Kwalify::Errors.validate_error(:map_has_enum, schema, path, obj) if hash.key?('enum') - errors << Kwalify::Errors.validate_error(:map_has_pattern, schema, path, obj) if hash.key?('pattern') - errors << Kwalify::Errors.validate_error(:map_has_sequence, schema, path, obj) if hash.key?('sequence') - else - errors << Kwalify::Errors.validate_error(:scalar_has_sequence, schema, path, obj) if hash.key?('sequence') - errors << Kwalify::Errors.validate_error(:scalar_has_mapping, schema, path, obj) if hash.key?('mapping') + end + # + if hash.key?('sequence') + val = hash['sequence'] + if val != nil && !val.is_a?(Array) + errors << Kwalify.validate_error(:sequence_notseq, rule, "#{path}/sequence", val) + elsif val == nil || val.empty? + errors << Kwalify.validate_error(:sequence_noelem, rule, "#{path}/sequence", val) + elsif val.length > 1 + errors << Kwalify.validate_error(:sequence_toomany, rule, "#{path}/sequence", val) end - elsif schema.name == "SEQUENCE" - if !obj.is_a?(Array) - errors << Kwalify::Errors.validate_error(:sequence_not_seq, schema, path, obj) - else - errors << Kwalify::Errors.validate_error(:sequence_no_elem, schema, path, obj) if obj.empty? - errors << Kwalify::Errors.validate_error(:sequence_too_many, schema, path, obj) if obj.length > 1 + end + # + if hash.key?('mapping') + val = hash['mapping'] + if val != nil && !val.is_a?(Hash) + errors << Kwalify.validate_error(:mapping_notmap, rule, "#{path}/mapping", val) + elsif val == nil || val.empty? + errors << Kwalify.validate_error(:mapping_noelem, rule, "#{path}/mapping", val) end - elsif schema.name == "MAPPING" - if !obj.is_a?(Hash) - errors << Kwalify::Errors.validate_error(:mapping_not_map, schema, path, obj) - else - errors << Kwalify::Errors.validate_error(:mapping_no_elem, schema, path, obj) if obj.empty? + end + # + if type == 'seq' + errors << Kwalify.validate_error(:seq_nosequence, rule, path, nil) unless hash.key?('sequence') + #errors << Kwalify.validate_error(:seq_conflict, rule, path, 'enum:') if hash.key?('enum') + errors << Kwalify.validate_error(:seq_conflict, rule, path, 'pattern:') if hash.key?('pattern') + errors << Kwalify.validate_error(:seq_conflict, rule, path, 'mapping:') if hash.key?('mapping') + #errors << Kwalify.validate_error(:seq_conflict, rule, path, 'range:') if hash.key?('range') + errors << Kwalify.validate_error(:seq_conflict, rule, path, 'length:') if hash.key?('length') + elsif type == 'map' + errors << Kwalify.validate_error(:map_nomapping, rule, path, nil) unless hash.key?('mapping') + #errors << Kwalify.validate_error(:map_conflict, rule, path, 'enum:') if hash.key?('enum') + errors << Kwalify.validate_error(:map_conflict, rule, path, 'pattern:') if hash.key?('pattern') + errors << Kwalify.validate_error(:map_conflict, rule, path, 'sequence:') if hash.key?('sequence') + #errors << Kwalify.validate_error(:map_conflict, rule, path, 'range:') if hash.key?('range') + errors << Kwalify.validate_error(:map_conflict, rule, path, 'length:') if hash.key?('length') + else + errors << Kwalify.validate_error(:scalar_conflict, rule, path, 'sequence:') if hash.key?('sequence') + errors << Kwalify.validate_error(:scalar_conflict, rule, path, 'mapping:') if hash.key?('mapping') + if hash.key?('enum') + errors << Kwalify.validate_error(:enum_conflict, rule, path, 'range:') if hash.key?('range') + errors << Kwalify.validate_error(:enum_conflict, rule, path, 'length:') if hash.key?('length') + errors << Kwalify.validate_error(:enum_conflict, rule, path, 'pattern:') if hash.key?('pattern') end end - } - return validator + + end # end of def validate_hook() + + end # end of class MetaValidator + + + schema = YAML.load(META_SCHEMA) + META_VALIDATOR = MetaValidator.new(schema) + + def self.meta_validator + return META_VALIDATOR end end -