kwalify 0.6.1 → 0.7.0

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