kwalify 0.4.1 → 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.
- data/ChangeLog +14 -3
- data/README.txt +3 -3
- data/bin/kwalify +4 -15
- data/doc/users-guide.html +237 -61
- data/examples/address-book/address-book.schema.yaml +1 -1
- data/examples/invoice/invoice.schema.yaml +2 -2
- data/examples/tapkit/tapkit.schema.yaml +39 -39
- data/lib/kwalify.rb +4 -4
- data/lib/kwalify/errors.rb +21 -14
- data/lib/kwalify/main.rb +357 -0
- data/lib/kwalify/messages.rb +38 -9
- data/lib/kwalify/meta-validator.rb +96 -64
- data/lib/kwalify/rule.rb +356 -269
- data/lib/kwalify/types.rb +53 -35
- data/lib/kwalify/util/assert-diff.rb +2 -2
- data/lib/kwalify/util/option-parser.rb +2 -2
- data/lib/kwalify/util/yaml-helper.rb +2 -2
- data/lib/kwalify/validator.rb +8 -17
- data/lib/kwalify/{parser.rb → yaml-parser.rb} +70 -41
- data/test/test-main.rb +179 -0
- data/test/test-main.yaml +756 -0
- data/test/test-metavalidator.rb +38 -721
- data/test/test-metavalidator.yaml +1104 -0
- data/test/test-rule.rb +60 -0
- data/test/test-rule.yaml +314 -0
- data/test/test-validator.rb +5 -5
- data/test/test-validator.yaml +816 -0
- data/test/{test-parser.rb → test-yamlparser.rb} +17 -17
- data/test/test-yamlparser.yaml +1080 -0
- data/test/test.rb +5 -3
- data/todo.txt +1 -0
- metadata +16 -11
- data/lib/kwalify/main-program.rb +0 -258
    
        data/lib/kwalify/messages.rb
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            ###
         | 
| 2 | 
            -
            ### $Rev:  | 
| 3 | 
            -
            ### $Release: 0. | 
| 2 | 
            +
            ### $Rev: 42 $
         | 
| 3 | 
            +
            ### $Release: 0.5.0 $
         | 
| 4 4 | 
             
            ### copyright(c) 2005 kuwata-lab all rights reserved.
         | 
| 5 5 | 
             
            ###
         | 
| 6 6 |  | 
| @@ -14,26 +14,32 @@ module Kwalify | |
| 14 14 |  | 
| 15 15 |  | 
| 16 16 | 
             
               ##----- begin
         | 
| 17 | 
            -
               # filename: lib/kwalify/main | 
| 18 | 
            -
               @@messages[: | 
| 19 | 
            -
               @@messages[: | 
| 20 | 
            -
               @@messages[: | 
| 21 | 
            -
               @@messages[: | 
| 17 | 
            +
               # filename: lib/kwalify/main.rb
         | 
| 18 | 
            +
               @@messages[:command_option_noaction] = "command-line option '-f' or '-m' required."
         | 
| 19 | 
            +
               @@messages[:meta_empty]           = "%s: empty.\n"
         | 
| 20 | 
            +
               @@messages[:meta_valid]           = "%s: ok.\n"
         | 
| 21 | 
            +
               @@messages[:meta_invalid]         = "%s: NG!\n"
         | 
| 22 22 | 
             
               @@messages[:schema_empty]         = "%s#%d: empty.\n"
         | 
| 23 23 | 
             
               @@messages[:validation_valid]     = "%s#%d: valid.\n"
         | 
| 24 24 | 
             
               @@messages[:validation_invalid]   = "%s#%d: INVALID\n"
         | 
| 25 | 
            +
               @@messages[:command_property_invalid] = "%s: invalid property."
         | 
| 26 | 
            +
               @@messages[:command_option_noarg] = "-%s: argument required."
         | 
| 27 | 
            +
               @@messages[:command_option_noschema] = "-%s: schema filename required."
         | 
| 28 | 
            +
               @@messages[:command_option_invalid] = "-%s: invalid command option."
         | 
| 25 29 | 
             
               # --
         | 
| 26 30 | 
             
               # filename: lib/kwalify/rule.rb
         | 
| 27 31 | 
             
               @@messages[:schema_notmap]        = "schema definition is not a mapping."
         | 
| 32 | 
            +
               @@messages[:key_unknown]          = "unknown key."
         | 
| 28 33 | 
             
               @@messages[:type_notstr]          = "not a string."
         | 
| 29 34 | 
             
               @@messages[:type_unknown]         = "unknown type."
         | 
| 30 35 | 
             
               @@messages[:required_notbool]     = "not a boolean."
         | 
| 36 | 
            +
               @@messages[:pattern_notstr]       = "not a string (or regexp)"
         | 
| 31 37 | 
             
               @@messages[:pattern_notmatch]     = "should be '/..../'."
         | 
| 32 38 | 
             
               @@messages[:pattern_syntaxerr]    = "has regexp error."
         | 
| 33 39 | 
             
               @@messages[:enum_notseq]          = "not a sequence."
         | 
| 34 40 | 
             
               @@messages[:enum_notscalar]       = "not available with seq or map."
         | 
| 35 | 
            -
               @@messages[:enum_duplicate]       = "duplicated enum value."
         | 
| 36 41 | 
             
               @@messages[:enum_type_unmatch]    = "%s type expected."
         | 
| 42 | 
            +
               @@messages[:enum_duplicate]       = "duplicated enum value."
         | 
| 37 43 | 
             
               @@messages[:assert_notstr]        = "not a string."
         | 
| 38 44 | 
             
               @@messages[:assert_noval]         = "'val' is not used."
         | 
| 39 45 | 
             
               @@messages[:assert_syntaxerr]     = "expression syntax error."
         | 
| @@ -43,12 +49,20 @@ module Kwalify | |
| 43 49 | 
             
               @@messages[:range_undefined]      = "undefined key."
         | 
| 44 50 | 
             
               @@messages[:range_twomax]         = "both 'max' and 'max-ex' are not available at once."
         | 
| 45 51 | 
             
               @@messages[:range_twomin]         = "both 'min' and 'min-ex' are not available at once."
         | 
| 52 | 
            +
               @@messages[:range_maxltmin]       = "max '%s' is less than min '%s'."
         | 
| 53 | 
            +
               @@messages[:range_maxleminex]     = "max '%s' is less than or equal to min-ex '%s'."
         | 
| 54 | 
            +
               @@messages[:range_maxexlemin]     = "max-ex '%s' is less than or equal to min '%s'."
         | 
| 55 | 
            +
               @@messages[:range_maxexleminex]   = "max-ex '%s' is less than or equal to min-ex '%s'."
         | 
| 46 56 | 
             
               @@messages[:length_notmap]        = "not a mapping."
         | 
| 47 57 | 
             
               @@messages[:length_nottext]       = "is available only with string or text."
         | 
| 48 58 | 
             
               @@messages[:length_notint]        = "not an integer."
         | 
| 49 59 | 
             
               @@messages[:length_undefined]     = "undefined key."
         | 
| 50 60 | 
             
               @@messages[:length_twomax]        = "both 'max' and 'max-ex' are not available at once."
         | 
| 51 61 | 
             
               @@messages[:length_twomin]        = "both 'min' and 'min-ex' are not available at once."
         | 
| 62 | 
            +
               @@messages[:length_maxltmin]      = "max '%s' is less than min '%s'."
         | 
| 63 | 
            +
               @@messages[:length_maxleminex]    = "max '%s' is less than or equal to min-ex '%s'."
         | 
| 64 | 
            +
               @@messages[:length_maxexlemin]    = "max-ex '%s' is less than or equal to min '%s'."
         | 
| 65 | 
            +
               @@messages[:length_maxexleminex]  = "max-ex '%s' is less than or equal to min-ex '%s'."
         | 
| 52 66 | 
             
               @@messages[:ident_notbool]        = "not a boolean."
         | 
| 53 67 | 
             
               @@messages[:ident_notscalar]      = "is available only with a scalar type."
         | 
| 54 68 | 
             
               @@messages[:ident_onroot]         = "is not available on root element."
         | 
| @@ -61,7 +75,6 @@ module Kwalify | |
| 61 75 | 
             
               @@messages[:sequence_toomany]     = "required just one element."
         | 
| 62 76 | 
             
               @@messages[:mapping_notmap]       = "not a mapping."
         | 
| 63 77 | 
             
               @@messages[:mapping_noelem]       = "required at least one element."
         | 
| 64 | 
            -
               @@messages[:key_unknown]          = "unknown key."
         | 
| 65 78 | 
             
               @@messages[:seq_nosequence]       = "type 'seq' requires 'sequence:'."
         | 
| 66 79 | 
             
               @@messages[:seq_conflict]         = "not available with sequence."
         | 
| 67 80 | 
             
               @@messages[:map_nomapping]        = "type 'map' requires 'mapping:'."
         | 
| @@ -87,6 +100,22 @@ module Kwalify | |
| 87 100 | 
             
               @@messages[:required_nokey]       = "key '%s:' is required."
         | 
| 88 101 | 
             
               @@messages[:key_undefined]        = "key '%s' is undefined."
         | 
| 89 102 | 
             
               # --
         | 
| 103 | 
            +
               # filename: lib/kwalify/yaml-parser.rb
         | 
| 104 | 
            +
               @@messages[:flow_hastail]         = "flow style sequence is closed but got '%s'."
         | 
| 105 | 
            +
               @@messages[:flow_eof]             = "found EOF when parsing flow style."
         | 
| 106 | 
            +
               @@messages[:flow_noseqitem]       = "sequence item required (or last comma is extra)."
         | 
| 107 | 
            +
               @@messages[:flow_seqnotclosed]    = "flow style sequence requires ']'."
         | 
| 108 | 
            +
               @@messages[:flow_mapnoitem]       = "mapping item required (or last comma is extra)."
         | 
| 109 | 
            +
               @@messages[:flow_mapnotclosed]    = "flow style mapping requires '}'."
         | 
| 110 | 
            +
               @@messages[:flow_nocolon]         = "':' expected but got '%s'."
         | 
| 111 | 
            +
               @@messages[:anchor_duplicated]    = "anchor '%s' is already used."
         | 
| 112 | 
            +
               @@messages[:alias_extradata]      = "alias cannot take any data."
         | 
| 113 | 
            +
               @@messages[:anchor_notfound]      = "anchor '%s' not found"
         | 
| 114 | 
            +
               @@messages[:sequence_noitem]      = "sequence item is expected."
         | 
| 115 | 
            +
               @@messages[:sequence_badindent]   = "illegal indent of sequence."
         | 
| 116 | 
            +
               @@messages[:mapping_noitem]       = "mapping item is expected."
         | 
| 117 | 
            +
               @@messages[:mapping_badindent]    = "illegal indent of mapping."
         | 
| 118 | 
            +
               # --
         | 
| 90 119 | 
             
               ##----- end
         | 
| 91 120 |  | 
| 92 121 |  | 
| @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            ###
         | 
| 2 | 
            -
            ### $Rev:  | 
| 3 | 
            -
            ### $Release: 0. | 
| 2 | 
            +
            ### $Rev: 42 $
         | 
| 3 | 
            +
            ### $Release: 0.5.0 $
         | 
| 4 4 | 
             
            ### copyright(c) 2005 kuwata-lab all rights reserved.
         | 
| 5 5 | 
             
            ###
         | 
| 6 6 |  | 
| @@ -11,7 +11,21 @@ require 'yaml' | |
| 11 11 |  | 
| 12 12 | 
             
            module Kwalify
         | 
| 13 13 |  | 
| 14 | 
            -
             | 
| 14 | 
            +
             | 
| 15 | 
            +
               ##
         | 
| 16 | 
            +
               ## ex.
         | 
| 17 | 
            +
               ##   meta_validator = Kwalify::MetaValidator.instance()
         | 
| 18 | 
            +
               ##   schema = File.load_file('schema.yaml')
         | 
| 19 | 
            +
               ##   errors = meta_validator.validate(schema)
         | 
| 20 | 
            +
               ##   if !errors.empty?
         | 
| 21 | 
            +
               ##     errors.each do |error|
         | 
| 22 | 
            +
               ##       puts "[#{error.path}] #{error.message}"
         | 
| 23 | 
            +
               ##     end
         | 
| 24 | 
            +
               ##   end
         | 
| 25 | 
            +
               ##
         | 
| 26 | 
            +
               class MetaValidator < Validator
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  META_SCHEMA = <<'END'
         | 
| 15 29 | 
             
            name:      MAIN
         | 
| 16 30 | 
             
            type:      map
         | 
| 17 31 | 
             
            required:  yes
         | 
| @@ -53,6 +67,7 @@ mapping:   &main-rule | |
| 53 67 | 
             
                type:      seq
         | 
| 54 68 | 
             
                sequence:
         | 
| 55 69 | 
             
                  - type:     scalar
         | 
| 70 | 
            +
                    unique:   yes
         | 
| 56 71 | 
             
             "pattern":
         | 
| 57 72 | 
             
                type:      str
         | 
| 58 73 | 
             
             "assert":
         | 
| @@ -69,8 +84,6 @@ mapping:   &main-rule | |
| 69 84 | 
             
                    type:     scalar
         | 
| 70 85 | 
             
                 "min-ex":
         | 
| 71 86 | 
             
                    type:     scalar
         | 
| 72 | 
            -
                 #complement":
         | 
| 73 | 
            -
                 #   type:     boolean
         | 
| 74 87 | 
             
             "length":
         | 
| 75 88 | 
             
                type:      map
         | 
| 76 89 | 
             
                mapping:
         | 
| @@ -106,18 +119,6 @@ mapping:   &main-rule | |
| 106 119 | 
             
            END
         | 
| 107 120 |  | 
| 108 121 |  | 
| 109 | 
            -
               ##
         | 
| 110 | 
            -
               ## ex.
         | 
| 111 | 
            -
               ##   meta_validator = Kwalify.meta_validator()
         | 
| 112 | 
            -
               ##   schema = File.load_file('schema.yaml')
         | 
| 113 | 
            -
               ##   errors = meta_validator.validate(schema)
         | 
| 114 | 
            -
               ##   if !errors.empty?
         | 
| 115 | 
            -
               ##     errors.each do |error|
         | 
| 116 | 
            -
               ##       puts "[#{error.path}] #{error.message}"
         | 
| 117 | 
            -
               ##     end
         | 
| 118 | 
            -
               ##   end
         | 
| 119 | 
            -
               ##
         | 
| 120 | 
            -
               class MetaValidator < Validator
         | 
| 121 122 | 
             
                  def initialize(schema, &block)
         | 
| 122 123 | 
             
                     super
         | 
| 123 124 | 
             
                  end
         | 
| @@ -128,14 +129,11 @@ END | |
| 128 129 | 
             
                     #
         | 
| 129 130 | 
             
                     hash = value
         | 
| 130 131 | 
             
                     type = hash['type']
         | 
| 131 | 
            -
                     type =  | 
| 132 | 
            -
                      | 
| 133 | 
            -
             | 
| 134 | 
            -
                      | 
| 135 | 
            -
                      | 
| 136 | 
            -
                     unless klass
         | 
| 137 | 
            -
                        errors << validate_error(:type_unknown, rule, "#{path}/type", type.to_s)
         | 
| 138 | 
            -
                     end
         | 
| 132 | 
            +
                     type = Types::DEFAULT_TYPE if type == nil
         | 
| 133 | 
            +
                     klass = Types.type_class(type)
         | 
| 134 | 
            +
                     #unless klass
         | 
| 135 | 
            +
                     #   errors << validate_error(:type_unknown, rule, "#{path}/type", type)
         | 
| 136 | 
            +
                     #end
         | 
| 139 137 | 
             
                     #
         | 
| 140 138 | 
             
                     if hash.key?('pattern')
         | 
| 141 139 | 
             
                        val = hash['pattern']
         | 
| @@ -148,15 +146,15 @@ END | |
| 148 146 | 
             
                     end
         | 
| 149 147 | 
             
                     #
         | 
| 150 148 | 
             
                     if hash.key?('enum')
         | 
| 151 | 
            -
                        if  | 
| 149 | 
            +
                        if Types.collection_type?(type)
         | 
| 152 150 | 
             
                           errors << validate_error(:enum_notscalar, rule, path, 'enum:')
         | 
| 153 151 | 
             
                        else
         | 
| 154 | 
            -
                           elem_table = {}
         | 
| 152 | 
            +
                           #elem_table = {}
         | 
| 155 153 | 
             
                           hash['enum'].each do |elem|
         | 
| 156 | 
            -
                              if elem_table[elem]
         | 
| 157 | 
            -
             | 
| 158 | 
            -
                              end
         | 
| 159 | 
            -
                              elem_table[elem] = true
         | 
| 154 | 
            +
                              #if elem_table[elem]
         | 
| 155 | 
            +
                              #   errors << validate_error(:enum_duplicate, rule, "#{path}/enum", elem.to_s)
         | 
| 156 | 
            +
                              #end
         | 
| 157 | 
            +
                              #elem_table[elem] = true
         | 
| 160 158 | 
             
                              unless elem.is_a?(klass)
         | 
| 161 159 | 
             
                                 errors << validate_error(:enum_type_unmatch, rule, "#{path}/enum", elem, [Kwalify.word(type)])
         | 
| 162 160 | 
             
                              end
         | 
| @@ -166,7 +164,7 @@ END | |
| 166 164 | 
             
                     #
         | 
| 167 165 | 
             
                     if hash.key?('assert')
         | 
| 168 166 | 
             
                        val =  hash['assert']
         | 
| 169 | 
            -
                        val =~ /\bval\b/ or errors << validate_error(:assert_noval, rule, "#{path}/assert", val)
         | 
| 167 | 
            +
                        #val =~ /\bval\b/ or errors << validate_error(:assert_noval, rule, "#{path}/assert", val)
         | 
| 170 168 | 
             
                        begin
         | 
| 171 169 | 
             
                           eval "proc { |val| #{val} }"
         | 
| 172 170 | 
             
                        rescue SyntaxError => ex
         | 
| @@ -177,9 +175,10 @@ END | |
| 177 175 | 
             
                     if hash.key?('range')
         | 
| 178 176 | 
             
                        val = hash['range']
         | 
| 179 177 | 
             
                        curr_path = path + "/range"
         | 
| 180 | 
            -
                        if ! val.is_a?(Hash)
         | 
| 181 | 
            -
             | 
| 182 | 
            -
                        elsif  | 
| 178 | 
            +
                        #if ! val.is_a?(Hash)
         | 
| 179 | 
            +
                        #   errors << validate_error(:range_notmap, rule, curr_path, val)
         | 
| 180 | 
            +
                        #elsif ...
         | 
| 181 | 
            +
                        if Types.collection_type?(type) || type == 'bool' || type == 'any'
         | 
| 183 182 | 
             
                           errors << validate_error(:range_notscalar, rule, path, 'range:')
         | 
| 184 183 | 
             
                        else
         | 
| 185 184 | 
             
                           val.each do |rkey, rval|
         | 
| @@ -200,35 +199,63 @@ END | |
| 200 199 | 
             
                        if val.key?('min') && val.key?('min-ex')
         | 
| 201 200 | 
             
                           errors << validate_error(:range_twomin, rule, curr_path, nil)
         | 
| 202 201 | 
             
                        end
         | 
| 202 | 
            +
                        max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
         | 
| 203 | 
            +
                        if max
         | 
| 204 | 
            +
                           if min && max < min
         | 
| 205 | 
            +
                              errors << validate_error(:range_maxltmin, rule, curr_path, nil, [max, min])
         | 
| 206 | 
            +
                           elsif min_ex && max <= min_ex
         | 
| 207 | 
            +
                              errors << validate_error(:range_maxleminex, rule, curr_path, nil, [max, min_ex])
         | 
| 208 | 
            +
                           end
         | 
| 209 | 
            +
                        elsif max_ex
         | 
| 210 | 
            +
                           if min && max_ex <= min
         | 
| 211 | 
            +
                              errors << validate_error(:range_maxexlemin, rule, curr_path, nil, [max_ex, min])
         | 
| 212 | 
            +
                           elsif min_ex && max_ex <= min_ex
         | 
| 213 | 
            +
                              errors << validate_error(:range_maxexleminex, rule, curr_path, nil, [max_ex, min_ex])
         | 
| 214 | 
            +
                           end
         | 
| 215 | 
            +
                        end
         | 
| 203 216 | 
             
                     end
         | 
| 204 217 | 
             
                     #
         | 
| 205 218 | 
             
                     if hash.key?('length')
         | 
| 206 219 | 
             
                        val = hash['length']
         | 
| 207 220 | 
             
                        curr_path = path + "/length"
         | 
| 208 | 
            -
                        val.is_a?(Hash) or errors << validate_error(:length_notmap, rule, curr_path, val)
         | 
| 221 | 
            +
                        #val.is_a?(Hash) or errors << validate_error(:length_notmap, rule, curr_path, val)
         | 
| 209 222 | 
             
                        unless type == 'str' || type == 'text'
         | 
| 210 223 | 
             
                           errors << validate_error(:length_nottext, rule, path, 'length:')
         | 
| 211 224 | 
             
                        end
         | 
| 212 | 
            -
                        val.each do |lkey, lval|
         | 
| 213 | 
            -
             | 
| 214 | 
            -
             | 
| 215 | 
            -
             | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 218 | 
            -
             | 
| 219 | 
            -
             | 
| 220 | 
            -
             | 
| 221 | 
            -
                        end
         | 
| 225 | 
            +
                        #val.each do |lkey, lval|
         | 
| 226 | 
            +
                        #   #case lkey
         | 
| 227 | 
            +
                        #   #when 'max', 'min', 'max-ex', 'min-ex'
         | 
| 228 | 
            +
                        #      unless lval.is_a?(Integer)
         | 
| 229 | 
            +
                        #         errors << validate_error(:length_notint, rule, "#{curr_path}/#{lkey}", lval)
         | 
| 230 | 
            +
                        #      end
         | 
| 231 | 
            +
                        #   #else
         | 
| 232 | 
            +
                        #   #   errors << validate_error(:length_undefined, rule, curr_path, "#{lkey}:")
         | 
| 233 | 
            +
                        #   #end
         | 
| 234 | 
            +
                        #end
         | 
| 222 235 | 
             
                        if val.key?('max') && val.key?('max-ex')
         | 
| 223 236 | 
             
                           errors << validate_error(:length_twomax, rule, curr_path, nil)
         | 
| 224 237 | 
             
                        end
         | 
| 225 238 | 
             
                        if val.key?('min') && val.key?('min-ex')
         | 
| 226 239 | 
             
                           errors << validate_error(:length_twomin, rule, curr_path, nil)
         | 
| 227 240 | 
             
                        end
         | 
| 241 | 
            +
                        max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
         | 
| 242 | 
            +
                        if max
         | 
| 243 | 
            +
                           if min && max < min
         | 
| 244 | 
            +
                              errors << validate_error(:length_maxltmin, rule, curr_path, nil, [max, min])
         | 
| 245 | 
            +
                           elsif min_ex && max <= min_ex
         | 
| 246 | 
            +
                              errors << validate_error(:length_maxleminex, rule, curr_path, nil, [max, min_ex])
         | 
| 247 | 
            +
                           end
         | 
| 248 | 
            +
                        elsif max_ex
         | 
| 249 | 
            +
                           if min && max_ex <= min
         | 
| 250 | 
            +
                              errors << validate_error(:length_maxexlemin, rule, curr_path, nil, [max_ex, min])
         | 
| 251 | 
            +
                           elsif min_ex && max_ex <= min_ex
         | 
| 252 | 
            +
                              errors << validate_error(:length_maxexleminex, rule, curr_path, nil, [max_ex, min_ex])
         | 
| 253 | 
            +
                           end
         | 
| 254 | 
            +
                        end
         | 
| 228 255 | 
             
                     end
         | 
| 229 256 | 
             
                     #
         | 
| 230 257 | 
             
                     if hash.key?('unique')
         | 
| 231 | 
            -
                        if hash['unique'] && (type | 
| 258 | 
            +
                        if hash['unique'] && Types.collection_type?(type)
         | 
| 232 259 | 
             
                           errors << validate_error(:unique_notscalar, rule, path, "unique:")
         | 
| 233 260 | 
             
                        end
         | 
| 234 261 | 
             
                        if path.empty?
         | 
| @@ -237,7 +264,7 @@ END | |
| 237 264 | 
             
                     end
         | 
| 238 265 | 
             
                     #
         | 
| 239 266 | 
             
                     if hash.key?('ident')
         | 
| 240 | 
            -
                        if hash['ident'] && (type | 
| 267 | 
            +
                        if hash['ident'] && Types.collection_type?(type)
         | 
| 241 268 | 
             
                           errors << validate_error(:ident_notscalar, rule, path, "ident:")
         | 
| 242 269 | 
             
                        end
         | 
| 243 270 | 
             
                        if path.empty?
         | 
| @@ -247,21 +274,18 @@ END | |
| 247 274 | 
             
                     #
         | 
| 248 275 | 
             
                     if hash.key?('sequence')
         | 
| 249 276 | 
             
                        val = hash['sequence']
         | 
| 250 | 
            -
                        if val != nil && !val.is_a?(Array)
         | 
| 251 | 
            -
             | 
| 252 | 
            -
                        elsif  | 
| 277 | 
            +
                        #if val != nil && !val.is_a?(Array)
         | 
| 278 | 
            +
                        #   errors << validate_error(:sequence_notseq,  rule, "#{path}/sequence", val)
         | 
| 279 | 
            +
                        #elsif ...
         | 
| 280 | 
            +
                        if val == nil || val.empty?
         | 
| 253 281 | 
             
                           errors << validate_error(:sequence_noelem,  rule, "#{path}/sequence", val)
         | 
| 254 282 | 
             
                        elsif val.length > 1
         | 
| 255 283 | 
             
                           errors << validate_error(:sequence_toomany, rule, "#{path}/sequence", val)
         | 
| 256 284 | 
             
                        else
         | 
| 257 | 
            -
                            | 
| 258 | 
            -
                            | 
| 259 | 
            -
             | 
| 260 | 
            -
             | 
| 261 | 
            -
                              end
         | 
| 262 | 
            -
                              #if child['unique'] && child['type'] != 'map'
         | 
| 263 | 
            -
                              #   errors << validate_error(:unique_notmap, nil, "#{path}/sequence/0", 'unique:')
         | 
| 264 | 
            -
                              #end
         | 
| 285 | 
            +
                           elem = val[0]
         | 
| 286 | 
            +
                           assert_error("elem.class=#{elem.class}") unless elem.is_a?(Hash)
         | 
| 287 | 
            +
                           if elem['ident'] && elem['type'] != 'map'
         | 
| 288 | 
            +
                              errors << validate_error(:ident_notmap, nil, "#{path}/sequence/0", 'ident:')
         | 
| 265 289 | 
             
                           end
         | 
| 266 290 | 
             
                        end
         | 
| 267 291 | 
             
                     end
         | 
| @@ -281,14 +305,14 @@ END | |
| 281 305 | 
             
                        errors << validate_error(:seq_conflict, rule, path, 'pattern:')     if hash.key?('pattern')
         | 
| 282 306 | 
             
                        errors << validate_error(:seq_conflict, rule, path, 'mapping:')     if hash.key?('mapping')
         | 
| 283 307 | 
             
                        #errors << validate_error(:seq_conflict, rule, path, 'range:')       if hash.key?('range')
         | 
| 284 | 
            -
                        errors << validate_error(:seq_conflict, rule, path, 'length:')      if hash.key?('length')
         | 
| 308 | 
            +
                        #errors << validate_error(:seq_conflict, rule, path, 'length:')      if hash.key?('length')
         | 
| 285 309 | 
             
                     elsif type == 'map'
         | 
| 286 310 | 
             
                        errors << validate_error(:map_nomapping, rule, path, nil)       unless hash.key?('mapping')
         | 
| 287 311 | 
             
                        #errors << validate_error(:map_conflict, rule, path, 'enum:')        if hash.key?('enum')
         | 
| 288 312 | 
             
                        errors << validate_error(:map_conflict, rule, path, 'pattern:')     if hash.key?('pattern')
         | 
| 289 313 | 
             
                        errors << validate_error(:map_conflict, rule, path, 'sequence:')    if hash.key?('sequence')
         | 
| 290 314 | 
             
                        #errors << validate_error(:map_conflict, rule, path, 'range:')       if hash.key?('range')
         | 
| 291 | 
            -
                        errors << validate_error(:map_conflict, rule, path, 'length:')      if hash.key?('length')
         | 
| 315 | 
            +
                        #errors << validate_error(:map_conflict, rule, path, 'length:')      if hash.key?('length')
         | 
| 292 316 | 
             
                     else
         | 
| 293 317 | 
             
                        errors << validate_error(:scalar_conflict, rule, path, 'sequence:') if hash.key?('sequence')
         | 
| 294 318 | 
             
                        errors << validate_error(:scalar_conflict, rule, path, 'mapping:')  if hash.key?('mapping')
         | 
| @@ -301,13 +325,21 @@ END | |
| 301 325 |  | 
| 302 326 | 
             
                  end  # end of def validate_hook()
         | 
| 303 327 |  | 
| 328 | 
            +
             | 
| 329 | 
            +
                  schema = YAML.load(META_SCHEMA)
         | 
| 330 | 
            +
                  @instance = MetaValidator.new(schema)
         | 
| 331 | 
            +
             | 
| 332 | 
            +
                  def self.instance()
         | 
| 333 | 
            +
                     return @instance
         | 
| 334 | 
            +
                  end
         | 
| 335 | 
            +
             | 
| 336 | 
            +
             | 
| 304 337 | 
             
               end # end of class MetaValidator
         | 
| 305 338 |  | 
| 306 339 |  | 
| 307 | 
            -
                | 
| 308 | 
            -
               META_VALIDATOR = MetaValidator.new(schema)
         | 
| 340 | 
            +
               META_VALIDATOR = MetaValidator.instance()
         | 
| 309 341 |  | 
| 310 | 
            -
               def self.meta_validator
         | 
| 342 | 
            +
               def self.meta_validator           # obsolete
         | 
| 311 343 | 
             
                  return META_VALIDATOR
         | 
| 312 344 | 
             
               end
         | 
| 313 345 |  | 
    
        data/lib/kwalify/rule.rb
    CHANGED
    
    | @@ -1,6 +1,6 @@ | |
| 1 1 | 
             
            ###
         | 
| 2 | 
            -
            ### $Rev:  | 
| 3 | 
            -
            ### $Release: 0. | 
| 2 | 
            +
            ### $Rev: 42 $
         | 
| 3 | 
            +
            ### $Release: 0.5.0 $
         | 
| 4 4 | 
             
            ### copyright(c) 2005 kuwata-lab all rights reserved.
         | 
| 5 5 | 
             
            ###
         | 
| 6 6 |  | 
| @@ -14,273 +14,375 @@ module Kwalify | |
| 14 14 | 
             
                  include Kwalify::ErrorHelper
         | 
| 15 15 |  | 
| 16 16 | 
             
                  def initialize(hash=nil, parent=nil)
         | 
| 17 | 
            -
                      | 
| 17 | 
            +
                     init(hash, "", {}) if hash
         | 
| 18 18 | 
             
                     @parent = parent
         | 
| 19 19 | 
             
                  end
         | 
| 20 | 
            +
             | 
| 20 21 | 
             
                  attr_accessor :parent
         | 
| 22 | 
            +
                  #attr_reader   :id
         | 
| 23 | 
            +
                  attr_reader :name
         | 
| 24 | 
            +
                  attr_reader :desc
         | 
| 25 | 
            +
                  attr_reader :enum
         | 
| 26 | 
            +
                  attr_reader :required
         | 
| 27 | 
            +
                  attr_reader :type
         | 
| 28 | 
            +
                  attr_reader :type_class
         | 
| 29 | 
            +
                  attr_reader :pattern
         | 
| 30 | 
            +
                  attr_reader :regexp
         | 
| 31 | 
            +
                  attr_reader :sequence
         | 
| 32 | 
            +
                  attr_reader :mapping
         | 
| 33 | 
            +
                  attr_reader :assert
         | 
| 34 | 
            +
                  attr_reader :assert_proc
         | 
| 35 | 
            +
                  attr_reader :range
         | 
| 36 | 
            +
                  attr_reader :length
         | 
| 37 | 
            +
                  attr_reader :ident
         | 
| 38 | 
            +
                  attr_reader :unique
         | 
| 39 | 
            +
             | 
| 21 40 |  | 
| 22 | 
            -
                  def  | 
| 41 | 
            +
                  def init(hash, path="", rule_table={})
         | 
| 23 42 | 
             
                     unless hash.is_a?(Hash)
         | 
| 24 43 | 
             
                        #* key=:schema_notmap  msg="schema definition is not a mapping."
         | 
| 25 44 | 
             
                        raise Kwalify.schema_error(:schema_notmap, nil, (!path || path.empty? ? "/" : path), nil)
         | 
| 26 45 | 
             
                     end
         | 
| 27 | 
            -
             | 
| 28 46 | 
             
                     rule = self
         | 
| 29 47 | 
             
                     rule_table[hash.__id__] = rule
         | 
| 48 | 
            +
                     ## 'type:' entry
         | 
| 49 | 
            +
                     _init_type_value(hash['type'], rule, path)
         | 
| 50 | 
            +
                     ## other entries
         | 
| 51 | 
            +
                     hash.each do |key, val|
         | 
| 52 | 
            +
                        code = key.intern
         | 
| 53 | 
            +
                        curr_path = "#{path}/#{key}"
         | 
| 54 | 
            +
                        case code
         | 
| 55 | 
            +
                        #when "id"
         | 
| 56 | 
            +
                        #   @id       = val
         | 
| 57 | 
            +
                        when :type      ;  # done
         | 
| 58 | 
            +
                        when :name      ;  _init_name_value(    val, rule, path)
         | 
| 59 | 
            +
                        when :desc      ;  _init_desc_value(    val, rule, path)
         | 
| 60 | 
            +
                        when :required  ;  _init_required_value(val, rule, path)
         | 
| 61 | 
            +
                        when :pattern   ;  _init_pattern_value( val, rule, path)
         | 
| 62 | 
            +
                        when :enum      ;  _init_enum_value(    val, rule, path)
         | 
| 63 | 
            +
                        when :assert    ;  _init_assert_value(  val, rule, path)
         | 
| 64 | 
            +
                        when :range     ;  _init_range_value(   val, rule, path)
         | 
| 65 | 
            +
                        when :length    ;  _init_length_value(  val, rule, path)
         | 
| 66 | 
            +
                        when :ident     ;  _init_ident_value(   val, rule, path)
         | 
| 67 | 
            +
                        when :unique    ;  _init_unique_value(  val, rule, path)
         | 
| 68 | 
            +
                        when :sequence  ;  _init_sequence_value(val, rule, path, rule_table)
         | 
| 69 | 
            +
                        when :mapping   ;  _init_mapping_value( val, rule, path, rule_table)
         | 
| 70 | 
            +
                        else
         | 
| 71 | 
            +
                           #* key=:key_unknown  msg="unknown key."
         | 
| 72 | 
            +
                           raise schema_error(:key_unknown, rule, curr_path, "#{key}:")
         | 
| 73 | 
            +
                        end
         | 
| 74 | 
            +
                     end
         | 
| 75 | 
            +
                     check_confliction(hash, rule, path)
         | 
| 76 | 
            +
                     return self
         | 
| 77 | 
            +
                  end # end of def init
         | 
| 78 | 
            +
             | 
| 79 | 
            +
             | 
| 80 | 
            +
                  private
         | 
| 30 81 |  | 
| 31 | 
            -
             | 
| 32 | 
            -
             | 
| 33 | 
            -
                     @type =  | 
| 82 | 
            +
             | 
| 83 | 
            +
                  def _init_type_value(val, rule, path)
         | 
| 84 | 
            +
                     @type = val
         | 
| 85 | 
            +
                     @type = Types::DEFAULT_TYPE if @type == nil
         | 
| 34 86 | 
             
                     unless @type.is_a?(String)
         | 
| 35 87 | 
             
                        #* key=:type_notstr  msg="not a string."
         | 
| 36 88 | 
             
                        raise schema_error(:type_notstr, rule, "#{path}/type", @type.to_s)
         | 
| 37 89 | 
             
                     end
         | 
| 38 | 
            -
                     @ | 
| 39 | 
            -
                     #if @ | 
| 90 | 
            +
                     @type_class = Types.type_class(@type)
         | 
| 91 | 
            +
                     #if @type_class == nil
         | 
| 40 92 | 
             
                     #   begin
         | 
| 41 | 
            -
                     #      @ | 
| 93 | 
            +
                     #      @type_class = Kernel.const_get(@type)
         | 
| 42 94 | 
             
                     #   rescue NameError
         | 
| 43 95 | 
             
                     #   end
         | 
| 44 96 | 
             
                     #end
         | 
| 45 | 
            -
                     unless @ | 
| 97 | 
            +
                     unless @type_class
         | 
| 46 98 | 
             
                        #* key=:type_unknown  msg="unknown type."
         | 
| 47 99 | 
             
                        raise schema_error(:type_unknown, rule, "#{path}/type", @type.to_s)
         | 
| 48 100 | 
             
                     end
         | 
| 101 | 
            +
                  end
         | 
| 49 102 |  | 
| 50 | 
            -
                     ## other key
         | 
| 51 | 
            -
                     hash.each do |key, val|
         | 
| 52 | 
            -
                        curr_path = "#{path}/#{key}"
         | 
| 53 | 
            -
                        case key
         | 
| 54 | 
            -
                        #when "id"
         | 
| 55 | 
            -
                        #   @id       = val
         | 
| 56 | 
            -
                        when "name"
         | 
| 57 | 
            -
                           @name = val
         | 
| 58 103 |  | 
| 59 | 
            -
             | 
| 60 | 
            -
             | 
| 104 | 
            +
                  def _init_name_value(val, rule, path)
         | 
| 105 | 
            +
                     @name = val
         | 
| 106 | 
            +
                  end
         | 
| 61 107 |  | 
| 62 | 
            -
                        when "type"
         | 
| 63 | 
            -
                           # done
         | 
| 64 108 |  | 
| 65 | 
            -
             | 
| 66 | 
            -
             | 
| 67 | 
            -
             | 
| 68 | 
            -
                              #* key=:required_notbool  msg="not a boolean."
         | 
| 69 | 
            -
                              raise schema_error(:required_notbool, rule, curr_path, val)
         | 
| 70 | 
            -
                           end
         | 
| 109 | 
            +
                  def _init_desc_value(val, rule, path)
         | 
| 110 | 
            +
                     @desc = val
         | 
| 111 | 
            +
                  end
         | 
| 71 112 |  | 
| 72 | 
            -
                        when "pattern"
         | 
| 73 | 
            -
                           unless val =~ /\A\/(.*)\/([mi]?[mi]?)\z/
         | 
| 74 | 
            -
                              #* key=:pattern_notmatch  msg="should be '/..../'."
         | 
| 75 | 
            -
                              raise schema_error(:pattern_notmatch, rule, curr_path, val)
         | 
| 76 | 
            -
                           end
         | 
| 77 | 
            -
                           pat = $1; opt = $2
         | 
| 78 | 
            -
                           flag = 0
         | 
| 79 | 
            -
                           flag += Regexp::IGNORECASE if opt.include?("i")
         | 
| 80 | 
            -
                           flag += Regexp::MULTILINE  if opt.include?("m")
         | 
| 81 | 
            -
                           begin
         | 
| 82 | 
            -
                              @pattern = Regexp.compile(pat, flag)
         | 
| 83 | 
            -
                           rescue RegexpError => ex
         | 
| 84 | 
            -
                              #* key=:pattern_syntaxerr  msg="has regexp error."
         | 
| 85 | 
            -
                              raise schema_error(:pattern_syntaxerr, rule, curr_path, val)
         | 
| 86 | 
            -
                           end
         | 
| 87 113 |  | 
| 88 | 
            -
             | 
| 89 | 
            -
             | 
| 90 | 
            -
             | 
| 91 | 
            -
             | 
| 92 | 
            -
             | 
| 93 | 
            -
             | 
| 94 | 
            -
             | 
| 95 | 
            -
                              #* key=:enum_notscalar  msg="not available with seq or map."
         | 
| 96 | 
            -
                              raise schema_error(:enum_notscalar, rule, path, 'enum:')
         | 
| 97 | 
            -
                           end
         | 
| 98 | 
            -
                           elem_table = {}
         | 
| 99 | 
            -
                           @enum.each do |elem|
         | 
| 100 | 
            -
                              unless !elem_table[elem]
         | 
| 101 | 
            -
                                 #* key=:enum_duplicate  msg="duplicated enum value."
         | 
| 102 | 
            -
                                 raise schema_error(:enum_duplicate, rule, curr_path, elem.to_s)
         | 
| 103 | 
            -
                              end
         | 
| 104 | 
            -
                              elem_table[elem] = true
         | 
| 105 | 
            -
                              unless elem.is_a?(@klass)
         | 
| 106 | 
            -
                                 #* key=:enum_type_unmatch  msg="%s type expected."
         | 
| 107 | 
            -
                                 raise schema_error(:enum_type_unmatch, rule, curr_path, elem, [Kwalify.word(@type)])
         | 
| 108 | 
            -
                              end
         | 
| 109 | 
            -
                           end
         | 
| 114 | 
            +
                  def _init_required_value(val, rule, path)
         | 
| 115 | 
            +
                     @required = val
         | 
| 116 | 
            +
                     unless val.is_a?(Boolean)  #|| val == nil
         | 
| 117 | 
            +
                        #* key=:required_notbool  msg="not a boolean."
         | 
| 118 | 
            +
                        raise schema_error(:required_notbool, rule, "#{path}/required", val)
         | 
| 119 | 
            +
                     end
         | 
| 120 | 
            +
                  end
         | 
| 110 121 |  | 
| 111 | 
            -
             | 
| 112 | 
            -
             | 
| 113 | 
            -
             | 
| 114 | 
            -
             | 
| 115 | 
            -
             | 
| 116 | 
            -
             | 
| 117 | 
            -
             | 
| 118 | 
            -
             | 
| 119 | 
            -
             | 
| 120 | 
            -
             | 
| 121 | 
            -
             | 
| 122 | 
            -
             | 
| 123 | 
            -
             | 
| 124 | 
            -
             | 
| 125 | 
            -
             | 
| 126 | 
            -
             | 
| 122 | 
            +
                  def _init_pattern_value(val, rule, path)
         | 
| 123 | 
            +
                     @pattern = val
         | 
| 124 | 
            +
                     unless val.is_a?(String) || val.is_a?(Regexp)
         | 
| 125 | 
            +
                        #* key=:pattern_notstr  msg="not a string (or regexp)"
         | 
| 126 | 
            +
                        raise schema_error(:pattern_notstr, rule, "#{path}/pattern", val)
         | 
| 127 | 
            +
                     end
         | 
| 128 | 
            +
                     unless val =~ /\A\/(.*)\/([mi]?[mi]?)\z/
         | 
| 129 | 
            +
                        #* key=:pattern_notmatch  msg="should be '/..../'."
         | 
| 130 | 
            +
                        raise schema_error(:pattern_notmatch, rule, "#{path}/pattern", val)
         | 
| 131 | 
            +
                     end
         | 
| 132 | 
            +
                     pat = $1; opt = $2
         | 
| 133 | 
            +
                     flag = 0
         | 
| 134 | 
            +
                     flag += Regexp::IGNORECASE if opt.include?("i")
         | 
| 135 | 
            +
                     flag += Regexp::MULTILINE  if opt.include?("m")
         | 
| 136 | 
            +
                     begin
         | 
| 137 | 
            +
                        @regexp = Regexp.compile(pat, flag)
         | 
| 138 | 
            +
                     rescue RegexpError => ex
         | 
| 139 | 
            +
                        #* key=:pattern_syntaxerr  msg="has regexp error."
         | 
| 140 | 
            +
                        raise schema_error(:pattern_syntaxerr, rule, "#{path}/pattern", val)
         | 
| 141 | 
            +
                     end
         | 
| 142 | 
            +
                  end
         | 
| 127 143 |  | 
| 128 | 
            -
                        when "range"
         | 
| 129 | 
            -
                           @range = val
         | 
| 130 | 
            -
                           unless val.is_a?(Hash)
         | 
| 131 | 
            -
                              #* key=:range_notmap  msg="not a mapping."
         | 
| 132 | 
            -
                              raise schema_error(:range_notmap, rule, curr_path, val)
         | 
| 133 | 
            -
                           end
         | 
| 134 | 
            -
                           if @type == 'map' || @type == 'seq' || @type == 'bool'
         | 
| 135 | 
            -
                              #* key=:range_notscalar  msg="is available only with scalar type."
         | 
| 136 | 
            -
                              raise schema_error(:range_notscalar, rule, path, 'range:')
         | 
| 137 | 
            -
                           end
         | 
| 138 | 
            -
                           val.each do |rkey, rval|
         | 
| 139 | 
            -
                              case rkey
         | 
| 140 | 
            -
                              when 'max', 'min', 'max-ex', 'min-ex'
         | 
| 141 | 
            -
                                 unless rval.is_a?(@klass)
         | 
| 142 | 
            -
                                    typename = Kwalify.word(@type) || @type
         | 
| 143 | 
            -
                                    #* key=:range_type_unmatch  msg="not a %s."
         | 
| 144 | 
            -
                                    raise schema_error(:range_type_unmatch, rule, "#{curr_path}/#{rkey}", rval, [typename])
         | 
| 145 | 
            -
                                 end
         | 
| 146 | 
            -
                              else
         | 
| 147 | 
            -
                                 #* key=:range_undefined  msg="undefined key."
         | 
| 148 | 
            -
                                 raise schema_error(:range_undefined, rule, "#{curr_path}/#{rkey}", "#{rkey}:")
         | 
| 149 | 
            -
                              end
         | 
| 150 | 
            -
                           end
         | 
| 151 | 
            -
                           if val.key?('max') && val.key?('max-ex')
         | 
| 152 | 
            -
                              #* key=:range_twomax msg="both 'max' and 'max-ex' are not available at once."
         | 
| 153 | 
            -
                              raise schema_error(:range_twomax, rule, curr_path, nil)
         | 
| 154 | 
            -
                           end
         | 
| 155 | 
            -
                           if val.key?('min') && val.key?('min-ex')
         | 
| 156 | 
            -
                              #* key=:range_twomin msg="both 'min' and 'min-ex' are not available at once."
         | 
| 157 | 
            -
                              raise schema_error(:range_twomin, rule, curr_path, nil)
         | 
| 158 | 
            -
                           end
         | 
| 159 144 |  | 
| 160 | 
            -
             | 
| 161 | 
            -
             | 
| 162 | 
            -
             | 
| 163 | 
            -
             | 
| 164 | 
            -
             | 
| 165 | 
            -
             | 
| 166 | 
            -
             | 
| 167 | 
            -
             | 
| 168 | 
            -
             | 
| 169 | 
            -
             | 
| 170 | 
            -
             | 
| 171 | 
            -
             | 
| 172 | 
            -
             | 
| 173 | 
            -
             | 
| 174 | 
            -
             | 
| 175 | 
            -
             | 
| 176 | 
            -
             | 
| 177 | 
            -
             | 
| 178 | 
            -
             | 
| 179 | 
            -
             | 
| 180 | 
            -
             | 
| 181 | 
            -
             | 
| 182 | 
            -
             | 
| 183 | 
            -
                              #* key=:length_twomax msg="both 'max' and 'max-ex' are not available at once."
         | 
| 184 | 
            -
                              raise schema_error(:length_twomax, rule, curr_path, nil)
         | 
| 185 | 
            -
                           end
         | 
| 186 | 
            -
                           if val.key?('min') && val.key?('min-ex')
         | 
| 187 | 
            -
                              #* key=:length_twomin msg="both 'min' and 'min-ex' are not available at once."
         | 
| 188 | 
            -
                              raise schema_error(:length_twomin, rule, curr_path, nil)
         | 
| 189 | 
            -
                           end
         | 
| 145 | 
            +
                  def _init_enum_value(val, rule, path)
         | 
| 146 | 
            +
                     @enum = val
         | 
| 147 | 
            +
                     unless val.is_a?(Array)
         | 
| 148 | 
            +
                        #* key=:enum_notseq  msg="not a sequence."
         | 
| 149 | 
            +
                        raise schema_error(:enum_notseq, rule, "#{path}/enum", val)
         | 
| 150 | 
            +
                     end
         | 
| 151 | 
            +
                     if Types.collection_type?(@type)   # unless Kwalify.scalar_class?(@type_class)
         | 
| 152 | 
            +
                        #* key=:enum_notscalar  msg="not available with seq or map."
         | 
| 153 | 
            +
                        raise schema_error(:enum_notscalar, rule, path, 'enum:')
         | 
| 154 | 
            +
                     end
         | 
| 155 | 
            +
                     elem_table = {}
         | 
| 156 | 
            +
                     @enum.each do |elem|
         | 
| 157 | 
            +
                        unless elem.is_a?(@type_class)
         | 
| 158 | 
            +
                           #* key=:enum_type_unmatch  msg="%s type expected."
         | 
| 159 | 
            +
                           raise schema_error(:enum_type_unmatch, rule, "#{path}/enum", elem, [Kwalify.word(@type)])
         | 
| 160 | 
            +
                        end
         | 
| 161 | 
            +
                        if elem_table[elem]
         | 
| 162 | 
            +
                           #* key=:enum_duplicate  msg="duplicated enum value."
         | 
| 163 | 
            +
                           raise schema_error(:enum_duplicate, rule, "#{path}/enum", elem.to_s)
         | 
| 164 | 
            +
                        end
         | 
| 165 | 
            +
                        elem_table[elem] = true
         | 
| 166 | 
            +
                     end
         | 
| 167 | 
            +
                  end
         | 
| 190 168 |  | 
| 191 | 
            -
                        when "ident"
         | 
| 192 | 
            -
                           @ident = val
         | 
| 193 | 
            -
                           @required = true
         | 
| 194 | 
            -
                           unless val.is_a?(Boolean)
         | 
| 195 | 
            -
                              #* key=:ident_notbool  msg="not a boolean."
         | 
| 196 | 
            -
                              raise schema_error(:ident_notbool, rule, curr_path, val)
         | 
| 197 | 
            -
                           end
         | 
| 198 | 
            -
                           if @type == 'map' || @type == 'seq'
         | 
| 199 | 
            -
                              #* key=:ident_notscalar  msg="is available only with a scalar type."
         | 
| 200 | 
            -
                              raise schema_error(:ident_notscalar, rule, path, "ident:")
         | 
| 201 | 
            -
                           end
         | 
| 202 | 
            -
                           if path.empty?
         | 
| 203 | 
            -
                              #* key=:ident_onroot  msg="is not available on root element."
         | 
| 204 | 
            -
                              raise schema_error(:ident_onroot, rule, "/", "ident:")
         | 
| 205 | 
            -
                           end
         | 
| 206 | 
            -
                           unless @parent && @parent.type == 'map'
         | 
| 207 | 
            -
                              #* key=:ident_notmap  msg="is available only with an element of mapping."
         | 
| 208 | 
            -
                              raise schema_error(:ident_notmap, rule, path, "ident:")
         | 
| 209 | 
            -
                           end
         | 
| 210 169 |  | 
| 211 | 
            -
             | 
| 212 | 
            -
             | 
| 213 | 
            -
             | 
| 214 | 
            -
             | 
| 215 | 
            -
             | 
| 216 | 
            -
             | 
| 217 | 
            -
             | 
| 218 | 
            -
             | 
| 219 | 
            -
             | 
| 220 | 
            -
             | 
| 221 | 
            -
             | 
| 222 | 
            -
             | 
| 223 | 
            -
             | 
| 224 | 
            -
             | 
| 225 | 
            -
             | 
| 226 | 
            -
             | 
| 227 | 
            -
             | 
| 228 | 
            -
                           #end
         | 
| 229 | 
            -
             | 
| 230 | 
            -
                        when "sequence"
         | 
| 231 | 
            -
                           if val != nil && !val.is_a?(Array)
         | 
| 232 | 
            -
                              #* key=:sequence_notseq  msg="not a sequence."
         | 
| 233 | 
            -
                              raise schema_error(:sequence_notseq, rule, curr_path, val)
         | 
| 234 | 
            -
                           elsif val == nil || val.empty?
         | 
| 235 | 
            -
                              #* key=:sequence_noelem  msg="required one element."
         | 
| 236 | 
            -
                              raise schema_error(:sequence_noelem, rule, curr_path, val)
         | 
| 237 | 
            -
                           elsif val.length > 1
         | 
| 238 | 
            -
                              #* key=:sequence_toomany  msg="required just one element."
         | 
| 239 | 
            -
                              raise schema_error(:sequence_toomany, rule, curr_path, val)
         | 
| 240 | 
            -
                           else
         | 
| 241 | 
            -
                              elem = val[0]
         | 
| 242 | 
            -
                              elem ||= {}
         | 
| 243 | 
            -
                              i = 0   # or 1?  *index*
         | 
| 244 | 
            -
                              rule = rule_table[elem.__id__]
         | 
| 245 | 
            -
                              rule ||= Rule.new(nil, self).configure(elem, "#{curr_path}/#{i}", rule_table)
         | 
| 246 | 
            -
                              @sequence = [ rule ]
         | 
| 247 | 
            -
                           end
         | 
| 170 | 
            +
                  def _init_assert_value(val, rule, path)
         | 
| 171 | 
            +
                     @assert = val
         | 
| 172 | 
            +
                     unless val.is_a?(String)
         | 
| 173 | 
            +
                        #* key=:assert_notstr  msg="not a string."
         | 
| 174 | 
            +
                        raise schema_error(:assert_notstr, rule, "#{path}/assert", val)
         | 
| 175 | 
            +
                     end
         | 
| 176 | 
            +
                     unless val =~ /\bval\b/
         | 
| 177 | 
            +
                        #* key=:assert_noval  msg="'val' is not used."
         | 
| 178 | 
            +
                        raise schema_error(:assert_noval, rule, "#{path}/assert", val)
         | 
| 179 | 
            +
                     end
         | 
| 180 | 
            +
                     begin
         | 
| 181 | 
            +
                        @assert_proc = eval "proc { |val| #{val} }"
         | 
| 182 | 
            +
                     rescue SyntaxError => ex
         | 
| 183 | 
            +
                        #* key=:assert_syntaxerr  msg="expression syntax error."
         | 
| 184 | 
            +
                        raise schema_error(:assert_syntaxerr, rule, "#{path}/assert", val)
         | 
| 185 | 
            +
                     end
         | 
| 186 | 
            +
                  end
         | 
| 248 187 |  | 
| 249 | 
            -
             | 
| 250 | 
            -
             | 
| 251 | 
            -
             | 
| 252 | 
            -
             | 
| 253 | 
            -
             | 
| 254 | 
            -
             | 
| 255 | 
            -
             | 
| 256 | 
            -
             | 
| 257 | 
            -
             | 
| 258 | 
            -
             | 
| 259 | 
            -
             | 
| 260 | 
            -
             | 
| 261 | 
            -
             | 
| 262 | 
            -
             | 
| 263 | 
            -
             | 
| 264 | 
            -
             | 
| 265 | 
            -
             | 
| 266 | 
            -
             | 
| 267 | 
            -
             | 
| 268 | 
            -
                                 rule = rule_table[elem.__id__]
         | 
| 269 | 
            -
                                 rule ||= Rule.new(nil, self).configure(elem, "#{curr_path}/#{key}", rule_table)
         | 
| 270 | 
            -
                                 if key == '='
         | 
| 271 | 
            -
                                    @mapping.default = rule
         | 
| 272 | 
            -
                                 else
         | 
| 273 | 
            -
                                    @mapping[key] = rule
         | 
| 274 | 
            -
                                 end
         | 
| 275 | 
            -
                              end if val
         | 
| 188 | 
            +
             | 
| 189 | 
            +
                  def _init_range_value(val, rule, path)
         | 
| 190 | 
            +
                     @range = val
         | 
| 191 | 
            +
                     curr_path = "#{path}/range"
         | 
| 192 | 
            +
                     unless val.is_a?(Hash)
         | 
| 193 | 
            +
                        #* key=:range_notmap  msg="not a mapping."
         | 
| 194 | 
            +
                        raise schema_error(:range_notmap, rule, curr_path, val)
         | 
| 195 | 
            +
                     end
         | 
| 196 | 
            +
                     if Types.collection_type?(@type) || @type == 'bool'
         | 
| 197 | 
            +
                        #* key=:range_notscalar  msg="is available only with scalar type."
         | 
| 198 | 
            +
                        raise schema_error(:range_notscalar, rule, path, 'range:')
         | 
| 199 | 
            +
                     end
         | 
| 200 | 
            +
                     val.each do |k, v|
         | 
| 201 | 
            +
                        case k
         | 
| 202 | 
            +
                        when 'max', 'min', 'max-ex', 'min-ex'
         | 
| 203 | 
            +
                           unless v.is_a?(@type_class)
         | 
| 204 | 
            +
                              typename = Kwalify.word(@type) || @type
         | 
| 205 | 
            +
                              #* key=:range_type_unmatch  msg="not a %s."
         | 
| 206 | 
            +
                              raise schema_error(:range_type_unmatch, rule, "#{curr_path}/#{k}", v, [typename])
         | 
| 276 207 | 
             
                           end
         | 
| 208 | 
            +
                        else
         | 
| 209 | 
            +
                           #* key=:range_undefined  msg="undefined key."
         | 
| 210 | 
            +
                           raise schema_error(:range_undefined, rule, "#{curr_path}/#{k}", "#{k}:")
         | 
| 211 | 
            +
                        end
         | 
| 212 | 
            +
                     end
         | 
| 213 | 
            +
                     if val.key?('max') && val.key?('max-ex')
         | 
| 214 | 
            +
                        #* key=:range_twomax  msg="both 'max' and 'max-ex' are not available at once."
         | 
| 215 | 
            +
                        raise schema_error(:range_twomax, rule, curr_path, nil)
         | 
| 216 | 
            +
                     end
         | 
| 217 | 
            +
                     if val.key?('min') && val.key?('min-ex')
         | 
| 218 | 
            +
                        #* key=:range_twomin  msg="both 'min' and 'min-ex' are not available at once."
         | 
| 219 | 
            +
                        raise schema_error(:range_twomin, rule, curr_path, nil)
         | 
| 220 | 
            +
                     end
         | 
| 221 | 
            +
                     max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
         | 
| 222 | 
            +
                     if max
         | 
| 223 | 
            +
                        if min && max < min
         | 
| 224 | 
            +
                           #* key=:range_maxltmin  msg="max '%s' is less than min '%s'."
         | 
| 225 | 
            +
                           raise validate_error(:range_maxltmin, rule, curr_path, nil, [max, min])
         | 
| 226 | 
            +
                        elsif min_ex && max <= min_ex
         | 
| 227 | 
            +
                           #* key=:range_maxleminex  msg="max '%s' is less than or equal to min-ex '%s'."
         | 
| 228 | 
            +
                           raise validate_error(:range_maxleminex, rule, curr_path, nil, [max, min_ex])
         | 
| 229 | 
            +
                        end
         | 
| 230 | 
            +
                     elsif max_ex
         | 
| 231 | 
            +
                        if min && max_ex <= min
         | 
| 232 | 
            +
                           #* key=:range_maxexlemin msg="max-ex '%s' is less than or equal to min '%s'."
         | 
| 233 | 
            +
                           raise validate_error(:range_maxexlemin, rule, curr_path, nil, [max_ex, min])
         | 
| 234 | 
            +
                        elsif min_ex && max_ex <= min_ex
         | 
| 235 | 
            +
                           #* key=:range_maxexleminex msg="max-ex '%s' is less than or equal to min-ex '%s'."
         | 
| 236 | 
            +
                           raise validate_error(:range_maxexleminex, rule, curr_path, nil, [max_ex, min_ex])
         | 
| 237 | 
            +
                        end
         | 
| 238 | 
            +
                     end
         | 
| 239 | 
            +
                  end
         | 
| 277 240 |  | 
| 241 | 
            +
             | 
| 242 | 
            +
                  def _init_length_value(val, rule, path)
         | 
| 243 | 
            +
                     @length = val
         | 
| 244 | 
            +
                     curr_path = "#{path}/length"
         | 
| 245 | 
            +
                     unless val.is_a?(Hash)
         | 
| 246 | 
            +
                        #* key=:length_notmap  msg="not a mapping."
         | 
| 247 | 
            +
                        raise schema_error(:length_notmap, rule, curr_path, val)
         | 
| 248 | 
            +
                     end
         | 
| 249 | 
            +
                     unless @type == 'str' || @type == 'text'
         | 
| 250 | 
            +
                        #* key=:length_nottext  msg="is available only with string or text."
         | 
| 251 | 
            +
                        raise schema_error(:length_nottext, rule, path, 'length:')
         | 
| 252 | 
            +
                     end
         | 
| 253 | 
            +
                     val.each do |k, v|
         | 
| 254 | 
            +
                        case k
         | 
| 255 | 
            +
                        when 'max', 'min', 'max-ex', 'min-ex'
         | 
| 256 | 
            +
                           unless v.is_a?(Integer)
         | 
| 257 | 
            +
                              #* key=:length_notint  msg="not an integer."
         | 
| 258 | 
            +
                              raise schema_error(:length_notint, rule, "#{curr_path}/#{k}", v)
         | 
| 259 | 
            +
                           end
         | 
| 278 260 | 
             
                        else
         | 
| 279 | 
            -
                           #* key=: | 
| 280 | 
            -
                           raise schema_error(: | 
| 261 | 
            +
                           #* key=:length_undefined  msg="undefined key."
         | 
| 262 | 
            +
                           raise schema_error(:length_undefined, rule, "#{curr_path}/#{k}", "#{k}:")
         | 
| 263 | 
            +
                        end
         | 
| 264 | 
            +
                     end
         | 
| 265 | 
            +
                     if val.key?('max') && val.key?('max-ex')
         | 
| 266 | 
            +
                        #* key=:length_twomax msg="both 'max' and 'max-ex' are not available at once."
         | 
| 267 | 
            +
                        raise schema_error(:length_twomax, rule, curr_path, nil)
         | 
| 268 | 
            +
                     end
         | 
| 269 | 
            +
                     if val.key?('min') && val.key?('min-ex')
         | 
| 270 | 
            +
                        #* key=:length_twomin msg="both 'min' and 'min-ex' are not available at once."
         | 
| 271 | 
            +
                        raise schema_error(:length_twomin, rule, curr_path, nil)
         | 
| 272 | 
            +
                     end
         | 
| 273 | 
            +
                     max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
         | 
| 274 | 
            +
                     if max
         | 
| 275 | 
            +
                        if min && max < min
         | 
| 276 | 
            +
                           #* key=:length_maxltmin  msg="max '%s' is less than min '%s'."
         | 
| 277 | 
            +
                           raise validate_error(:length_maxltmin, rule, curr_path, nil, [max, min])
         | 
| 278 | 
            +
                        elsif min_ex && max <= min_ex
         | 
| 279 | 
            +
                           #* key=:length_maxleminex  msg="max '%s' is less than or equal to min-ex '%s'."
         | 
| 280 | 
            +
                           raise validate_error(:length_maxleminex, rule, curr_path, nil, [max, min_ex])
         | 
| 281 | 
            +
                        end
         | 
| 282 | 
            +
                     elsif max_ex
         | 
| 283 | 
            +
                        if min && max_ex <= min
         | 
| 284 | 
            +
                           #* key=:length_maxexlemin  msg="max-ex '%s' is less than or equal to min '%s'."
         | 
| 285 | 
            +
                           raise validate_error(:length_maxexlemin, rule, curr_path, nil, [max_ex, min])
         | 
| 286 | 
            +
                        elsif min_ex && max_ex <= min_ex
         | 
| 287 | 
            +
                           #* key=:length_maxexleminex  msg="max-ex '%s' is less than or equal to min-ex '%s'."
         | 
| 288 | 
            +
                           raise validate_error(:length_maxexleminex, rule, curr_path, nil, [max_ex, min_ex])
         | 
| 289 | 
            +
                        end
         | 
| 290 | 
            +
                     end
         | 
| 291 | 
            +
                  end
         | 
| 292 | 
            +
             | 
| 293 | 
            +
             | 
| 294 | 
            +
                  def _init_ident_value(val, rule, path)
         | 
| 295 | 
            +
                     @ident = val
         | 
| 296 | 
            +
                     @required = true
         | 
| 297 | 
            +
                     unless val.is_a?(Boolean)
         | 
| 298 | 
            +
                        #* key=:ident_notbool  msg="not a boolean."
         | 
| 299 | 
            +
                        raise schema_error(:ident_notbool, rule, "#{path}/ident", val)
         | 
| 300 | 
            +
                     end
         | 
| 301 | 
            +
                     if @type == 'map' || @type == 'seq'
         | 
| 302 | 
            +
                        #* key=:ident_notscalar  msg="is available only with a scalar type."
         | 
| 303 | 
            +
                        raise schema_error(:ident_notscalar, rule, path, "ident:")
         | 
| 304 | 
            +
                     end
         | 
| 305 | 
            +
                     if path.empty?
         | 
| 306 | 
            +
                        #* key=:ident_onroot  msg="is not available on root element."
         | 
| 307 | 
            +
                        raise schema_error(:ident_onroot, rule, "/", "ident:")
         | 
| 308 | 
            +
                     end
         | 
| 309 | 
            +
                     unless @parent && @parent.type == 'map'
         | 
| 310 | 
            +
                        #* key=:ident_notmap  msg="is available only with an element of mapping."
         | 
| 311 | 
            +
                        raise schema_error(:ident_notmap, rule, path, "ident:")
         | 
| 312 | 
            +
                     end
         | 
| 313 | 
            +
                  end
         | 
| 314 | 
            +
             | 
| 315 | 
            +
             | 
| 316 | 
            +
                  def _init_unique_value(val, rule, path)
         | 
| 317 | 
            +
                     @unique = val
         | 
| 318 | 
            +
                     unless val.is_a?(Boolean)
         | 
| 319 | 
            +
                        #* key=:unique_notbool  msg="not a boolean."
         | 
| 320 | 
            +
                        raise schema_error(:unique_notbool, rule, "#{path}/unique", val)
         | 
| 321 | 
            +
                     end
         | 
| 322 | 
            +
                     if @type == 'map' || @type == 'seq'
         | 
| 323 | 
            +
                        #* key=:unique_notscalar  msg="is available only with a scalar type."
         | 
| 324 | 
            +
                        raise schema_error(:unique_notscalar, rule, path, "unique:")
         | 
| 325 | 
            +
                     end
         | 
| 326 | 
            +
                     if path.empty?
         | 
| 327 | 
            +
                        #* key=:unique_onroot  msg="is not available on root element."
         | 
| 328 | 
            +
                        raise schema_error(:unique_onroot, rule, "/", "unique:")
         | 
| 329 | 
            +
                     end
         | 
| 330 | 
            +
                  end
         | 
| 331 | 
            +
             | 
| 332 | 
            +
             | 
| 333 | 
            +
                  def _init_sequence_value(val, rule, path, rule_table)
         | 
| 334 | 
            +
                     if val != nil && !val.is_a?(Array)
         | 
| 335 | 
            +
                        #* key=:sequence_notseq  msg="not a sequence."
         | 
| 336 | 
            +
                        raise schema_error(:sequence_notseq, rule, "#{path}/sequence", val)
         | 
| 337 | 
            +
                     elsif val == nil || val.empty?
         | 
| 338 | 
            +
                        #* key=:sequence_noelem  msg="required one element."
         | 
| 339 | 
            +
                        raise schema_error(:sequence_noelem, rule, "#{path}/sequence", val)
         | 
| 340 | 
            +
                     elsif val.length > 1
         | 
| 341 | 
            +
                        #* key=:sequence_toomany  msg="required just one element."
         | 
| 342 | 
            +
                        raise schema_error(:sequence_toomany, rule, "#{path}/sequence", val)
         | 
| 343 | 
            +
                     else
         | 
| 344 | 
            +
                        elem = val[0]
         | 
| 345 | 
            +
                        elem ||= {}
         | 
| 346 | 
            +
                        i = 0   # or 1?  *index*
         | 
| 347 | 
            +
                        rule = rule_table[elem.__id__]
         | 
| 348 | 
            +
                        rule ||= Rule.new(nil, self).init(elem, "#{path}/sequence/#{i}", rule_table)
         | 
| 349 | 
            +
                        @sequence = [ rule ]
         | 
| 350 | 
            +
                     end
         | 
| 351 | 
            +
                  end
         | 
| 352 | 
            +
             | 
| 353 | 
            +
             | 
| 354 | 
            +
                  def _init_mapping_value(val, rule, path, rule_table)
         | 
| 355 | 
            +
                     if val != nil && !val.is_a?(Hash)
         | 
| 356 | 
            +
                        #* key=:mapping_notmap  msg="not a mapping."
         | 
| 357 | 
            +
                        raise schema_error(:mapping_notmap, rule, "#{path}/mapping", val)
         | 
| 358 | 
            +
                     elsif val == nil || (val.empty? && !val.default)
         | 
| 359 | 
            +
                        #* key=:mapping_noelem  msg="required at least one element."
         | 
| 360 | 
            +
                        raise schema_error(:mapping_noelem, rule, "#{path}/mapping", val)
         | 
| 361 | 
            +
                     else
         | 
| 362 | 
            +
                        @mapping = {}
         | 
| 363 | 
            +
                        if val.default
         | 
| 364 | 
            +
                           elem = val.default  # hash
         | 
| 365 | 
            +
                           rule = rule_table[elem.__id__]
         | 
| 366 | 
            +
                           rule ||= Rule.new(nil, self).init(elem, "#{path}/mapping/=", rule_table)
         | 
| 367 | 
            +
                           @mapping.default = rule
         | 
| 281 368 | 
             
                        end
         | 
| 369 | 
            +
                        val.each do |k, v|
         | 
| 370 | 
            +
                           ##* key=:key_duplicate  msg="key duplicated."
         | 
| 371 | 
            +
                           #raise schema_error(:key_duplicate, rule, "#{path}/mapping", key) if @mapping.key?(key)
         | 
| 372 | 
            +
                           v ||= {}
         | 
| 373 | 
            +
                           rule = rule_table[v.__id__]
         | 
| 374 | 
            +
                           rule ||= Rule.new(nil, self).init(v, "#{path}/mapping/#{k}", rule_table)
         | 
| 375 | 
            +
                           if k == '='
         | 
| 376 | 
            +
                              @mapping.default = rule
         | 
| 377 | 
            +
                           else
         | 
| 378 | 
            +
                              @mapping[k] = rule
         | 
| 379 | 
            +
                           end
         | 
| 380 | 
            +
                        end if val
         | 
| 282 381 | 
             
                     end
         | 
| 382 | 
            +
                  end
         | 
| 283 383 |  | 
| 384 | 
            +
             | 
| 385 | 
            +
                  def check_confliction(hash, rule, path)
         | 
| 284 386 | 
             
                     if @type == 'seq'
         | 
| 285 387 | 
             
                        #* key=:seq_nosequence  msg="type 'seq' requires 'sequence:'."
         | 
| 286 388 | 
             
                        raise schema_error(:seq_nosequence, rule, path, nil) unless hash.key?('sequence')
         | 
| @@ -310,28 +412,7 @@ module Kwalify | |
| 310 412 | 
             
                           raise schema_error(:enum_conflict, rule, path, 'pattern:') if @pattern
         | 
| 311 413 | 
             
                        end
         | 
| 312 414 | 
             
                     end
         | 
| 313 | 
            -
             | 
| 314 | 
            -
                     return self
         | 
| 315 | 
            -
             | 
| 316 | 
            -
                  end # end of def configure
         | 
| 317 | 
            -
             | 
| 318 | 
            -
                  #attr_reader   :id
         | 
| 319 | 
            -
                  attr_reader :name
         | 
| 320 | 
            -
                  attr_reader :desc
         | 
| 321 | 
            -
                  attr_reader :enum
         | 
| 322 | 
            -
                  attr_reader :required
         | 
| 323 | 
            -
                  attr_reader :type
         | 
| 324 | 
            -
                  attr_reader :klass
         | 
| 325 | 
            -
                  attr_reader :pattern
         | 
| 326 | 
            -
                  attr_reader :sequence
         | 
| 327 | 
            -
                  attr_reader :mapping
         | 
| 328 | 
            -
                  attr_reader :assert
         | 
| 329 | 
            -
                  attr_reader :assert_proc
         | 
| 330 | 
            -
                  attr_reader :range
         | 
| 331 | 
            -
                  attr_reader :length
         | 
| 332 | 
            -
                  attr_reader :ident
         | 
| 333 | 
            -
                  attr_reader :unique
         | 
| 334 | 
            -
             | 
| 415 | 
            +
                  end
         | 
| 335 416 |  | 
| 336 417 | 
             
                  #def inspect()
         | 
| 337 418 | 
             
                  #   str = "";  level = 0;  done = {}
         | 
| @@ -340,7 +421,7 @@ module Kwalify | |
| 340 421 | 
             
                  #end
         | 
| 341 422 |  | 
| 342 423 |  | 
| 343 | 
            -
                   | 
| 424 | 
            +
                  protected
         | 
| 344 425 |  | 
| 345 426 |  | 
| 346 427 | 
             
                  def _inspect(str="", level=0, done={})
         | 
| @@ -348,9 +429,9 @@ module Kwalify | |
| 348 429 | 
             
                     str << "  " * level << "name:      #{@name}\n"             if @name     != nil
         | 
| 349 430 | 
             
                     str << "  " * level << "desc:      #{@desc}\n"             if @desc     != nil
         | 
| 350 431 | 
             
                     str << "  " * level << "type:      #{@type}\n"             if @type     != nil
         | 
| 351 | 
            -
                     str << "  " * level << "klass:     #{@ | 
| 432 | 
            +
                     str << "  " * level << "klass:     #{@type_class.name}\n"  if @type_class    != nil
         | 
| 352 433 | 
             
                     str << "  " * level << "required:  #{@required}\n"         if @required != nil
         | 
| 353 | 
            -
                     str << "  " * level << "pattern:   #{@ | 
| 434 | 
            +
                     str << "  " * level << "pattern:   #{@regexp.inspect}\n"   if @pattern  != nil
         | 
| 354 435 | 
             
                     str << "  " * level << "assert:    #{@assert}\n"           if @assert   != nil
         | 
| 355 436 | 
             
                     str << "  " * level << "ident:     #{@ident}\n"            if @ident    != nil
         | 
| 356 437 | 
             
                     str << "  " * level << "unique:    #{@unique}\n"           if @unique   != nil
         | 
| @@ -360,25 +441,31 @@ module Kwalify | |
| 360 441 | 
             
                           str << "  " * (level+1) << "- #{item}\n"
         | 
| 361 442 | 
             
                        end
         | 
| 362 443 | 
             
                     end
         | 
| 363 | 
            -
                     if @range | 
| 444 | 
            +
                     if @range != nil
         | 
| 364 445 | 
             
                        str << "  " * level
         | 
| 365 446 | 
             
                        str << "range:     { "
         | 
| 366 | 
            -
                         | 
| 367 | 
            -
                         | 
| 368 | 
            -
             | 
| 369 | 
            -
             | 
| 370 | 
            -
             | 
| 371 | 
            -
             | 
| 372 | 
            -
             | 
| 373 | 
            -
             | 
| 447 | 
            +
                        colon = ""
         | 
| 448 | 
            +
                        %w[max max-ex min min-ex].each do |key|
         | 
| 449 | 
            +
                           val = @range[key]
         | 
| 450 | 
            +
                           if val != nil
         | 
| 451 | 
            +
                              str << colon << "#{key}: #{val.inspect}"
         | 
| 452 | 
            +
                              colon = ", "
         | 
| 453 | 
            +
                           end
         | 
| 454 | 
            +
                        end
         | 
| 455 | 
            +
                        str << " }\n"
         | 
| 456 | 
            +
                     end
         | 
| 457 | 
            +
                     if @length != nil
         | 
| 374 458 | 
             
                        str << "  " * level
         | 
| 375 459 | 
             
                        str << "length:     { "
         | 
| 376 | 
            -
                         | 
| 377 | 
            -
                         | 
| 378 | 
            -
             | 
| 379 | 
            -
             | 
| 380 | 
            -
             | 
| 381 | 
            -
             | 
| 460 | 
            +
                        colon = ""
         | 
| 461 | 
            +
                        %w[max max-ex min min-ex].each do |key|
         | 
| 462 | 
            +
                           val = @length[key]
         | 
| 463 | 
            +
                           if val != nil
         | 
| 464 | 
            +
                              str << colon << "#{key}: #{val.inspect}"
         | 
| 465 | 
            +
                              colon = ", "
         | 
| 466 | 
            +
                           end
         | 
| 467 | 
            +
                        end
         | 
| 468 | 
            +
                        str << " }\n"
         | 
| 382 469 | 
             
                     end
         | 
| 383 470 | 
             
                     @sequence.each do |rule|
         | 
| 384 471 | 
             
                        if done[rule.__id__]
         |