ddao-kwalify 0.7.1

Sign up to get free protection for your applications and to get access to all the features.
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