ios_parser 0.3.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,231 @@
1
+ require_relative '../../spec_helper'
2
+ require 'ios_parser'
3
+ require 'ios_parser/lexer'
4
+
5
+ module IOSParser
6
+ describe Lexer do
7
+ describe '#call' do
8
+ subject { klass.new.call(input) }
9
+
10
+ let(:subject_pure) do
11
+ IOSParser::PureLexer.new.call(input)
12
+ end
13
+
14
+ context 'indented region' do
15
+ let(:input) { <<-END }
16
+ policy-map mypolicy_in
17
+ class myservice_service
18
+ police 300000000 1000000 exceed-action policed-dscp-transmit
19
+ set dscp cs1
20
+ class other_service
21
+ police 600000000 1000000 exceed-action policed-dscp-transmit
22
+ set dscp cs2
23
+ END
24
+
25
+ let(:output) do
26
+ ['policy-map', 'mypolicy_in', :EOL,
27
+ :INDENT,
28
+ 'class', 'myservice_service', :EOL,
29
+ :INDENT,
30
+ 'police', 300_000_000, 1_000_000, 'exceed-action',
31
+ 'policed-dscp-transmit', :EOL,
32
+ :INDENT,
33
+ 'set', 'dscp', 'cs1', :EOL,
34
+ :DEDENT, :DEDENT,
35
+ 'class', 'other_service', :EOL,
36
+ :INDENT,
37
+ 'police', 600_000_000, 1_000_000, 'exceed-action',
38
+ 'policed-dscp-transmit', :EOL,
39
+ :INDENT,
40
+ 'set', 'dscp', 'cs2', :EOL, :DEDENT, :DEDENT, :DEDENT
41
+ ]
42
+ end
43
+
44
+ subject { klass.new.call(input).map(&:last) }
45
+ it('enclosed in symbols') { should == output }
46
+
47
+ it('enclosed in symbols (using the pure ruby lexer)') do
48
+ expect(subject_pure.map(&:last)).to eq output
49
+ end
50
+ end
51
+
52
+ context 'ASR indented regions' do
53
+ context 'indented region' do
54
+ let(:input) { <<-END }
55
+ router static
56
+ vrf MGMT
57
+ address-family ipv4 unicast
58
+ 0.0.0.0/0 1.2.3.4
59
+ !
60
+ !
61
+ !
62
+ router ospf 12345
63
+ nsr
64
+ END
65
+
66
+ let(:expectation) do
67
+ ['router', 'static', :EOL,
68
+ :INDENT, 'vrf', 'MGMT', :EOL,
69
+ :INDENT, 'address-family', 'ipv4', 'unicast', :EOL,
70
+ :INDENT, '0.0.0.0/0', '1.2.3.4', :EOL,
71
+ :DEDENT, :DEDENT, :DEDENT,
72
+ 'router', 'ospf', 12_345, :EOL,
73
+ :INDENT, 'nsr', :EOL,
74
+ :DEDENT
75
+ ]
76
+ end
77
+
78
+ it 'pure' do
79
+ tokens = IOSParser::PureLexer.new.call(input)
80
+ expect(tokens.map(&:last)).to eq expectation
81
+ end # it 'pure' do
82
+
83
+ it 'c' do
84
+ tokens = IOSParser::CLexer.new.call(input)
85
+ expect(tokens.map(&:last)).to eq expectation
86
+ end # it 'c' do
87
+ end # context 'indented region' do
88
+ end # context 'ASR indented regions' do
89
+
90
+ context 'banners' do
91
+ let(:input) do
92
+ <<-END
93
+ banner foobar ^
94
+ asdf 1234 9786 asdf
95
+ line 2
96
+ line 3
97
+ ^
98
+ END
99
+ end
100
+
101
+ let(:output) do
102
+ [[0, 'banner'], [7, 'foobar'], [14, :BANNER_BEGIN],
103
+ [16, "asdf 1234 9786 asdf\nline 2\nline 3\n "],
104
+ [52, :BANNER_END], [53, :EOL]]
105
+ end
106
+
107
+ it('tokenized and enclosed in symbols') { should == output }
108
+
109
+ it('tokenized and enclodes in symbols (using the pure ruby lexer)') do
110
+ expect(subject_pure).to eq output
111
+ end
112
+ end
113
+
114
+ context 'decimal number' do
115
+ let(:input) { 'boson levels at 93.2' }
116
+ let(:output) { ['boson', 'levels', 'at', 93.2] }
117
+ subject { klass.new.call(input).map(&:last) }
118
+ it('converts to Float') { should == output }
119
+ end
120
+
121
+ context 'cryptographic certificate' do
122
+ let(:input) do
123
+ <<END
124
+ crypto pki certificate chain TP-self-signed-0123456789
125
+ certificate self-signed 01
126
+ FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
127
+ EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE
128
+ DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD AAAA
129
+ quit
130
+ !
131
+ END
132
+ end
133
+
134
+ let(:output) do
135
+ [[0, 'crypto'],
136
+ [7, 'pki'],
137
+ [11, 'certificate'],
138
+ [23, 'chain'],
139
+ [29, 'TP-self-signed-0123456789'],
140
+ [54, :EOL],
141
+ [56, :INDENT],
142
+ [56, 'certificate'],
143
+ [68, 'self-signed'],
144
+ [80, '01'],
145
+ [85, :CERTIFICATE_BEGIN],
146
+ [85,
147
+ 'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF '\
148
+ 'FFFFFFFF EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE '\
149
+ 'EEEEEEEE EEEEEEEE DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD '\
150
+ 'DDDDDDDD DDDDDDDD DDDDDDDD AAAA'],
151
+ [323, :CERTIFICATE_END],
152
+ [323, :EOL],
153
+ [323, :DEDENT]
154
+ ]
155
+ end
156
+
157
+ subject { klass.new.call(input) }
158
+ it('tokenized') { expect(subject).to eq output }
159
+
160
+ it('tokenized (using the pure ruby lexer)') do
161
+ expect(subject_pure).to eq output
162
+ end
163
+ end
164
+
165
+ context 'comments' do
166
+ let(:input) { 'ip addr 127.0.0.0.1 ! asdfsdf' }
167
+ let(:output) { ['ip', 'addr', '127.0.0.0.1'] }
168
+ subject { klass.new.call(input).map(&:last) }
169
+ it('dropped') { should == output }
170
+ end
171
+
172
+ context 'quoted octothorpe' do
173
+ let(:input) { <<-EOS }
174
+ vlan 1
175
+ name "a #"
176
+ vlan 2
177
+ name d
178
+ EOS
179
+
180
+ let(:output) do
181
+ [
182
+ 'vlan', 1, :EOL,
183
+ :INDENT, 'name', '"a #"', :EOL,
184
+ :DEDENT,
185
+ 'vlan', 2, :EOL,
186
+ :INDENT, 'name', 'd', :EOL,
187
+ :DEDENT
188
+ ]
189
+ end
190
+
191
+ it { expect(subject_pure.map(&:last)).to eq output }
192
+ it { expect(subject.map(&:last)).to eq output }
193
+ end # context 'quoted octothorpe' do
194
+
195
+ context 'vlan range' do
196
+ let(:input) { 'switchport trunk allowed vlan 50-90' }
197
+ let(:output) do
198
+ [
199
+ [0, 'switchport'],
200
+ [11, 'trunk'],
201
+ [17, 'allowed'],
202
+ [25, 'vlan'],
203
+ [30, '50-90']
204
+ ]
205
+ end
206
+ it { should == output }
207
+ end # context 'vlan range' do
208
+
209
+ context 'partial dedent' do
210
+ let(:input) do
211
+ <<END
212
+ class-map match-any foobar
213
+ description blahblahblah
214
+ match access-group fred
215
+ END
216
+ end
217
+
218
+ let(:output) do
219
+ [
220
+ 'class-map', 'match-any', 'foobar', :EOL,
221
+ :INDENT, 'description', 'blahblahblah', :EOL,
222
+ 'match', 'access-group', 'fred', :EOL,
223
+ :DEDENT
224
+ ]
225
+ end
226
+
227
+ it { expect(subject_pure.map(&:last)).to eq output }
228
+ end
229
+ end
230
+ end
231
+ end
@@ -0,0 +1,101 @@
1
+ require_relative '../spec_helper'
2
+ require 'ios_parser'
3
+
4
+ describe IOSParser do
5
+ describe '.parse' do
6
+ context 'indented region' do
7
+ let(:input) { <<-END }
8
+ policy-map mypolicy_in
9
+ class myservice_service
10
+ police 300000000 1000000 exceed-action policed-dscp-transmit
11
+ set dscp cs1
12
+ class other_service
13
+ police 600000000 1000000 exceed-action policed-dscp-transmit
14
+ set dscp cs2
15
+ command_with_no_args
16
+ END
17
+
18
+ let(:output) do
19
+ {
20
+ commands:
21
+ [{ args: ['policy-map', 'mypolicy_in'],
22
+ commands:
23
+ [{ args: %w(class myservice_service),
24
+ commands: [{ args: ['police', 300_000_000, 1_000_000,
25
+ 'exceed-action',
26
+ 'policed-dscp-transmit'],
27
+ commands: [{ args: %w(set dscp cs1),
28
+ commands: [], pos: 114 }],
29
+ pos: 50
30
+ }],
31
+ pos: 24
32
+ },
33
+
34
+ { args: %w(class other_service),
35
+ commands: [{ args: ['police', 600_000_000, 1_000_000,
36
+ 'exceed-action',
37
+ 'policed-dscp-transmit'],
38
+ commands: [{ args: %w(set dscp cs2),
39
+ commands: [], pos: 214 },
40
+ { args: ['command_with_no_args'],
41
+ commands: [], pos: 230 }],
42
+ pos: 150
43
+ }],
44
+ pos: 128
45
+ }],
46
+ pos: 0
47
+ }]
48
+ }
49
+ end
50
+
51
+ subject { described_class.parse(input) }
52
+
53
+ it('constructs the right AST') do
54
+ should be_a IOSParser::IOS::Document
55
+ expect(subject.to_hash).to eq output
56
+ end
57
+ end # context 'indented region'
58
+
59
+ context 'partial outdent' do
60
+ let(:input) do
61
+ <<END
62
+ class-map match-any foobar
63
+ description blah blah blah
64
+ match access-group fred
65
+ END
66
+ end
67
+
68
+ let(:output) do
69
+ {
70
+ commands:
71
+ [
72
+ {
73
+ args: ['class-map', 'match-any', 'foobar'],
74
+ commands: [
75
+ {
76
+ args: %w(description blah blah blah),
77
+ commands: [],
78
+ pos: 29
79
+ },
80
+ {
81
+ args: ['match', 'access-group', 'fred'],
82
+ commands: [],
83
+ pos: 57
84
+ }
85
+ ],
86
+ pos: 0
87
+ }
88
+ ]
89
+ }
90
+ end
91
+
92
+ subject { described_class.parse(input) }
93
+
94
+ it 'constructs the right AST' do
95
+ should be_a IOSParser::IOS::Document
96
+ actual = subject.to_hash
97
+ expect(actual).to eq(output)
98
+ end
99
+ end # context "partial outdent" do
100
+ end # describe '.parse'
101
+ end # describe IOSParser
@@ -0,0 +1,5 @@
1
+ $LOAD_PATH << File.dirname(__FILE__) + '/../lib'
2
+
3
+ def klass
4
+ described_class
5
+ end
metadata ADDED
@@ -0,0 +1,164 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: ios_parser
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.0
5
+ platform: ruby
6
+ authors:
7
+ - Ben Miller
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2016-03-05 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '3.2'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '3.2'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rubocop
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '0.37'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '0.37'
41
+ - !ruby/object:Gem::Dependency
42
+ name: guard
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '2.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '2.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: guard-rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '4.5'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '4.5'
69
+ - !ruby/object:Gem::Dependency
70
+ name: guard-rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.2'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.2'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rake-compiler
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '0.9'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '0.9'
97
+ description:
98
+ email: bjmllr@gmail.com
99
+ executables: []
100
+ extensions:
101
+ - ext/ios_parser/c_lexer/extconf.rb
102
+ extra_rdoc_files: []
103
+ files:
104
+ - ".gitignore"
105
+ - ".rubocop.yml"
106
+ - ".travis.yml"
107
+ - CHANGELOG.md
108
+ - CODE_OF_CONDUCT.md
109
+ - Gemfile
110
+ - Guardfile
111
+ - LICENSE.txt
112
+ - README.md
113
+ - Rakefile
114
+ - bin/console
115
+ - bin/setup
116
+ - doc/state_machine.graphviz
117
+ - doc/state_machine.png
118
+ - ext/ios_parser/c_lexer/extconf.rb
119
+ - ext/ios_parser/c_lexer/lexer.c
120
+ - ios_parser.gemspec
121
+ - lib/ios_parser.rb
122
+ - lib/ios_parser/ios.rb
123
+ - lib/ios_parser/ios/command.rb
124
+ - lib/ios_parser/ios/document.rb
125
+ - lib/ios_parser/ios/queryable.rb
126
+ - lib/ios_parser/lexer.rb
127
+ - lib/ios_parser/pure.rb
128
+ - lib/ios_parser/version.rb
129
+ - spec/lib/ios_parser/ios/queryable_spec.rb
130
+ - spec/lib/ios_parser/ios_spec.rb
131
+ - spec/lib/ios_parser/lexer_spec.rb
132
+ - spec/lib/ios_parser_spec.rb
133
+ - spec/spec_helper.rb
134
+ homepage: https://github.com/bjmllr/ios_parser
135
+ licenses:
136
+ - GPL-3.0
137
+ metadata: {}
138
+ post_install_message:
139
+ rdoc_options: []
140
+ require_paths:
141
+ - lib
142
+ required_ruby_version: !ruby/object:Gem::Requirement
143
+ requirements:
144
+ - - ">="
145
+ - !ruby/object:Gem::Version
146
+ version: '0'
147
+ required_rubygems_version: !ruby/object:Gem::Requirement
148
+ requirements:
149
+ - - ">="
150
+ - !ruby/object:Gem::Version
151
+ version: '0'
152
+ requirements: []
153
+ rubyforge_project:
154
+ rubygems_version: 2.5.1
155
+ signing_key:
156
+ specification_version: 4
157
+ summary: convert network switch and router config files to structured data
158
+ test_files:
159
+ - spec/lib/ios_parser/ios/queryable_spec.rb
160
+ - spec/lib/ios_parser/ios_spec.rb
161
+ - spec/lib/ios_parser/lexer_spec.rb
162
+ - spec/lib/ios_parser_spec.rb
163
+ - spec/spec_helper.rb
164
+ has_rdoc: