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,85 @@
1
+ ##
2
+ ## original:
3
+ ## http://www.spice-of-life.net/tapkit/ja/TapKitUserGuide_J_c5_s6.html#doc7_1532
4
+ ##
5
+
6
+ adapter_name: DBI
7
+
8
+ connection:
9
+ url: dbi:Mysql:examples
10
+ user: mysql
11
+ password: mysql
12
+
13
+ entities:
14
+ -
15
+ name: Employee
16
+ external_name: EMPLOYEE
17
+
18
+ attributes:
19
+ -
20
+ name: employee_id
21
+ column_name: EMPLOYEE_ID
22
+ external_type: int
23
+ class_name: Integer
24
+ -
25
+ name: name
26
+ column_name: NAME
27
+ external_type: char
28
+ class_name: String
29
+ width: 64
30
+ -
31
+ name: company_id
32
+ column_name: COMPANY_ID
33
+ external_type: int
34
+ class_name: Integer
35
+
36
+ relationships:
37
+ -
38
+ name: company
39
+ destination: Company
40
+ to_many: false
41
+ joins:
42
+ -
43
+ source: company_id
44
+ destination: company_id
45
+
46
+ primary_key_attributes:
47
+ - employee_id
48
+
49
+ class_properties:
50
+ - name
51
+ - company
52
+
53
+ -
54
+ name: Company
55
+ external_name: COMPANY
56
+
57
+ attributes:
58
+ -
59
+ name: company_id
60
+ column_name: COMPANY_ID
61
+ external_type: int
62
+ class_name: Integer
63
+ -
64
+ name: name
65
+ column_name: NAME
66
+ external_type: char
67
+ class_name: String
68
+ width: 64
69
+
70
+ relationships:
71
+ -
72
+ name: employees
73
+ destination: Employee
74
+ to_many: true
75
+ joins:
76
+ -
77
+ source: company_id
78
+ destination: company_id
79
+
80
+ primary_key_attributes:
81
+ - company_id
82
+
83
+ class_properties:
84
+ - name
85
+ - employees
@@ -0,0 +1,67 @@
1
+ ###
2
+ ### $Rev: 99 $
3
+ ### $Release: 0.7.1 $
4
+ ### copyright(c) 2006 kuwata-lab.com all rights reserved.
5
+ ###
6
+
7
+
8
+ module Kwalify
9
+
10
+ RELEASE = ("$Release: 0.7.1 $" =~ /[.\d]+/) && $&
11
+
12
+ end
13
+
14
+ require 'kwalify/types'
15
+ require 'kwalify/messages'
16
+ require 'kwalify/errors'
17
+ require 'kwalify/rule'
18
+ require 'kwalify/validator'
19
+ require 'kwalify/meta-validator'
20
+ require 'kwalify/yaml-parser'
21
+ #require 'kwalify/parser/base'
22
+ #require 'kwalify/parser/yaml'
23
+
24
+
25
+ module Kwalify
26
+
27
+ module Util
28
+
29
+ autoload :HashLike, 'kwalify/util/hashlike'
30
+
31
+ end
32
+
33
+ module Yaml
34
+
35
+ autoload :Parser, 'kwalify/parser/yaml'
36
+
37
+ ## read yaml_str, parse it, and return yaml document.
38
+ ##
39
+ ## opts:
40
+ ## ::validator: Kwalify::Validator object
41
+ ## ::preceding_aliass: allow preceding alias if true
42
+ ## ::data_binding: enable data binding if true
43
+ ## ::untabify: expand tab chars if true
44
+ ## ::filename: filename
45
+ def self.load(yaml_str, opts={})
46
+ #require 'kwalify/parser/yaml'
47
+ parser = Kwalify::Yaml::Parser.new(opts[:validator])
48
+ parser.preceding_alias = true if opts[:preceding_alias]
49
+ parser.data_binding = true if opts[:data_binding]
50
+ yaml_str = Kwalify::Util.untabify(yaml_str) if opts[:untabify]
51
+ ydoc = parser.parse(yaml_str, :filename=>opts[:filename])
52
+ return ydoc
53
+ end
54
+
55
+ ## read file, parse it, and return yaml document.
56
+ ## see Kwalify::Yaml::Parser.load()
57
+ def self.load_file(filename, opts={})
58
+ opts[:filename] = filename
59
+ return self.load(File.read(filename), opts)
60
+ end
61
+
62
+ end
63
+
64
+ module Json
65
+ end
66
+
67
+ end
@@ -0,0 +1,128 @@
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
+
9
+ module Kwalify
10
+
11
+ class KwalifyError < StandardError
12
+ end
13
+
14
+
15
+ class AssertionError < KwalifyError
16
+ def initialize(msg)
17
+ super("*** assertion error: " + msg)
18
+ end
19
+ end
20
+
21
+
22
+ class BaseError < KwalifyError
23
+ def initialize(message="", path=nil, value=nil, rule=nil, error_symbol=nil)
24
+ super(message)
25
+ @path = path.is_a?(Array) ? '/'+path.join('/') : path
26
+ @rule = rule
27
+ @value = value
28
+ @error_symbol = error_symbol
29
+ @filename = @linenum = nil
30
+ end
31
+ attr_accessor :error_symbol, :rule, :path, :value
32
+ attr_accessor :filename, :linenum, :column
33
+
34
+ def to_path
35
+ return @path == '' ? "/" : @path
36
+ end
37
+
38
+ alias _to_s to_s
39
+ alias message to_s
40
+
41
+ def to_s
42
+ s = ''
43
+ s << @filename << ":" if @filename
44
+ s << "#{@linenum}:#{@column} " if @linenum
45
+ s << "[#{to_path()}] " if @path
46
+ s << _to_s()
47
+ return s
48
+ end
49
+
50
+ def <=>(ex)
51
+ #return @linenum <=> ex.linenum
52
+ v = 0
53
+ v = @linenum <=> ex.linenum if @linenum && ex.linenum
54
+ v = @column <=> ex.column if v == 0 && @column && ex.column
55
+ v = @path <=> ex.path if v == 0
56
+ return v
57
+ end
58
+ end
59
+
60
+
61
+ class SchemaError < BaseError
62
+ def initialize(message="", path=nil, rule=nil, value=nil, error_symbol=nil)
63
+ super(message, path, rule, value, error_symbol)
64
+ end
65
+ end
66
+
67
+
68
+ class ValidationError < BaseError
69
+ def initialize(message="", path=nil, rule=nil, value=nil, error_symbol=nil)
70
+ super(message, path, rule, value, error_symbol)
71
+ end
72
+ end
73
+
74
+
75
+ ## syntax error for YAML and JSON
76
+ class SyntaxError < BaseError #KwalifyError
77
+ def initialize(msg, linenum=nil, error_symbol=nil)
78
+ super(linenum ? "line #{linenum}: #{msg}" : msg)
79
+ @linenum = linenum
80
+ @error_symbol = error_symbol
81
+ end
82
+ #attr_accessor :linenum, :error_symbol
83
+ def message
84
+ "file: #{@filename}, line #{@linenum}: #{super}"
85
+ end
86
+ end
87
+
88
+
89
+ ## (obsolete) use Kwalify::SyntaxError instead
90
+ class YamlSyntaxError < SyntaxError
91
+ end
92
+
93
+
94
+ module ErrorHelper
95
+
96
+ #module_function
97
+
98
+ def assert_error(message="")
99
+ raise AssertionError.new(message)
100
+ end
101
+
102
+ def validate_error(error_symbol, rule, path, val, args=nil)
103
+ msg = _build_message(error_symbol, val, args);
104
+ path = '/'+path.join('/') if path.is_a?(Array)
105
+ return ValidationError.new(msg, path, val, rule, error_symbol)
106
+ end
107
+ module_function :validate_error
108
+
109
+ def schema_error(error_symbol, rule, path, val, args=nil)
110
+ msg = _build_message(error_symbol, val, args);
111
+ path = '/'+path.join('/') if path.is_a?(Array)
112
+ return SchemaError.new(msg, path, val, rule, error_symbol)
113
+ end
114
+
115
+ def _build_message(message_key, val, args)
116
+ msg = Kwalify.msg(message_key)
117
+ assert_error("message_key=#{message_key.inspect}") unless msg
118
+ msg = msg % args if args
119
+ msg = "'#{val.to_s.gsub(/\n/, '\n')}': #{msg}" if !val.nil? && Types.scalar?(val)
120
+ return msg;
121
+ end
122
+ module_function :_build_message
123
+
124
+ end
125
+
126
+ extend ErrorHelper
127
+
128
+ end
@@ -0,0 +1,58 @@
1
+ ## $Rev: 95 $
2
+ ## $Date: 2008-01-27 22:49:22 +0900 (Sun, 27 Jan 2008) $
3
+ ## copyright(c) 2005-2008 kuwata-lab all rights reserved.
4
+
5
+ name: MAIN
6
+ type: map
7
+ required: yes
8
+ mapping: &main-rule
9
+ "name": { type: str }
10
+ "desc": { type: str }
11
+ "class": { type: str }
12
+ "type":
13
+ type: str
14
+ #required: yes
15
+ enum: [ seq, map, str, int, float, number, bool, text,
16
+ date, time, timestamp, any, scalar ]
17
+ "required": { type: bool } # equivarent to 'not-null'
18
+ "enum":
19
+ type: seq
20
+ sequence:
21
+ - type: scalar
22
+ unique: yes
23
+ "pattern": { type: str }
24
+ "assert": { type: str, pattern: /\bval\b/ }
25
+ "range":
26
+ type: map
27
+ mapping:
28
+ "max": { type: scalar }
29
+ "min": { type: scalar }
30
+ "max-ex": { type: scalar }
31
+ "min-ex": { type: scalar }
32
+ "length":
33
+ type: map
34
+ mapping:
35
+ "max": { type: int }
36
+ "min": { type: int }
37
+ "max-ex": { type: int }
38
+ "min-ex": { type: int }
39
+ "ident": { type: bool } # equivarent to 'primary-key' (undocumented)
40
+ "unique": { type: bool }
41
+ "default": { type: scalar } # used only in action's template
42
+ "sequence":
43
+ name: SEQUENCE
44
+ type: seq
45
+ sequence:
46
+ - type: map
47
+ mapping: *main-rule
48
+ name: MAIN
49
+ #required: yes
50
+ "mapping":
51
+ name: MAPPING
52
+ type: map
53
+ mapping:
54
+ =:
55
+ type: map
56
+ mapping: *main-rule
57
+ name: MAIN
58
+ #required: yes
@@ -0,0 +1,442 @@
1
+ ###
2
+ ### $Rev: 95 $
3
+ ### $Release: 0.7.1 $
4
+ ### copyright(c) 2005-2008 kuwata-lab all rights reserved.
5
+ ###
6
+
7
+ require 'yaml'
8
+ require 'erb'
9
+ require 'kwalify'
10
+ require 'kwalify/util'
11
+ require 'kwalify/util/ordered-hash'
12
+
13
+
14
+ module Kwalify
15
+
16
+
17
+ class CommandOptionError < KwalifyError
18
+ def initialize(message, option, error_symbol)
19
+ super(message)
20
+ @option = option
21
+ @error_symbol = error_symbol
22
+ end
23
+ attr_reader :option, :error_symbol
24
+ end
25
+
26
+
27
+ ##
28
+ ## ex.
29
+ ## command = File.basename($0)
30
+ ## begin
31
+ ## main = Kwalify::Main.new(command)
32
+ ## s = main.execute
33
+ ## print s if s
34
+ ## rescue Kwalify::CommandOptionError => ex
35
+ ## $stderr.puts "ERROR: #{ex.message}"
36
+ ## exit 1
37
+ ## rescue Kwalify::KwalifyError => ex
38
+ ## $stderr.puts "ERROR: #{ex.message}"
39
+ ## exit 1
40
+ ## end
41
+ ##
42
+ class Main
43
+
44
+
45
+ def initialize(command=nil)
46
+ @command = command || File.basename($0)
47
+ @options = {}
48
+ @properties = {}
49
+ @template_path = []
50
+ $:.each do |path|
51
+ tpath = "#{path}/kwalify/templates"
52
+ @template_path << tpath if test(?d, tpath)
53
+ end
54
+ end
55
+
56
+
57
+ def debug?
58
+ @options[:debug]
59
+ end
60
+
61
+
62
+ def _inspect()
63
+ sb = []
64
+ sb << "command: #{@command}\n"
65
+ sb << "options:\n"
66
+ @options.keys.sort {|k1,k2| k1.to_s<=>k2.to_s }.each do |key|
67
+ sb << " - #{key}: #{@options[key]}\n"
68
+ end
69
+ sb << "properties:\n"
70
+ @properties.keys.sort_by {|k| k.to_s}.each do |key|
71
+ sb << " - #{key}: #{@properties[key]}\n"
72
+ end
73
+ #sb << "template_path:\n"
74
+ #@template_path.each do |path|
75
+ # sb << " - #{path}\n"
76
+ #end
77
+ return sb.join
78
+ end
79
+
80
+
81
+ def execute(argv=ARGV)
82
+ ## parse command-line options
83
+ filenames = _parse_argv(argv)
84
+
85
+ ## help or version
86
+ if @options[:help] || @options[:version]
87
+ action = @options[:action]
88
+ s = ''
89
+ s << _version() << "\n" if @options[:version]
90
+ s << _usage() if @options[:help] && !action
91
+ s << _describe_properties(action) if @options[:help] && action
92
+ puts s
93
+ return
94
+ end
95
+
96
+ # validation
97
+ if @options[:meta2]
98
+ validate_schemafiles2(filenames)
99
+ elsif @options[:meta]
100
+ validate_schemafiles(filenames)
101
+ elsif @options[:action]
102
+ unless @options[:schema]
103
+ #* key=:command_option_actionnoschema msg="schema filename is not specified."
104
+ raise option_error(:command_option_actionnoschema, @options[:action])
105
+ end
106
+ perform_action(@options[:action], @options[:schema])
107
+ elsif @options[:schema]
108
+ if @options[:debug]
109
+ inspect_schema(@options[:schema])
110
+ else
111
+ validate_files(filenames, @options[:schema])
112
+ end
113
+ else
114
+ #* key=:command_option_noaction msg="command-line option '-f' or '-m' required."
115
+ raise option_error(:command_option_noaction, @command)
116
+ end
117
+ return
118
+ end
119
+
120
+
121
+ def self.main(command, argv=ARGV)
122
+ begin
123
+ main = Kwalify::Main.new(command)
124
+ s = main.execute(argv)
125
+ print s if s
126
+ rescue Kwalify::CommandOptionError => ex
127
+ raise ex if main.debug?
128
+ $stderr.puts ex.message
129
+ exit 1
130
+ rescue Kwalify::KwalifyError => ex
131
+ raise ex if main.debug?
132
+ $stderr.puts "ERROR: #{ex.to_s}"
133
+ exit 1
134
+ #rescue => ex
135
+ # if main.debug?
136
+ # raise ex
137
+ # else
138
+ # $stderr.puts ex.message
139
+ # exit 1
140
+ # end
141
+ end
142
+ end
143
+
144
+
145
+ private
146
+
147
+
148
+ def option_error(error_symbol, arg)
149
+ msg = Kwalify.msg(error_symbol) % arg
150
+ return CommandOptionError.new(msg, arg, error_symbol)
151
+ end
152
+
153
+
154
+ def _find_template(action)
155
+ template_filename = action + '.eruby'
156
+ unless test(?f, template_filename)
157
+ pathlist = []
158
+ pathlist.concat(@options[:tpath].split(/,/)) if @options[:tpath]
159
+ pathlist.concat(@template_path)
160
+ tpath = pathlist.find {|path| test(?f, "#{path}/#{template_filename}") }
161
+ #* key=:command_option_notemplate msg="%s: invalid action (template not found).\n"
162
+ raise option_error(:command_option_notemplate, action) unless tpath
163
+ template_filename = "#{tpath}/#{action}.eruby"
164
+ end
165
+ return template_filename
166
+ end
167
+
168
+
169
+ def apply_template(template_filename, hash)
170
+ template = File.read(template_filename)
171
+ trim_mode = 1
172
+ erb = ERB.new(template, nil, trim_mode)
173
+ context = Object.new
174
+ hash.each do |key, val|
175
+ context.instance_variable_set("@#{key}", val)
176
+ end
177
+ s = context.instance_eval(erb.src, template_filename)
178
+ return s
179
+ end
180
+
181
+
182
+ def _describe_properties(action)
183
+ template_filename = _find_template(action)
184
+ s = apply_template(template_filename, :describe=>true)
185
+ return s
186
+ end
187
+
188
+
189
+ def perform_action(action, schema_filename, describe=false)
190
+ template_filename = _find_template(action)
191
+ schema = _load_schemafile(schema_filename, ordered=true)
192
+ validator = Kwalify::Validator.new(schema)
193
+ @properties[:schema_filename] = schema_filename
194
+ hash = { :validator=>validator, :schema=>schema, :properties=>@properties }
195
+ s = apply_template(template_filename, hash)
196
+ puts s if s && !s.empty?
197
+ end
198
+
199
+
200
+ def inspect_schema(schema_filename)
201
+ schema = _load_schemafile(schema_filename)
202
+ if schema.nil?
203
+ puts "nil"
204
+ else
205
+ validator = Kwalify::Validator.new(schema) # error raised when schema is wrong
206
+ puts validator._inspect()
207
+ end
208
+ end
209
+
210
+
211
+ ## -f schemafile datafile
212
+ def validate_files(filenames, schema_filename)
213
+ schema = _load_schemafile(schema_filename)
214
+ validator = Kwalify::Validator.new(schema)
215
+ _validate_files(validator, filenames)
216
+ end
217
+
218
+
219
+ def _load_schemafile(schema_filename, ordered=false)
220
+ str = File.read(schema_filename)
221
+ if str.empty?
222
+ #* key=:schema_empty msg="%s: empty schema.\n"
223
+ msg = Kwalify.msg(:schema_emtpy) % filename
224
+ raise CommandOptionError.new(msg)
225
+ end
226
+ str = Util.untabify(str) if @options[:untabify]
227
+ parser = Kwalify::Yaml::Parser.new()
228
+ parser.preceding_alias = true if @options[:preceding]
229
+ parser.mapping_class = Kwalify::Util::OrderedHash if ordered
230
+ schema = parser.parse(str, :filename=>schema_filename) # or YAML.load(str)
231
+ return schema
232
+ end
233
+
234
+
235
+ ## -m schemafile
236
+ def validate_schemafiles(schema_filenames)
237
+ meta_validator = Kwalify::MetaValidator.instance()
238
+ _validate_files(meta_validator, schema_filenames)
239
+ end
240
+
241
+
242
+ ## -M schemafile
243
+ def validate_schemafiles2(schema_filenames)
244
+ parser = Kwalify::Yaml::Parser.new()
245
+ parser.preceding_alias = true if @options[:preceding]
246
+ for schema_filename in schema_filenames
247
+ str = File.read(schema_filename)
248
+ str = Util.untabify(str) if @options[:untabify]
249
+ schema = parser.parse(str, :filename=>schema_filename)
250
+ Kwalify::Validator.new(schema) # exception raised when schema has errors
251
+ end
252
+ end
253
+
254
+
255
+ def _validate_files(validator, filenames)
256
+ ## parser
257
+ if @options[:linenum] || @options[:preceding]
258
+ parser = Kwalify::Yaml::Parser.new(validator)
259
+ parser.preceding_alias = true if @options[:preceding]
260
+ else
261
+ parser = nil
262
+ end
263
+ ## filenames
264
+ if filenames.empty?
265
+ filenames = [ $stdin ]
266
+ end
267
+ for filename in filenames
268
+ ## read input
269
+ if filename.is_a?(IO)
270
+ input = filename.read()
271
+ filename = '(stdin)'
272
+ else
273
+ input = File.read(filename)
274
+ end
275
+ if input.empty?
276
+ #* key=:validation_empty msg="%s#%d: empty."
277
+ puts kwalify.msg(:validation_empty) % [filename, i]
278
+ #puts "#{filename}##{i}: empty."
279
+ next
280
+ end
281
+ input = Util.untabify(input) if @options[:untabify]
282
+ ## parse input
283
+ if parser
284
+ #i = 0
285
+ #ydoc = parser.parse(input, :filename=>filename)
286
+ #_show_errors(filename, i, ydoc, parser.errors)
287
+ #while parser.has_next?
288
+ # i += 1
289
+ # ydoc = parser.parse_next()
290
+ # _show_errors(filename, i, ydoc, parser.errors)
291
+ #end
292
+ i = 0
293
+ parser.parse_stream(input, :filename=>filename) do |ydoc|
294
+ _show_errors(filename, i, ydoc, parser.errors)
295
+ i += 1
296
+ end
297
+ else
298
+ i = 0
299
+ YAML.load_documents(input) do |ydoc|
300
+ errors = validator.validate(ydoc)
301
+ _show_errors(filename, i, ydoc, errors)
302
+ i += 1
303
+ end
304
+ end
305
+ end
306
+ end
307
+
308
+
309
+ def _show_errors(filename, i, ydoc, errors, ok_label="valid.", ng_label="INVALID")
310
+ if errors && !errors.empty?
311
+ puts "#{filename}##{i}: #{ng_label}"
312
+ errors.sort!
313
+ for error in errors
314
+ e = error
315
+ if @options[:emacs]
316
+ raise unless @options[:linenum]
317
+ puts "#{filename}:#{e.linenum}:#{e.column} [#{e.path}] #{e.message}\n"
318
+ elsif @options[:linenum]
319
+ puts " - (line #{e.linenum}) [#{e.path}] #{e.message}\n"
320
+ else
321
+ puts " - [#{e.path}] #{e.message}\n"
322
+ end
323
+ end
324
+ elsif ydoc.nil?
325
+ #* key=:validation_empty msg="%s#%d: empty.\n"
326
+ puts kwalify.msg(:validation_empty) % [filename, i]
327
+ else
328
+ #* key=:validation_valid msg="%s#%d: valid."
329
+ puts Kwalify.msg(:validation_valid) % [filename, i] unless @options[:quiet]
330
+ #puts "#{filename}##{i} - #{ok_label}" unless @options[:quiet]
331
+ end
332
+ end
333
+
334
+
335
+ def _usage()
336
+ #msg = Kwalify.msg(:command_help) % [@command, @command, @command]
337
+ msg = Kwalify.msg(:command_help)
338
+ return msg
339
+ end
340
+
341
+
342
+ def _version()
343
+ return RELEASE
344
+ end
345
+
346
+
347
+ def _to_value(str)
348
+ case str
349
+ when nil, "null", "nil" ; return nil
350
+ when "true", "yes" ; return true
351
+ when "false", "no" ; return false
352
+ when /\A\d+\z/ ; return str.to_i
353
+ when /\A\d+\.\d+\z/ ; return str.to_f
354
+ when /\/(.*)\// ; return Regexp.new($1)
355
+ when /\A'.*'\z/, /\A".*"\z/ ; return eval(str)
356
+ else ; return str
357
+ end
358
+ end
359
+
360
+
361
+ def _parse_argv(argv)
362
+ option_table = {
363
+ ?h => :help,
364
+ ?v => :version,
365
+ ?q => :quiet,
366
+ ?s => :quiet,
367
+ ?t => :untabify,
368
+ #?z => :meta,
369
+ ?m => :meta,
370
+ ?M => :meta2,
371
+ ?E => :emacs,
372
+ ?l => :linenum,
373
+ ?f => :schema,
374
+ ?D => :debug,
375
+ ?a => :action,
376
+ ?I => :tpath,
377
+ ?P => :preceding,
378
+ }
379
+
380
+ errcode_table = {
381
+ #* key=:command_option_schema_required msg="-%s: schema filename required."
382
+ ?f => :command_option_schema_required,
383
+ #* key=:command_option_action_required msg="-%s: action required."
384
+ ?a => :command_option_action_required,
385
+ #* key=:command_option_tpath_required msg="-%s: template path required."
386
+ ?I => :command_option_tpath_required,
387
+ }
388
+
389
+ while argv[0] && argv[0][0] == ?-
390
+ optstr = argv.shift
391
+ optstr = optstr[1, optstr.length-1]
392
+ ## property
393
+ if optstr[0] == ?-
394
+ unless optstr =~ /\A\-([-\w]+)(?:=(.*))?\z/
395
+ #* key=:command_property_invalid msg="%s: invalid property."
396
+ raise option_error(:command_property_invalid, optstr)
397
+ end
398
+ prop_name = $1; prop_value = $2
399
+ key = prop_name.gsub(/-/, '_').intern
400
+ value = prop_value.nil? ? true : _to_value(prop_value)
401
+ @properties[key] = value
402
+ ## option
403
+ else
404
+ while optstr && !optstr.empty?
405
+ optchar = optstr[0]
406
+ optstr[0,1] = ""
407
+ unless option_table.key?(optchar)
408
+ #* key=:command_option_invalid msg="-%s: invalid command option."
409
+ raise option_error(:command_option_invalid, optchar.chr)
410
+ end
411
+ optkey = option_table[optchar]
412
+ case optchar
413
+ when ?f, ?a, ?I
414
+ arg = optstr.empty? ? argv.shift : optstr
415
+ raise option_error(errcode_table[optchar], optchar.chr) unless arg
416
+ @options[optkey] = arg
417
+ optstr = ''
418
+ else
419
+ @options[optkey] = true
420
+ end
421
+ end
422
+ end
423
+ end # end of while
424
+ #
425
+ @options[:linenum] = true if @options[:emacs]
426
+ @options[:help] = true if @properties[:help]
427
+ @options[:version] = true if @properties[:version]
428
+ filenames = argv
429
+ return filenames
430
+ end
431
+
432
+
433
+ def _domain_type?(doc)
434
+ klass = defined?(YAML::DomainType) ? YAML::DomainType : YAML::Syck::DomainType
435
+ return doc.is_a?(klass)
436
+ end
437
+
438
+
439
+ end
440
+
441
+
442
+ end