rubyang 0.1.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,44 @@
1
+ # coding: utf-8
2
+
3
+ require 'json'
4
+ require 'rexml/document'
5
+
6
+ def json_to_xml( json_str )
7
+ hash = JSON.parse( json_str )
8
+ if hash.keys.size > 1
9
+ raise 'root key size must be 1'
10
+ end
11
+ #doc_xml = REXML::Document.new( "<#{hash.keys.first} />" )
12
+ doc_xml = REXML::Document.new
13
+ json_to_xml_recursive( hash.keys.first, hash.values.first, doc_xml )
14
+ return doc_xml.to_s
15
+ end
16
+
17
+ def json_to_xml_recursive( _key, _value, _doc_xml )
18
+ doc_xml = _doc_xml.add_element( _key )
19
+ case _value
20
+ when Hash
21
+ _value.each{ |key, value|
22
+ case value
23
+ when Hash
24
+ json_to_xml_recursive( key, value, doc_xml )
25
+ when Array
26
+ value.each{ |hash|
27
+ json_to_xml_recursive( key, hash, doc_xml )
28
+ }
29
+ else
30
+ doc_xml.add_element( key ).add_text value
31
+ end
32
+ }
33
+ else
34
+ raise "case value when other than Hash is not implemented"
35
+ end
36
+ end
37
+
38
+
39
+ if __FILE__ == $0
40
+ json_str = '{"config": {"a": [{"b1": {"c1": "c1"}}, {"b2": {"c2": "c2"}}]}}'
41
+ puts json_to_xml( json_str )
42
+ json_str = '{"config":{"leaf1":"0"}}'
43
+ puts json_to_xml( json_str )
44
+ end
@@ -0,0 +1,1060 @@
1
+ # coding: utf-8
2
+
3
+ require 'json'
4
+ require 'base64'
5
+
6
+ require_relative '../model'
7
+ require_relative '../xpath'
8
+
9
+ module Rubyang
10
+ class Database
11
+ class SchemaTree
12
+ class Type
13
+ attr_reader :arg
14
+ end
15
+ class IntegerType < Type
16
+ def initialize arg
17
+ @arg = arg
18
+ range = case arg
19
+ when 'int8' then '-128..127'
20
+ when 'int16' then '-32768..32767'
21
+ when 'int32' then '-2147483648..2147483647'
22
+ when 'int64' then '-9223372036854775808..9223372036854775807'
23
+ when 'uint8' then '0..255'
24
+ when 'uint16' then '0..65535'
25
+ when 'uint32' then '0..4294967295'
26
+ when 'uint64' then '0..18446744073709551615'
27
+ end
28
+ @range = Range.new range
29
+ end
30
+ def update_range arg
31
+ @range.update arg
32
+ end
33
+ def valid? value
34
+ result = true
35
+ result &&= @range.valid? value
36
+ result
37
+ end
38
+ end
39
+ class StringType < Type
40
+ attr_reader :length, :pattern
41
+ def initialize
42
+ @arg = 'string'
43
+ @length = Length.new
44
+ @pattern = Pattern.new
45
+ end
46
+ def update_length arg
47
+ @length.update arg
48
+ end
49
+ def update_pattern arg
50
+ @pattern.update arg
51
+ end
52
+ def valid? value
53
+ result = true
54
+ result &&= @length.valid? value
55
+ result &&= @pattern.valid? value
56
+ result
57
+ end
58
+ end
59
+ class BooleanType < Type
60
+ def initialize
61
+ @arg = 'boolean'
62
+ end
63
+ def valid? value
64
+ if 'true' == value
65
+ true
66
+ elsif 'false' == value
67
+ true
68
+ else
69
+ false
70
+ end
71
+ end
72
+ end
73
+ class EnumerationType < Type
74
+ def initialize
75
+ @arg = 'enumeration'
76
+ @enum = Enum.new
77
+ end
78
+ def update_enum arg
79
+ @enum.update arg
80
+ end
81
+ def valid? value
82
+ result = true
83
+ result &&= @enum.valid? value
84
+ result
85
+ end
86
+ end
87
+ class BitsType < Type
88
+ def initialize
89
+ @arg = 'bits'
90
+ @bit = Bit.new
91
+ end
92
+ def update_bit arg
93
+ @bit.update arg
94
+ end
95
+ def valid? value
96
+ result = true
97
+ result &&= @bit.valid? value
98
+ result
99
+ end
100
+ end
101
+ class BinaryType < Type
102
+ def initialize
103
+ @arg = 'binary'
104
+ @length = Length.new
105
+ end
106
+ def update_length arg
107
+ @length.update arg
108
+ end
109
+ def valid? value
110
+ result = true
111
+ result &&= @length.valid? Base64.strict_decode64( value )
112
+ result
113
+ end
114
+ end
115
+ class LeafrefType < Type
116
+ def initialize interior_schema_node, path_arg
117
+ @arg = 'leafref'
118
+ @path_arg = path_arg
119
+ @path = Path.new interior_schema_node, path_arg
120
+ end
121
+ def path
122
+ @path_arg
123
+ @path.path
124
+ end
125
+ def valid? data_tree, value
126
+ result = true
127
+ result &&= @path.valid? data_tree, true
128
+ result
129
+ end
130
+ end
131
+
132
+ class Path
133
+ attr_reader :path
134
+
135
+ def initialize interior_schema_node, arg
136
+ @path = Rubyang::Xpath::Parser.parse arg
137
+ if !(@path[0].axis.name == Rubyang::Xpath::Axis::PARENT && @path[0].node_test.node_test == Rubyang::Xpath::NodeTest::NodeType::NODE)
138
+ raise "unsupported path: #{@path}"
139
+ end
140
+ target = interior_schema_node.evaluate_xpath( @path[1..-1] )
141
+ if target.size == 0
142
+ raise ArgumentError, "#{arg} is not valid"
143
+ end
144
+ @target = target
145
+ end
146
+ def valid? data_tree, value
147
+ true
148
+ end
149
+ end
150
+ class Range
151
+ def initialize arg
152
+ @range = [[-Float::INFINITY, Float::INFINITY]]
153
+ self.update arg
154
+ end
155
+ def valid? value
156
+ if @range.find{ |min2, max2| (min2..max2).include?( value.to_i ) }
157
+ true
158
+ else
159
+ false
160
+ end
161
+ end
162
+ def update arg
163
+ new_range = Array.new
164
+ arg.gsub( ' ', '' ).split( '|' ).each{ |range_part|
165
+ case range_part
166
+ when /[^\.]+\.\.[^\.]+/
167
+ min, max = range_part.split('..')
168
+ else
169
+ min = max = range_part
170
+ end
171
+ case min
172
+ when /^min$/
173
+ min = @range.map{ |r| r[0] }.min
174
+ else
175
+ min = min.to_i
176
+ end
177
+ case max
178
+ when /^max$/
179
+ max = @range.map{ |r| r[1] }.max
180
+ else
181
+ max = max.to_i
182
+ end
183
+ unless @range.find{ |min2, max2| (min2..max2).include?( min ) && (min2..max2).include?( max ) }
184
+ raise ArgumentError, "#{range_part} is not valid"
185
+ end
186
+ new_range.push [min, max]
187
+ }
188
+ @range = new_range
189
+ end
190
+ def to_s
191
+ @range.map{ |l| "#{l[0]}..#{l[1]}" }.join( "|" )
192
+ end
193
+ end
194
+ class Length
195
+ def initialize
196
+ @length = [[0, 18446744073709551615]]
197
+ end
198
+ def valid? value
199
+ if @length.find{ |min2, max2| (min2..max2).include?( value.size ) }
200
+ true
201
+ else
202
+ false
203
+ end
204
+ end
205
+ def update arg
206
+ new_length = Array.new
207
+ arg.gsub( ' ', '' ).split( '|' ).each{ |length_part|
208
+ case length_part
209
+ when /[^\.]+\.\.[^\.]+/
210
+ min, max = length_part.split('..')
211
+ else
212
+ min = max = length_part
213
+ end
214
+ case min
215
+ when /^min$/
216
+ min = @length.map{ |r| r[0] }.min
217
+ else
218
+ min = min.to_i
219
+ end
220
+ case max
221
+ when /^max$/
222
+ max = @length.map{ |r| r[1] }.max
223
+ else
224
+ max = max.to_i
225
+ end
226
+ unless @length.find{ |min2, max2| (min2..max2).include?( min ) && (min2..max2).include?( max ) }
227
+ raise ArgumentError, "#{length_part} is not valid"
228
+ end
229
+ new_length.push [min, max]
230
+ }
231
+ @length = new_length
232
+ end
233
+ def to_s
234
+ @length.map{ |l| "#{l[0]}..#{l[1]}" }.join( "|" )
235
+ end
236
+ end
237
+ class Pattern
238
+ def initialize
239
+ @pattern = Regexp.new( '.*' )
240
+ end
241
+ def valid? value
242
+ if @pattern =~ value
243
+ true
244
+ else
245
+ false
246
+ end
247
+ end
248
+ def update arg
249
+ @pattern = Regexp.new( arg )
250
+ end
251
+ def to_s
252
+ @pattern.inspect
253
+ end
254
+ end
255
+ class Enum
256
+ def initialize
257
+ @enum = []
258
+ end
259
+ def valid? value
260
+ if @enum.find{ |e| e == value }
261
+ true
262
+ else
263
+ false
264
+ end
265
+ end
266
+ def update arg
267
+ if @enum.find{ |e| e == arg }
268
+ raise ArgumentError, "#{arg} is not valid"
269
+ end
270
+ @enum.push arg
271
+ end
272
+ end
273
+ class Bit
274
+ def initialize
275
+ @bit = []
276
+ end
277
+ def valid? value
278
+ values = value.split( ' ' )
279
+ if values.inject( true ){ |result, v| result && @bit.find{ |b| b == v } }
280
+ true
281
+ else
282
+ false
283
+ end
284
+ end
285
+ def update arg
286
+ if @bit.find{ |b| b == arg }
287
+ raise ArgumentError, "#{arg} is not valid"
288
+ end
289
+ @bit.push arg
290
+ end
291
+ end
292
+
293
+ class SchemaNode
294
+ attr_accessor :yangs, :arg, :yang, :parent, :module
295
+ def initialize yangs, arg, yang, parent, _module
296
+ @yangs = yangs
297
+ @arg = arg
298
+ @yang = yang
299
+ @parent = parent
300
+ @module = _module
301
+ end
302
+ def model
303
+ @yang
304
+ end
305
+ def namespace
306
+ @module.substmt( 'namespace' )[0].arg
307
+ end
308
+ def prefix
309
+ @module.substmt( 'prefix' )[0].arg
310
+ end
311
+ def root
312
+ if @parent == nil
313
+ self
314
+ else
315
+ @parent.root
316
+ end
317
+ end
318
+ def to_json
319
+ h = Hash.new
320
+ self.to_json_recursive( h )
321
+ h.to_json
322
+ end
323
+ def evaluate_xpath location_steps, current=self
324
+ location_step = location_steps.first
325
+ candidates_by_axis = self.evaluate_xpath_axis( location_step, current )
326
+ candidates_by_node_test = candidates_by_axis.inject([]){ |cs, c| cs + c.evaluate_xpath_node_test( location_step, current ) }
327
+ candidates_by_predicates = candidates_by_node_test.inject([]){ |cs, c| cs + c.evaluate_xpath_predicates( location_step, current ) }
328
+ if location_steps[1..-1].size == 0
329
+ candidates_by_predicates
330
+ else
331
+ candidates_by_predicates.inject([]){ |cs, c| c.evaluate_xpath( location_steps[1..-1], current ) }
332
+ end
333
+ end
334
+ def evaluate_xpath_axis location_step, current
335
+ case location_step.axis.name
336
+ when Rubyang::Xpath::Axis::PARENT
337
+ [@parent]
338
+ when Rubyang::Xpath::Axis::CHILD
339
+ @children
340
+ else
341
+ raise "location_step.axis.name: #{location_step.axis.name} NOT implemented"
342
+ end
343
+ end
344
+ def evaluate_xpath_node_test location_step, current
345
+ case location_step.node_test.node_test_type
346
+ when Rubyang::Xpath::NodeTest::NodeTestType::NAME_TEST
347
+ if self.model.arg == location_step.node_test.node_test
348
+ [self]
349
+ else
350
+ []
351
+ end
352
+ when Rubyang::Xpath::NodeTest::NodeTestType::NODE_TYPE
353
+ case location_step.node_test.node_test
354
+ when Rubyang::Xpath::NodeTest::NodeType::COMMENT
355
+ raise "node-type: comment is not implemented"
356
+ when Rubyang::Xpath::NodeTest::NodeType::TEXT
357
+ raise "node-type: text is not implemented"
358
+ when Rubyang::Xpath::NodeTest::NodeType::NODE
359
+ [self]
360
+ else
361
+ raise "node-type not match to comment or text or node"
362
+ end
363
+ when Rubyang::Xpath::NodeTest::NodeTestType::PROCESSING_INSTRUCTION
364
+ raise "processing-instruction is not implemented"
365
+ else
366
+ raise ""
367
+ end
368
+ end
369
+ def evaluate_xpath_predicates location_step, current
370
+ case location_step.predicates.size
371
+ when 0
372
+ [self]
373
+ else
374
+ location_step.predicates.inject([]){ |cs, predicate|
375
+ self.evaluate_xpath_predicate_expr predicate.expr, current
376
+ }
377
+ end
378
+ end
379
+ def evaluate_xpath_predicate_expr expr, current
380
+ case expr
381
+ when Rubyang::Xpath::Predicate::OrExpr
382
+ if Rubyang::Xpath::Parser::DEBUG
383
+ puts
384
+ puts "in OrExpr"
385
+ puts "op1: #{expr.op1}"
386
+ puts "op2: #{expr.op2}"
387
+ puts
388
+ end
389
+ op1 = expr.op1
390
+ op2 = expr.op2
391
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
392
+ if op2 == nil
393
+ op1_result
394
+ else
395
+ op2_result = self.evaluate_xpath_predicate_expr( op2, current )
396
+ op1_result | op2_result
397
+ end
398
+ when Rubyang::Xpath::Predicate::AndExpr
399
+ if Rubyang::Xpath::Parser::DEBUG
400
+ puts
401
+ puts "in AndExpr"
402
+ puts "op1: #{expr.op1}"
403
+ puts "op2: #{expr.op2}"
404
+ puts
405
+ end
406
+ op1 = expr.op1
407
+ op2 = expr.op2
408
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
409
+ if op2 == nil
410
+ op1_result
411
+ else
412
+ op2_result = self.evaluate_xpath_predicate_expr( op2, current )
413
+ op1_result & op2_result
414
+ end
415
+ when Rubyang::Xpath::Predicate::EqualityExpr
416
+ if Rubyang::Xpath::Parser::DEBUG
417
+ puts
418
+ puts "in EqualityExpr"
419
+ puts "op1: #{expr.op1}"
420
+ puts "op2: #{expr.op2}"
421
+ puts "operator: #{expr.operator}"
422
+ puts
423
+ end
424
+ op1 = expr.op1
425
+ op2 = expr.op2
426
+ operator = expr.operator
427
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
428
+ if op2 == nil
429
+ op1_result
430
+ else
431
+ case operator
432
+ when /^\=$/
433
+ op2_result = self.evaluate_xpath_predicate_expr( op2, current )
434
+ if op1_result.size > 0 and op2_result.size >0
435
+ [self]
436
+ else
437
+ []
438
+ end
439
+ #op1_result.select{ |a| op2_result.map{ |b| b.value }.include? a }
440
+ when /^\!\=$/
441
+ raise "Equality Expr: '!=' not implemented"
442
+ else
443
+ raise "Equality Expr: other than '=' and '!=' not implemented"
444
+ end
445
+ end
446
+ when Rubyang::Xpath::Predicate::RelationalExpr
447
+ if Rubyang::Xpath::Parser::DEBUG
448
+ puts
449
+ puts "in RelationalExpr"
450
+ puts "op1: #{expr.op1}"
451
+ puts "op2: #{expr.op2}"
452
+ puts "operator: #{expr.operator}"
453
+ puts
454
+ end
455
+ op1 = expr.op1
456
+ op2 = expr.op2
457
+ operator = expr.operator
458
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
459
+ if op2 == nil
460
+ op1_result
461
+ else
462
+ case operator
463
+ when /^\>$/
464
+ raise "Relational Expr: '>' not implemented"
465
+ when /^\<$/
466
+ raise "Relational Expr: '<' not implemented"
467
+ when /^\>\=$/
468
+ raise "Relational Expr: '>=' not implemented"
469
+ when /^\<\=$/
470
+ raise "Relational Expr: '<=' not implemented"
471
+ else
472
+ raise "Relational Expr: other than '>', '<', '>=' and '<=' not implemented"
473
+ end
474
+ end
475
+ when Rubyang::Xpath::Predicate::AdditiveExpr
476
+ if Rubyang::Xpath::Parser::DEBUG
477
+ puts
478
+ puts "in AdditiveExpr"
479
+ puts "op1: #{expr.op1}"
480
+ puts "op2: #{expr.op2}"
481
+ puts "operator: #{expr.operator}"
482
+ puts
483
+ end
484
+ op1 = expr.op1
485
+ op2 = expr.op2
486
+ operator = expr.operator
487
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
488
+ if op2 == nil
489
+ op1_result
490
+ else
491
+ case operator
492
+ when /^\+$/
493
+ raise "Additive Expr: '+' not implemented"
494
+ when /^\-$/
495
+ raise "Additive Expr: '-' not implemented"
496
+ else
497
+ raise "Additive Expr: other than '+' and '-' not implemented"
498
+ end
499
+ end
500
+ when Rubyang::Xpath::Predicate::MultiplicativeExpr
501
+ if Rubyang::Xpath::Parser::DEBUG
502
+ puts
503
+ puts "in MultiplicativeExpr"
504
+ puts "op1: #{expr.op1}"
505
+ puts "op2: #{expr.op2}"
506
+ puts "operator: #{expr.operator}"
507
+ puts
508
+ end
509
+ op1 = expr.op1
510
+ op2 = expr.op2
511
+ operator = expr.operator
512
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
513
+ if op2 == nil
514
+ op1_result
515
+ else
516
+ case operator
517
+ when /^\*$/
518
+ raise "Multiplicative Expr: '*' not implemented"
519
+ when /^\/$/
520
+ raise "Multiplicative Expr: '/' not implemented"
521
+ else
522
+ raise "Multiplicative Expr: other than '*' and '/' not implemented"
523
+ end
524
+ end
525
+ when Rubyang::Xpath::Predicate::UnaryExpr
526
+ if Rubyang::Xpath::Parser::DEBUG
527
+ puts
528
+ puts "in UnaryExpr"
529
+ puts "op1: #{expr.op1}"
530
+ puts "operator: #{expr.operator}"
531
+ puts
532
+ end
533
+ op1 = expr.op1
534
+ operator = expr.operator
535
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
536
+ case operator
537
+ when nil
538
+ op1_result
539
+ when /^\-$/
540
+ raise "Unary Expr: '-' not implemented"
541
+ else
542
+ raise "Unary Expr: other than '-' not implemented"
543
+ end
544
+ when Rubyang::Xpath::Predicate::UnionExpr
545
+ if Rubyang::Xpath::Parser::DEBUG
546
+ puts
547
+ puts "in UnionExpr"
548
+ puts "op1: #{expr.op1}"
549
+ puts "op2: #{expr.op2}"
550
+ puts "operator: #{expr.operator}"
551
+ puts
552
+ end
553
+ op1 = expr.op1
554
+ op2 = expr.op2
555
+ operator = expr.operator
556
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
557
+ if op2 == nil
558
+ op1_result
559
+ else
560
+ case operator
561
+ when /^\|$/
562
+ raise "Union Expr: '|' not implemented"
563
+ else
564
+ raise "Union Expr: other than '|' not implemented"
565
+ end
566
+ end
567
+ when Rubyang::Xpath::Predicate::PathExpr
568
+ if Rubyang::Xpath::Parser::DEBUG
569
+ puts
570
+ puts "in PathExpr"
571
+ puts "op1: #{expr.op1}"
572
+ puts "op2: #{expr.op2}"
573
+ puts "operator: #{expr.operator}"
574
+ puts
575
+ end
576
+ op1 = expr.op1
577
+ op2 = expr.op2
578
+ operator = expr.operator
579
+ case op1
580
+ when Rubyang::Xpath::LocationSteps
581
+ op1_result = self.evaluate_xpath( op1, current )
582
+ when Rubyang::Xpath::Predicate::FilterExpr
583
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
584
+ if op2 == nil
585
+ op1_result
586
+ else
587
+ case operator
588
+ when /^\/$/
589
+ case op2
590
+ when Rubyang::Xpath::LocationSteps
591
+ if !(op2[0].axis.name == Rubyang::Xpath::Axis::PARENT &&
592
+ op2[0].node_test.node_test == Rubyang::Xpath::NodeTest::NodeType::NODE)
593
+ raise "unsupported path: #{op2}"
594
+ end
595
+ current.evaluate_xpath (op1_result + op2[1..-1]), current
596
+ else
597
+ raise "Path Expr: op1 is not LocationSteps"
598
+ end
599
+ when /^\/\/$/
600
+ raise "Path Expr: '//' not implemented"
601
+ else
602
+ raise "Path Expr: other than '/' and '//' not implemented"
603
+ end
604
+ end
605
+ else
606
+ raise ""
607
+ end
608
+ when Rubyang::Xpath::Predicate::FilterExpr
609
+ if Rubyang::Xpath::Parser::DEBUG
610
+ puts
611
+ puts "in FilterExpr"
612
+ puts "op1: #{expr.op1}"
613
+ puts "op2: #{expr.op2}"
614
+ puts
615
+ end
616
+ op1 = expr.op1
617
+ op2 = expr.op2
618
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
619
+ if op2 == nil
620
+ op1_result
621
+ else
622
+ op2_result = self.evaluate_xpath_predicate_expr( op2.expr, current )
623
+ raise "Filter Expr: Filter Predicate not implemented"
624
+ end
625
+ when Rubyang::Xpath::Predicate::PrimaryExpr
626
+ if Rubyang::Xpath::Parser::DEBUG
627
+ puts
628
+ puts "in PrimaryExpr"
629
+ puts "op1: #{expr.op1}"
630
+ puts
631
+ end
632
+ op1 = expr.op1
633
+ case op1
634
+ when Rubyang::Xpath::Predicate::Expr
635
+ raise "Primary Expr: '( Expr )' not implemented"
636
+ when Rubyang::Xpath::Predicate::FunctionCall
637
+ op1_result = self.evaluate_xpath_predicate_expr( op1, current )
638
+ when /^\$.*$/
639
+ raise "Primary Expr: 'Variable Reference' not implemented"
640
+ else
641
+ raise "Primary Expr: 'Literal' and 'Number' not implemented"
642
+ end
643
+ when Rubyang::Xpath::Predicate::FunctionCall
644
+ if Rubyang::Xpath::Parser::DEBUG
645
+ puts
646
+ puts "in FunctionCall"
647
+ puts "name: #{expr.name}"
648
+ puts "args: #{expr.args}"
649
+ puts
650
+ end
651
+ name = expr.name
652
+ case name
653
+ when Rubyang::Xpath::Predicate::FunctionCall::CURRENT
654
+ Rubyang::Xpath::LocationSteps.new
655
+ else
656
+ raise "FunctionCall: #{name} not implemented"
657
+ end
658
+ else
659
+ raise "Unrecognized predicate: #{predicate}"
660
+ end
661
+ end
662
+ end
663
+
664
+ class InteriorSchemaNode < SchemaNode
665
+ attr_accessor :yangs, :arg, :yang, :parent, :children
666
+
667
+ def initialize yangs, arg, yang, parent, _module
668
+ super yangs, arg, yang, parent, _module
669
+ @children = []
670
+ end
671
+
672
+ def resolve_type type_stmt, yangs, current_module, typedef_list
673
+ case type_stmt.arg
674
+ when 'int8', 'int16', 'int32', 'int64', 'uint8', 'uint16', 'uint32', 'uint64'
675
+ type = IntegerType.new type_stmt.arg
676
+ type_stmt.substmts( Rubyang::Model::TypeBodyStmtList ).each{ |s|
677
+ case s
678
+ when Rubyang::Model::Range
679
+ type.update_range s.arg
680
+ else
681
+ raise ArgumentError, "#{s} is not valid"
682
+ end
683
+ }
684
+ when 'string'
685
+ type = StringType.new
686
+ type_stmt.substmts( Rubyang::Model::TypeBodyStmtList ).each{ |s|
687
+ case s
688
+ when Rubyang::Model::Length
689
+ type.update_length s.arg
690
+ when Rubyang::Model::Pattern
691
+ type.update_pattern s.arg
692
+ else
693
+ raise ArgumentError, "#{s} is not valid"
694
+ end
695
+ }
696
+ when 'boolean'
697
+ type = BooleanType.new
698
+ type_stmt.substmts( Rubyang::Model::TypeBodyStmtList ).each{ |s|
699
+ raise ArgumentError, "#{s} is not valid"
700
+ }
701
+ when 'enumeration'
702
+ type = EnumerationType.new
703
+ type_stmt.substmts( Rubyang::Model::TypeBodyStmtList ).each{ |s|
704
+ case s
705
+ when Rubyang::Model::Enum
706
+ type.update_enum s.arg
707
+ else
708
+ raise ArgumentError, "#{s} is not valid"
709
+ end
710
+ }
711
+ when 'bits'
712
+ type = BitsType.new
713
+ type_stmt.substmts( Rubyang::Model::TypeBodyStmtList ).each{ |s|
714
+ case s
715
+ when Rubyang::Model::Bit
716
+ type.update_bit s.arg
717
+ else
718
+ raise ArgumentError, "#{s} is not valid"
719
+ end
720
+ }
721
+ when 'binary'
722
+ type = BinaryType.new
723
+ type_stmt.substmts( Rubyang::Model::TypeBodyStmtList ).each{ |s|
724
+ case s
725
+ when Rubyang::Model::Length
726
+ type.update_length s.arg
727
+ else
728
+ raise ArgumentError, "#{s} is not valid"
729
+ end
730
+ }
731
+ when 'leafref'
732
+ type = LeafrefType.new self, type_stmt.substmt( 'path' )[0].arg
733
+ else
734
+ case type_stmt.arg
735
+ when /^[^:]+$/
736
+ arg = type_stmt.arg
737
+ if typedef_list.find{ |s| s.arg == arg }
738
+ typedef_stmt = typedef_list.find{ |s| s.arg == arg }
739
+ type = resolve_type typedef_stmt.substmt( 'type' )[0], yangs, current_module, typedef_list
740
+ else
741
+ include_submodule = current_module.substmt( 'include' ).map{ |s|
742
+ yangs.find{ |y| y.arg == s.arg }
743
+ }.find{ |s|
744
+ s.substmt( 'typedef' ).find{ |t| t.arg == arg }
745
+ }
746
+ typedef_stmt = include_submodule.substmt( 'typedef' ).find{ |s| s.arg == arg }
747
+ type = resolve_type typedef_stmt.substmt( 'type' )[0], yangs, include_submodule, include_submodule.substmt( 'typedef' )
748
+ end
749
+ when /^[^:]+:[^:]+$/
750
+ prefix, arg = type_stmt.arg.split(':')
751
+ case current_module
752
+ when Rubyang::Model::Module
753
+ case prefix
754
+ when current_module.substmt( 'prefix' )[0].arg
755
+ typedef_stmt = typedef_list.find{ |s| s.arg == arg }
756
+ type = resolve_type typedef_stmt.substmt( 'type' )[0], yangs, current_module, typedef_list
757
+ else
758
+ import_module = yangs.find{ |y|
759
+ y.arg == current_module.substmt( 'import' ).find{ |s| s.substmt( 'prefix' )[0].arg == prefix }.arg
760
+ }
761
+ typedef_stmt = import_module.substmt( 'typedef' ).find{ |s| s.arg == arg }
762
+ type = resolve_type typedef_stmt.substmt( 'type' )[0], yangs, import_module, import_module.substmt( 'typedef' )
763
+ end
764
+ when Rubyang::Model::Submodule
765
+ case prefix
766
+ when current_module.substmt( 'belongs-to' )[0].substmt( 'prefix' )[0].arg
767
+ typedef_stmt = typedef_list.find{ |s| s.arg == arg }
768
+ type = resolve_type typedef_stmt.substmt( 'type' )[0], yangs, current_module, typedef_list
769
+ else
770
+ import_module = yangs.find{ |y|
771
+ y.arg == current_module.substmt( 'import' ).find{ |s| s.substmt( 'prefix' )[0].arg == prefix }.arg
772
+ }
773
+ typedef_stmt = import_module.substmt( 'typedef' ).find{ |s| s.arg == arg }
774
+ type = resolve_type typedef_stmt.substmt( 'type' )[0], yangs, import_module, import_module.substmt( 'typedef' )
775
+ end
776
+ else
777
+ raise
778
+ end
779
+ end
780
+ end
781
+ type
782
+ end
783
+
784
+ def load_yang yang, yangs=@yangs, parent_module=yang, current_module=yang, grouping_list=[], typedef_list=[]
785
+ case yang
786
+ when Rubyang::Model::Module
787
+ yangs.push yang
788
+ module_arg = yang.arg
789
+ namespace_arg = yang.substmt( 'namespace' )[0].arg
790
+ prefix_arg = yang.substmt( 'prefix' )[0].arg
791
+ grouping_list += yang.substmt( 'grouping' )
792
+ typedef_list += yang.substmt( 'typedef' )
793
+ yang.substmt( 'include' ).each{ |i|
794
+ i.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
795
+ self.load_yang s, yangs, parent_module, i, i.substmt( 'grouping' ), i.substmt( 'typedef' )
796
+ }
797
+ }
798
+ yang.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
799
+ self.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
800
+ }
801
+ when Rubyang::Model::Submodule
802
+ yangs.push yang
803
+ when Rubyang::Model::Container
804
+ container_arg = yang.arg
805
+ grouping_list += yang.substmt( 'grouping' )
806
+ typedef_list += yang.substmt( 'typedef' )
807
+ self.children.push Container.new( yangs, container_arg, yang, self, parent_module )
808
+ yang.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
809
+ self.children.last.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
810
+ }
811
+ when Rubyang::Model::Leaf
812
+ leaf_arg = yang.arg
813
+ type = self.resolve_type yang.substmt( 'type' )[0], yangs, current_module, typedef_list
814
+ self.children.push Leaf.new( yangs, leaf_arg, yang, self, parent_module, type )
815
+ when Rubyang::Model::LeafList
816
+ leaf_arg = yang.arg
817
+ type = self.resolve_type yang.substmt( 'type' )[0], yangs, current_module, typedef_list
818
+ self.children.push LeafList.new( yangs, leaf_arg, yang, self, parent_module, type )
819
+ when Rubyang::Model::List
820
+ list_arg = yang.arg
821
+ grouping_list += yang.substmt( 'grouping' )
822
+ typedef_list += yang.substmt( 'typedef' )
823
+ self.children.push List.new( yangs, list_arg, yang, self, parent_module )
824
+ yang.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
825
+ self.children.last.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
826
+ }
827
+ when Rubyang::Model::Choice
828
+ choice_arg = yang.arg
829
+ grouping_list += yang.substmt( 'grouping' )
830
+ typedef_list += yang.substmt( 'typedef' )
831
+ self.children.push Choice.new( yangs, choice_arg, yang, self, parent_module )
832
+ yang.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
833
+ self.children.last.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
834
+ }
835
+ when Rubyang::Model::Case
836
+ case_arg = yang.arg
837
+ grouping_list += yang.substmt( 'grouping' )
838
+ typedef_list += yang.substmt( 'typedef' )
839
+ self.children.push Case.new( yangs, case_arg, yang, self, parent_module )
840
+ yang.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
841
+ self.children.last.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
842
+ }
843
+ when Rubyang::Model::Augment
844
+ target_node = self.resolve_node( yang.arg )
845
+ yang.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
846
+ target_node.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
847
+ }
848
+ when Rubyang::Model::Uses
849
+ self.resolve_uses( yang, yangs, parent_module, current_module, grouping_list, typedef_list )
850
+ end
851
+ end
852
+
853
+ def resolve_uses uses_stmt, yangs, parent_module, current_module, grouping_list, typedef_list
854
+ case uses_stmt.arg
855
+ when /^[^:]+$/
856
+ arg = uses_stmt.arg
857
+ if grouping_list.find{ |s| s.arg == arg }
858
+ grouping_stmt = grouping_list.find{ |s| s.arg == arg }
859
+ grouping_list += grouping_stmt.substmt( 'grouping' )
860
+ typedef_list += grouping_stmt.substmt( 'typedef' )
861
+ grouping_stmt.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
862
+ self.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
863
+ }
864
+ else
865
+ include_submodule = current_module.substmt( 'include' ).map{ |s|
866
+ yangs.find{ |y| y.arg == s.arg }
867
+ }.find{ |s|
868
+ s.substmt( 'grouping' ).find{ |t| t.arg == arg }
869
+ }
870
+ grouping_stmt = include_submodule.substmt( 'grouping' ).find{ |s| s.arg == arg }
871
+ grouping_list = include_submodule.substmt( 'grouping' ) + grouping_stmt.substmt( 'grouping' )
872
+ typedef_list = include_submodule.substmt( 'typedef' ) + grouping_stmt.substmt( 'typedef' )
873
+ grouping_stmt.substmt( Rubyang::Model::DataDefStmtList ).each{ |s|
874
+ self.load_yang s, yangs, parent_module, include_submodule, grouping_list, typedef_list
875
+ }
876
+ end
877
+ when /^[^:]+:[^:]+$/
878
+ prefix, arg = uses_stmt.arg.split(':')
879
+ case current_module
880
+ when Rubyang::Model::Module
881
+ case prefix
882
+ when current_module.substmt( 'prefix' )[0].arg
883
+ grouping_stmt = grouping_list.find{ |s| s.arg == arg }
884
+ grouping_list += grouping_stmt.substmt( 'grouping' )
885
+ typedef_list += grouping_stmt.substmt( 'typedef' )
886
+ grouping_stmt.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
887
+ self.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
888
+ }
889
+ else
890
+ import_module = yangs.find{ |y|
891
+ y.arg == current_module.substmt( 'import' ).find{ |s| s.substmt( 'prefix' )[0].arg == prefix }.arg
892
+ }
893
+ grouping_stmt = import_module.substmt( 'grouping' ).find{ |s| s.arg == arg }
894
+ grouping_list = import_module.substmt( 'grouping' ) + grouping_stmt.substmt( 'grouping' )
895
+ typedef_list = import_module.substmt( 'typedef' ) + grouping_stmt.substmt( 'typedef' )
896
+ grouping_stmt.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
897
+ self.load_yang s, yangs, parent_module, import_module, grouping_list, typedef_list
898
+ }
899
+ end
900
+ when Rubyang::Model::Submodule
901
+ case prefix
902
+ when current_module.substmt( 'belongs-to' )[0].substmt( 'prefix' )[0].arg
903
+ grouping_stmt = grouping_list.find{ |s| s.arg == arg }
904
+ grouping_list += grouping_stmt.substmt( 'grouping' )
905
+ typedef_list += grouping_stmt.substmt( 'typedef' )
906
+ grouping_stmt.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
907
+ self.load_yang s, yangs, parent_module, current_module, grouping_list, typedef_list
908
+ }
909
+ else
910
+ import_module = yangs.find{ |y|
911
+ y.arg == current_module.substmt( 'import' ).find{ |s| s.substmt( 'prefix' )[0].arg == prefix }.arg
912
+ }
913
+ grouping_stmt = import_module.substmt( 'grouping' ).find{ |s| s.arg == arg }
914
+ grouping_list = import_module.substmt( 'grouping' ) + grouping_stmt.substmt( 'grouping' )
915
+ typedef_list = import_module.substmt( 'typedef' ) + grouping_stmt.substmt( 'typedef' )
916
+ grouping_stmt.substmts( Rubyang::Model::DataDefStmtList ).each{ |s|
917
+ self.load_yang s, yangs, parent_module, import_module, grouping_list, typedef_list
918
+ }
919
+ end
920
+ else
921
+ raise
922
+ end
923
+ end
924
+ end
925
+ def resolve_node path
926
+ path_splitted = path.split( '/' )
927
+ next_node = case path_splitted.first
928
+ when '', '.'
929
+ self
930
+ when '..'
931
+ self
932
+ else
933
+ @children.find{ |c| c.model.arg == path_splitted.first }
934
+ end
935
+ if path_splitted.size == 1
936
+ next_node
937
+ else
938
+ next_node.resolve_node( path_splitted[1..-1].join( '/' ) )
939
+ end
940
+ end
941
+ end
942
+
943
+ class LeafSchemaNode < SchemaNode
944
+ attr_reader :yangs, :arg, :yang, :parent, :module, :type
945
+ def initialize yangs, arg, yang, parent, _module, type
946
+ super yangs, arg, yang, parent, _module
947
+ @type = type
948
+ end
949
+ def type
950
+ @type
951
+ end
952
+ end
953
+
954
+ class Root < InteriorSchemaNode
955
+ def initialize yangs, arg=nil, yang=nil, parent=nil, _module=nil
956
+ super
957
+ end
958
+ def namespace
959
+ 'http://rubyang/config/0.1'
960
+ end
961
+ def prefix
962
+ ''
963
+ end
964
+ def to_json_recursive h
965
+ @children.each{ |c|
966
+ c.to_json_recursive h
967
+ }
968
+ h
969
+ end
970
+ end
971
+
972
+ class Container < InteriorSchemaNode
973
+ def to_json_recursive h
974
+ h['type'] = 'container'
975
+ h['arg'] = @arg
976
+ h['children'] = Hash.new
977
+ @children.each{ |c|
978
+ c.to_json_recursive h['children']
979
+ }
980
+ h
981
+ end
982
+ end
983
+
984
+ class Leaf < LeafSchemaNode
985
+ def to_json_recursive h
986
+ h['type'] = 'leaf'
987
+ h['arg'] = @arg
988
+ case @type
989
+ when Rubyang::Database::SchemaTree::StringType
990
+ h['datatype'] = 'string'
991
+ h['parameters'] = Hash.new
992
+ h['parameters']['length'] = @type.length.to_s
993
+ h['parameters']['pattern'] = @type.pattern.to_s
994
+ else
995
+ raise
996
+ end
997
+ h
998
+ end
999
+ end
1000
+
1001
+ class List < InteriorSchemaNode
1002
+ def keys
1003
+ @yang.substmt( 'key' )[0].arg.split( /[ \t]+/ )
1004
+ end
1005
+ end
1006
+
1007
+ class LeafList < LeafSchemaNode
1008
+ end
1009
+
1010
+ class Choice < InteriorSchemaNode
1011
+ end
1012
+
1013
+ class Case < InteriorSchemaNode
1014
+ end
1015
+
1016
+ class Rpc < SchemaNode
1017
+ end
1018
+ class Input < SchemaNode
1019
+ end
1020
+ class Output < SchemaNode
1021
+ end
1022
+ class Notification < SchemaNode
1023
+ end
1024
+ class Anyxml < SchemaNode
1025
+ end
1026
+
1027
+ def initialize yangs
1028
+ @yangs = yangs
1029
+ @root = Root.new @yangs
1030
+ end
1031
+ def root
1032
+ @root
1033
+ end
1034
+ def load model
1035
+ @root.load_yang( model )
1036
+ end
1037
+ end
1038
+ end
1039
+ end
1040
+
1041
+ if __FILE__ == $0
1042
+ require_relative '../../rubyang'
1043
+ yang_str =<<-EOB
1044
+ module module1 {
1045
+ namespace "http://module1.rspec/";
1046
+ prefix module1;
1047
+ container container1 {
1048
+ leaf leaf1 {
1049
+ type string {
1050
+ length 0..10;
1051
+ pattern '[0-9]+';
1052
+ }
1053
+ }
1054
+ }
1055
+ }
1056
+ EOB
1057
+ db = Rubyang::Database.new
1058
+ db.load_model Rubyang::Model::Parser.parse( yang_str )
1059
+ puts db.configure.schema.to_json
1060
+ end