ddao-kwalify 0.7.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (208) hide show
  1. data/CHANGES.txt +243 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.txt +61 -0
  4. data/bin/kwalify +13 -0
  5. data/contrib/inline-require +153 -0
  6. data/contrib/kwalify +4159 -0
  7. data/doc-api/classes/CommandOptionError.html +184 -0
  8. data/doc-api/classes/CommandOptionParser.html +325 -0
  9. data/doc-api/classes/Kwalify.html +292 -0
  10. data/doc-api/classes/Kwalify/AssertionError.html +148 -0
  11. data/doc-api/classes/Kwalify/BaseError.html +297 -0
  12. data/doc-api/classes/Kwalify/BaseParser.html +461 -0
  13. data/doc-api/classes/Kwalify/CommandOptionError.html +168 -0
  14. data/doc-api/classes/Kwalify/ErrorHelper.html +223 -0
  15. data/doc-api/classes/Kwalify/HashInterface.html +118 -0
  16. data/doc-api/classes/Kwalify/Json.html +105 -0
  17. data/doc-api/classes/Kwalify/KwalifyError.html +111 -0
  18. data/doc-api/classes/Kwalify/Main.html +339 -0
  19. data/doc-api/classes/Kwalify/MetaValidator.html +448 -0
  20. data/doc-api/classes/Kwalify/Parser.html +155 -0
  21. data/doc-api/classes/Kwalify/PlainYamlParser.html +523 -0
  22. data/doc-api/classes/Kwalify/PlainYamlParser/Alias.html +165 -0
  23. data/doc-api/classes/Kwalify/Rule.html +433 -0
  24. data/doc-api/classes/Kwalify/SchemaError.html +148 -0
  25. data/doc-api/classes/Kwalify/SyntaxError.html +185 -0
  26. data/doc-api/classes/Kwalify/Types.html +302 -0
  27. data/doc-api/classes/Kwalify/Util.html +389 -0
  28. data/doc-api/classes/Kwalify/Util/HashLike.html +246 -0
  29. data/doc-api/classes/Kwalify/Util/OrderedHash.html +330 -0
  30. data/doc-api/classes/Kwalify/ValidationError.html +148 -0
  31. data/doc-api/classes/Kwalify/Validator.html +381 -0
  32. data/doc-api/classes/Kwalify/Yaml.html +194 -0
  33. data/doc-api/classes/Kwalify/Yaml/Parser.html +1538 -0
  34. data/doc-api/classes/Kwalify/YamlParser.html +542 -0
  35. data/doc-api/classes/Kwalify/YamlSyntaxError.html +119 -0
  36. data/doc-api/classes/Test.html +107 -0
  37. data/doc-api/classes/Test/Unit.html +101 -0
  38. data/doc-api/created.rid +1 -0
  39. data/doc-api/files/__/README_txt.html +172 -0
  40. data/doc-api/files/kwalify/errors_rb.html +114 -0
  41. data/doc-api/files/kwalify/main_rb.html +118 -0
  42. data/doc-api/files/kwalify/messages_rb.html +107 -0
  43. data/doc-api/files/kwalify/meta-validator_rb.html +117 -0
  44. data/doc-api/files/kwalify/parser/base_rb.html +116 -0
  45. data/doc-api/files/kwalify/parser/yaml_rb.html +117 -0
  46. data/doc-api/files/kwalify/rule_rb.html +116 -0
  47. data/doc-api/files/kwalify/types_rb.html +114 -0
  48. data/doc-api/files/kwalify/util/assert-text-equal_rb.html +115 -0
  49. data/doc-api/files/kwalify/util/hash-interface_rb.html +114 -0
  50. data/doc-api/files/kwalify/util/hashlike_rb.html +107 -0
  51. data/doc-api/files/kwalify/util/option-parser_rb.html +107 -0
  52. data/doc-api/files/kwalify/util/ordered-hash_rb.html +107 -0
  53. data/doc-api/files/kwalify/util/testcase-helper_rb.html +115 -0
  54. data/doc-api/files/kwalify/util_rb.html +107 -0
  55. data/doc-api/files/kwalify/validator_rb.html +117 -0
  56. data/doc-api/files/kwalify/yaml-parser_rb.html +117 -0
  57. data/doc-api/files/kwalify_rb.html +121 -0
  58. data/doc-api/fr_class_index.html +57 -0
  59. data/doc-api/fr_file_index.html +45 -0
  60. data/doc-api/fr_method_index.html +168 -0
  61. data/doc-api/index.html +24 -0
  62. data/doc-api/rdoc-style.css +208 -0
  63. data/doc/docstyle.css +188 -0
  64. data/doc/img/fig01.png +0 -0
  65. data/doc/users-guide.html +2050 -0
  66. data/examples/address-book/Makefile +10 -0
  67. data/examples/address-book/address-book.schema.yaml +45 -0
  68. data/examples/address-book/address-book.yaml +36 -0
  69. data/examples/data-binding/BABEL.data.yaml +63 -0
  70. data/examples/data-binding/BABEL.schema.yaml +31 -0
  71. data/examples/data-binding/Makefile +8 -0
  72. data/examples/data-binding/Rakefile +13 -0
  73. data/examples/data-binding/main.rb +27 -0
  74. data/examples/invoice/Makefile +9 -0
  75. data/examples/invoice/invoice.schema.yaml +43 -0
  76. data/examples/invoice/invoice.yaml +32 -0
  77. data/examples/tapkit/Makefile +10 -0
  78. data/examples/tapkit/main.rb +7 -0
  79. data/examples/tapkit/tapkit.schema.yaml +146 -0
  80. data/examples/tapkit/tapkit.yaml +85 -0
  81. data/lib/kwalify.rb +67 -0
  82. data/lib/kwalify/errors.rb +128 -0
  83. data/lib/kwalify/kwalify.schema.yaml +58 -0
  84. data/lib/kwalify/main.rb +442 -0
  85. data/lib/kwalify/messages.rb +173 -0
  86. data/lib/kwalify/meta-validator.rb +276 -0
  87. data/lib/kwalify/parser/base.rb +127 -0
  88. data/lib/kwalify/parser/yaml.rb +841 -0
  89. data/lib/kwalify/rule.rb +560 -0
  90. data/lib/kwalify/templates/genclass-java.eruby +222 -0
  91. data/lib/kwalify/templates/genclass-php.eruby +104 -0
  92. data/lib/kwalify/templates/genclass-ruby.eruby +113 -0
  93. data/lib/kwalify/types.rb +156 -0
  94. data/lib/kwalify/util.rb +157 -0
  95. data/lib/kwalify/util/assert-text-equal.rb +46 -0
  96. data/lib/kwalify/util/hash-interface.rb +18 -0
  97. data/lib/kwalify/util/hashlike.rb +51 -0
  98. data/lib/kwalify/util/option-parser.rb +220 -0
  99. data/lib/kwalify/util/ordered-hash.rb +57 -0
  100. data/lib/kwalify/util/testcase-helper.rb +112 -0
  101. data/lib/kwalify/validator.rb +282 -0
  102. data/lib/kwalify/yaml-parser.rb +870 -0
  103. data/setup.rb +1585 -0
  104. data/test/Rookbook.yaml +10 -0
  105. data/test/data/users-guide/AddressBook.java.expected +40 -0
  106. data/test/data/users-guide/BABEL.data.yaml +24 -0
  107. data/test/data/users-guide/BABEL.schema.yaml +30 -0
  108. data/test/data/users-guide/ExampleAddressBook.java +47 -0
  109. data/test/data/users-guide/Group.java.expected +24 -0
  110. data/test/data/users-guide/Person.java.expected +44 -0
  111. data/test/data/users-guide/address_book.rb +52 -0
  112. data/test/data/users-guide/address_book.schema.yaml +28 -0
  113. data/test/data/users-guide/address_book.yaml +27 -0
  114. data/test/data/users-guide/answers-schema.yaml +12 -0
  115. data/test/data/users-guide/answers-validator.rb +52 -0
  116. data/test/data/users-guide/babel_genclass.result +26 -0
  117. data/test/data/users-guide/config.schema.yaml +7 -0
  118. data/test/data/users-guide/config.yaml +4 -0
  119. data/test/data/users-guide/document01a.yaml +3 -0
  120. data/test/data/users-guide/document01b.yaml +3 -0
  121. data/test/data/users-guide/document02a.yaml +4 -0
  122. data/test/data/users-guide/document02b.yaml +4 -0
  123. data/test/data/users-guide/document03a.yaml +6 -0
  124. data/test/data/users-guide/document03b.yaml +6 -0
  125. data/test/data/users-guide/document04a.yaml +9 -0
  126. data/test/data/users-guide/document04b.yaml +9 -0
  127. data/test/data/users-guide/document05a.yaml +11 -0
  128. data/test/data/users-guide/document05b.yaml +12 -0
  129. data/test/data/users-guide/document06a.yaml +15 -0
  130. data/test/data/users-guide/document06b.yaml +16 -0
  131. data/test/data/users-guide/document07a.yaml +9 -0
  132. data/test/data/users-guide/document07b.yaml +7 -0
  133. data/test/data/users-guide/document12a.json +10 -0
  134. data/test/data/users-guide/document12b.json +6 -0
  135. data/test/data/users-guide/document13a.yaml +17 -0
  136. data/test/data/users-guide/document14a.yaml +3 -0
  137. data/test/data/users-guide/document14b.yaml +3 -0
  138. data/test/data/users-guide/document15a.yaml +6 -0
  139. data/test/data/users-guide/document15b.yaml +5 -0
  140. data/test/data/users-guide/example_address_book.rb +10 -0
  141. data/test/data/users-guide/example_address_book_java.result +32 -0
  142. data/test/data/users-guide/example_address_book_ruby.result +31 -0
  143. data/test/data/users-guide/genclass_java.result +4 -0
  144. data/test/data/users-guide/howto-validation-with-parsing.rb +28 -0
  145. data/test/data/users-guide/howto-validation.rb +25 -0
  146. data/test/data/users-guide/howto3.rb +6 -0
  147. data/test/data/users-guide/howto3.result +5 -0
  148. data/test/data/users-guide/howto3.yaml +8 -0
  149. data/test/data/users-guide/howto5_databinding.result +111 -0
  150. data/test/data/users-guide/invalid01.result +3 -0
  151. data/test/data/users-guide/invalid02.result +5 -0
  152. data/test/data/users-guide/invalid03.result +5 -0
  153. data/test/data/users-guide/invalid04.result +4 -0
  154. data/test/data/users-guide/invalid05.result +11 -0
  155. data/test/data/users-guide/invalid06.result +4 -0
  156. data/test/data/users-guide/invalid07.result +3 -0
  157. data/test/data/users-guide/invalid08.result +3 -0
  158. data/test/data/users-guide/invalid12.json +8 -0
  159. data/test/data/users-guide/invalid14.result +4 -0
  160. data/test/data/users-guide/invalid15.result +4 -0
  161. data/test/data/users-guide/loadbabel.rb +27 -0
  162. data/test/data/users-guide/loadconfig.rb +16 -0
  163. data/test/data/users-guide/loadconfig.result +6 -0
  164. data/test/data/users-guide/models.rb +22 -0
  165. data/test/data/users-guide/option_ha.result +6 -0
  166. data/test/data/users-guide/option_ha_genclass_java.result +7 -0
  167. data/test/data/users-guide/schema01.yaml +3 -0
  168. data/test/data/users-guide/schema02.yaml +12 -0
  169. data/test/data/users-guide/schema03.yaml +9 -0
  170. data/test/data/users-guide/schema04.yaml +20 -0
  171. data/test/data/users-guide/schema05.yaml +29 -0
  172. data/test/data/users-guide/schema06.yaml +11 -0
  173. data/test/data/users-guide/schema12.json +12 -0
  174. data/test/data/users-guide/schema13.yaml +13 -0
  175. data/test/data/users-guide/schema14.yaml +5 -0
  176. data/test/data/users-guide/schema15.yaml +21 -0
  177. data/test/data/users-guide/valid01.result +2 -0
  178. data/test/data/users-guide/valid02.result +2 -0
  179. data/test/data/users-guide/valid03.result +2 -0
  180. data/test/data/users-guide/valid04.result +2 -0
  181. data/test/data/users-guide/valid05.result +2 -0
  182. data/test/data/users-guide/valid06.result +2 -0
  183. data/test/data/users-guide/valid07.result +2 -0
  184. data/test/data/users-guide/valid08.result +2 -0
  185. data/test/data/users-guide/valid12.result +2 -0
  186. data/test/data/users-guide/valid13.result +2 -0
  187. data/test/data/users-guide/valid14.result +2 -0
  188. data/test/data/users-guide/valid15.result +2 -0
  189. data/test/data/users-guide/validate08.rb +37 -0
  190. data/test/test-action.rb +78 -0
  191. data/test/test-action.yaml +738 -0
  192. data/test/test-databinding.rb +83 -0
  193. data/test/test-databinding.yaml +339 -0
  194. data/test/test-main.rb +157 -0
  195. data/test/test-main.yaml +384 -0
  196. data/test/test-metavalidator.rb +80 -0
  197. data/test/test-metavalidator.yaml +1179 -0
  198. data/test/test-parser-yaml.rb +57 -0
  199. data/test/test-parser-yaml.yaml +1749 -0
  200. data/test/test-rule.rb +26 -0
  201. data/test/test-rule.yaml +317 -0
  202. data/test/test-users-guide.rb +75 -0
  203. data/test/test-validator.rb +95 -0
  204. data/test/test-validator.yaml +986 -0
  205. data/test/test-yaml-parser.rb +47 -0
  206. data/test/test-yaml-parser.yaml +1226 -0
  207. data/test/test.rb +60 -0
  208. metadata +261 -0
@@ -0,0 +1,57 @@
1
+ ###
2
+ ### $Rev: 84 $
3
+ ### 0.7.1
4
+ ### $COPYRIGHT$
5
+ ###
6
+
7
+ module Kwalify
8
+
9
+ module Util
10
+
11
+ class OrderedHash < Hash
12
+
13
+ def initialize(*args, &block)
14
+ super
15
+ @_keys = []
16
+ end
17
+
18
+ alias __set__ []=
19
+
20
+ def put(key, val)
21
+ @_keys << key unless self.key?(key)
22
+ __set__(key, val)
23
+ end
24
+
25
+ def add(key, val)
26
+ @_keys.delete_at(@_keys.index(key)) if self.key?(key)
27
+ @_keys << key
28
+ __set__(key, val)
29
+ end
30
+
31
+ alias []= put
32
+ #alias []= add
33
+
34
+ def keys
35
+ return @_keys.dup
36
+ end
37
+
38
+ def values
39
+ return @_keys.collect {|key| self[key] }
40
+ end
41
+
42
+ def delete(key)
43
+ @_keys.delete_at(@_keys.index(key)) if self.key?(key)
44
+ super
45
+ end
46
+
47
+ def each
48
+ @_keys.each do |key|
49
+ yield key, self[key]
50
+ end
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
57
+ end
@@ -0,0 +1,112 @@
1
+ ###
2
+ ### $Rev: 83 $
3
+ ### $Release: 0.7.1 $
4
+ ### copyright(c) 2005-2008 kuwata-lab all rights reserved.
5
+ ###
6
+
7
+ require 'yaml'
8
+ require 'test/unit/testcase'
9
+
10
+
11
+ class Test::Unit::TestCase # :nodoc:
12
+
13
+
14
+ def self._untabify(str, width=8) # :nodoc:
15
+ sb = []
16
+ str.scan(/(.*?)\t/m) do |s, |
17
+ len = (n = s.rindex(?\n)) ? s.length - n - 1 : s.length
18
+ sb << s << (" " * (width - len % width))
19
+ end
20
+ str = (sb << $').join if $'
21
+ return str
22
+ end
23
+
24
+
25
+ def self.load_yaml_documents(filename, options={}) # :nodoc:
26
+ str = File.read(filename)
27
+ if filename =~ /\.rb$/
28
+ str =~ /^__END__$/ or raise "*** error: __END__ is not found in '#{filename}'."
29
+ str = $'
30
+ end
31
+ str = _untabify(str) unless options[:tabify] == false
32
+ #
33
+ identkey = options[:identkey] || 'name'
34
+ list = []
35
+ table = {}
36
+ YAML.load_documents(str) do |ydoc|
37
+ if ydoc.is_a?(Hash)
38
+ list << ydoc
39
+ elsif ydoc.is_a?(Array)
40
+ list += ydoc
41
+ else
42
+ raise "*** invalid ydoc: #{ydoc.inspect}"
43
+ end
44
+ end
45
+ #
46
+ list.each do |ydoc|
47
+ ident = ydoc[identkey]
48
+ ident or raise "*** #{identkey} is not found."
49
+ table[ident] and raise "*** #{identkey} '#{ident}' is duplicated."
50
+ table[ident] = ydoc
51
+ yield(ydoc) if block_given?
52
+ end
53
+ #
54
+ return list
55
+ end
56
+
57
+
58
+ def self.load_yaml_testdata(filename, options={}) # :nodoc:
59
+ identkey = options[:identkey] || 'name'
60
+ testmethod = options[:testmethod] || '_test'
61
+ lang = options[:lang]
62
+ load_yaml_documents(filename, options) do |ydoc|
63
+ ident = ydoc[identkey]
64
+ s = "def test_#{ident}\n"
65
+ ydoc.each do |key, val|
66
+ if key[-1] == ?*
67
+ key = key[0, key.length-1]
68
+ val = val[lang]
69
+ end
70
+ s << " @#{key} = #{val.inspect}\n"
71
+ end
72
+ s << " #{testmethod}\n"
73
+ s << "end\n"
74
+ #$stderr.puts "*** #{method_name()}(): eval_str=<<'END'\n#{s}END" if $DEBUG
75
+ module_eval s # not eval!
76
+ end
77
+ end
78
+
79
+
80
+ def self.method_name # :nodoc:
81
+ return (caller[0] =~ /in `(.*?)'/) && $1
82
+ end
83
+
84
+
85
+ def self.load_yaml_testdata_with_each_lang(filename, options={}) # :nodoc:
86
+ identkey = options[:identkey] || 'name'
87
+ testmethod = options[:testmethod] || '_test'
88
+ langs = defined?($lang) && $lang ? [ $lang ] : options[:langs]
89
+ langs or raise "*** #{method_name()}(): option ':langs' is required."
90
+ #
91
+ load_yaml_documents(filename, options) do |ydoc|
92
+ ident = ydoc[identkey]
93
+ langs.each do |lang|
94
+ s = "def test_#{ident}_#{lang}\n"
95
+ s << " @lang = #{lang.inspect}\n"
96
+ ydoc.each do |key, val|
97
+ if key[-1] == ?*
98
+ key = key[0, key.length-1]
99
+ val = val[lang]
100
+ end
101
+ s << " @#{key} = #{val.inspect}\n"
102
+ end
103
+ s << " #{testmethod}\n"
104
+ s << "end\n"
105
+ #$stderr.puts "*** #{method_name()}(): eval_str=<<'END'\n#{s}END" if $DEBUG
106
+ module_eval s # not eval!
107
+ end
108
+ end
109
+ end
110
+
111
+
112
+ end
@@ -0,0 +1,282 @@
1
+ ###
2
+ ### $Rev: 99 $
3
+ ### $Release: 0.7.1 $
4
+ ### copyright(c) 2005-2008 kuwata-lab all rights reserved.
5
+ ###
6
+
7
+ require 'kwalify/messages'
8
+ require 'kwalify/errors'
9
+ require 'kwalify/types'
10
+ require 'kwalify/rule'
11
+
12
+ module Kwalify
13
+
14
+ ##
15
+ ## validate YAML document
16
+ ##
17
+ ## ex1. validate yaml document
18
+ ## schema = YAML.load_file('schema.yaml')
19
+ ## validator = Kwalify::Validator.new(schema)
20
+ ## document = YAML.load_file('document.yaml')
21
+ ## erros = validator.validate(document)
22
+ ## if errors && !errors.empty?
23
+ ## errors.each do |err|
24
+ ## puts "- [#{err.path}] #{err.message}"
25
+ ## end
26
+ ## end
27
+ ##
28
+ ## ex2. validate with parsing
29
+ ## schema = YAML.load_file('schema.yaml')
30
+ ## validator = Kwalify::Validator.new(schema)
31
+ ## parser = Kwalify::Yaml::Parser.new(validator)
32
+ ## document = parser.parse(File.read('document.yaml'))
33
+ ## errors = parser.errors
34
+ ## if errors && errors.empty?
35
+ ## errors.each do |e|
36
+ ## puts "#{e.linenum}:#{e.column} [#{e.path}] #{e.message}"
37
+ ## end
38
+ ## end
39
+ ##
40
+ class Validator
41
+ include Kwalify::ErrorHelper
42
+
43
+
44
+ def initialize(hash_or_rule, &block)
45
+ obj = hash_or_rule
46
+ @rule = (obj.nil? || obj.is_a?(Rule)) ? obj : Rule.new(obj)
47
+ @block = block
48
+ end
49
+ attr_reader :rule
50
+
51
+
52
+ def _inspect
53
+ @rule._inspect
54
+ end
55
+
56
+
57
+ def validate(value)
58
+ path = ''; errors = []; done = {}; uniq_table = nil
59
+ _validate(value, @rule, path, errors, done, uniq_table)
60
+ return errors
61
+ end
62
+
63
+
64
+ protected
65
+
66
+
67
+ def validate_hook(value, rule, path, errors)
68
+ ## may be overrided by subclass
69
+ end
70
+
71
+
72
+ public
73
+
74
+
75
+ def _validate(value, rule, path, errors, done, uniq_table, recursive=true)
76
+ #if Types.collection?(value)
77
+ if !Types.scalar?(value)
78
+ #if done[value.__id__]
79
+ # rule2 = done[value.__id__]
80
+ # if rule2.is_a?(Rule)
81
+ # return if rule.equal?(rule2)
82
+ # done[value.__id__] = [rule2, rule]
83
+ # elsif rule2.is_a?(Array)
84
+ # return if rule2.any? {|r| r.equal?(rule)}
85
+ # done[value.__id__] << rule
86
+ # else
87
+ # raise "unreachable"
88
+ # end
89
+ #end
90
+ return if done[value.__id__] # avoid infinite loop
91
+ done[value.__id__] = rule
92
+ end
93
+ if rule.required && value.nil?
94
+ #* key=:required_novalue msg="value required but none."
95
+ errors << validate_error(:required_novalue, rule, path, value)
96
+ return
97
+ end
98
+ if rule.type_class && !value.nil? && !value.is_a?(rule.type_class)
99
+ unless rule.classobj && value.is_a?(rule.classobj)
100
+ #* key=:type_unmatch msg="not a %s."
101
+ errors << validate_error(:type_unmatch, rule, path, value, [Kwalify.word(rule.type)])
102
+ return
103
+ end
104
+ end
105
+ #
106
+ n = errors.length
107
+ if rule.sequence
108
+ _validate_sequence(value, rule, path, errors, done, uniq_table, recursive)
109
+ elsif rule.mapping
110
+ _validate_mapping(value, rule, path, errors, done, uniq_table, recursive)
111
+ else
112
+ _validate_scalar(value, rule, path, errors, done, uniq_table)
113
+ end
114
+ return unless errors.length == n
115
+ #
116
+ #path_str = path.is_a?(Array) ? '/'+path.join('/') : path
117
+ #validate_hook(value, rule, path_str, errors)
118
+ #@block.call(value, rule, path_str, errors) if @block
119
+ validate_hook(value, rule, path, errors)
120
+ @block.call(value, rule, path, errors) if @block
121
+ end
122
+
123
+
124
+ private
125
+
126
+
127
+ def _validate_sequence(list, seq_rule, path, errors, done, uniq_table, recursive=true)
128
+ assert_error("seq_rule.sequence.class==#{seq_rule.sequence.class.name} (expected Array)") unless seq_rule.sequence.is_a?(Array)
129
+ assert_error("seq_rule.sequence.length==#{seq_rule.sequence.length} (expected 1)") unless seq_rule.sequence.length == 1
130
+ return if list.nil? || !recursive
131
+ rule = seq_rule.sequence[0]
132
+ uniq_table = rule._uniqueness_check_table()
133
+ list.each_with_index do |val, i|
134
+ child_path = path.is_a?(Array) ? path + [i] : "#{path}/#{i}"
135
+ _validate(val, rule, child_path, errors, done, uniq_table) ## validate recursively
136
+ end
137
+ end
138
+
139
+
140
+ def _validate_mapping(hash, map_rule, path, errors, done, uniq_table, recursive=true)
141
+ assert_error("map_rule.mapping.class==#{map_rule.mapping.class.name} (expected Hash)") unless map_rule.mapping.is_a?(Hash)
142
+ return if hash.nil?
143
+ return if !recursive
144
+ _validate_mapping_required_keys(hash, map_rule, path, errors)
145
+ hash.each do |key, val|
146
+ rule = map_rule.mapping[key]
147
+ child_path = path.is_a?(Array) ? path+[key] : "#{path}/#{key}"
148
+ unless rule
149
+ #* key=:key_undefined msg="key '%s' is undefined."
150
+ errors << validate_error(:key_undefined, rule, child_path, hash, ["#{key}:"])
151
+ ##* key=:key_undefined msg="undefined key."
152
+ #errors << validate_error(:key_undefined, rule, child_path, "#{key}:")
153
+ else
154
+ _validate(val, rule, child_path, errors, done,
155
+ uniq_table ? uniq_table[key] : nil) ## validate recursively
156
+ end
157
+ end
158
+ end
159
+
160
+
161
+ def _validate_mapping_required_keys(hash, map_rule, path, errors) #:nodoc:
162
+ map_rule.mapping.each do |key, rule|
163
+ #next unless rule.required
164
+ #val = hash.is_a?(Hash) ? hash[key] : hash.instance_variable_get("@#{key}")
165
+ #if val.nil?
166
+ if rule.required && hash[key].nil? # or !hash.key?(key)
167
+ #* key=:required_nokey msg="key '%s:' is required."
168
+ errors << validate_error(:required_nokey, rule, path, hash, [key])
169
+ end
170
+ end
171
+ end
172
+ public :_validate_mapping_required_keys
173
+
174
+
175
+ def _validate_scalar(value, rule, path, errors, done, uniq_table)
176
+ assert_error("rule.sequence.class==#{rule.sequence.class.name} (expected NilClass)") if rule.sequence
177
+ assert_error("rule.mapping.class==#{rule.mapping.class.name} (expected NilClass)") if rule.mapping
178
+ _validate_assert( value, rule, path, errors) if rule.assert_proc
179
+ _validate_enum( value, rule, path, errors) if rule.enum
180
+ return if value.nil?
181
+ _validate_pattern(value, rule, path, errors) if rule.pattern
182
+ _validate_range( value, rule, path, errors) if rule.range
183
+ _validate_length( value, rule, path, errors) if rule.length
184
+ _validate_unique( value, rule, path, errors, uniq_table) if uniq_table
185
+ end
186
+
187
+
188
+ def _validate_unique(value, rule, path, errors, uniq_table)
189
+ assert_error "uniq_table=#{uniq_table.inspect}" unless rule.unique || rule.ident
190
+ if uniq_table.key?(value)
191
+ exist_at = uniq_table[value]
192
+ exist_at = "/#{exist_at.join('/')}" if exist_at.is_a?(Array)
193
+ #* key=:value_notunique msg="is already used at '%s'."
194
+ errors << validate_error(:value_notunique, rule, path, value, exist_at)
195
+ else
196
+ uniq_table[value] = path.dup
197
+ end
198
+ end
199
+ public :_validate_unique
200
+
201
+
202
+ def _validate_assert(value, rule, path, errors)
203
+ assert_error("rule=#{rule._inspect}") unless rule.assert_proc
204
+ unless rule.assert_proc.call(value)
205
+ #* key=:assert_failed msg="assertion expression failed (%s)."
206
+ errors << validate_error(:assert_failed, rule, path, value, [rule.assert])
207
+ end
208
+ end
209
+
210
+
211
+ def _validate_enum(value, rule, path, errors)
212
+ assert_error("rule=#{rule._inspect}") unless rule.enum
213
+ unless rule.enum.include?(value)
214
+ keyname = path.is_a?(Array) ? path[-1] : File.basename(path)
215
+ keyname = 'enum' if keyname =~ /\A\d+\z/
216
+ #* key=:enum_notexist msg="invalid %s value."
217
+ errors << validate_error(:enum_notexist, rule, path, value, [keyname])
218
+ end
219
+ end
220
+
221
+
222
+ def _validate_pattern(value, rule, path, errors)
223
+ assert_error("rule=#{rule._inspect}") unless rule.pattern
224
+ unless value.to_s =~ rule.regexp
225
+ #* key=:pattern_unmatch msg="not matched to pattern %s."
226
+ errors << validate_error(:pattern_unmatch, rule, path, value, [rule.pattern])
227
+ end
228
+ end
229
+
230
+
231
+ def _validate_range(value, rule, path, errors)
232
+ assert_error("rule=#{rule._inspect}") unless rule.range
233
+ assert_error("value.class=#{value.class.name}") unless Types.scalar?(value)
234
+ h = rule.range
235
+ max, min, max_ex, min_ex = h['max'], h['min'], h['max-ex'], h['min-ex']
236
+ if max && max < value
237
+ #* key=:range_toolarge msg="too large (> max %s)."
238
+ errors << validate_error(:range_toolarge, rule, path, value, [max.to_s])
239
+ end
240
+ if min && min > value
241
+ #* key=:range_toosmall msg="too small (< min %s)."
242
+ errors << validate_error(:range_toosmall, rule, path, value, [min.to_s])
243
+ end
244
+ if max_ex && max_ex <= value
245
+ #* key=:range_toolargeex msg="too large (>= max %s)."
246
+ errors << validate_error(:range_toolargeex, rule, path, value, [max_ex.to_s])
247
+ end
248
+ if min_ex && min_ex >= value
249
+ #* key=:range_toosmallex msg="too small (<= min %s)."
250
+ errors << validate_error(:range_toosmallex, rule, path, value, [min_ex.to_s])
251
+ end
252
+ end
253
+
254
+
255
+ def _validate_length(value, rule, path, errors)
256
+ assert_error("rule=#{rule._inspect}") unless rule.length
257
+ assert_error("value.class=#{value.class.name}") unless value.is_a?(String) || value.is_a?(Text)
258
+ len = value.to_s.length
259
+ h = rule.length
260
+ max, min, max_ex, min_ex = h['max'], h['min'], h['max-ex'], h['min-ex']
261
+ if max && max < len
262
+ #* key=:length_toolong msg="too long (length %d > max %d)."
263
+ errors << validate_error(:length_toolong, rule, path, value, [len, max])
264
+ end
265
+ if min && min > len
266
+ #* key=:length_tooshort msg="too short (length %d < min %d)."
267
+ errors << validate_error(:length_tooshort, rule, path, value, [len, min])
268
+ end
269
+ if max_ex && max_ex <= len
270
+ #* key=:length_toolongex msg="too long (length %d >= max %d)."
271
+ errors << validate_error(:length_toolongex, rule, path, value, [len, max_ex])
272
+ end
273
+ if min_ex && min_ex >= len
274
+ #* key=:length_tooshortex msg="too short (length %d <= min %d)."
275
+ errors << validate_error(:length_tooshortex, rule, path, value, [len, min_ex])
276
+ end
277
+ end
278
+
279
+
280
+ end
281
+
282
+ end