kwalify 0.1.0 → 0.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,326 @@
1
+ ###
2
+ ### $Rev: 18 $
3
+ ### $Release: 0.2.0 $
4
+ ### copyright(c) 2005 kuwata-lab all rights reserved.
5
+ ###
6
+
7
+ require 'kwalify/messages'
8
+ require 'kwalify/errors'
9
+ require 'kwalify/types'
10
+
11
+ module Kwalify
12
+
13
+ class Rule
14
+ include Kwalify::ErrorHelper
15
+
16
+ def initialize(hash=nil)
17
+ configure(hash, "", {}) if hash
18
+ end
19
+
20
+ def configure(hash, path="", rule_table={})
21
+ unless hash.is_a?(Hash)
22
+ #* key=:schema_notmap msg="schema definition is not a mapping."
23
+ raise Kwalify.schema_error(:schema_notmap, nil, "/", nil)
24
+ end
25
+
26
+ rule = self
27
+ rule_table[hash.__id__] = rule
28
+
29
+ ## 'type:'
30
+ @type = hash['type']
31
+ @type = Kwalify::DEFAULT_TYPE if @type == nil
32
+ unless @type.is_a?(String)
33
+ #* key=:type_notstr msg="not a string."
34
+ raise schema_error(:type_notstr, rule, "#{path}/type", @type.to_s)
35
+ end
36
+ @klass = Kwalify.get_type_class(@type)
37
+ #if @klass == nil
38
+ # begin
39
+ # @klass = Kernel.const_get(@type)
40
+ # rescue NameError
41
+ # end
42
+ #end
43
+ unless @klass
44
+ #* key=:type_unknown msg="unknown type."
45
+ raise schema_error(:type_unknown, rule, "#{path}/type", @type.to_s)
46
+ end
47
+
48
+ ## other key
49
+ hash.each do |key, val|
50
+ curr_path = "#{path}/#{key}"
51
+ case key
52
+ #when "id"
53
+ # @id = val
54
+ when "name"
55
+ @name = val
56
+
57
+ when "desc"
58
+ @desc = val
59
+
60
+ when "type"
61
+ # done
62
+
63
+ when "required"
64
+ @required = val
65
+ unless val == nil || val.is_a?(Boolean)
66
+ #* key=:required_notbool msg="not a boolean."
67
+ raise schema_error(:required_notbool, rule, curr_path, val)
68
+ end
69
+
70
+ when "pattern"
71
+ pat = (val =~ /\A\/(.*)\/([mi]?[mi]?)\z/ ? $1 : val)
72
+ begin
73
+ @pattern = Regexp.compile(pat)
74
+ rescue RegexpError => ex
75
+ #* key=:pattern_syntaxerr msg="has regexp error."
76
+ raise schema_error(:pattern_syntaxerr, rule, curr_path, val)
77
+ end
78
+
79
+ when "enum"
80
+ @enum = val
81
+ unless val.is_a?(Array)
82
+ #* key=:enum_notseq msg="not a sequence."
83
+ raise schema_error(:enum_notseq, rule, curr_path, val)
84
+ end
85
+ if @type == 'seq' || @type == 'map' # unless Kwalify.scalar_class?(@klass)
86
+ #* key=:enum_notscalar msg="not available with seq or map."
87
+ raise schema_error(:enum_notscalar, rule, path, 'enum:')
88
+ end
89
+ elem_table = {}
90
+ @enum.each do |elem|
91
+ unless !elem_table[elem]
92
+ #* key=:enum_duplicate msg="duplicated enum value."
93
+ raise schema_error(:enum_duplicate, rule, curr_path, elem.to_s)
94
+ end
95
+ elem_table[elem] = true
96
+ unless elem.is_a?(@klass)
97
+ #* key=:enum_type_unmatch msg="%s type expected."
98
+ raise schema_error(:enum_type_unmatch, rule, curr_path, elem, [Kwalify.word(@type)])
99
+ end
100
+ end
101
+
102
+ when "assert" # or "cond-expr" ?
103
+ unless val.is_a?(String)
104
+ #* key=:assert_notstr msg="not a string."
105
+ raise schema_error(:assert_notstr, rule, curr_path, val)
106
+ end
107
+ unless val =~ /\bval\b/
108
+ #* key=:assert_noval msg="'val' is not used."
109
+ raise schema_error(:assert_noval, rule, curr_path, val)
110
+ end
111
+ begin
112
+ @assert = val
113
+ @assert_proc = eval "proc { |val| #{val} }"
114
+ rescue SyntaxError => ex
115
+ #* key=:assert_syntaxerr msg="expression syntax error."
116
+ raise schema_error(:assert_syntaxerr, rule, curr_path, val)
117
+ end
118
+
119
+ when "range"
120
+ @range = val
121
+ unless val.is_a?(Hash)
122
+ #* key=:range_notmap msg="not a mapping."
123
+ raise schema_error(:range_notmap, rule, curr_path, val)
124
+ end
125
+ if @type == 'map' || @type == 'seq' || @type == 'bool'
126
+ #* key=:range_notscalar msg="is available only with scalar type."
127
+ raise schema_error(:range_notscalar, rule, path, 'range:')
128
+ end
129
+ val.each do |rkey, rval|
130
+ case rkey
131
+ when 'max', 'min'
132
+ unless rval.is_a?(@klass)
133
+ typename = Kwalify.word(@type) || @type
134
+ #* key=:range_type_unmatch msg="not a %s."
135
+ raise schema_error(:range_type_unmatch, rule, "#{curr_path}/#{rkey}", rval, [typename])
136
+ end
137
+ else
138
+ #* key=:range_undefined msg="undefined key."
139
+ raise schema_error(:range_undefined, rule, curr_path, "#{rkey}:")
140
+ end
141
+ end
142
+
143
+ when "length" # or "width"
144
+ @length = val
145
+ unless val.is_a?(Hash)
146
+ #* key=:length_notmap msg="not a mapping."
147
+ raise schema_error(:length_notmap, rule, curr_path, val)
148
+ end
149
+ unless @type == 'str' || @type == 'text'
150
+ #* key=:length_nottext msg="is available only with string or text."
151
+ raise schema_error(:length_nottext, rule, path, 'length:')
152
+ end
153
+ val.each do |lkey, lval|
154
+ case lkey
155
+ when 'max', 'min'
156
+ unless lval.is_a?(Integer)
157
+ #* key=:length_notint msg="not an integer."
158
+ raise schema_error(:length_notint, rule, "#{curr_path}/#{lkey}", lval)
159
+ end
160
+ else
161
+ #* key=:length_undefined msg="undefined key."
162
+ raise schema_error(:length_undefined, rule, curr_path, "#{lkey}:")
163
+ end
164
+ end
165
+
166
+ when "sequence"
167
+ if val != nil && !val.is_a?(Array)
168
+ #* key=:sequence_notseq msg="not a sequence."
169
+ raise schema_error(:sequence_notseq, rule, curr_path, val)
170
+ elsif val == nil || val.empty?
171
+ #* key=:sequence_noelem msg="required one element."
172
+ raise schema_error(:sequence_noelem, rule, curr_path, val)
173
+ elsif val.length > 1
174
+ #* key=:sequence_toomany msg="required just one element."
175
+ raise schema_error(:sequence_toomany, rule, curr_path, val)
176
+ else
177
+ elem = val[0]
178
+ elem ||= {}
179
+ i = 0 # or 1? *index*
180
+ rule = rule_table[elem.__id__]
181
+ rule ||= Rule.new.configure(elem, "#{curr_path}/#{i}", rule_table)
182
+ @sequence = [ rule ]
183
+ end
184
+
185
+ when "mapping"
186
+ if val != nil && !val.is_a?(Hash)
187
+ #* key=:mapping_notmap msg="not a mapping."
188
+ raise schema_error(:mapping_notmap, rule, curr_path, val)
189
+ elsif val == nil || val.empty?
190
+ #* key=:mapping_noelem msg="required at least one element."
191
+ raise schema_error(:mapping_noelem, rule, curr_path, val)
192
+ else
193
+ @mapping = {}
194
+ val.each do |key, elem|
195
+ ##* key=:key_duplicate msg="key duplicated."
196
+ #raise schema_error(:key_duplicate, rule, curr_path, key) if @mapping.key?(key)
197
+ elem ||= {}
198
+ rule = rule_table[elem.__id__]
199
+ rule ||= Rule.new.configure(elem, "#{curr_path}/#{key}", rule_table)
200
+ if key == '*'
201
+ @mapping.default = rule
202
+ else
203
+ @mapping[key] = rule
204
+ end
205
+ end
206
+ end
207
+
208
+ else
209
+ #* key=:key_unknown msg="unknown key."
210
+ raise schema_error(:key_unknown, rule, path, "#{key}:")
211
+ end
212
+ end
213
+
214
+ if @type == 'seq'
215
+ #* key=:seq_nosequence msg="type 'seq' requires 'sequence:'."
216
+ raise Kwalify.validate_error(:seq_nosequence, rule, path, nil) unless hash.key?('sequence')
217
+ #* key=:seq_conflict msg="not available with sequence."
218
+ raise schema_error(:seq_conflict, rule, path, 'enum:') if @enum
219
+ raise schema_error(:seq_conflict, rule, path, 'pattern:') if @pattern
220
+ raise schema_error(:seq_conflict, rule, path, 'mapping:') if @mapping
221
+ raise schema_error(:seq_conflict, rule, path, 'range:') if @range
222
+ raise schema_error(:seq_conflict, rule, path, 'length:') if @length
223
+ elsif @type == 'map'
224
+ #* key=:map_nomapping msg="type 'map' requires 'mapping:'."
225
+ raise Kwalify.validate_error(:map_nomapping, rule, path, nil) unless hash.key?('mapping')
226
+ #* key=:map_conflict msg="not available with mapping."
227
+ raise schema_error(:map_conflict, rule, path, 'enum:') if @enum
228
+ raise schema_error(:map_conflict, rule, path, 'pattern:') if @pattern
229
+ raise schema_error(:map_conflict, rule, path, 'sequence:') if @sequence
230
+ raise schema_error(:map_conflict, rule, path, 'range:') if @range
231
+ raise schema_error(:map_conflict, rule, path, 'length:') if @length
232
+ else
233
+ #* key=:scalar_conflict msg="not available with scalar type."
234
+ raise schema_error(:scalar_conflict, rule, path, 'sequence:') if @sequence
235
+ raise schema_error(:scalar_conflict, rule, path, 'mapping:') if @mapping
236
+ if @enum
237
+ #* key=:enum_conflict msg="not available with 'enum:'."
238
+ raise schema_error(:enum_conflict, rule, path, 'range:') if @range
239
+ raise schema_error(:enum_conflict, rule, path, 'length:') if @length
240
+ raise schema_error(:enum_conflict, rule, path, 'pattern:') if @pattern
241
+ end
242
+ end
243
+
244
+ return self
245
+
246
+ end # end of def configure
247
+
248
+ #attr_reader :id
249
+ attr_reader :name
250
+ attr_reader :desc
251
+ attr_reader :enum
252
+ attr_reader :required
253
+ attr_reader :type
254
+ attr_reader :klass
255
+ attr_reader :pattern
256
+ attr_reader :sequence
257
+ attr_reader :mapping
258
+ attr_reader :assert
259
+ attr_reader :assert_proc
260
+ attr_reader :range
261
+ attr_reader :length
262
+
263
+
264
+ #def inspect()
265
+ # str = ""; level = 0; done = {}
266
+ # _inspect(str, level, done)
267
+ # return str
268
+ #end
269
+
270
+
271
+ #protected
272
+
273
+
274
+ def _inspect(str="", level=0, done={})
275
+ done[self.__id__] = true
276
+ str << " " * level << "name: #{@name}\n" if @name != nil
277
+ str << " " * level << "desc: #{@desc}\n" if @desc != nil
278
+ str << " " * level << "type: #{@type}\n" if @type != nil
279
+ str << " " * level << "klass: #{@klass.name}\n" if @klass != nil
280
+ str << " " * level << "required: #{@required}\n" if @required != nil
281
+ str << " " * level << "pattern: #{@pattern.inspect}\n" if @pattern != nil
282
+ str << " " * level << "assert: #{@assert}\n" if @assert != nil
283
+ if @enum != nil
284
+ str << " " * level << "enum:\n"
285
+ @enum.each do |item|
286
+ str << " " * (level+1) << "- #{item}\n"
287
+ end
288
+ end
289
+ if @range != nil
290
+ str << " " * level
291
+ str << "range: { "
292
+ str << "max: #{@range['max'].inspect}" if @range['max'] != nil
293
+ str << ", " if @range['max'] != nil && @range['min'] != nil
294
+ str << "min: #{@range['min'].inspect}" if @range['min'] != nil
295
+ str << "}\n"
296
+ end
297
+ if @length != nil
298
+ str << " " * level
299
+ str << "length: { "
300
+ str << "max: #{@length['max'].inspect}" if @length['max'] != nil
301
+ str << ", " if @length['max'] != nil && @length['min'] != nil
302
+ str << "min: #{@length['min'].inspect}" if @length['min'] != nil
303
+ str << "}\n"
304
+ end
305
+ @sequence.each do |rule|
306
+ if done[rule.__id__]
307
+ str << " " * (level+1) << "- ...\n"
308
+ else
309
+ str << " " * (level+1) << "- \n"
310
+ rule._inspect(str, level+2, done)
311
+ end
312
+ end if @sequence
313
+ @mapping.each do |key, rule|
314
+ if done[rule.__id__]
315
+ str << ' ' * (level+1) << '"' << key << "\": ...\n"
316
+ else
317
+ str << ' ' * (level+1) << '"' << key << "\":\n"
318
+ rule._inspect(str, level+2, done)
319
+ end
320
+ end if @mapping
321
+ return str
322
+ end
323
+
324
+ end
325
+
326
+ end
@@ -1,6 +1,6 @@
1
1
  ###
2
- ### $Rev: 7 $
3
- ### $Release: 0.1.0 $
2
+ ### $Rev: 18 $
3
+ ### $Release: 0.2.0 $
4
4
  ### copyright(c) 2005 kuwata-lab all rights reserved.
5
5
  ###
6
6
 
@@ -11,60 +11,126 @@ module Kwalify
11
11
  module Boolean
12
12
  end
13
13
  end
14
- #module Boolean; end
15
14
  class TrueClass
16
15
  include Kwalify::Boolean
17
- #include Boolean
18
16
  end
19
17
  class FalseClass
20
18
  include Kwalify::Boolean
21
- #include Boolean
22
19
  end
20
+ #module Boolean; end
21
+ #class TrueClass
22
+ # include Boolean
23
+ #end
24
+ #class FalseClass
25
+ # include Boolean
26
+ #end
23
27
 
24
28
 
25
29
  module Kwalify
26
30
  module Text
27
31
  end
28
32
  end
29
- #module Text; end
30
33
  class String
31
34
  include Kwalify::Text
32
- #include Text
33
35
  end
34
36
  class Numeric
35
37
  include Kwalify::Text
36
- #include Text
38
+ end
39
+ #module Text; end
40
+ #class String
41
+ # include Text
42
+ #end
43
+ #class Numeric
44
+ # include Text
45
+ #end
46
+
47
+
48
+ module Kwalify
49
+ module Scalar
50
+ end
51
+ end
52
+ class String
53
+ include Kwalify::Scalar
54
+ end
55
+ class Numeric
56
+ include Kwalify::Scalar
57
+ end
58
+ class Date
59
+ include Kwalify::Scalar
60
+ end
61
+ class Time
62
+ include Kwalify::Scalar
63
+ end
64
+ class TrueClass
65
+ include Kwalify::Scalar
66
+ end
67
+ class FalseClass
68
+ include Kwalify::Scalar
69
+ end
70
+ class NilClass
71
+ include Kwalify::Scalar
72
+ end
73
+ module Kwalify
74
+ module Text
75
+ include Kwalify::Scalar
76
+ end
37
77
  end
38
78
 
39
79
 
40
80
  module Kwalify
41
81
 
42
- DEFAULT_TYPE = "string" ## use "string" as default of @type
82
+ DEFAULT_TYPE = "str" ## use "str" as default of @type
43
83
 
44
84
  @@type_table = {
45
85
  "seq" => Array,
46
- "sequence" => Array,
47
- #"list" => Array,
48
- #"array" => Array,
49
86
  "map" => Hash,
50
- "mapping" => Hash,
51
- #"hash" => Hash,
87
+ "str" => String,
88
+ #"string" => String,
52
89
  "text" => Text,
53
- "string" => String,
54
- "integer" => Integer,
90
+ "int" => Integer,
91
+ #"integer" => Integer,
55
92
  "float" => Float,
56
93
  "number" => Numeric,
57
94
  #"numeric" => Numeric,
58
95
  "date" => Date,
59
96
  "time" => Time,
60
- "boolean" => Boolean,
61
- #"bool" => Boolean,
62
- "object" => Object,
97
+ "timestamp" => Time,
98
+ "bool" => Boolean,
99
+ #"boolean" => Boolean,
100
+ #"object" => Object,
63
101
  "any" => Object,
102
+ "scalar" => Scalar,
64
103
  }
65
-
104
+
66
105
  def self.type_table
67
106
  return @@type_table
68
107
  end
69
108
 
109
+ def self.get_type_class(type)
110
+ klass = @@type_table[type]
111
+ #assert_error('type=#{type.inspect}') unless klass
112
+ return klass
113
+ end
114
+
115
+
116
+ module TypeHelper
117
+ def collection_class?(klass)
118
+ return klass == Array || klass == Hash
119
+ end
120
+
121
+ def scalar_class?(klass)
122
+ return klass != Array && klass != Hash && klass != Object
123
+ end
124
+
125
+ def collection?(val)
126
+ return collection_class?(val.class)
127
+ end
128
+
129
+ def scalar?(val)
130
+ return scalar_class?(val.class)
131
+ end
132
+ end
133
+
134
+ extend TypeHelper
135
+
70
136
  end