kwalify 0.6.1 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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