rkwalify 1.4.0.pre.beta

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 (250) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/ruby.yml +39 -0
  3. data/.gitignore +63 -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 +61 -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 +339 -0
  20. data/CONTRIBUTING.md +34 -0
  21. data/CONTRIBUTORS.md +16 -0
  22. data/Gemfile +16 -0
  23. data/Gemfile.lock +146 -0
  24. data/MIT-LICENSE +21 -0
  25. data/README.md +70 -0
  26. data/ROLL-OUT-STRATEGY.md +90 -0
  27. data/Rakefile +11 -0
  28. data/bin/kwalify +4167 -0
  29. data/bin/kwalify.rb +4167 -0
  30. data/bin/kwalify.schema.yaml +59 -0
  31. data/contrib/inline-require +181 -0
  32. data/contrib/kwalify +4167 -0
  33. data/contrib/kwalify-0.7.2 +4160 -0
  34. data/devbin/README.md +35 -0
  35. data/devbin/chk-rad-repo.sh +20 -0
  36. data/devbin/chkcopyrights.sh +42 -0
  37. data/devbin/chkspelling.sh +25 -0
  38. data/devbin/got-all-rel-numbers.sh +6 -0
  39. data/devbin/mkbig-rkwalify.sh +7 -0
  40. data/devbin/mkgem_file.sh +5 -0
  41. data/devbin/mktag +3 -0
  42. data/devbin/ruby_rails_wordlist.txt +195 -0
  43. data/devbin/runtests.sh +6 -0
  44. data/devbin/smoke-tests.golden +331 -0
  45. data/devbin/smoke-tests.sh +145 -0
  46. data/devbin/update-rel-numbers.sh +8 -0
  47. data/doc/docstyle.css +188 -0
  48. data/doc/img/fig01.png +0 -0
  49. data/doc/users-guide.html +2051 -0
  50. data/doc-api/classes/CommandOptionError.html +184 -0
  51. data/doc-api/classes/CommandOptionParser.html +325 -0
  52. data/doc-api/classes/Kwalify/AssertionError.html +148 -0
  53. data/doc-api/classes/Kwalify/BaseError.html +297 -0
  54. data/doc-api/classes/Kwalify/BaseParser.html +461 -0
  55. data/doc-api/classes/Kwalify/CommandOptionError.html +168 -0
  56. data/doc-api/classes/Kwalify/ErrorHelper.html +223 -0
  57. data/doc-api/classes/Kwalify/HashInterface.html +118 -0
  58. data/doc-api/classes/Kwalify/Json.html +105 -0
  59. data/doc-api/classes/Kwalify/KwalifyError.html +111 -0
  60. data/doc-api/classes/Kwalify/Main.html +339 -0
  61. data/doc-api/classes/Kwalify/MetaValidator.html +448 -0
  62. data/doc-api/classes/Kwalify/Parser.html +155 -0
  63. data/doc-api/classes/Kwalify/PlainYamlParser/Alias.html +165 -0
  64. data/doc-api/classes/Kwalify/PlainYamlParser.html +523 -0
  65. data/doc-api/classes/Kwalify/Rule.html +433 -0
  66. data/doc-api/classes/Kwalify/SchemaError.html +148 -0
  67. data/doc-api/classes/Kwalify/SyntaxError.html +185 -0
  68. data/doc-api/classes/Kwalify/Types.html +302 -0
  69. data/doc-api/classes/Kwalify/Util/HashLike.html +246 -0
  70. data/doc-api/classes/Kwalify/Util/OrderedHash.html +330 -0
  71. data/doc-api/classes/Kwalify/Util.html +390 -0
  72. data/doc-api/classes/Kwalify/ValidationError.html +148 -0
  73. data/doc-api/classes/Kwalify/Validator.html +381 -0
  74. data/doc-api/classes/Kwalify/Yaml/Parser.html +1538 -0
  75. data/doc-api/classes/Kwalify/Yaml.html +194 -0
  76. data/doc-api/classes/Kwalify/YamlParser.html +542 -0
  77. data/doc-api/classes/Kwalify/YamlSyntaxError.html +119 -0
  78. data/doc-api/classes/Kwalify.html +292 -0
  79. data/doc-api/classes/Test/Unit.html +101 -0
  80. data/doc-api/classes/Test.html +107 -0
  81. data/doc-api/created.rid +1 -0
  82. data/doc-api/files/__/README_txt.html +153 -0
  83. data/doc-api/files/kwalify/errors_rb.html +114 -0
  84. data/doc-api/files/kwalify/main_rb.html +118 -0
  85. data/doc-api/files/kwalify/messages_rb.html +107 -0
  86. data/doc-api/files/kwalify/meta-validator_rb.html +117 -0
  87. data/doc-api/files/kwalify/parser/base_rb.html +116 -0
  88. data/doc-api/files/kwalify/parser/yaml_rb.html +117 -0
  89. data/doc-api/files/kwalify/rule_rb.html +116 -0
  90. data/doc-api/files/kwalify/types_rb.html +114 -0
  91. data/doc-api/files/kwalify/util/assert-text-equal_rb.html +115 -0
  92. data/doc-api/files/kwalify/util/hash-interface_rb.html +114 -0
  93. data/doc-api/files/kwalify/util/hashlike_rb.html +107 -0
  94. data/doc-api/files/kwalify/util/option-parser_rb.html +107 -0
  95. data/doc-api/files/kwalify/util/ordered-hash_rb.html +107 -0
  96. data/doc-api/files/kwalify/util/testcase-helper_rb.html +115 -0
  97. data/doc-api/files/kwalify/util_rb.html +107 -0
  98. data/doc-api/files/kwalify/validator_rb.html +117 -0
  99. data/doc-api/files/kwalify/yaml-parser_rb.html +117 -0
  100. data/doc-api/files/kwalify_rb.html +121 -0
  101. data/doc-api/fr_class_index.html +57 -0
  102. data/doc-api/fr_file_index.html +45 -0
  103. data/doc-api/fr_method_index.html +168 -0
  104. data/doc-api/index.html +24 -0
  105. data/doc-api/rdoc-style.css +208 -0
  106. data/examples/address-book/Makefile +10 -0
  107. data/examples/address-book/address-book.schema.yaml +45 -0
  108. data/examples/address-book/address-book.yaml +36 -0
  109. data/examples/data-binding/BABEL.data.yaml +63 -0
  110. data/examples/data-binding/BABEL.schema.yaml +31 -0
  111. data/examples/data-binding/Makefile +8 -0
  112. data/examples/data-binding/Rakefile +13 -0
  113. data/examples/data-binding/main.rb +25 -0
  114. data/examples/invoice/Makefile +9 -0
  115. data/examples/invoice/invoice.schema.yaml +43 -0
  116. data/examples/invoice/invoice.yaml +32 -0
  117. data/examples/tapkit/Makefile +10 -0
  118. data/examples/tapkit/main.rb +7 -0
  119. data/examples/tapkit/tapkit.schema.yaml +146 -0
  120. data/examples/tapkit/tapkit.yaml +85 -0
  121. data/lib/kwalify/errors.rb +127 -0
  122. data/lib/kwalify/kwalify.schema.yaml +58 -0
  123. data/lib/kwalify/main.rb +442 -0
  124. data/lib/kwalify/messages.rb +173 -0
  125. data/lib/kwalify/meta-validator.rb +276 -0
  126. data/lib/kwalify/parser/base.rb +128 -0
  127. data/lib/kwalify/parser/yaml.rb +841 -0
  128. data/lib/kwalify/rule.rb +562 -0
  129. data/lib/kwalify/templates/genclass-java.eruby +222 -0
  130. data/lib/kwalify/templates/genclass-php.eruby +104 -0
  131. data/lib/kwalify/templates/genclass-ruby.eruby +113 -0
  132. data/lib/kwalify/types.rb +156 -0
  133. data/lib/kwalify/util/assert-text-equal.rb +46 -0
  134. data/lib/kwalify/util/hash-interface.rb +18 -0
  135. data/lib/kwalify/util/hashlike.rb +51 -0
  136. data/lib/kwalify/util/option-parser.rb +220 -0
  137. data/lib/kwalify/util/ordered-hash.rb +57 -0
  138. data/lib/kwalify/util/testcase-helper.rb +112 -0
  139. data/lib/kwalify/util.rb +159 -0
  140. data/lib/kwalify/validator.rb +282 -0
  141. data/lib/kwalify/version.rb +5 -0
  142. data/lib/kwalify/yaml-parser.rb +871 -0
  143. data/lib/kwalify.rb +61 -0
  144. data/rkwalify.gemspec +26 -0
  145. data/test/Rookbook.yaml +15 -0
  146. data/test/data/users-guide/AddressBook.java.expected +40 -0
  147. data/test/data/users-guide/BABEL.data.yaml +24 -0
  148. data/test/data/users-guide/BABEL.schema.yaml +30 -0
  149. data/test/data/users-guide/ExampleAddressBook.java +47 -0
  150. data/test/data/users-guide/Group.java.expected +24 -0
  151. data/test/data/users-guide/Person.java.expected +44 -0
  152. data/test/data/users-guide/address_book.rb +52 -0
  153. data/test/data/users-guide/address_book.schema.yaml +28 -0
  154. data/test/data/users-guide/address_book.yaml +27 -0
  155. data/test/data/users-guide/answers-schema.yaml +12 -0
  156. data/test/data/users-guide/answers-validator.rb +53 -0
  157. data/test/data/users-guide/babel_genclass.result +26 -0
  158. data/test/data/users-guide/config.schema.yaml +7 -0
  159. data/test/data/users-guide/config.yaml +4 -0
  160. data/test/data/users-guide/document01a.yaml +3 -0
  161. data/test/data/users-guide/document01b.yaml +3 -0
  162. data/test/data/users-guide/document02a.yaml +4 -0
  163. data/test/data/users-guide/document02b.yaml +4 -0
  164. data/test/data/users-guide/document03a.yaml +6 -0
  165. data/test/data/users-guide/document03b.yaml +6 -0
  166. data/test/data/users-guide/document04a.yaml +9 -0
  167. data/test/data/users-guide/document04b.yaml +9 -0
  168. data/test/data/users-guide/document05a.yaml +11 -0
  169. data/test/data/users-guide/document05b.yaml +12 -0
  170. data/test/data/users-guide/document06a.yaml +15 -0
  171. data/test/data/users-guide/document06b.yaml +16 -0
  172. data/test/data/users-guide/document07a.yaml +9 -0
  173. data/test/data/users-guide/document07b.yaml +7 -0
  174. data/test/data/users-guide/document12a.json +10 -0
  175. data/test/data/users-guide/document12b.json +6 -0
  176. data/test/data/users-guide/document13a.yaml +17 -0
  177. data/test/data/users-guide/document14a.yaml +3 -0
  178. data/test/data/users-guide/document14b.yaml +3 -0
  179. data/test/data/users-guide/document15a.yaml +6 -0
  180. data/test/data/users-guide/document15b.yaml +5 -0
  181. data/test/data/users-guide/example_address_book.rb +11 -0
  182. data/test/data/users-guide/example_address_book_java.result +32 -0
  183. data/test/data/users-guide/example_address_book_ruby.result +31 -0
  184. data/test/data/users-guide/genclass_java.result +4 -0
  185. data/test/data/users-guide/howto-validation-with-parsing.rb +28 -0
  186. data/test/data/users-guide/howto-validation.rb +25 -0
  187. data/test/data/users-guide/howto3.rb +6 -0
  188. data/test/data/users-guide/howto3.result +5 -0
  189. data/test/data/users-guide/howto3.yaml +8 -0
  190. data/test/data/users-guide/howto5_databinding.result +111 -0
  191. data/test/data/users-guide/invalid01.result +3 -0
  192. data/test/data/users-guide/invalid02.result +5 -0
  193. data/test/data/users-guide/invalid03.result +5 -0
  194. data/test/data/users-guide/invalid04.result +4 -0
  195. data/test/data/users-guide/invalid05.result +11 -0
  196. data/test/data/users-guide/invalid06.result +4 -0
  197. data/test/data/users-guide/invalid07.result +3 -0
  198. data/test/data/users-guide/invalid08.result +3 -0
  199. data/test/data/users-guide/invalid12.json +8 -0
  200. data/test/data/users-guide/invalid14.result +4 -0
  201. data/test/data/users-guide/invalid15.result +4 -0
  202. data/test/data/users-guide/loadbabel.rb +27 -0
  203. data/test/data/users-guide/loadconfig.rb +17 -0
  204. data/test/data/users-guide/loadconfig.result +6 -0
  205. data/test/data/users-guide/models.rb +24 -0
  206. data/test/data/users-guide/option_ha.result +6 -0
  207. data/test/data/users-guide/option_ha_genclass_java.result +7 -0
  208. data/test/data/users-guide/schema01.yaml +3 -0
  209. data/test/data/users-guide/schema02.yaml +12 -0
  210. data/test/data/users-guide/schema03.yaml +9 -0
  211. data/test/data/users-guide/schema04.yaml +20 -0
  212. data/test/data/users-guide/schema05.yaml +29 -0
  213. data/test/data/users-guide/schema06.yaml +11 -0
  214. data/test/data/users-guide/schema12.json +12 -0
  215. data/test/data/users-guide/schema13.yaml +13 -0
  216. data/test/data/users-guide/schema14.yaml +5 -0
  217. data/test/data/users-guide/schema15.yaml +21 -0
  218. data/test/data/users-guide/valid01.result +2 -0
  219. data/test/data/users-guide/valid02.result +2 -0
  220. data/test/data/users-guide/valid03.result +2 -0
  221. data/test/data/users-guide/valid04.result +2 -0
  222. data/test/data/users-guide/valid05.result +2 -0
  223. data/test/data/users-guide/valid06.result +2 -0
  224. data/test/data/users-guide/valid07.result +2 -0
  225. data/test/data/users-guide/valid08.result +2 -0
  226. data/test/data/users-guide/valid12.result +2 -0
  227. data/test/data/users-guide/valid13.result +2 -0
  228. data/test/data/users-guide/valid14.result +2 -0
  229. data/test/data/users-guide/valid15.result +2 -0
  230. data/test/data/users-guide/validate08.rb +37 -0
  231. data/test/test-action.rb +73 -0
  232. data/test/test-action.yaml +738 -0
  233. data/test/test-databinding.rb +84 -0
  234. data/test/test-databinding.yaml +339 -0
  235. data/test/test-main.rb +156 -0
  236. data/test/test-main.yaml +409 -0
  237. data/test/test-metavalidator.rb +80 -0
  238. data/test/test-metavalidator.yaml +1179 -0
  239. data/test/test-parser-yaml.rb +57 -0
  240. data/test/test-parser-yaml.yaml +1753 -0
  241. data/test/test-rule.rb +26 -0
  242. data/test/test-rule.yaml +317 -0
  243. data/test/test-users-guide.rb +82 -0
  244. data/test/test-util.rb +125 -0
  245. data/test/test-validator.rb +95 -0
  246. data/test/test-validator.yaml +986 -0
  247. data/test/test-yaml-parser.rb +47 -0
  248. data/test/test-yaml-parser.yaml +1226 -0
  249. data/test/test.rb +77 -0
  250. metadata +297 -0
@@ -0,0 +1,871 @@
1
+ ###
2
+ ### $Rev$
3
+ ### $Release 1.4.0-beta $
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
+ require 'date'
13
+
14
+
15
+ module Kwalify
16
+
17
+ ##
18
+ ## base class of yaml parser
19
+ ##
20
+ ## ex.
21
+ ## str = ARGF.read()
22
+ ## parser = Kwalify::PlainYamlParser.new(str)
23
+ ## doc = parser.parse()
24
+ ## p doc
25
+ ##
26
+ class PlainYamlParser
27
+
28
+ class Alias
29
+ def initialize(label, linenum)
30
+ @label = label
31
+ @linenum = linenum
32
+ end
33
+ attr_reader :label, :linenum
34
+ end
35
+
36
+
37
+ def initialize(yaml_str)
38
+ @lines = yaml_str.split("\n")
39
+ @line = nil
40
+ @linenum = 0
41
+ @anchors = {}
42
+ @aliases = {}
43
+ end
44
+
45
+
46
+ def parse()
47
+ data = parse_child(0)
48
+ if data.nil? && @end_flag == '---'
49
+ data = parse_child(0)
50
+ end
51
+ resolve_aliases(data) unless @aliases.empty?
52
+ return data
53
+ end
54
+
55
+
56
+ def has_next?
57
+ return @end_flag != 'EOF'
58
+ end
59
+
60
+
61
+ def parse_all
62
+ list = []
63
+ while has_next()
64
+ doc = parse()
65
+ list << doc
66
+ end
67
+ return list
68
+ end
69
+
70
+
71
+ protected
72
+
73
+
74
+ def create_sequence(linenum=nil)
75
+ return []
76
+ end
77
+
78
+ def add_to_seq(seq, value, linenum)
79
+ seq << value
80
+ end
81
+
82
+ def set_seq_at(seq, i, value, linenum)
83
+ seq[i] = value
84
+ end
85
+
86
+ def create_mapping(linenum=nil)
87
+ return {}
88
+ end
89
+
90
+ def add_to_map(map, key, value, linenum)
91
+ map[key] = value
92
+ end
93
+
94
+ def set_map_with(map, key, value, linenum)
95
+ map[key] = value
96
+ end
97
+
98
+ def set_default(map, value, linenum)
99
+ map.value = value
100
+ end
101
+
102
+ def merge_map(map, map2, linenum)
103
+ map2.each do |key, val|
104
+ map[key] = value unless map.key?(key)
105
+ end
106
+ end
107
+
108
+ def create_scalar(value, linenum=nil)
109
+ return value
110
+ end
111
+
112
+
113
+ def current_line
114
+ return @line
115
+ end
116
+
117
+ def current_linenum
118
+ return @linenum
119
+ end
120
+
121
+
122
+ private
123
+
124
+
125
+ def getline
126
+ line = _getline()
127
+ line = _getline() while line && line =~ /^\s*($|\#)/
128
+ return line
129
+ end
130
+
131
+ def _getline
132
+ @line = @lines[@linenum]
133
+ @linenum += 1
134
+ case @line
135
+ when nil ; @end_flag = 'EOF'
136
+ when /^\.\.\.$/ ; @end_flag = '...'; @line = nil
137
+ when /^---(\s+.*)?$/ ; @end_flag = '---'; @line = nil
138
+ else ; @end_flag = nil
139
+ end
140
+ return @line
141
+ end
142
+
143
+
144
+ def reset_sbuf(str)
145
+ @sbuf = str[-1] == ?\n ? str : str + "\n"
146
+ @index = -1
147
+ end
148
+
149
+
150
+ def _getchar
151
+ @index += 1
152
+ ch = @sbuf[@index]
153
+ while ch.nil?
154
+ break if (line = getline()).nil?
155
+ reset_sbuf(line)
156
+ @index += 1
157
+ ch = @sbuf[@index]
158
+ end
159
+ return ch
160
+ end
161
+
162
+ def getchar
163
+ ch = _getchar()
164
+ ch = _getchar() while ch && white?(ch)
165
+ return ch
166
+ end
167
+
168
+ def getchar_or_nl
169
+ ch = _getchar()
170
+ ch = _getchar() while ch && white?(ch) && ch != ?\n
171
+ return ch
172
+ end
173
+
174
+ def current_char
175
+ return @sbuf[@index]
176
+ end
177
+
178
+ def getlabel
179
+ if @sbuf[@index..] =~ /\A\w[-\w]*/
180
+ label = $&
181
+ @index += label.length
182
+ else
183
+ label = nil
184
+ end
185
+ return label
186
+ end
187
+
188
+ #--
189
+ #def syntax_error(error_symbol, linenum=@linenum)
190
+ # msg = Kwalify.msg(error_symbol) % [linenum]
191
+ # return Kwalify::YamlSyntaxError.new(msg, linenum,error_symbol)
192
+ #end
193
+ #++
194
+ def syntax_error(error_symbol, arg=nil, linenum=@linenum)
195
+ msg = Kwalify.msg(error_symbol)
196
+ msg = msg % arg.to_a unless arg.nil?
197
+ return Kwalify::YamlSyntaxError.new(msg, linenum, error_symbol)
198
+ end
199
+
200
+ def parse_child(column)
201
+ line = getline()
202
+ return create_scalar(nil) if !line
203
+ line =~ /^( *)(.*)/
204
+ indent = $1.length
205
+ return create_scalar(nil) if indent < column
206
+ value = $2
207
+ return parse_value(column, value, indent)
208
+ end
209
+
210
+
211
+ def parse_value(column, value, value_start_column)
212
+ case value
213
+ when /^-( |$)/
214
+ data = parse_sequence(value_start_column, value)
215
+ when /^(:?:?[-.\w]+\*?|'.*?'|".*?"|=|<<) *:( |$)/
216
+ #when /^:?["']?[-.\w]+["']? *:( |$)/ #'
217
+ data = parse_mapping(value_start_column, value)
218
+ when /^\[/, /^\{/
219
+ data = parse_flowstyle(column, value)
220
+ when /^\&[-\w]+( |$)/
221
+ data = parse_anchor(column, value)
222
+ when /^\*[-\w]+( |$)/
223
+ data = parse_alias(column, value)
224
+ when /^[|>]/
225
+ data = parse_block_text(column, value)
226
+ when /^!/
227
+ data = parse_tag(column, value)
228
+ when /^\#/
229
+ data = parse_child(column)
230
+ else
231
+ data = parse_scalar(column, value)
232
+ end
233
+ return data
234
+ end
235
+
236
+ def white?(ch)
237
+ return ch == ?\ || ch == ?\t || ch == ?\n || ch == ?\r
238
+ end
239
+
240
+
241
+ ##
242
+ ## flowstyle ::= flow_seq | flow_map | flow_scalar | alias
243
+ ##
244
+ ## flow_seq ::= '[' [ flow_seq_item { ',' sp flow_seq_item } ] ']'
245
+ ## flow_seq_item ::= flowstyle
246
+ ##
247
+ ## flow_map ::= '{' [ flow_map_item { ',' sp flow_map_item } ] '}'
248
+ ## flow_map_item ::= flowstyle ':' sp flowstyle
249
+ ##
250
+ ## flow_scalar ::= string | number | boolean | symbol | date
251
+ ##
252
+
253
+ def parse_flowstyle(column, value)
254
+ reset_sbuf(value)
255
+ getchar()
256
+ data = parse_flow(0)
257
+ ch = current_char
258
+ assert ch == ?] || ch == ?}
259
+ ch = getchar_or_nl()
260
+ unless ch == ?\n || ch == ?# || ch.nil?
261
+ #* key=:flow_hastail msg="flow style sequence is closed but got '%s'."
262
+ raise syntax_error(:flow_hastail, [ch.chr])
263
+ end
264
+ getline() if !ch.nil?
265
+ return data
266
+ end
267
+
268
+ def parse_flow(depth)
269
+ ch = current_char()
270
+ #ch = getchar()
271
+ if ch.nil?
272
+ #* key=:flow_eof msg="found EOF when parsing flow style."
273
+ rase syntax_error(:flow_eof)
274
+ end
275
+ ## alias
276
+ if ch == ?*
277
+ _getchar()
278
+ label = getlabel()
279
+ unless label
280
+ #* key=:flow_alias_label msg="alias name expected."
281
+ rase syntax_error(:flow_alias_label)
282
+ end
283
+ data = @anchors[label]
284
+ unless data
285
+ data = register_alias(label)
286
+ #raise syntax_error("anchor '#{label}' not found (cannot refer to backward or child anchor).")
287
+ end
288
+ return data
289
+ end
290
+ ## anchor
291
+ label = nil
292
+ if ch == ?&
293
+ _getchar()
294
+ label = getlabel()
295
+ unless label
296
+ #* key=:flow_anchor_label msg="anchor name expected."
297
+ rase syntax_error(:flow_anchor_label)
298
+ end
299
+ ch = current_char()
300
+ ch = getchar() if white?(ch)
301
+ end
302
+ ## flow data
303
+ if ch == ?[
304
+ data = parse_flow_seq(depth)
305
+ elsif ch == ?{
306
+ data = parse_flow_map(depth)
307
+ else
308
+ data = parse_flow_scalar(depth)
309
+ end
310
+ ## register anchor
311
+ register_anchor(label, data) if label
312
+ return data
313
+ end
314
+
315
+ def parse_flow_seq(depth)
316
+ assert current_char() == ?[
317
+ seq = create_sequence() # []
318
+ ch = getchar()
319
+ if ch != ?}
320
+ linenum = current_linenum()
321
+ #seq << parse_flow_seq_item(depth + 1)
322
+ add_to_seq(seq, parse_flow_seq_item(depth + 1), linenum)
323
+ while (ch = current_char()) == ?,
324
+ ch = getchar()
325
+ if ch == ?]
326
+ #* key=:flow_noseqitem msg="sequence item required (or last comma is extra)."
327
+ raise syntax_error(:flow_noseqitem)
328
+ end
329
+ #break if ch == ?]
330
+ linenum = current_linenum()
331
+ #seq << parse_flow_seq_item(depth + 1)
332
+ add_to_seq(seq, parse_flow_seq_item(depth + 1), linenum)
333
+ end
334
+ end
335
+ unless current_char() == ?]
336
+ #* key=:flow_seqnotclosed msg="flow style sequence requires ']'."
337
+ raise syntax_error(:flow_seqnotclosed)
338
+ end
339
+ getchar() if depth > 0
340
+ return seq
341
+ end
342
+
343
+ def parse_flow_seq_item(depth)
344
+ return parse_flow(depth)
345
+ end
346
+
347
+ def parse_flow_map(depth)
348
+ assert current_char() == ?{ #}
349
+ map = create_mapping() # {}
350
+ ch = getchar()
351
+ if ch != ?}
352
+ linenum = current_linenum()
353
+ key, value = parse_flow_map_item(depth + 1)
354
+ #map[key] = value
355
+ add_to_map(map, key, value, linenum)
356
+ while (ch = current_char()) == ?,
357
+ ch = getchar()
358
+ if ch == ?}
359
+ #* key=:flow_mapnoitem msg="mapping item required (or last comma is extra)."
360
+ raise syntax_error(:flow_mapnoitem)
361
+ end
362
+ #break if ch == ?}
363
+ linenum = current_linenum()
364
+ key, value = parse_flow_map_item(depth + 1)
365
+ #map[key] = value
366
+ add_to_map(map, key, value, linenum)
367
+ end
368
+ end
369
+ unless current_char() == ?}
370
+ #* key=:flow_mapnotclosed msg="flow style mapping requires '}'."
371
+ raise syntax_error(:flow_mapnotclosed)
372
+ end
373
+ getchar() if depth > 0
374
+ return map
375
+ end
376
+
377
+ def parse_flow_map_item(depth)
378
+ key = parse_flow(depth)
379
+ unless (ch = current_char()) == ?:
380
+ $stderr.puts "*** debug: key=#{key.inspect}"
381
+ s = ch ? "'#{ch.chr}'" : "EOF"
382
+ #* key=:flow_nocolon msg="':' expected but got %s."
383
+ raise syntax_error(:flow_nocolon, [s])
384
+ end
385
+ getchar()
386
+ value = parse_flow(depth)
387
+ return key, value
388
+ end
389
+
390
+ def parse_flow_scalar(depth)
391
+ case ch = current_char()
392
+ when ?", ?' #"
393
+ endch = ch
394
+ s = ''
395
+ while (ch = _getchar()) != nil && ch != endch
396
+ if ch == ?\\
397
+ ch = _getchar()
398
+ if ch.nil?
399
+ #* key=:flow_str_notclosed msg="%s: string not closed."
400
+ raise syntax_error(:flow_str_notclosed, endch == ?" ? "'\"'" : '"\'"')
401
+ end
402
+ if endch == ?"
403
+ case ch
404
+ when ?\\ ; s << "\\"
405
+ when ?" ; s << "\""
406
+ when ?n ; s << "\n"
407
+ when ?r ; s << "\r"
408
+ when ?t ; s << "\t"
409
+ when ?b ; s << "\b"
410
+ else ; s << "\\" << ch.chr
411
+ end
412
+ elsif endch == ?'
413
+ case ch
414
+ when ?\\ ; s << '\\'
415
+ when ?' ; s << '\''
416
+ else ; s << '\\' << ch.chr
417
+ end
418
+ end
419
+ else
420
+ s << ch.chr
421
+ end
422
+ end
423
+ getchar()
424
+ scalar = s
425
+ else
426
+ s = ch.chr
427
+ while (ch = _getchar()) != nil && ch != ?: && ch != ?, && ch != ?] && ch != ?}
428
+ s << ch.chr
429
+ end
430
+ scalar = to_scalar(s.strip)
431
+ end
432
+ return create_scalar(scalar)
433
+ end
434
+
435
+
436
+ def parse_tag(column, value)
437
+ assert value =~ /^!\S+/
438
+ value =~ /^!(\S+)((\s+)(.*))?$/
439
+ tag = $1
440
+ space = $3
441
+ value2 = $4
442
+ if value2 && !value2.empty?
443
+ value_start_column = column + 1 + tag.length + space.length
444
+ data = parse_value(column, value2, value_start_column)
445
+ else
446
+ data = parse_child(column)
447
+ end
448
+ return data
449
+ end
450
+
451
+
452
+ def parse_anchor(column, value)
453
+ assert value =~ /^\&([-\w]+)(( *)(.*))?$/
454
+ label = $1
455
+ space = $3
456
+ value2 = $4
457
+ if value2 && !value2.empty?
458
+ #column2 = column + 1 + label.length + space.length
459
+ #data = parse_value(column2, value2)
460
+ value_start_column = column + 1 + label.length + space.length
461
+ data = parse_value(column, value2, value_start_column)
462
+ else
463
+ #column2 = column + 1
464
+ #data = parse_child(column2)
465
+ data = parse_child(column)
466
+ end
467
+ register_anchor(label, data)
468
+ return data
469
+ end
470
+
471
+ def register_anchor(label, data)
472
+ if @anchors[label]
473
+ #* key=:anchor_duplicated msg="anchor '%s' is already used."
474
+ raise syntax_error(:anchor_duplicated, [label])
475
+ end
476
+ @anchors[label] = data
477
+ end
478
+
479
+ def parse_alias(column, value)
480
+ assert value =~ /^\*([-\w]+)(( *)(.*))?$/
481
+ label = $1
482
+ space = $3
483
+ value2 = $4
484
+ if value2 && !value2.empty? && value2[0] != ?\#
485
+ #* key=:alias_extradata msg="alias cannot take any data."
486
+ raise syntax_error(:alias_extradata)
487
+ end
488
+ data = @anchors[label]
489
+ unless data
490
+ data = register_alias(label)
491
+ #raise syntax_error("anchor '#{label}' not found (cannot refer to backward or child anchor).")
492
+ end
493
+ getline()
494
+ return data
495
+ end
496
+
497
+ def register_alias(label)
498
+ @aliases[label] ||= 0
499
+ @aliases[label] += 1
500
+ return Alias.new(label, @linenum)
501
+ end
502
+
503
+
504
+ def resolve_aliases(data)
505
+ @resolved ||= {}
506
+ return if @resolved[data.__id__]
507
+ @resolved[data.__id__] = data
508
+ case data
509
+ when Array
510
+ seq = data
511
+ seq.each_with_index do |val, i|
512
+ if val.is_a?(Alias)
513
+ anchor = val
514
+ if @anchors.key?(anchor.label)
515
+ #seq[i] = @anchors[anchor.label]
516
+ set_seq_at(seq, i, @anchors[anchor.label], anchor.linenum)
517
+ else
518
+ #* key=:anchor_notfound msg="anchor '%s' not found"
519
+ raise syntax_error(:anchor_notfound, [anchor.label], val.linenum)
520
+ end
521
+ elsif val.is_a?(Array) || val.is_a?(Hash)
522
+ resolve_aliases(val)
523
+ end
524
+ end
525
+ when Hash
526
+ map = data
527
+ map.each do |key, val|
528
+ if val.is_a?(Alias)
529
+ if @anchors.key?(val.label)
530
+ anchor = val
531
+ #map[key] = @anchors[anchor.label]
532
+ set_map_with(map, key, @anchors[anchor.label], anchor.linenum)
533
+ else
534
+ ## :anchor_notfound is already defined on above
535
+ raise syntax_error(:anchor_notfound, [val.label], val.linenum)
536
+ end
537
+ elsif val.is_a?(Array) || val.is_a?(Hash)
538
+ resolve_aliases(val)
539
+ end
540
+ end
541
+ else
542
+ assert !data.is_a?(Alias)
543
+ end
544
+ end
545
+
546
+
547
+ def parse_block_text(column, value)
548
+ assert value =~ /^[>|\|]/
549
+ value =~ /^([>|\|])([-+]?)(\d+)?\s*(.*)$/
550
+ char = $1
551
+ indicator = $2
552
+ sep = char == "|" ? "\n" : " "
553
+ margin = $3 && !$3.empty? ? $3.to_i : nil
554
+ #text = $4.empty? ? '' : $4 + sep
555
+ text = $4
556
+ s = ''
557
+ empty = ''
558
+ min_indent = -1
559
+ while line = _getline()
560
+ line =~ /^( *)(.*)/
561
+ indent = $1.length
562
+ if $2.empty?
563
+ empty << "\n"
564
+ elsif indent < column
565
+ break
566
+ else
567
+ min_indent = indent if min_indent < 0 || min_indent > indent
568
+ s << empty << line
569
+ empty = ''
570
+ end
571
+ end
572
+ s << empty if indicator == '+' && char != '>'
573
+ s[-1] = "" if indicator == '-'
574
+ min_indent = column + margin - 1 if margin
575
+ if min_indent > 0
576
+ sp = ' ' * min_indent
577
+ s.gsub!(/^#{sp}/, '')
578
+ end
579
+ if char == '>'
580
+ s.gsub!(/([^\n])\n([^\n])/, '\1 \2')
581
+ s.gsub!(/\n(\n+)/, '\1')
582
+ s << empty if indicator == '+'
583
+ end
584
+ getline() if current_line() =~ /^\s*\#/
585
+ return create_scalar(text + s)
586
+ end
587
+
588
+
589
+ def parse_sequence(column, value)
590
+ assert value =~ /^-(( +)(.*))?$/
591
+ seq = create_sequence() # []
592
+ while true
593
+ unless value =~ /^-(( +)(.*))?$/
594
+ #* key=:sequence_noitem msg="sequence item is expected."
595
+ raise syntax_error(:sequence_noitem)
596
+ end
597
+ value2 = $3
598
+ space = $2
599
+ column2 = column + 1
600
+ linenum = current_linenum()
601
+ #
602
+ if !value2 || value2.empty?
603
+ elem = parse_child(column2)
604
+ else
605
+ value_start_column = column2 + space.length
606
+ elem = parse_value(column2, value2, value_start_column)
607
+ end
608
+ add_to_seq(seq, elem, linenum) #seq << elem
609
+ #
610
+ line = current_line()
611
+ break unless line
612
+ line =~ /^( *)(.*)/
613
+ indent = $1.length
614
+ if indent < column
615
+ break
616
+ elsif indent > column
617
+ #* key=:sequence_badindent msg="illegal indent of sequence."
618
+ raise syntax_error(:sequence_badindent)
619
+ end
620
+ value = $2
621
+ end
622
+ return seq
623
+ end
624
+
625
+
626
+ def parse_mapping(column, value)
627
+ #assert value =~ /^(:?["']?[-.\w]+["']? *):(( +)(.*))?$/ #'
628
+ assert value =~ /^((?::?[-.\w]+\*?|'.*?'|".*?"|=|<<) *):(( +)(.*))?$/
629
+ map = create_mapping() # {}
630
+ while true
631
+ #unless value =~ /^(:?["']?[-.\w]+["']? *):(( +)(.*))?$/ #'
632
+ unless value =~ /^((?::?[-.\w]+\*?|'.*?'|".*?"|=|<<) *):(( +)(.*))?$/
633
+ #* key=:mapping_noitem msg="mapping item is expected."
634
+ raise syntax_error(:mapping_noitem)
635
+ end
636
+ v = $1.strip
637
+ key = to_scalar(v)
638
+ value2 = $4
639
+ column2 = column + 1
640
+ linenum = current_linenum()
641
+ #
642
+ if !value2 || value2.empty?
643
+ elem = parse_child(column2)
644
+ else
645
+ value_start_column = column2 + $1.length + $3.length
646
+ elem = parse_value(column2, value2, value_start_column)
647
+ end
648
+ case v
649
+ when '='
650
+ set_default(map, elem, linenum)
651
+ when '<<'
652
+ merge_map(map, elem, linenum)
653
+ else
654
+ add_to_map(map, key, elem, linenum) # map[key] = elem
655
+ end
656
+ #
657
+ line = current_line()
658
+ break unless line
659
+ line =~ /^( *)(.*)/
660
+ indent = $1.length
661
+ if indent < column
662
+ break
663
+ elsif indent > column
664
+ #* key=:mapping_badindent msg="illegal indent of mapping."
665
+ raise syntax_error(:mapping_badindent)
666
+ end
667
+ value = $2
668
+ end
669
+ return map
670
+ end
671
+
672
+
673
+ def parse_scalar(indent, value)
674
+ data = create_scalar(to_scalar(value))
675
+ getline()
676
+ return data
677
+ end
678
+
679
+
680
+ def to_scalar(str)
681
+ case str
682
+ when /^"(.*)["`]([ \t]*\#.*$)?/ ; return $1
683
+ #when /^'(.*)'([ \t]*\#.*$)?/ ; return $1
684
+ when /^(.*\S)[ \t]*\#/ ; str = $1
685
+ end
686
+
687
+ case str
688
+ when /^-?\d+$/ ; return str.to_i # integer
689
+ when /^-?\d+\.\d+$/ ; return str.to_f # float
690
+ when "true", "yes", "on" ; return true # true
691
+ when "false", "no", "off" ; return false # false
692
+ when "null", "~" ; return nil # nil
693
+ #when /^"(.*)"$/ ; return $1 # "string"
694
+ #when /^'(.*)'$/ ; return $1 # 'string'
695
+ when /^:(\w+)$/ ; return $1.intern # :symbol
696
+ when /^(\d\d\d\d)-(\d\d)-(\d\d)$/ # date
697
+ year, month, day = $1.to_i, $2.to_i, $3.to_i
698
+ return Date.new(year, month, day)
699
+ when /^(\d\d\d\d)-(\d\d)-(\d\d)(?:[Tt]|[ \t]+)(\d\d?):(\d\d):(\d\d)(\.\d*)?(?:Z|[ \t]*([-+]\d\d?)(?::(\d\d))?)?$/
700
+ year, mon, mday, hour, min, sec, usec, tzone_h, tzone_m = $1, $2, $3, $4, $5, $6, $7, $8, $9
701
+ #Time.utc(sec, min, hour, mday, mon, year, wday, yday, isdst, zone)
702
+ #t = Time.utc(sec, min, hour, mday, mon, year, nil, nil, nil, nil)
703
+ #Time.utc(year[, mon[, day[, hour[, min[, sec[, usec]]]]]])
704
+ time = Time.utc(year, mon, day, hour, min, sec, usec)
705
+ if tzone_h
706
+ diff_sec = tzone_h.to_i * 60 * 60
707
+ if tzone_m
708
+ if diff_sec > 0 ; diff_sec += tzone_m.to_i * 60
709
+ else ; diff_sec -= tzone_m.to_i * 60
710
+ end
711
+ end
712
+ p diff_sec
713
+ time -= diff_sec
714
+ end
715
+ return time
716
+ end
717
+ return str
718
+ end
719
+
720
+
721
+ def assert(bool_expr)
722
+ raise "*** assertion error" unless bool_expr
723
+ end
724
+
725
+ end
726
+
727
+
728
+
729
+ ##
730
+ ## (OBSOLETE) yaml parser
731
+ ##
732
+ ## this class has been obsoleted. use Kwalify::Yaml::Parser instead.
733
+ ##
734
+ ## ex.
735
+ ## # load document with YamlParser
736
+ ## str = ARGF.read()
737
+ ## parser = Kwalify::YamlParser.new(str)
738
+ ## document = parser.parse()
739
+ ##
740
+ ## # validate document
741
+ ## schema = YAML.load(File.read('schema.yaml'))
742
+ ## validator = Kwalify::Validator.new(schema)
743
+ ## errors = validator.validate(document)
744
+ ##
745
+ ## # print validation result
746
+ ## if errors && !errors.empty?
747
+ ## parser.set_errors_linenum(errors)
748
+ ## errors.sort.each do |error|
749
+ ## print "line %d: path %s: %s" % [error.linenum, error.path, error.message]
750
+ ## end
751
+ ## end
752
+ ##
753
+ class YamlParser < PlainYamlParser
754
+
755
+ def initialize(*args)
756
+ super
757
+ @linenums_table = {} # object_id -> hash or array
758
+ end
759
+
760
+ def parse()
761
+ @doc = super
762
+ return @doc
763
+ end
764
+
765
+ def path_linenum(path)
766
+ return 1 if path.empty? || path == '/'
767
+ elems = path.split('/')
768
+ elems.shift if path[0] == ?/ # delete empty string on head
769
+ last_elem = elems.pop
770
+ c = @doc # collection
771
+ elems.each do |elem|
772
+ if c.is_a?(Array)
773
+ c = c[elem.to_i]
774
+ elsif c.is_a?(Hash)
775
+ c = c[elem]
776
+ else
777
+ assert false
778
+ end
779
+ end
780
+ linenums = @linenums_table[c.__id__]
781
+ if c.is_a?(Array)
782
+ linenum = linenums[last_elem.to_i]
783
+ elsif c.is_a?(Hash)
784
+ linenum = linenums[last_elem]
785
+ end
786
+ return linenum
787
+ end
788
+
789
+ def set_errors_linenum(errors)
790
+ errors.each do |error|
791
+ error.linenum = path_linenum(error.path)
792
+ end
793
+ end
794
+
795
+ def set_error_linenums(errors)
796
+ warn "*** Kwalify::YamlParser#set_error_linenums() is obsolete. You should use set_errors_linenum() instead."
797
+ set_errors_linenum(errors)
798
+ end
799
+
800
+ protected
801
+
802
+ def create_sequence(linenum=current_linenum())
803
+ seq = []
804
+ @linenums_table[seq.__id__] = []
805
+ return seq
806
+ end
807
+
808
+ def add_to_seq(seq, value, linenum)
809
+ seq << value
810
+ @linenums_table[seq.__id__] << linenum
811
+ end
812
+
813
+ def set_seq_at(seq, i, value, linenum)
814
+ seq[i] = value
815
+ @linenums_table[seq.__id__][i] = linenum
816
+ end
817
+
818
+ def create_mapping(linenum=current_linenum())
819
+ map = {}
820
+ @linenums_table[map.__id__] = {}
821
+ return map
822
+ end
823
+
824
+ def add_to_map(map, key, value, linenum)
825
+ map[key] = value
826
+ @linenums_table[map.__id__][key] = linenum
827
+ end
828
+
829
+ def set_map_with(map, key, value, linenum)
830
+ map[key] = value
831
+ @linenums_table[map.__id__][key] = linenum
832
+ end
833
+
834
+ def set_default(map, value, linenum)
835
+ map.default = value
836
+ @linenums_table[map.__id__][:'='] = linenum
837
+ end
838
+
839
+ def merge_map(map, collection, linenum)
840
+ t = @linenums_table[map.__id__]
841
+ list = collection.is_a?(Array) ? collection : [ collection ]
842
+ list.each do |m|
843
+ t2 = @linenums_table[m.__id__]
844
+ m.each do |key, val|
845
+ unless map.key?(key)
846
+ map[key] = val
847
+ t[key] = t2[key]
848
+ end
849
+ end
850
+ end
851
+ end
852
+
853
+ def create_scalar(value, linenum=current_linenum())
854
+ data = super(value)
855
+ #return Scalar.new(data, linenum)
856
+ return data
857
+ end
858
+
859
+ end
860
+
861
+
862
+ ## alias of YamlParser class
863
+ class Parser < YamlParser
864
+ def initialize(yaml_str)
865
+ super
866
+ #warn "*** class Kwalify::Parser is obsolete. Please use Kwalify::YamlParser instead."
867
+ end
868
+ end
869
+
870
+
871
+ end