junoser 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.md +69 -0
- data/Rakefile +37 -0
- data/bin/console +14 -0
- data/bin/setup +7 -0
- data/example/vsrx-12.1.x47.rb +38421 -0
- data/exe/junoser +51 -0
- data/junoser.gemspec +27 -0
- data/lib/junoser/cli.rb +55 -0
- data/lib/junoser/development.rb +2 -0
- data/lib/junoser/display/base.rb +40 -0
- data/lib/junoser/display/config_store.rb +52 -0
- data/lib/junoser/display/set.rb +82 -0
- data/lib/junoser/display/structure.rb +29 -0
- data/lib/junoser/display.rb +16 -0
- data/lib/junoser/parser.rb +38453 -0
- data/lib/junoser/ruler.rb +173 -0
- data/lib/junoser/transformer.rb +41 -0
- data/lib/junoser/version.rb +3 -0
- data/lib/junoser/xsd/base.rb +54 -0
- data/lib/junoser/xsd/choice.rb +33 -0
- data/lib/junoser/xsd/complex_type.rb +74 -0
- data/lib/junoser/xsd/element.rb +100 -0
- data/lib/junoser/xsd/enumeration.rb +30 -0
- data/lib/junoser/xsd/parsable.rb +33 -0
- data/lib/junoser/xsd/restriction.rb +34 -0
- data/lib/junoser/xsd/sequence.rb +39 -0
- data/lib/junoser/xsd/simple_content.rb +31 -0
- data/lib/junoser.rb +3 -0
- metadata +146 -0
@@ -0,0 +1,173 @@
|
|
1
|
+
module Junoser
|
2
|
+
class Ruler
|
3
|
+
OFFSET = ' '
|
4
|
+
|
5
|
+
def initialize(input)
|
6
|
+
@rule = input
|
7
|
+
end
|
8
|
+
|
9
|
+
def to_rule
|
10
|
+
rule_header << rule << rule_footer
|
11
|
+
end
|
12
|
+
|
13
|
+
def rule
|
14
|
+
str = @rule.read
|
15
|
+
str = process_reserved_element(str)
|
16
|
+
str = str.split(/\n/).map {|l| format(process_line(l)) }.join("\n")
|
17
|
+
end
|
18
|
+
|
19
|
+
|
20
|
+
private
|
21
|
+
|
22
|
+
def process_line(str)
|
23
|
+
return str if str =~ /^(.* do|end)$/
|
24
|
+
|
25
|
+
str.gsub!(/("[^"]+")/) { "str(#$1)" } # "foo" -> str("foo")
|
26
|
+
|
27
|
+
str.gsub!(/^(\s*)arg(\.as\(:\S+\))? \($/) { "#{$1}b(arg#$2," } # arg ( -> b(arg,
|
28
|
+
str.gsub!(/^(\s*)(str\(\S+\)) ([^ \t\n\r\f\(|,]+)(\.as\(:\S+\))?(,?)$/) { "#{$1}a(#$2, #$3)#$4#$5" } # str("foo") bar -> a(str("foo"), bar)
|
29
|
+
str.gsub!(/^(\s*)(str\(\S+\)) \((.*)\)(,?)$/) { "#{$1}a(#$2, #$3)#$4" } # str("foo") (a | b) -> a(str("foo"), a | b)
|
30
|
+
|
31
|
+
str.gsub!(/^(\s*)(str\(\S+\)) \($/) { "#{$1}b(#$2," } # str("foo") ( -> b(str("foo"),
|
32
|
+
str.gsub!(/^(\s*)(\(.*\))(\.as\(:\S\))? \($/) { "#{$1}b(#$2#$3," } # (a | b) ( -> b((a | b),
|
33
|
+
str.gsub!(/^(\s*)(str\(\S+\)) ([^ \t\n\r\f\(|,]+) \($/) { "#{$1}b(a(#$2, #$3)," } # str("foo") bar ( -> b(a(str("foo"), bar),
|
34
|
+
str.gsub!(/^(\s*)(str\(\S+\)) \((.*)\) \($/) { "#{$1}a(#$2, #$3," } # str("foo") (a | b) ( -> a(str("foo"), a | b,
|
35
|
+
|
36
|
+
str
|
37
|
+
end
|
38
|
+
|
39
|
+
def process_reserved_element(str)
|
40
|
+
str.gsub! /"\$\S+"/, 'arg'
|
41
|
+
str.gsub! '"as-number" arg', 'arg'
|
42
|
+
str.gsub! '"equal-literal"', '"="'
|
43
|
+
str.gsub! '"plus-literal"', '"+"'
|
44
|
+
str.gsub! '"minus-literal"', '"-"'
|
45
|
+
|
46
|
+
str.gsub!(/\((.*) \| "name"\)/) { "(#$1 | arg)" }
|
47
|
+
str.gsub! '"vlan" ("id-name" | "all")', '"vlan" ("all" | arg)'
|
48
|
+
str.gsub!(/("ssh-\S+") arg/) { "#$1 (quote | arg)" }
|
49
|
+
str.gsub! '"metric-value" arg', 'arg'
|
50
|
+
str.gsub! '"limit-threshold" arg', 'arg'
|
51
|
+
str.gsub! '"filename" arg', 'arg'
|
52
|
+
str.gsub! '"description" arg', '"description" (quote | arg)'
|
53
|
+
str.gsub! '"as-path-prepend" arg', '"as-path-prepend" (quote | arg)'
|
54
|
+
|
55
|
+
|
56
|
+
str.gsub!(/^(\s*)"inline-services"/) do
|
57
|
+
format(['"inline-services" (',
|
58
|
+
' "bandwidth" ("1g" | "10g")',
|
59
|
+
')'], $1)
|
60
|
+
end
|
61
|
+
str.gsub!(/^(\s*)"ieee-802.3ad" \(\s*sc\(\s*"lacp" \(\s*sc\(/) do
|
62
|
+
format(['"802.3ad" (',
|
63
|
+
' sc(',
|
64
|
+
' arg,',
|
65
|
+
' "lacp" (',
|
66
|
+
' sc(',
|
67
|
+
' "force-up",'], $1)
|
68
|
+
end
|
69
|
+
str.gsub!(/^(\s*)"as-path" \(\s*sc\(\s*"path" arg/) do
|
70
|
+
format(['"as-path" (',
|
71
|
+
' sc(',
|
72
|
+
' arg'], $1)
|
73
|
+
end
|
74
|
+
str.gsub!(/^(\s*)"as-path" arg \(\s*sc\(\s*"path" arg\s*\)/) do
|
75
|
+
format(['"as-path" arg (',
|
76
|
+
' sc(',
|
77
|
+
' quote,',
|
78
|
+
' arg',
|
79
|
+
' )'], $1)
|
80
|
+
end
|
81
|
+
|
82
|
+
%w[metric metric2 metric3 metric4 tag tag2 preference preference2 color color2 local-preference].each do |key|
|
83
|
+
str.gsub!(/^(\s*"#{key}" \(\s*sc\(\s*c\(\s*)"#{key}" arg/) { "#{$1}arg" }
|
84
|
+
end
|
85
|
+
|
86
|
+
str.gsub!(/(s\(\s*)"address" \(\s*arg\s*\)/) { "#{$1}arg" }
|
87
|
+
str.gsub!(/^(\s*"idle-timeout" \(\s*sc\(\s*c\(\s*"forever",\s*)"timeout" arg/) { "#{$1}arg" }
|
88
|
+
|
89
|
+
str = omit_label(str, 'contents', 'syslog_object')
|
90
|
+
str = omit_label(str, 'interface', 'cos_interfaces_type')
|
91
|
+
str = omit_label(str, 'interface', 'ir_interfaces_type')
|
92
|
+
str = omit_label(str, 'interface', 'interfaces_type')
|
93
|
+
str = omit_label(str, 'client-address-list', 'client_address_object')
|
94
|
+
str = omit_label(str, 'prefix-list-item', 'prefix_list_items')
|
95
|
+
str = omit_label(str, 'instance', 'juniper_routing_instance')
|
96
|
+
str = omit_label(str, 'vlan', 'vlan_type')
|
97
|
+
|
98
|
+
str.gsub!(/"icmp"(.*)"icmp6"/) { %["icmpv6"#$1"icmp"] }
|
99
|
+
str.gsub!(/"http"(.*)"https"/) { %["https"#$1"http"] }
|
100
|
+
str.gsub!(/"snmp"(.*)"snmptrap"/) { %["snmptrap"#$1"snmp"] }
|
101
|
+
|
102
|
+
str
|
103
|
+
end
|
104
|
+
|
105
|
+
def omit_label(str, label, content)
|
106
|
+
str.gsub(/(\s*)"#{label}" \(\s*#{content}\s*\)/) { "#{$1}#{content}" }
|
107
|
+
end
|
108
|
+
|
109
|
+
def format(str, offset=OFFSET)
|
110
|
+
case str
|
111
|
+
when String
|
112
|
+
str.empty? ? '' : offset + str
|
113
|
+
when Array
|
114
|
+
str.map {|s| s.empty? ? '' : offset + s.to_s }.join("\n")
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def rule_header
|
119
|
+
<<-EOS
|
120
|
+
require 'parslet'
|
121
|
+
|
122
|
+
module Junoser
|
123
|
+
class Parser < Parslet::Parser
|
124
|
+
# block with children maybe
|
125
|
+
def b(object, *children)
|
126
|
+
children.inject(object) {|rule, child| rule.as(:label) >> (space >> child.as(:child) | eos) }
|
127
|
+
end
|
128
|
+
|
129
|
+
# with an argument, and children maybe
|
130
|
+
def a(object, arg, *children)
|
131
|
+
b(object.as(:statement) >> space >> arg.as(:argument), *children)
|
132
|
+
end
|
133
|
+
|
134
|
+
# choice
|
135
|
+
def c(*objects)
|
136
|
+
objects.inject {|rule, object| rule | object }
|
137
|
+
end
|
138
|
+
|
139
|
+
# sequence
|
140
|
+
def s(*objects)
|
141
|
+
# TODO: eval "minOccurs" attribute of choice element
|
142
|
+
objects.inject {|rule, object| rule >> (space >> object).maybe }
|
143
|
+
end
|
144
|
+
|
145
|
+
# sequential choice
|
146
|
+
def sc(*objects)
|
147
|
+
(c(*objects) >> space.maybe).repeat(0)
|
148
|
+
end
|
149
|
+
|
150
|
+
rule(:arg) { match('\\S').repeat(1) }
|
151
|
+
rule(:space) { match('\\s').repeat(1) }
|
152
|
+
rule(:any) { match('.').repeat(1) }
|
153
|
+
rule(:eos) { match('$') }
|
154
|
+
rule(:dotted) { match('[^. \\t\\n\\r\\f]').repeat(1) >> match('\.') >> match('[^. \\t\\n\\r\\f]').repeat(1) }
|
155
|
+
rule(:quote) { match('"') >> match('[^"]').repeat(1) >> match('"') }
|
156
|
+
rule(:address) { match('[0-9a-fA-F:\.]').repeat(1) }
|
157
|
+
rule(:prefix ) { address >> (match('/') >> match('[0-9]').repeat(1)).maybe }
|
158
|
+
|
159
|
+
root(:set)
|
160
|
+
rule(:set) { (str('set') | str('deactivate')) >> space >> configuration.as(:config) }
|
161
|
+
|
162
|
+
EOS
|
163
|
+
end
|
164
|
+
|
165
|
+
def rule_footer
|
166
|
+
<<-EOS
|
167
|
+
|
168
|
+
end
|
169
|
+
end
|
170
|
+
EOS
|
171
|
+
end
|
172
|
+
end
|
173
|
+
end
|
@@ -0,0 +1,41 @@
|
|
1
|
+
require 'parslet'
|
2
|
+
|
3
|
+
module Junoser
|
4
|
+
class Transformer < Parslet::Transform
|
5
|
+
rule(config: simple(:config)) do
|
6
|
+
config.to_s
|
7
|
+
end
|
8
|
+
|
9
|
+
rule(config: sequence(:configs)) do
|
10
|
+
configs.join("\n")
|
11
|
+
end
|
12
|
+
|
13
|
+
rule(arg: simple(:arg)) do
|
14
|
+
"arg(#{arg})"
|
15
|
+
end
|
16
|
+
|
17
|
+
rule(label: simple(:label)) do
|
18
|
+
label.to_s
|
19
|
+
end
|
20
|
+
|
21
|
+
rule(label: simple(:label), child: simple(:child)) do
|
22
|
+
"#{label}\n#{child}"
|
23
|
+
end
|
24
|
+
|
25
|
+
rule(label: simple(:label), child: sequence(:children)) do
|
26
|
+
%[#{label}\n#{children.join("\n")}]
|
27
|
+
end
|
28
|
+
|
29
|
+
rule(statement: simple(:statement), argument: simple(:argument)) do
|
30
|
+
"#{statement} #{argument}"
|
31
|
+
end
|
32
|
+
|
33
|
+
rule(statement: simple(:statement), argument: sequence(:arguments)) do
|
34
|
+
%[#{statement}\n#{arguments.join("\n")}]
|
35
|
+
end
|
36
|
+
|
37
|
+
rule(oneline: simple(:str)) do
|
38
|
+
str.gsub "\n", ' '
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
module Junoser
|
2
|
+
module Xsd
|
3
|
+
module Base
|
4
|
+
attr_reader :xml
|
5
|
+
|
6
|
+
OFFSET = ' '
|
7
|
+
|
8
|
+
def initialize(xml, options={})
|
9
|
+
@xml = xml
|
10
|
+
@depth = options[:depth] || 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def config
|
14
|
+
raise "ERROR: no implementation"
|
15
|
+
end
|
16
|
+
|
17
|
+
def children
|
18
|
+
@children||= xml.xpath('./*[not(self::xsd:annotation)]')
|
19
|
+
end
|
20
|
+
|
21
|
+
def root?
|
22
|
+
@depth == 1
|
23
|
+
end
|
24
|
+
|
25
|
+
def inspect
|
26
|
+
["#<#{self.class}:0x#{object_id}",
|
27
|
+
"xml=#{xml.namespace.prefix}:#{xml.name}" <<
|
28
|
+
" attributes=" << Hash[xml.attributes.map {|k, v| [k, v.value] }].to_s <<
|
29
|
+
(respond_to?(:label) ? " label=#{label}" : ''),
|
30
|
+
"config=[",
|
31
|
+
*config.map {|c| c.inspect },
|
32
|
+
']>'].join("\n#{OFFSET*(@depth+1)}")
|
33
|
+
end
|
34
|
+
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def oneliner?
|
39
|
+
@oneliner ||= !xml.xpath('./xsd:annotation/xsd:appinfo/flag[contains(text(), "oneliner")]').empty?
|
40
|
+
end
|
41
|
+
|
42
|
+
def has_single_child_of?(klass)
|
43
|
+
config.size == 1 && config.first.is_a?(klass)
|
44
|
+
end
|
45
|
+
|
46
|
+
def format(header, content=nil, footer=nil)
|
47
|
+
str = OFFSET*@depth << header.to_s
|
48
|
+
str << "\n" << content if content
|
49
|
+
str << "\n" << OFFSET*@depth << footer if footer
|
50
|
+
str
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'junoser/xsd/base'
|
2
|
+
require 'junoser/xsd/element'
|
3
|
+
|
4
|
+
module Junoser
|
5
|
+
module Xsd
|
6
|
+
class Choice
|
7
|
+
include Base
|
8
|
+
|
9
|
+
def config
|
10
|
+
@config ||= children.map {|child|
|
11
|
+
case child.name
|
12
|
+
when 'element'
|
13
|
+
Junoser::Xsd::Element.new(child, depth: @depth+1)
|
14
|
+
when 'choice'
|
15
|
+
Junoser::Xsd::Choice.new(child, depth: @depth+1)
|
16
|
+
else
|
17
|
+
raise "ERROR: unknown element: #{child.name}"
|
18
|
+
end
|
19
|
+
}.compact
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
case
|
24
|
+
when config.empty?
|
25
|
+
when has_single_child_of?(Junoser::Xsd::Choice)
|
26
|
+
format('c(', config.first.config.map(&:to_s).compact.join(",\n"), ')')
|
27
|
+
else
|
28
|
+
format('c(', config.map(&:to_s).compact.join(",\n"), ')')
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
require 'junoser/xsd/base'
|
2
|
+
require 'junoser/xsd/element'
|
3
|
+
require 'junoser/xsd/sequence'
|
4
|
+
require 'junoser/xsd/simple_content'
|
5
|
+
|
6
|
+
module Junoser
|
7
|
+
module Xsd
|
8
|
+
class ComplexType
|
9
|
+
include Base
|
10
|
+
|
11
|
+
def initialize(xml, options={})
|
12
|
+
super
|
13
|
+
raise "ERROR: #{xml.name} shouldn't have name '#{xml['name']}'" if xml['name'] && !root?
|
14
|
+
@argument = find_name_element
|
15
|
+
end
|
16
|
+
|
17
|
+
def config
|
18
|
+
@config ||= children.map {|child|
|
19
|
+
case child.name
|
20
|
+
when 'sequence'
|
21
|
+
Junoser::Xsd::Sequence.new(child, depth: @depth+1)
|
22
|
+
when 'simpleContent'
|
23
|
+
Junoser::Xsd::SimpleContent.new(child, depth: @depth+1)
|
24
|
+
when 'attribute'
|
25
|
+
'arg'
|
26
|
+
else
|
27
|
+
raise "ERROR: unknown element: #{child.name}"
|
28
|
+
end
|
29
|
+
}.compact
|
30
|
+
end
|
31
|
+
|
32
|
+
def to_s
|
33
|
+
str = config.map {|c| c.is_a?(String) ? format(OFFSET + c) : c.to_s }.compact.join("\n")
|
34
|
+
|
35
|
+
str = case [!argument.nil?, !str.empty?]
|
36
|
+
when [true, true]
|
37
|
+
format("#{argument} (", str, ')')
|
38
|
+
when [true, false]
|
39
|
+
format(argument)
|
40
|
+
when [false, true]
|
41
|
+
simple_argument?(str) ? "#{str}.as(:arg)" : str
|
42
|
+
else
|
43
|
+
''
|
44
|
+
end
|
45
|
+
|
46
|
+
oneliner? ? "#{str}.as(:oneline)" : str
|
47
|
+
end
|
48
|
+
|
49
|
+
|
50
|
+
private
|
51
|
+
|
52
|
+
def argument
|
53
|
+
return unless @argument
|
54
|
+
|
55
|
+
arg = Junoser::Xsd::Element.new(@argument, depth: @depth+1).config
|
56
|
+
raise "ERROR: argument shouldn't consist of multiple elements" if arg.size > 1
|
57
|
+
|
58
|
+
if root?
|
59
|
+
arg.first.to_s.strip + ".as(:arg)"
|
60
|
+
else
|
61
|
+
arg.first.to_s.strip
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
def find_name_element
|
66
|
+
xml.xpath('./xsd:sequence/xsd:element[@name="name"]').remove.first
|
67
|
+
end
|
68
|
+
|
69
|
+
def simple_argument?(str)
|
70
|
+
root? && str =~ /\A\s*arg\z/
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,100 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
require 'junoser/xsd/base'
|
3
|
+
require 'junoser/xsd/complex_type'
|
4
|
+
|
5
|
+
module Junoser
|
6
|
+
module Xsd
|
7
|
+
class Element
|
8
|
+
include Base
|
9
|
+
|
10
|
+
def initialize(xml, options={})
|
11
|
+
super
|
12
|
+
@argument = find_name_element || find_single_simple_type || find_simple_type_attribute
|
13
|
+
end
|
14
|
+
|
15
|
+
def config
|
16
|
+
@config ||= children.map {|child|
|
17
|
+
case child.name
|
18
|
+
when 'complexType'
|
19
|
+
Junoser::Xsd::ComplexType.new(child, depth: @depth+1)
|
20
|
+
when 'simpleType'
|
21
|
+
'arg'
|
22
|
+
else
|
23
|
+
raise "ERROR: unknown element: #{child.name}"
|
24
|
+
end
|
25
|
+
}.compact
|
26
|
+
end
|
27
|
+
|
28
|
+
def to_s
|
29
|
+
str = config.map {|c| c.is_a?(String) ? format(OFFSET + c) : c.to_s }.compact.join("\n")
|
30
|
+
|
31
|
+
str = case
|
32
|
+
when str.empty? && xml['type']
|
33
|
+
l = label ? "#{label} (" : '('
|
34
|
+
format(l, format(OFFSET + xml['type'].underscore), ')')
|
35
|
+
when str.empty?
|
36
|
+
format(label)
|
37
|
+
else
|
38
|
+
l = label ? "#{label} (" : '('
|
39
|
+
format(l, str, ')')
|
40
|
+
end
|
41
|
+
|
42
|
+
oneliner? ? "#{str}.as(:oneline)" : str
|
43
|
+
end
|
44
|
+
|
45
|
+
def content
|
46
|
+
str = config.map {|c| c.is_a?(String) ? format(OFFSET + c) : c.to_s }.compact.join("\n")
|
47
|
+
|
48
|
+
case
|
49
|
+
when str.empty? && xml['type']
|
50
|
+
format(OFFSET + xml['type'].underscore)
|
51
|
+
when str.empty?
|
52
|
+
''
|
53
|
+
else
|
54
|
+
str
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
|
59
|
+
private
|
60
|
+
|
61
|
+
def label
|
62
|
+
return unless xml['name']
|
63
|
+
|
64
|
+
%["#{xml['name']}" #{argument}].strip
|
65
|
+
end
|
66
|
+
|
67
|
+
def argument
|
68
|
+
return unless @argument
|
69
|
+
|
70
|
+
case
|
71
|
+
when @argument.is_a?(String)
|
72
|
+
@argument
|
73
|
+
when @argument.name == 'simpleType'
|
74
|
+
'arg'
|
75
|
+
else
|
76
|
+
arg = Junoser::Xsd::Element.new(@argument, depth: @depth+1).config
|
77
|
+
raise "ERROR: argument shouldn't consist of multiple elements" if arg.size > 1
|
78
|
+
arg.first.to_s.strip
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
def find_name_element
|
83
|
+
xml.xpath('./xsd:complexType/xsd:sequence/xsd:element[@name="name"]').remove.first
|
84
|
+
end
|
85
|
+
|
86
|
+
def find_single_simple_type
|
87
|
+
simples = xml.xpath('./xsd:simpleType').remove
|
88
|
+
raise "ERROR: Element shouldn't have simpleType child and another" if simples.size > 1
|
89
|
+
simples.first
|
90
|
+
end
|
91
|
+
|
92
|
+
def find_simple_type_attribute
|
93
|
+
if xml['type'] =~ /^xsd:.*/
|
94
|
+
xml.remove_attribute 'type'
|
95
|
+
'arg'
|
96
|
+
end
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
require 'junoser/xsd/base'
|
2
|
+
|
3
|
+
module Junoser
|
4
|
+
module Xsd
|
5
|
+
class Enumeration
|
6
|
+
include Base
|
7
|
+
|
8
|
+
def initialize(xml, options={})
|
9
|
+
super
|
10
|
+
end
|
11
|
+
|
12
|
+
def config
|
13
|
+
raise "ERROR: unknown Enumeration format" if children.size > 1
|
14
|
+
|
15
|
+
has_match? ? 'arg' : %["#{xml['value']}"]
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
format(OFFSET + config)
|
20
|
+
end
|
21
|
+
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def has_match?
|
26
|
+
return true unless xml.xpath('.//match').empty?
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,33 @@
|
|
1
|
+
require 'active_support/inflector'
|
2
|
+
require 'junoser/xsd/complex_type'
|
3
|
+
require 'junoser/xsd/element'
|
4
|
+
require 'nokogiri'
|
5
|
+
|
6
|
+
module Junoser
|
7
|
+
module Xsd
|
8
|
+
module Parsable
|
9
|
+
def to_config
|
10
|
+
rule = "rule(:#{self['name'].underscore}) do\n"
|
11
|
+
|
12
|
+
case name
|
13
|
+
when 'complexType'
|
14
|
+
rule << Junoser::Xsd::ComplexType.new(self, depth: 1).to_s
|
15
|
+
when 'element'
|
16
|
+
rule << Junoser::Xsd::Element.new(self, depth: 1).content
|
17
|
+
else
|
18
|
+
raise "ERROR: unknown element: #{name}"
|
19
|
+
end
|
20
|
+
|
21
|
+
rule << "\nend\n\n"
|
22
|
+
end
|
23
|
+
|
24
|
+
def remove_unused
|
25
|
+
xpath('/xsd:schema/*[self::xsd:import]').remove
|
26
|
+
xpath('//xsd:element[@ref="undocumented" or @ref="junos:comment"]').remove
|
27
|
+
self
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
Nokogiri::XML::Element.include Junoser::Xsd::Parsable
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'junoser/xsd/base'
|
2
|
+
require 'junoser/xsd/enumeration'
|
3
|
+
|
4
|
+
module Junoser
|
5
|
+
module Xsd
|
6
|
+
class Restriction
|
7
|
+
include Base
|
8
|
+
|
9
|
+
def children
|
10
|
+
@children||= xml.xpath('./*[not(self::xsd:annotation or ' +
|
11
|
+
'self::xsd:minInclusive or self::xsd:maxInclusive or ' +
|
12
|
+
'self::xsd:minLength or self::xsd:maxLength)]')
|
13
|
+
end
|
14
|
+
|
15
|
+
def config
|
16
|
+
@config ||= children.map {|child|
|
17
|
+
case child.name
|
18
|
+
when 'enumeration'
|
19
|
+
Junoser::Xsd::Enumeration.new(child, depth: @depth+1)
|
20
|
+
else
|
21
|
+
raise "ERROR: unknown element: #{child.name}"
|
22
|
+
end
|
23
|
+
}.compact
|
24
|
+
end
|
25
|
+
|
26
|
+
def to_s
|
27
|
+
return format('arg') if config.empty?
|
28
|
+
|
29
|
+
str = '(' + config.map {|c| c.to_s.strip }.compact.join(' | ') + ')'
|
30
|
+
format(str)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require 'junoser/xsd/base'
|
2
|
+
require 'junoser/xsd/choice'
|
3
|
+
require 'junoser/xsd/element'
|
4
|
+
|
5
|
+
module Junoser
|
6
|
+
module Xsd
|
7
|
+
class Sequence
|
8
|
+
include Base
|
9
|
+
|
10
|
+
def config
|
11
|
+
@config ||= children.map {|child|
|
12
|
+
case child.name
|
13
|
+
when 'choice'
|
14
|
+
Junoser::Xsd::Choice.new(child, depth: @depth+1)
|
15
|
+
when 'element'
|
16
|
+
Junoser::Xsd::Element.new(child, depth: @depth+1)
|
17
|
+
when 'any'
|
18
|
+
'any'
|
19
|
+
else
|
20
|
+
raise "ERROR: unknown element: #{child.name}"
|
21
|
+
end
|
22
|
+
}.compact
|
23
|
+
end
|
24
|
+
|
25
|
+
def to_s
|
26
|
+
case
|
27
|
+
when config.empty?
|
28
|
+
when has_single_child_of?(Junoser::Xsd::Choice)
|
29
|
+
child = config.first
|
30
|
+
str = child.config.map(&:to_s).compact.join(",\n")
|
31
|
+
format('sc(', str, ')') unless str.empty?
|
32
|
+
else
|
33
|
+
str = config.map {|c| c.is_a?(String) ? format(OFFSET + c) : c.to_s }.compact.join(",\n")
|
34
|
+
format('s(', str, ')')
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
require 'junoser/xsd/base'
|
2
|
+
require 'junoser/xsd/restriction'
|
3
|
+
|
4
|
+
module Junoser
|
5
|
+
module Xsd
|
6
|
+
class SimpleContent
|
7
|
+
include Base
|
8
|
+
|
9
|
+
def config
|
10
|
+
@config ||= children.map {|child|
|
11
|
+
case child.name
|
12
|
+
when 'restriction'
|
13
|
+
Junoser::Xsd::Restriction.new(child, depth: @depth+1)
|
14
|
+
when 'extension'
|
15
|
+
'arg'
|
16
|
+
else
|
17
|
+
raise "ERROR: unknown element: #{child.name}"
|
18
|
+
end
|
19
|
+
}.compact
|
20
|
+
end
|
21
|
+
|
22
|
+
def to_s
|
23
|
+
return if config.empty?
|
24
|
+
raise "ERROR: simpleContent shouldn't have multiple children" if config.size > 1
|
25
|
+
|
26
|
+
child = config.first
|
27
|
+
child.is_a?(String) ? format(OFFSET + child) : child.to_s
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
data/lib/junoser.rb
ADDED