ddao-kwalify 0.7.1

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 (208) hide show
  1. data/CHANGES.txt +243 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.txt +61 -0
  4. data/bin/kwalify +13 -0
  5. data/contrib/inline-require +153 -0
  6. data/contrib/kwalify +4159 -0
  7. data/doc-api/classes/CommandOptionError.html +184 -0
  8. data/doc-api/classes/CommandOptionParser.html +325 -0
  9. data/doc-api/classes/Kwalify.html +292 -0
  10. data/doc-api/classes/Kwalify/AssertionError.html +148 -0
  11. data/doc-api/classes/Kwalify/BaseError.html +297 -0
  12. data/doc-api/classes/Kwalify/BaseParser.html +461 -0
  13. data/doc-api/classes/Kwalify/CommandOptionError.html +168 -0
  14. data/doc-api/classes/Kwalify/ErrorHelper.html +223 -0
  15. data/doc-api/classes/Kwalify/HashInterface.html +118 -0
  16. data/doc-api/classes/Kwalify/Json.html +105 -0
  17. data/doc-api/classes/Kwalify/KwalifyError.html +111 -0
  18. data/doc-api/classes/Kwalify/Main.html +339 -0
  19. data/doc-api/classes/Kwalify/MetaValidator.html +448 -0
  20. data/doc-api/classes/Kwalify/Parser.html +155 -0
  21. data/doc-api/classes/Kwalify/PlainYamlParser.html +523 -0
  22. data/doc-api/classes/Kwalify/PlainYamlParser/Alias.html +165 -0
  23. data/doc-api/classes/Kwalify/Rule.html +433 -0
  24. data/doc-api/classes/Kwalify/SchemaError.html +148 -0
  25. data/doc-api/classes/Kwalify/SyntaxError.html +185 -0
  26. data/doc-api/classes/Kwalify/Types.html +302 -0
  27. data/doc-api/classes/Kwalify/Util.html +389 -0
  28. data/doc-api/classes/Kwalify/Util/HashLike.html +246 -0
  29. data/doc-api/classes/Kwalify/Util/OrderedHash.html +330 -0
  30. data/doc-api/classes/Kwalify/ValidationError.html +148 -0
  31. data/doc-api/classes/Kwalify/Validator.html +381 -0
  32. data/doc-api/classes/Kwalify/Yaml.html +194 -0
  33. data/doc-api/classes/Kwalify/Yaml/Parser.html +1538 -0
  34. data/doc-api/classes/Kwalify/YamlParser.html +542 -0
  35. data/doc-api/classes/Kwalify/YamlSyntaxError.html +119 -0
  36. data/doc-api/classes/Test.html +107 -0
  37. data/doc-api/classes/Test/Unit.html +101 -0
  38. data/doc-api/created.rid +1 -0
  39. data/doc-api/files/__/README_txt.html +172 -0
  40. data/doc-api/files/kwalify/errors_rb.html +114 -0
  41. data/doc-api/files/kwalify/main_rb.html +118 -0
  42. data/doc-api/files/kwalify/messages_rb.html +107 -0
  43. data/doc-api/files/kwalify/meta-validator_rb.html +117 -0
  44. data/doc-api/files/kwalify/parser/base_rb.html +116 -0
  45. data/doc-api/files/kwalify/parser/yaml_rb.html +117 -0
  46. data/doc-api/files/kwalify/rule_rb.html +116 -0
  47. data/doc-api/files/kwalify/types_rb.html +114 -0
  48. data/doc-api/files/kwalify/util/assert-text-equal_rb.html +115 -0
  49. data/doc-api/files/kwalify/util/hash-interface_rb.html +114 -0
  50. data/doc-api/files/kwalify/util/hashlike_rb.html +107 -0
  51. data/doc-api/files/kwalify/util/option-parser_rb.html +107 -0
  52. data/doc-api/files/kwalify/util/ordered-hash_rb.html +107 -0
  53. data/doc-api/files/kwalify/util/testcase-helper_rb.html +115 -0
  54. data/doc-api/files/kwalify/util_rb.html +107 -0
  55. data/doc-api/files/kwalify/validator_rb.html +117 -0
  56. data/doc-api/files/kwalify/yaml-parser_rb.html +117 -0
  57. data/doc-api/files/kwalify_rb.html +121 -0
  58. data/doc-api/fr_class_index.html +57 -0
  59. data/doc-api/fr_file_index.html +45 -0
  60. data/doc-api/fr_method_index.html +168 -0
  61. data/doc-api/index.html +24 -0
  62. data/doc-api/rdoc-style.css +208 -0
  63. data/doc/docstyle.css +188 -0
  64. data/doc/img/fig01.png +0 -0
  65. data/doc/users-guide.html +2050 -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.rb +67 -0
  82. data/lib/kwalify/errors.rb +128 -0
  83. data/lib/kwalify/kwalify.schema.yaml +58 -0
  84. data/lib/kwalify/main.rb +442 -0
  85. data/lib/kwalify/messages.rb +173 -0
  86. data/lib/kwalify/meta-validator.rb +276 -0
  87. data/lib/kwalify/parser/base.rb +127 -0
  88. data/lib/kwalify/parser/yaml.rb +841 -0
  89. data/lib/kwalify/rule.rb +560 -0
  90. data/lib/kwalify/templates/genclass-java.eruby +222 -0
  91. data/lib/kwalify/templates/genclass-php.eruby +104 -0
  92. data/lib/kwalify/templates/genclass-ruby.eruby +113 -0
  93. data/lib/kwalify/types.rb +156 -0
  94. data/lib/kwalify/util.rb +157 -0
  95. data/lib/kwalify/util/assert-text-equal.rb +46 -0
  96. data/lib/kwalify/util/hash-interface.rb +18 -0
  97. data/lib/kwalify/util/hashlike.rb +51 -0
  98. data/lib/kwalify/util/option-parser.rb +220 -0
  99. data/lib/kwalify/util/ordered-hash.rb +57 -0
  100. data/lib/kwalify/util/testcase-helper.rb +112 -0
  101. data/lib/kwalify/validator.rb +282 -0
  102. data/lib/kwalify/yaml-parser.rb +870 -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 +384 -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-validator.rb +95 -0
  204. data/test/test-validator.yaml +986 -0
  205. data/test/test-yaml-parser.rb +47 -0
  206. data/test/test-yaml-parser.yaml +1226 -0
  207. data/test/test.rb +60 -0
  208. metadata +261 -0
@@ -0,0 +1,560 @@
1
+ ###
2
+ ### $Rev: 95 $
3
+ ### $Release: 0.7.1 $
4
+ ### copyright(c) 2005-2008 kuwata-lab all rights reserved.
5
+ ###
6
+
7
+ require 'kwalify/messages'
8
+ require 'kwalify/errors'
9
+ require 'kwalify/types'
10
+
11
+
12
+ module Kwalify
13
+
14
+
15
+ class Rule
16
+ include Kwalify::ErrorHelper
17
+
18
+ attr_accessor :parent
19
+ attr_reader :name
20
+ attr_reader :desc
21
+ attr_reader :enum
22
+ attr_reader :required
23
+ attr_reader :type
24
+ attr_reader :type_class
25
+ attr_reader :pattern
26
+ attr_reader :regexp
27
+ attr_reader :sequence
28
+ attr_reader :mapping
29
+ attr_reader :assert
30
+ attr_reader :assert_proc
31
+ attr_reader :range
32
+ attr_reader :length
33
+ attr_reader :ident
34
+ attr_reader :unique
35
+ attr_reader :default
36
+ attr_reader :classname
37
+ attr_reader :classobj
38
+
39
+
40
+ def initialize(hash=nil, parent=nil)
41
+ @ident = @unique = @sequence = @default = @enum = @pattern = @mapping = @range = @length = nil
42
+ _init(hash, "", {}) if hash
43
+ @parent = parent
44
+ end
45
+
46
+
47
+ def _init(hash, path="", rule_table={})
48
+ unless hash.is_a?(Hash)
49
+ #* key=:schema_notmap msg="schema definition is not a mapping."
50
+ raise Kwalify.schema_error(:schema_notmap, nil, (!path || path.empty? ? "/" : path), nil)
51
+ end
52
+ rule = self
53
+ rule_table[hash.__id__] = rule
54
+ ## 'type:' entry
55
+ curr_path = "#{path}/type"
56
+ _init_type_value(hash['type'], rule, curr_path)
57
+ ## other entries
58
+ hash.each do |key, val|
59
+ curr_path = "#{path}/#{key}"
60
+ sym = key.intern
61
+ method = get_init_method(sym)
62
+ unless method
63
+ #* key=:key_unknown msg="unknown key."
64
+ raise schema_error(:key_unknown, rule, curr_path, "#{key}:")
65
+ end
66
+ if sym == :sequence || sym == :mapping
67
+ __send__(method, val, rule, curr_path, rule_table)
68
+ else
69
+ __send__(method, val, rule, curr_path)
70
+ end
71
+ end
72
+ _check_confliction(hash, rule, path)
73
+ return self
74
+ end
75
+
76
+
77
+ keys = %w[type name desc required pattern enum assert range length
78
+ ident unique default sequence mapping class]
79
+ #table = keys.inject({}) {|h, k| h[k.intern] = "_init_#{k}_value".intern; h }
80
+ table = {}; keys.each {|k| table[k.intern] = "_init_#{k}_value".intern }
81
+ @@dispatch_table = table
82
+
83
+
84
+ protected
85
+
86
+
87
+ def get_init_method(sym)
88
+ @_dispatch_table ||= @@dispatch_table
89
+ return @_dispatch_table[sym]
90
+ end
91
+
92
+
93
+ private
94
+
95
+
96
+ def _init_type_value(val, rule, path)
97
+ @type = val
98
+ @type = Types::DEFAULT_TYPE if @type.nil?
99
+ unless @type.is_a?(String)
100
+ #* key=:type_notstr msg="not a string."
101
+ raise schema_error(:type_notstr, rule, path, @type.to_s)
102
+ end
103
+ @type_class = Types.type_class(@type)
104
+ #if @type_class.nil?
105
+ # begin
106
+ # @type_class = Kernel.const_get(@type)
107
+ # rescue NameError
108
+ # end
109
+ #end
110
+ unless @type_class
111
+ #* key=:type_unknown msg="unknown type."
112
+ raise schema_error(:type_unknown, rule, path, @type.to_s)
113
+ end
114
+ end
115
+
116
+
117
+ def _init_class_value(val, rule, path)
118
+ @classname = val
119
+ unless @type == 'map'
120
+ #* key=:class_notmap msg="available only with map type."
121
+ raise schema_error(:class_notmap, rule, path, 'class:')
122
+ end
123
+ begin
124
+ @classobj = Util.get_class(val)
125
+ rescue NameError
126
+ @classobj = nil
127
+ end
128
+ end
129
+
130
+
131
+ def _init_name_value(val, rule, path)
132
+ @name = val
133
+ end
134
+
135
+
136
+ def _init_desc_value(val, rule, path)
137
+ @desc = val
138
+ end
139
+
140
+
141
+ def _init_required_value(val, rule, path)
142
+ @required = val
143
+ unless val.is_a?(Boolean) #|| val.nil?
144
+ #* key=:required_notbool msg="not a boolean."
145
+ raise schema_error(:required_notbool, rule, path, val)
146
+ end
147
+ end
148
+
149
+
150
+ def _init_pattern_value(val, rule, path)
151
+ @pattern = val
152
+ unless val.is_a?(String) || val.is_a?(Regexp)
153
+ #* key=:pattern_notstr msg="not a string (or regexp)"
154
+ raise schema_error(:pattern_notstr, rule, path, val)
155
+ end
156
+ unless val =~ /\A\/(.*)\/([mi]?[mi]?)\z/
157
+ #* key=:pattern_notmatch msg="should be '/..../'."
158
+ raise schema_error(:pattern_notmatch, rule, path, val)
159
+ end
160
+ pat = $1; opt = $2
161
+ flag = 0
162
+ flag += Regexp::IGNORECASE if opt.include?("i")
163
+ flag += Regexp::MULTILINE if opt.include?("m")
164
+ begin
165
+ @regexp = Regexp.compile(pat, flag)
166
+ rescue RegexpError => ex
167
+ #* key=:pattern_syntaxerr msg="has regexp error."
168
+ raise schema_error(:pattern_syntaxerr, rule, path, val)
169
+ end
170
+ end
171
+
172
+
173
+ def _init_enum_value(val, rule, path)
174
+ @enum = val
175
+ unless val.is_a?(Array)
176
+ #* key=:enum_notseq msg="not a sequence."
177
+ raise schema_error(:enum_notseq, rule, path, val)
178
+ end
179
+ if Types.collection_type?(@type) # unless Kwalify.scalar_class?(@type_class)
180
+ #* key=:enum_notscalar msg="not available with seq or map."
181
+ raise schema_error(:enum_notscalar, rule, File.dirname(path), 'enum:')
182
+ end
183
+ elem_table = {}
184
+ @enum.each do |elem|
185
+ unless elem.is_a?(@type_class)
186
+ #* key=:enum_type_unmatch msg="%s type expected."
187
+ raise schema_error(:enum_type_unmatch, rule, path, elem, [Kwalify.word(@type)])
188
+ end
189
+ if elem_table[elem]
190
+ #* key=:enum_duplicate msg="duplicated enum value."
191
+ raise schema_error(:enum_duplicate, rule, path, elem.to_s)
192
+ end
193
+ elem_table[elem] = true
194
+ end
195
+ end
196
+
197
+
198
+ def _init_assert_value(val, rule, path)
199
+ @assert = val
200
+ unless val.is_a?(String)
201
+ #* key=:assert_notstr msg="not a string."
202
+ raise schema_error(:assert_notstr, rule, path, val)
203
+ end
204
+ unless val =~ /\bval\b/
205
+ #* key=:assert_noval msg="'val' is not used."
206
+ raise schema_error(:assert_noval, rule, path, val)
207
+ end
208
+ begin
209
+ @assert_proc = eval "proc { |val| #{val} }"
210
+ rescue ::SyntaxError => ex
211
+ #* key=:assert_syntaxerr msg="expression syntax error."
212
+ raise schema_error(:assert_syntaxerr, rule, path, val)
213
+ end
214
+ end
215
+
216
+
217
+ def _init_range_value(val, rule, path)
218
+ @range = val
219
+ unless val.is_a?(Hash)
220
+ #* key=:range_notmap msg="not a mapping."
221
+ raise schema_error(:range_notmap, rule, path, val)
222
+ end
223
+ if Types.collection_type?(@type) || @type == 'bool'
224
+ #* key=:range_notscalar msg="is available only with scalar type."
225
+ raise schema_error(:range_notscalar, rule, File.dirname(path), 'range:')
226
+ end
227
+ val.each do |k, v|
228
+ case k
229
+ when 'max', 'min', 'max-ex', 'min-ex'
230
+ unless v.is_a?(@type_class)
231
+ typename = Kwalify.word(@type) || @type
232
+ #* key=:range_type_unmatch msg="not a %s."
233
+ raise schema_error(:range_type_unmatch, rule, "#{path}/#{k}", v, [typename])
234
+ end
235
+ else
236
+ #* key=:range_undefined msg="undefined key."
237
+ raise schema_error(:range_undefined, rule, "#{path}/#{k}", "#{k}:")
238
+ end
239
+ end
240
+ if val.key?('max') && val.key?('max-ex')
241
+ #* key=:range_twomax msg="both 'max' and 'max-ex' are not available at once."
242
+ raise schema_error(:range_twomax, rule, path, nil)
243
+ end
244
+ if val.key?('min') && val.key?('min-ex')
245
+ #* key=:range_twomin msg="both 'min' and 'min-ex' are not available at once."
246
+ raise schema_error(:range_twomin, rule, path, nil)
247
+ end
248
+ max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
249
+ if max
250
+ if min && max < min
251
+ #* key=:range_maxltmin msg="max '%s' is less than min '%s'."
252
+ raise validate_error(:range_maxltmin, rule, path, nil, [max, min])
253
+ elsif min_ex && max <= min_ex
254
+ #* key=:range_maxleminex msg="max '%s' is less than or equal to min-ex '%s'."
255
+ raise validate_error(:range_maxleminex, rule, path, nil, [max, min_ex])
256
+ end
257
+ elsif max_ex
258
+ if min && max_ex <= min
259
+ #* key=:range_maxexlemin msg="max-ex '%s' is less than or equal to min '%s'."
260
+ raise validate_error(:range_maxexlemin, rule, path, nil, [max_ex, min])
261
+ elsif min_ex && max_ex <= min_ex
262
+ #* key=:range_maxexleminex msg="max-ex '%s' is less than or equal to min-ex '%s'."
263
+ raise validate_error(:range_maxexleminex, rule, path, nil, [max_ex, min_ex])
264
+ end
265
+ end
266
+ end
267
+
268
+
269
+ def _init_length_value(val, rule, path)
270
+ @length = val
271
+ unless val.is_a?(Hash)
272
+ #* key=:length_notmap msg="not a mapping."
273
+ raise schema_error(:length_notmap, rule, path, val)
274
+ end
275
+ unless @type == 'str' || @type == 'text'
276
+ #* key=:length_nottext msg="is available only with string or text."
277
+ raise schema_error(:length_nottext, rule, File.dirname(path), 'length:')
278
+ end
279
+ val.each do |k, v|
280
+ case k
281
+ when 'max', 'min', 'max-ex', 'min-ex'
282
+ unless v.is_a?(Integer)
283
+ #* key=:length_notint msg="not an integer."
284
+ raise schema_error(:length_notint, rule, "#{path}/#{k}", v)
285
+ end
286
+ else
287
+ #* key=:length_undefined msg="undefined key."
288
+ raise schema_error(:length_undefined, rule, "#{path}/#{k}", "#{k}:")
289
+ end
290
+ end
291
+ if val.key?('max') && val.key?('max-ex')
292
+ #* key=:length_twomax msg="both 'max' and 'max-ex' are not available at once."
293
+ raise schema_error(:length_twomax, rule, path, nil)
294
+ end
295
+ if val.key?('min') && val.key?('min-ex')
296
+ #* key=:length_twomin msg="both 'min' and 'min-ex' are not available at once."
297
+ raise schema_error(:length_twomin, rule, path, nil)
298
+ end
299
+ max, min, max_ex, min_ex = val['max'], val['min'], val['max-ex'], val['min-ex']
300
+ if max
301
+ if min && max < min
302
+ #* key=:length_maxltmin msg="max '%s' is less than min '%s'."
303
+ raise validate_error(:length_maxltmin, rule, path, nil, [max, min])
304
+ elsif min_ex && max <= min_ex
305
+ #* key=:length_maxleminex msg="max '%s' is less than or equal to min-ex '%s'."
306
+ raise validate_error(:length_maxleminex, rule, path, nil, [max, min_ex])
307
+ end
308
+ elsif max_ex
309
+ if min && max_ex <= min
310
+ #* key=:length_maxexlemin msg="max-ex '%s' is less than or equal to min '%s'."
311
+ raise validate_error(:length_maxexlemin, rule, path, nil, [max_ex, min])
312
+ elsif min_ex && max_ex <= min_ex
313
+ #* key=:length_maxexleminex msg="max-ex '%s' is less than or equal to min-ex '%s'."
314
+ raise validate_error(:length_maxexleminex, rule, path, nil, [max_ex, min_ex])
315
+ end
316
+ end
317
+ end
318
+
319
+
320
+ def _init_ident_value(val, rule, path)
321
+ @ident = val
322
+ @required = true
323
+ unless val.is_a?(Boolean)
324
+ #* key=:ident_notbool msg="not a boolean."
325
+ raise schema_error(:ident_notbool, rule, path, val)
326
+ end
327
+ if @type == 'map' || @type == 'seq'
328
+ #* key=:ident_notscalar msg="is available only with a scalar type."
329
+ raise schema_error(:ident_notscalar, rule, File.dirname(path), "ident:")
330
+ end
331
+ if File.dirname(path) == "/"
332
+ #* key=:ident_onroot msg="is not available on root element."
333
+ raise schema_error(:ident_onroot, rule, "/", "ident:")
334
+ end
335
+ unless @parent && @parent.type == 'map'
336
+ #* key=:ident_notmap msg="is available only with an element of mapping."
337
+ raise schema_error(:ident_notmap, rule, File.dirname(path), "ident:")
338
+ end
339
+ end
340
+
341
+
342
+ def _init_unique_value(val, rule, path)
343
+ @unique = val
344
+ unless val.is_a?(Boolean)
345
+ #* key=:unique_notbool msg="not a boolean."
346
+ raise schema_error(:unique_notbool, rule, path, val)
347
+ end
348
+ if @type == 'map' || @type == 'seq'
349
+ #* key=:unique_notscalar msg="is available only with a scalar type."
350
+ raise schema_error(:unique_notscalar, rule, File.dirname(path), "unique:")
351
+ end
352
+ if File.dirname(path) == "/"
353
+ #* key=:unique_onroot msg="is not available on root element."
354
+ raise schema_error(:unique_onroot, rule, "/", "unique:")
355
+ end
356
+ end
357
+
358
+
359
+ def _init_default_value(val, rule, path)
360
+ @default = val
361
+ unless Types.scalar?(val)
362
+ #* key=:default_nonscalarval msg="not a scalar."
363
+ raise schema_error(:default_nonscalarval, rule, path, val)
364
+ end
365
+ if @type == 'map' || @type == 'seq'
366
+ #* key=:default_notscalar msg="is available only with a scalar type."
367
+ raise schema_error(:default_notscalar, rule, File.dirname(path), "default:")
368
+ end
369
+ unless val.nil? || val.is_a?(@type_class)
370
+ #* key=:default_unmatch msg="not a %s."
371
+ raise schema_error(:default_unmatch, rule, path, val, [Kwalify.word(@type)])
372
+ end
373
+ end
374
+
375
+
376
+ def _init_sequence_value(val, rule, path, rule_table)
377
+ if !val.nil? && !val.is_a?(Array)
378
+ #* key=:sequence_notseq msg="not a sequence."
379
+ raise schema_error(:sequence_notseq, rule, path, val)
380
+ elsif val.nil? || val.empty?
381
+ #* key=:sequence_noelem msg="required one element."
382
+ raise schema_error(:sequence_noelem, rule, path, val)
383
+ elsif val.length > 1
384
+ #* key=:sequence_toomany msg="required just one element."
385
+ raise schema_error(:sequence_toomany, rule, path, val)
386
+ else
387
+ elem = val[0]
388
+ elem ||= {}
389
+ i = 0 # or 1? *index*
390
+ rule = rule_table[elem.__id__]
391
+ rule ||= Rule.new(nil, self)._init(elem, "#{path}/#{i}", rule_table)
392
+ @sequence = [ rule ]
393
+ end
394
+ end
395
+
396
+
397
+ def _init_mapping_value(val, rule, path, rule_table)
398
+ if !val.nil? && !val.is_a?(Hash)
399
+ #* key=:mapping_notmap msg="not a mapping."
400
+ raise schema_error(:mapping_notmap, rule, path, val)
401
+ elsif val.nil? || (val.empty? && !val.default)
402
+ #* key=:mapping_noelem msg="required at least one element."
403
+ raise schema_error(:mapping_noelem, rule, path, val)
404
+ else
405
+ @mapping = {}
406
+ if val.default
407
+ elem = val.default # hash
408
+ rule = rule_table[elem.__id__]
409
+ rule ||= Rule.new(nil, self)._init(elem, "#{path}/=", rule_table)
410
+ @mapping.default = rule
411
+ end
412
+ val.each do |k, v|
413
+ ##* key=:key_duplicate msg="key duplicated."
414
+ #raise schema_error(:key_duplicate, rule, path, key) if @mapping.key?(key)
415
+ v ||= {}
416
+ rule = rule_table[v.__id__]
417
+ rule ||= Rule.new(nil, self)._init(v, "#{path}/#{k}", rule_table)
418
+ if k == '='
419
+ @mapping.default = rule
420
+ else
421
+ @mapping[k] = rule
422
+ end
423
+ end if val
424
+ end
425
+ end
426
+
427
+
428
+ def _check_confliction(hash, rule, path)
429
+ if @type == 'seq'
430
+ #* key=:seq_nosequence msg="type 'seq' requires 'sequence:'."
431
+ raise schema_error(:seq_nosequence, rule, path, nil) unless hash.key?('sequence')
432
+ #* key=:seq_conflict msg="not available with sequence."
433
+ raise schema_error(:seq_conflict, rule, path, 'enum:') if @enum
434
+ raise schema_error(:seq_conflict, rule, path, 'pattern:') if @pattern
435
+ raise schema_error(:seq_conflict, rule, path, 'mapping:') if @mapping
436
+ raise schema_error(:seq_conflict, rule, path, 'range:') if @range
437
+ raise schema_error(:seq_conflict, rule, path, 'length:') if @length
438
+ elsif @type == 'map'
439
+ #* key=:map_nomapping msg="type 'map' requires 'mapping:'."
440
+ raise schema_error(:map_nomapping, rule, path, nil) unless hash.key?('mapping')
441
+ #* key=:map_conflict msg="not available with mapping."
442
+ raise schema_error(:map_conflict, rule, path, 'enum:') if @enum
443
+ raise schema_error(:map_conflict, rule, path, 'pattern:') if @pattern
444
+ raise schema_error(:map_conflict, rule, path, 'sequence:') if @sequence
445
+ raise schema_error(:map_conflict, rule, path, 'range:') if @range
446
+ raise schema_error(:map_conflict, rule, path, 'length:') if @length
447
+ else
448
+ #* key=:scalar_conflict msg="not available with scalar type."
449
+ raise schema_error(:scalar_conflict, rule, path, 'sequence:') if @sequence
450
+ raise schema_error(:scalar_conflict, rule, path, 'mapping:') if @mapping
451
+ if @enum
452
+ #* key=:enum_conflict msg="not available with 'enum:'."
453
+ raise schema_error(:enum_conflict, rule, path, 'range:') if @range
454
+ raise schema_error(:enum_conflict, rule, path, 'length:') if @length
455
+ raise schema_error(:enum_conflict, rule, path, 'pattern:') if @pattern
456
+ end
457
+ unless @default.nil?
458
+ #* key=:default_conflict msg="not available when 'required:' is true."
459
+ raise schema_error(:default_conflict, rule, path, 'default:') if @required
460
+ end
461
+ end
462
+ end
463
+
464
+ #def inspect()
465
+ # str = ""; level = 0; done = {}
466
+ # _inspect(str, level, done)
467
+ # return str
468
+ #end
469
+
470
+
471
+ protected
472
+
473
+
474
+ def _inspect(str="", level=0, done={})
475
+ done[self.__id__] = true
476
+ str << " " * level << "name: #{@name}\n" unless @name.nil?
477
+ str << " " * level << "desc: #{@desc}\n" unless @desc.nil?
478
+ str << " " * level << "type: #{@type}\n" unless @type.nil?
479
+ str << " " * level << "klass: #{@type_class.name}\n" unless @type_class.nil?
480
+ str << " " * level << "required: #{@required}\n" unless @required.nil?
481
+ str << " " * level << "pattern: #{@regexp.inspect}\n" unless @pattern.nil?
482
+ str << " " * level << "assert: #{@assert}\n" unless @assert.nil?
483
+ str << " " * level << "ident: #{@ident}\n" unless @ident.nil?
484
+ str << " " * level << "unique: #{@unique}\n" unless @unique.nil?
485
+ if !@enum.nil?
486
+ str << " " * level << "enum:\n"
487
+ @enum.each do |item|
488
+ str << " " * (level+1) << "- #{item}\n"
489
+ end
490
+ end
491
+ if !@range.nil?
492
+ str << " " * level
493
+ str << "range: { "
494
+ colon = ""
495
+ %w[max max-ex min min-ex].each do |key|
496
+ val = @range[key]
497
+ unless val.nil?
498
+ str << colon << "#{key}: #{val.inspect}"
499
+ colon = ", "
500
+ end
501
+ end
502
+ str << " }\n"
503
+ end
504
+ if !@length.nil?
505
+ str << " " * level
506
+ str << "length: { "
507
+ colon = ""
508
+ %w[max max-ex min min-ex].each do |key|
509
+ val = @length[key]
510
+ if !val.nil?
511
+ str << colon << "#{key}: #{val.inspect}"
512
+ colon = ", "
513
+ end
514
+ end
515
+ str << " }\n"
516
+ end
517
+ @sequence.each do |rule|
518
+ if done[rule.__id__]
519
+ str << " " * (level+1) << "- ...\n"
520
+ else
521
+ str << " " * (level+1) << "- \n"
522
+ rule._inspect(str, level+2, done)
523
+ end
524
+ end if @sequence
525
+ @mapping.each do |key, rule|
526
+ if done[rule.__id__]
527
+ str << ' ' * (level+1) << '"' << key << "\": ...\n"
528
+ else
529
+ str << ' ' * (level+1) << '"' << key << "\":\n"
530
+ rule._inspect(str, level+2, done)
531
+ end
532
+ end if @mapping
533
+ return str
534
+ end
535
+
536
+
537
+ public
538
+
539
+
540
+ def _uniqueness_check_table() # :nodoc:
541
+ uniq_table = nil
542
+ if @type == 'map'
543
+ @mapping.keys.each do |key|
544
+ rule = @mapping[key]
545
+ if rule.unique || rule.ident
546
+ uniq_table ||= {}
547
+ uniq_table[key] = {}
548
+ end
549
+ end
550
+ elsif @unique || @ident
551
+ uniq_table = {}
552
+ end
553
+ return uniq_table
554
+ end
555
+
556
+
557
+ end
558
+
559
+
560
+ end