dc-kwalify 0.7.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (209) hide show
  1. data/CHANGES.txt +252 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.txt +61 -0
  4. data/bin/kwalify +13 -0
  5. data/contrib/inline-require +179 -0
  6. data/contrib/kwalify +4160 -0
  7. data/doc/docstyle.css +188 -0
  8. data/doc/img/fig01.png +0 -0
  9. data/doc/users-guide.html +2050 -0
  10. data/doc-api/classes/CommandOptionError.html +184 -0
  11. data/doc-api/classes/CommandOptionParser.html +325 -0
  12. data/doc-api/classes/Kwalify/AssertionError.html +148 -0
  13. data/doc-api/classes/Kwalify/BaseError.html +297 -0
  14. data/doc-api/classes/Kwalify/BaseParser.html +461 -0
  15. data/doc-api/classes/Kwalify/CommandOptionError.html +168 -0
  16. data/doc-api/classes/Kwalify/ErrorHelper.html +223 -0
  17. data/doc-api/classes/Kwalify/HashInterface.html +118 -0
  18. data/doc-api/classes/Kwalify/Json.html +105 -0
  19. data/doc-api/classes/Kwalify/KwalifyError.html +111 -0
  20. data/doc-api/classes/Kwalify/Main.html +339 -0
  21. data/doc-api/classes/Kwalify/MetaValidator.html +448 -0
  22. data/doc-api/classes/Kwalify/Parser.html +155 -0
  23. data/doc-api/classes/Kwalify/PlainYamlParser/Alias.html +165 -0
  24. data/doc-api/classes/Kwalify/PlainYamlParser.html +523 -0
  25. data/doc-api/classes/Kwalify/Rule.html +433 -0
  26. data/doc-api/classes/Kwalify/SchemaError.html +148 -0
  27. data/doc-api/classes/Kwalify/SyntaxError.html +185 -0
  28. data/doc-api/classes/Kwalify/Types.html +302 -0
  29. data/doc-api/classes/Kwalify/Util/HashLike.html +246 -0
  30. data/doc-api/classes/Kwalify/Util/OrderedHash.html +330 -0
  31. data/doc-api/classes/Kwalify/Util.html +390 -0
  32. data/doc-api/classes/Kwalify/ValidationError.html +148 -0
  33. data/doc-api/classes/Kwalify/Validator.html +381 -0
  34. data/doc-api/classes/Kwalify/Yaml/Parser.html +1538 -0
  35. data/doc-api/classes/Kwalify/Yaml.html +194 -0
  36. data/doc-api/classes/Kwalify/YamlParser.html +542 -0
  37. data/doc-api/classes/Kwalify/YamlSyntaxError.html +119 -0
  38. data/doc-api/classes/Kwalify.html +292 -0
  39. data/doc-api/classes/Test/Unit.html +101 -0
  40. data/doc-api/classes/Test.html +107 -0
  41. data/doc-api/created.rid +1 -0
  42. data/doc-api/files/__/README_txt.html +172 -0
  43. data/doc-api/files/kwalify/errors_rb.html +114 -0
  44. data/doc-api/files/kwalify/main_rb.html +118 -0
  45. data/doc-api/files/kwalify/messages_rb.html +107 -0
  46. data/doc-api/files/kwalify/meta-validator_rb.html +117 -0
  47. data/doc-api/files/kwalify/parser/base_rb.html +116 -0
  48. data/doc-api/files/kwalify/parser/yaml_rb.html +117 -0
  49. data/doc-api/files/kwalify/rule_rb.html +116 -0
  50. data/doc-api/files/kwalify/types_rb.html +114 -0
  51. data/doc-api/files/kwalify/util/assert-text-equal_rb.html +115 -0
  52. data/doc-api/files/kwalify/util/hash-interface_rb.html +114 -0
  53. data/doc-api/files/kwalify/util/hashlike_rb.html +107 -0
  54. data/doc-api/files/kwalify/util/option-parser_rb.html +107 -0
  55. data/doc-api/files/kwalify/util/ordered-hash_rb.html +107 -0
  56. data/doc-api/files/kwalify/util/testcase-helper_rb.html +115 -0
  57. data/doc-api/files/kwalify/util_rb.html +107 -0
  58. data/doc-api/files/kwalify/validator_rb.html +117 -0
  59. data/doc-api/files/kwalify/yaml-parser_rb.html +117 -0
  60. data/doc-api/files/kwalify_rb.html +121 -0
  61. data/doc-api/fr_class_index.html +57 -0
  62. data/doc-api/fr_file_index.html +45 -0
  63. data/doc-api/fr_method_index.html +168 -0
  64. data/doc-api/index.html +24 -0
  65. data/doc-api/rdoc-style.css +208 -0
  66. data/examples/address-book/Makefile +10 -0
  67. data/examples/address-book/address-book.schema.yaml +45 -0
  68. data/examples/address-book/address-book.yaml +36 -0
  69. data/examples/data-binding/BABEL.data.yaml +63 -0
  70. data/examples/data-binding/BABEL.schema.yaml +31 -0
  71. data/examples/data-binding/Makefile +8 -0
  72. data/examples/data-binding/Rakefile +13 -0
  73. data/examples/data-binding/main.rb +27 -0
  74. data/examples/invoice/Makefile +9 -0
  75. data/examples/invoice/invoice.schema.yaml +43 -0
  76. data/examples/invoice/invoice.yaml +32 -0
  77. data/examples/tapkit/Makefile +10 -0
  78. data/examples/tapkit/main.rb +7 -0
  79. data/examples/tapkit/tapkit.schema.yaml +146 -0
  80. data/examples/tapkit/tapkit.yaml +85 -0
  81. data/lib/kwalify/errors.rb +127 -0
  82. data/lib/kwalify/kwalify.schema.yaml +58 -0
  83. data/lib/kwalify/main.rb +442 -0
  84. data/lib/kwalify/messages.rb +173 -0
  85. data/lib/kwalify/meta-validator.rb +275 -0
  86. data/lib/kwalify/parser/base.rb +127 -0
  87. data/lib/kwalify/parser/yaml.rb +841 -0
  88. data/lib/kwalify/rule.rb +559 -0
  89. data/lib/kwalify/templates/genclass-java.eruby +222 -0
  90. data/lib/kwalify/templates/genclass-php.eruby +104 -0
  91. data/lib/kwalify/templates/genclass-ruby.eruby +113 -0
  92. data/lib/kwalify/types.rb +156 -0
  93. data/lib/kwalify/util/assert-text-equal.rb +46 -0
  94. data/lib/kwalify/util/hash-interface.rb +18 -0
  95. data/lib/kwalify/util/hashlike.rb +51 -0
  96. data/lib/kwalify/util/option-parser.rb +220 -0
  97. data/lib/kwalify/util/ordered-hash.rb +57 -0
  98. data/lib/kwalify/util/testcase-helper.rb +112 -0
  99. data/lib/kwalify/util.rb +158 -0
  100. data/lib/kwalify/validator.rb +282 -0
  101. data/lib/kwalify/yaml-parser.rb +870 -0
  102. data/lib/kwalify.rb +67 -0
  103. data/setup.rb +1585 -0
  104. data/test/Rookbook.yaml +10 -0
  105. data/test/data/users-guide/AddressBook.java.expected +40 -0
  106. data/test/data/users-guide/BABEL.data.yaml +24 -0
  107. data/test/data/users-guide/BABEL.schema.yaml +30 -0
  108. data/test/data/users-guide/ExampleAddressBook.java +47 -0
  109. data/test/data/users-guide/Group.java.expected +24 -0
  110. data/test/data/users-guide/Person.java.expected +44 -0
  111. data/test/data/users-guide/address_book.rb +52 -0
  112. data/test/data/users-guide/address_book.schema.yaml +28 -0
  113. data/test/data/users-guide/address_book.yaml +27 -0
  114. data/test/data/users-guide/answers-schema.yaml +12 -0
  115. data/test/data/users-guide/answers-validator.rb +52 -0
  116. data/test/data/users-guide/babel_genclass.result +26 -0
  117. data/test/data/users-guide/config.schema.yaml +7 -0
  118. data/test/data/users-guide/config.yaml +4 -0
  119. data/test/data/users-guide/document01a.yaml +3 -0
  120. data/test/data/users-guide/document01b.yaml +3 -0
  121. data/test/data/users-guide/document02a.yaml +4 -0
  122. data/test/data/users-guide/document02b.yaml +4 -0
  123. data/test/data/users-guide/document03a.yaml +6 -0
  124. data/test/data/users-guide/document03b.yaml +6 -0
  125. data/test/data/users-guide/document04a.yaml +9 -0
  126. data/test/data/users-guide/document04b.yaml +9 -0
  127. data/test/data/users-guide/document05a.yaml +11 -0
  128. data/test/data/users-guide/document05b.yaml +12 -0
  129. data/test/data/users-guide/document06a.yaml +15 -0
  130. data/test/data/users-guide/document06b.yaml +16 -0
  131. data/test/data/users-guide/document07a.yaml +9 -0
  132. data/test/data/users-guide/document07b.yaml +7 -0
  133. data/test/data/users-guide/document12a.json +10 -0
  134. data/test/data/users-guide/document12b.json +6 -0
  135. data/test/data/users-guide/document13a.yaml +17 -0
  136. data/test/data/users-guide/document14a.yaml +3 -0
  137. data/test/data/users-guide/document14b.yaml +3 -0
  138. data/test/data/users-guide/document15a.yaml +6 -0
  139. data/test/data/users-guide/document15b.yaml +5 -0
  140. data/test/data/users-guide/example_address_book.rb +10 -0
  141. data/test/data/users-guide/example_address_book_java.result +32 -0
  142. data/test/data/users-guide/example_address_book_ruby.result +31 -0
  143. data/test/data/users-guide/genclass_java.result +4 -0
  144. data/test/data/users-guide/howto-validation-with-parsing.rb +28 -0
  145. data/test/data/users-guide/howto-validation.rb +25 -0
  146. data/test/data/users-guide/howto3.rb +6 -0
  147. data/test/data/users-guide/howto3.result +5 -0
  148. data/test/data/users-guide/howto3.yaml +8 -0
  149. data/test/data/users-guide/howto5_databinding.result +111 -0
  150. data/test/data/users-guide/invalid01.result +3 -0
  151. data/test/data/users-guide/invalid02.result +5 -0
  152. data/test/data/users-guide/invalid03.result +5 -0
  153. data/test/data/users-guide/invalid04.result +4 -0
  154. data/test/data/users-guide/invalid05.result +11 -0
  155. data/test/data/users-guide/invalid06.result +4 -0
  156. data/test/data/users-guide/invalid07.result +3 -0
  157. data/test/data/users-guide/invalid08.result +3 -0
  158. data/test/data/users-guide/invalid12.json +8 -0
  159. data/test/data/users-guide/invalid14.result +4 -0
  160. data/test/data/users-guide/invalid15.result +4 -0
  161. data/test/data/users-guide/loadbabel.rb +27 -0
  162. data/test/data/users-guide/loadconfig.rb +16 -0
  163. data/test/data/users-guide/loadconfig.result +6 -0
  164. data/test/data/users-guide/models.rb +22 -0
  165. data/test/data/users-guide/option_ha.result +6 -0
  166. data/test/data/users-guide/option_ha_genclass_java.result +7 -0
  167. data/test/data/users-guide/schema01.yaml +3 -0
  168. data/test/data/users-guide/schema02.yaml +12 -0
  169. data/test/data/users-guide/schema03.yaml +9 -0
  170. data/test/data/users-guide/schema04.yaml +20 -0
  171. data/test/data/users-guide/schema05.yaml +29 -0
  172. data/test/data/users-guide/schema06.yaml +11 -0
  173. data/test/data/users-guide/schema12.json +12 -0
  174. data/test/data/users-guide/schema13.yaml +13 -0
  175. data/test/data/users-guide/schema14.yaml +5 -0
  176. data/test/data/users-guide/schema15.yaml +21 -0
  177. data/test/data/users-guide/valid01.result +2 -0
  178. data/test/data/users-guide/valid02.result +2 -0
  179. data/test/data/users-guide/valid03.result +2 -0
  180. data/test/data/users-guide/valid04.result +2 -0
  181. data/test/data/users-guide/valid05.result +2 -0
  182. data/test/data/users-guide/valid06.result +2 -0
  183. data/test/data/users-guide/valid07.result +2 -0
  184. data/test/data/users-guide/valid08.result +2 -0
  185. data/test/data/users-guide/valid12.result +2 -0
  186. data/test/data/users-guide/valid13.result +2 -0
  187. data/test/data/users-guide/valid14.result +2 -0
  188. data/test/data/users-guide/valid15.result +2 -0
  189. data/test/data/users-guide/validate08.rb +37 -0
  190. data/test/test-action.rb +78 -0
  191. data/test/test-action.yaml +738 -0
  192. data/test/test-databinding.rb +83 -0
  193. data/test/test-databinding.yaml +339 -0
  194. data/test/test-main.rb +157 -0
  195. data/test/test-main.yaml +415 -0
  196. data/test/test-metavalidator.rb +80 -0
  197. data/test/test-metavalidator.yaml +1179 -0
  198. data/test/test-parser-yaml.rb +57 -0
  199. data/test/test-parser-yaml.yaml +1749 -0
  200. data/test/test-rule.rb +26 -0
  201. data/test/test-rule.yaml +317 -0
  202. data/test/test-users-guide.rb +75 -0
  203. data/test/test-util.rb +125 -0
  204. data/test/test-validator.rb +95 -0
  205. data/test/test-validator.yaml +986 -0
  206. data/test/test-yaml-parser.rb +47 -0
  207. data/test/test-yaml-parser.yaml +1226 -0
  208. data/test/test.rb +61 -0
  209. metadata +274 -0
@@ -0,0 +1,282 @@
1
+ ###
2
+ ### $Rev$
3
+ ### $Release: 0.7.2 $
4
+ ### copyright(c) 2005-2010 kuwata-lab all rights reserved.
5
+ ###
6
+
7
+ require 'kwalify/messages'
8
+ require 'kwalify/errors'
9
+ require 'kwalify/types'
10
+ require 'kwalify/rule'
11
+
12
+ module Kwalify
13
+
14
+ ##
15
+ ## validate YAML document
16
+ ##
17
+ ## ex1. validate yaml document
18
+ ## schema = YAML.load_file('schema.yaml')
19
+ ## validator = Kwalify::Validator.new(schema)
20
+ ## document = YAML.load_file('document.yaml')
21
+ ## erros = validator.validate(document)
22
+ ## if errors && !errors.empty?
23
+ ## errors.each do |err|
24
+ ## puts "- [#{err.path}] #{err.message}"
25
+ ## end
26
+ ## end
27
+ ##
28
+ ## ex2. validate with parsing
29
+ ## schema = YAML.load_file('schema.yaml')
30
+ ## validator = Kwalify::Validator.new(schema)
31
+ ## parser = Kwalify::Yaml::Parser.new(validator)
32
+ ## document = parser.parse(File.read('document.yaml'))
33
+ ## errors = parser.errors
34
+ ## if errors && errors.empty?
35
+ ## errors.each do |e|
36
+ ## puts "#{e.linenum}:#{e.column} [#{e.path}] #{e.message}"
37
+ ## end
38
+ ## end
39
+ ##
40
+ class Validator
41
+ include Kwalify::ErrorHelper
42
+
43
+
44
+ def initialize(hash_or_rule, &block)
45
+ obj = hash_or_rule
46
+ @rule = (obj.nil? || obj.is_a?(Rule)) ? obj : Rule.new(obj)
47
+ @block = block
48
+ end
49
+ attr_reader :rule
50
+
51
+
52
+ def _inspect
53
+ @rule._inspect
54
+ end
55
+
56
+
57
+ def validate(value)
58
+ path = ''; errors = []; done = {}; uniq_table = nil
59
+ _validate(value, @rule, path, errors, done, uniq_table)
60
+ return errors
61
+ end
62
+
63
+
64
+ protected
65
+
66
+
67
+ def validate_hook(value, rule, path, errors)
68
+ ## may be overrided by subclass
69
+ end
70
+
71
+
72
+ public
73
+
74
+
75
+ def _validate(value, rule, path, errors, done, uniq_table, recursive=true)
76
+ #if Types.collection?(value)
77
+ if !Types.scalar?(value)
78
+ #if done[value.__id__]
79
+ # rule2 = done[value.__id__]
80
+ # if rule2.is_a?(Rule)
81
+ # return if rule.equal?(rule2)
82
+ # done[value.__id__] = [rule2, rule]
83
+ # elsif rule2.is_a?(Array)
84
+ # return if rule2.any? {|r| r.equal?(rule)}
85
+ # done[value.__id__] << rule
86
+ # else
87
+ # raise "unreachable"
88
+ # end
89
+ #end
90
+ return if done[value.__id__] # avoid infinite loop
91
+ done[value.__id__] = rule
92
+ end
93
+ if rule.required && value.nil?
94
+ #* key=:required_novalue msg="value required but none."
95
+ errors << validate_error(:required_novalue, rule, path, value)
96
+ return
97
+ end
98
+ if rule.type_class && !value.nil? && !value.is_a?(rule.type_class)
99
+ unless rule.classobj && value.is_a?(rule.classobj)
100
+ #* key=:type_unmatch msg="not a %s."
101
+ errors << validate_error(:type_unmatch, rule, path, value, [Kwalify.word(rule.type)])
102
+ return
103
+ end
104
+ end
105
+ #
106
+ n = errors.length
107
+ if rule.sequence
108
+ _validate_sequence(value, rule, path, errors, done, uniq_table, recursive)
109
+ elsif rule.mapping
110
+ _validate_mapping(value, rule, path, errors, done, uniq_table, recursive)
111
+ else
112
+ _validate_scalar(value, rule, path, errors, done, uniq_table)
113
+ end
114
+ return unless errors.length == n
115
+ #
116
+ #path_str = path.is_a?(Array) ? '/'+path.join('/') : path
117
+ #validate_hook(value, rule, path_str, errors)
118
+ #@block.call(value, rule, path_str, errors) if @block
119
+ validate_hook(value, rule, path, errors)
120
+ @block.call(value, rule, path, errors) if @block
121
+ end
122
+
123
+
124
+ private
125
+
126
+
127
+ def _validate_sequence(list, seq_rule, path, errors, done, uniq_table, recursive=true)
128
+ assert_error("seq_rule.sequence.class==#{seq_rule.sequence.class.name} (expected Array)") unless seq_rule.sequence.is_a?(Array)
129
+ assert_error("seq_rule.sequence.length==#{seq_rule.sequence.length} (expected 1)") unless seq_rule.sequence.length == 1
130
+ return if list.nil? || !recursive
131
+ rule = seq_rule.sequence[0]
132
+ uniq_table = rule._uniqueness_check_table()
133
+ list.each_with_index do |val, i|
134
+ child_path = path.is_a?(Array) ? path + [i] : "#{path}/#{i}"
135
+ _validate(val, rule, child_path, errors, done, uniq_table) ## validate recursively
136
+ end
137
+ end
138
+
139
+
140
+ def _validate_mapping(hash, map_rule, path, errors, done, uniq_table, recursive=true)
141
+ assert_error("map_rule.mapping.class==#{map_rule.mapping.class.name} (expected Hash)") unless map_rule.mapping.is_a?(Hash)
142
+ return if hash.nil?
143
+ return if !recursive
144
+ _validate_mapping_required_keys(hash, map_rule, path, errors)
145
+ hash.each do |key, val|
146
+ rule = map_rule.mapping[key]
147
+ child_path = path.is_a?(Array) ? path+[key] : "#{path}/#{key}"
148
+ unless rule
149
+ #* key=:key_undefined msg="key '%s' is undefined."
150
+ errors << validate_error(:key_undefined, rule, child_path, hash, ["#{key}:"])
151
+ ##* key=:key_undefined msg="undefined key."
152
+ #errors << validate_error(:key_undefined, rule, child_path, "#{key}:")
153
+ else
154
+ _validate(val, rule, child_path, errors, done,
155
+ uniq_table ? uniq_table[key] : nil) ## validate recursively
156
+ end
157
+ end
158
+ end
159
+
160
+
161
+ def _validate_mapping_required_keys(hash, map_rule, path, errors) #:nodoc:
162
+ map_rule.mapping.each do |key, rule|
163
+ #next unless rule.required
164
+ #val = hash.is_a?(Hash) ? hash[key] : hash.instance_variable_get("@#{key}")
165
+ #if val.nil?
166
+ if rule.required && hash[key].nil? # or !hash.key?(key)
167
+ #* key=:required_nokey msg="key '%s:' is required."
168
+ errors << validate_error(:required_nokey, rule, path, hash, [key])
169
+ end
170
+ end
171
+ end
172
+ public :_validate_mapping_required_keys
173
+
174
+
175
+ def _validate_scalar(value, rule, path, errors, done, uniq_table)
176
+ assert_error("rule.sequence.class==#{rule.sequence.class.name} (expected NilClass)") if rule.sequence
177
+ assert_error("rule.mapping.class==#{rule.mapping.class.name} (expected NilClass)") if rule.mapping
178
+ _validate_assert( value, rule, path, errors) if rule.assert_proc
179
+ _validate_enum( value, rule, path, errors) if rule.enum
180
+ return if value.nil?
181
+ _validate_pattern(value, rule, path, errors) if rule.pattern
182
+ _validate_range( value, rule, path, errors) if rule.range
183
+ _validate_length( value, rule, path, errors) if rule.length
184
+ _validate_unique( value, rule, path, errors, uniq_table) if uniq_table
185
+ end
186
+
187
+
188
+ def _validate_unique(value, rule, path, errors, uniq_table)
189
+ assert_error "uniq_table=#{uniq_table.inspect}" unless rule.unique || rule.ident
190
+ if uniq_table.key?(value)
191
+ exist_at = uniq_table[value]
192
+ exist_at = "/#{exist_at.join('/')}" if exist_at.is_a?(Array)
193
+ #* key=:value_notunique msg="is already used at '%s'."
194
+ errors << validate_error(:value_notunique, rule, path, value, exist_at)
195
+ else
196
+ uniq_table[value] = path.dup
197
+ end
198
+ end
199
+ public :_validate_unique
200
+
201
+
202
+ def _validate_assert(value, rule, path, errors)
203
+ assert_error("rule=#{rule._inspect}") unless rule.assert_proc
204
+ unless rule.assert_proc.call(value)
205
+ #* key=:assert_failed msg="assertion expression failed (%s)."
206
+ errors << validate_error(:assert_failed, rule, path, value, [rule.assert])
207
+ end
208
+ end
209
+
210
+
211
+ def _validate_enum(value, rule, path, errors)
212
+ assert_error("rule=#{rule._inspect}") unless rule.enum
213
+ unless rule.enum.include?(value)
214
+ keyname = path.is_a?(Array) ? path[-1] : File.basename(path)
215
+ keyname = 'enum' if keyname =~ /\A\d+\z/
216
+ #* key=:enum_notexist msg="invalid %s value."
217
+ errors << validate_error(:enum_notexist, rule, path, value, [keyname])
218
+ end
219
+ end
220
+
221
+
222
+ def _validate_pattern(value, rule, path, errors)
223
+ assert_error("rule=#{rule._inspect}") unless rule.pattern
224
+ unless value.to_s =~ rule.regexp
225
+ #* key=:pattern_unmatch msg="not matched to pattern %s."
226
+ errors << validate_error(:pattern_unmatch, rule, path, value, [rule.pattern])
227
+ end
228
+ end
229
+
230
+
231
+ def _validate_range(value, rule, path, errors)
232
+ assert_error("rule=#{rule._inspect}") unless rule.range
233
+ assert_error("value.class=#{value.class.name}") unless Types.scalar?(value)
234
+ h = rule.range
235
+ max, min, max_ex, min_ex = h['max'], h['min'], h['max-ex'], h['min-ex']
236
+ if max && max < value
237
+ #* key=:range_toolarge msg="too large (> max %s)."
238
+ errors << validate_error(:range_toolarge, rule, path, value, [max.to_s])
239
+ end
240
+ if min && min > value
241
+ #* key=:range_toosmall msg="too small (< min %s)."
242
+ errors << validate_error(:range_toosmall, rule, path, value, [min.to_s])
243
+ end
244
+ if max_ex && max_ex <= value
245
+ #* key=:range_toolargeex msg="too large (>= max %s)."
246
+ errors << validate_error(:range_toolargeex, rule, path, value, [max_ex.to_s])
247
+ end
248
+ if min_ex && min_ex >= value
249
+ #* key=:range_toosmallex msg="too small (<= min %s)."
250
+ errors << validate_error(:range_toosmallex, rule, path, value, [min_ex.to_s])
251
+ end
252
+ end
253
+
254
+
255
+ def _validate_length(value, rule, path, errors)
256
+ assert_error("rule=#{rule._inspect}") unless rule.length
257
+ assert_error("value.class=#{value.class.name}") unless value.is_a?(String) || value.is_a?(Text)
258
+ len = value.to_s.length
259
+ h = rule.length
260
+ max, min, max_ex, min_ex = h['max'], h['min'], h['max-ex'], h['min-ex']
261
+ if max && max < len
262
+ #* key=:length_toolong msg="too long (length %d > max %d)."
263
+ errors << validate_error(:length_toolong, rule, path, value, [len, max])
264
+ end
265
+ if min && min > len
266
+ #* key=:length_tooshort msg="too short (length %d < min %d)."
267
+ errors << validate_error(:length_tooshort, rule, path, value, [len, min])
268
+ end
269
+ if max_ex && max_ex <= len
270
+ #* key=:length_toolongex msg="too long (length %d >= max %d)."
271
+ errors << validate_error(:length_toolongex, rule, path, value, [len, max_ex])
272
+ end
273
+ if min_ex && min_ex >= len
274
+ #* key=:length_tooshortex msg="too short (length %d <= min %d)."
275
+ errors << validate_error(:length_tooshortex, rule, path, value, [len, min_ex])
276
+ end
277
+ end
278
+
279
+
280
+ end
281
+
282
+ end