rkwalify 1.4.0.pre.preview1

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