ios_parser 0.4.1 → 0.5.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.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 3fa46ea53424609c1cc2bd44edfcebd86cedec95
4
- data.tar.gz: 632d1c06c880ca9d7ba17285c825ae4885fc4f08
3
+ metadata.gz: 181d9adcdc7d222fe6ef05a91624aa1277274371
4
+ data.tar.gz: f9a1920092018240b8e67f972e453f5e104b8bd9
5
5
  SHA512:
6
- metadata.gz: 052fe0ba301f4c002237b35134f4a97d7bf0ac175fd3d7217ee6634e5bc685939a84e0ec7eb44ffa05950c95c27d687010e3998162814db1f01c7d108951ff81
7
- data.tar.gz: c96e847e9af333cfa441588c57c1711c60323ae7d3cac08177a684fa26aa6d0fcd8da816926ffc815d64f50513f2d99c84676cb156eb11698a5cf7a7675c30db
6
+ metadata.gz: 4d4cf9efd75f3c563ffa92034dccbc265a5fd70778afb2f970df71641b1a94edc371befcd99e6d7bf989817b8fd1744a4d60b7340415ac7ec4fa4d2e8afd6586
7
+ data.tar.gz: 5fa9ebc0c746698ce75afd045d272826e9e48d54c86d4c20ab244e790b10f9255a36795a85331b1675d756fde9ac6b5d221bf0506391cb73a032e246e6ab41f7
data/CHANGELOG.md CHANGED
@@ -1,3 +1,10 @@
1
+ ## 0.5.0 (2017-04-26)
2
+
3
+ Enhancements:
4
+
5
+ - handle EOS-style banners
6
+
7
+
1
8
  ## 0.4.0 (2016-06-08)
2
9
 
3
10
  Enhancements:
data/Guardfile CHANGED
@@ -3,7 +3,7 @@ guard :rake, task: 'compile' do
3
3
  end
4
4
 
5
5
  guard :rspec, cmd: 'bundle exec rspec --color --fail-fast' do
6
- watch(%r{^spec/.+_spec\.rb$}) { |m| m }
6
+ watch(%r{^spec/.+_spec\.rb$})
7
7
  watch(%r{^lib/(.+)\.rb$}) { |m| "spec/lib/#{m[1]}_spec.rb" }
8
8
  watch('spec/spec_helper.rb') { 'spec' }
9
9
  watch(%r{^ext/(.+)\.[ch]$}) { 'spec' }
@@ -81,7 +81,7 @@ int is_certificate(LexInfo *lex) {
81
81
  return 1;
82
82
  }
83
83
 
84
- int is_banner(LexInfo *lex) {
84
+ int is_banner_begin(LexInfo *lex) {
85
85
  VALUE banner_ary, banner;
86
86
  int token_count = RARRAY_LEN(lex->tokens);
87
87
  int banner_pos = token_count - 2;
@@ -178,9 +178,20 @@ static VALUE initialize(VALUE self, VALUE input_text) {
178
178
 
179
179
  static void process_root(LexInfo * lex);
180
180
  static void process_start_of_line(LexInfo * lex);
181
+ static void start_banner(LexInfo * lex);
181
182
 
182
183
  static void process_newline(LexInfo *lex) {
183
184
  delimit(lex);
185
+
186
+ if (is_banner_begin(lex)) {
187
+ lex->token_state = LEX_STATE_BANNER;
188
+ start_banner(lex);
189
+ lex->pos = lex->pos + 1;
190
+ lex->token_start = lex->pos;
191
+ lex->token_length = 0;
192
+ return;
193
+ }
194
+
184
195
  lex->token_start = lex->pos;
185
196
  ADD_TOKEN(lex, ID2SYM(rb_intern("EOL")));
186
197
  lex->token_state = LEX_STATE_INDENT;
@@ -203,7 +214,7 @@ static void process_comment(LexInfo *lex) {
203
214
 
204
215
  static void process_quoted_string(LexInfo *lex) {
205
216
  char c = CURRENT_CHAR(lex);
206
-
217
+
207
218
  lex->token_length++;
208
219
  if (!lex->string_terminator) {
209
220
  lex->string_terminator = c;
@@ -301,24 +312,40 @@ static void start_certificate(LexInfo *lex) {
301
312
  process_certificate(lex);
302
313
  }
303
314
 
304
- static void process_banner(LexInfo *lex) {
305
- char c = CURRENT_CHAR(lex);
306
-
307
- if (c == lex->banner_delimiter &&
315
+ int is_banner_end_char(LexInfo *lex) {
316
+ return CURRENT_CHAR(lex) == lex->banner_delimiter &&
308
317
  (0 < lex->pos && '\n' == lex->text[lex->pos - 1] ||
309
- '\n' == lex->text[lex->pos + 1])) {
318
+ '\n' == lex->text[lex->pos + 1]);
319
+ }
320
+
321
+ int is_banner_end_string(LexInfo *lex) {
322
+ /* onlys accept the banner-ending string "EOF" */
323
+ return (CURRENT_CHAR(lex) == 'F' &&
324
+ lex->text[lex->pos - 1] == 'O' &&
325
+ lex->text[lex->pos - 2] == 'E' &&
326
+ lex->text[lex->pos - 3] == '\n');
327
+ }
328
+
329
+ static void process_banner(LexInfo *lex) {
330
+ if (lex->banner_delimiter && is_banner_end_char(lex)) {
310
331
  lex->token_length++;
311
332
  delimit(lex);
312
333
  lex->token_start = lex->pos;
313
334
  ADD_TOKEN(lex, ID2SYM(rb_intern("BANNER_END")));
314
335
  if (lex->text[lex->pos + 1] == 'C') { lex->pos++; }
336
+ } else if (!lex->banner_delimiter && is_banner_end_string(lex)) {
337
+ lex->token_length -= 1;
338
+ delimit(lex);
339
+ lex->token_start = lex->pos;
340
+ ADD_TOKEN(lex, ID2SYM(rb_intern("BANNER_END")));
315
341
  } else {
316
342
  lex->token_length++;
317
343
  }
318
344
  }
319
345
 
320
346
  static void start_banner(LexInfo *lex) {
321
- lex->banner_delimiter = CURRENT_CHAR(lex);
347
+ char c = CURRENT_CHAR(lex);
348
+ lex->banner_delimiter = (c == '\n') ? 0 : c;
322
349
  ADD_TOKEN(lex, ID2SYM(rb_intern("BANNER_BEGIN")));
323
350
  if ('\n' == lex->text[lex->pos + 2]) lex->pos++;
324
351
  }
@@ -359,7 +386,7 @@ static void process_root(LexInfo *lex) {
359
386
  if (IS_SPACE(c)) {
360
387
  delimit(lex);
361
388
 
362
- } else if (is_banner(lex)) {
389
+ } else if (is_banner_begin(lex)) {
363
390
  lex->token_state = LEX_STATE_BANNER;
364
391
  start_banner(lex);
365
392
  lex->pos = lex->pos + 2;
@@ -433,7 +460,7 @@ static VALUE call(VALUE self, VALUE input_text) {
433
460
  case (LEX_STATE_QUOTED_STRING):
434
461
  process_quoted_string(lex);
435
462
  break;
436
-
463
+
437
464
  case (LEX_STATE_WORD):
438
465
  process_word(lex);
439
466
  break;
@@ -81,7 +81,7 @@ module IOSParser
81
81
  self.state = :banner
82
82
  tokens << make_token(:BANNER_BEGIN)
83
83
  @token_start = @this_char + 2
84
- @banner_delimiter = char
84
+ @banner_delimiter = char == "\n" ? 'EOF' : char
85
85
  end
86
86
 
87
87
  def banner_begin?
@@ -89,21 +89,38 @@ module IOSParser
89
89
  end
90
90
 
91
91
  def banner
92
- if char == @banner_delimiter && (@text[@this_char - 1] == "\n" ||
93
- @text[@this_char + 1] == "\n")
94
- banner_end
92
+ if banner_end_char?
93
+ banner_end_char
94
+ elsif banner_end_string?
95
+ banner_end_string
95
96
  else
96
97
  token << char
97
98
  end
98
99
  end
99
100
 
100
- def banner_end
101
+ def banner_end_string
102
+ self.state = :root
103
+ token.chomp!(@banner_delimiter[0..-2])
104
+ tokens << make_token(token) << make_token(:BANNER_END)
105
+ self.token = ''
106
+ end
107
+
108
+ def banner_end_string?
109
+ @banner_delimiter.size > 1 && (token + char).end_with?(@banner_delimiter)
110
+ end
111
+
112
+ def banner_end_char
101
113
  self.state = :root
102
114
  banner_end_clean_token
103
115
  tokens << make_token(token) << make_token(:BANNER_END)
104
116
  self.token = ''
105
117
  end
106
118
 
119
+ def banner_end_char?
120
+ char == @banner_delimiter && (@text[@this_char - 1] == "\n" ||
121
+ @text[@this_char + 1] == "\n")
122
+ end
123
+
107
124
  def banner_end_clean_token
108
125
  token.slice!(0) if token[0] == 'C'
109
126
  token.slice!(0) if ["\n", ' '].include?(token[0])
@@ -157,10 +174,9 @@ module IOSParser
157
174
 
158
175
  def integer
159
176
  self.state = :integer
160
- case
161
- when dot? then decimal
162
- when digit? then token << char
163
- when word? then word
177
+ if dot? then decimal
178
+ elsif digit? then token << char
179
+ elsif word? then word
164
180
  else root
165
181
  end
166
182
  end
@@ -180,10 +196,9 @@ module IOSParser
180
196
 
181
197
  def decimal
182
198
  self.state = :decimal
183
- case
184
- when digit? then token << char
185
- when dot? then token << char
186
- when word? then word
199
+ if digit? then token << char
200
+ elsif dot? then token << char
201
+ elsif word? then word
187
202
  else root
188
203
  end
189
204
  end
@@ -247,6 +262,7 @@ module IOSParser
247
262
 
248
263
  def newline
249
264
  delimit
265
+ return banner_begin if banner_begin?
250
266
  self.state = :line_start
251
267
  self.indent = 0
252
268
  tokens << make_token(:EOL)
@@ -267,6 +283,13 @@ module IOSParser
267
283
 
268
284
  def delimit
269
285
  return if token.empty?
286
+
287
+ unless respond_to?(:"#{state}_token")
288
+ pos = @token_start || @this_char
289
+ raise LexError, "Unterminated #{state} starting at #{pos}: "\
290
+ "#{@text[pos..pos + 20].inspect}"
291
+ end
292
+
270
293
  tokens << send(:"#{state}_token")
271
294
  self.state = :root
272
295
  self.token = ''
@@ -1,7 +1,7 @@
1
1
  module IOSParser
2
2
  class << self
3
3
  def version
4
- '0.4.1'
4
+ '0.5.0'
5
5
  end
6
6
  end
7
7
  end
data/lib/ios_parser.rb CHANGED
@@ -31,7 +31,7 @@ module IOSParser
31
31
  end
32
32
 
33
33
  def json_to_ios(text)
34
- hash_to_ios JSON.load(text)
34
+ hash_to_ios JSON.parse(text)
35
35
  end
36
36
  end
37
37
  end
@@ -63,9 +63,9 @@ END
63
63
  end
64
64
 
65
65
  describe Array do
66
- let(:matcher) {
66
+ let(:matcher) do
67
67
  { contains: ['dscp'.freeze, 'cs1'.freeze].freeze }.freeze
68
- }
68
+ end
69
69
  it { should == expectation }
70
70
  end
71
71
  end # context 'matcher: contains' do
@@ -27,10 +27,8 @@ END
27
27
  'policed-dscp-transmit'],
28
28
  commands: [{ args: %w(set dscp cs1),
29
29
  commands: [], pos: 114 }],
30
- pos: 50
31
- }],
32
- pos: 24
33
- },
30
+ pos: 50 }],
31
+ pos: 24 },
34
32
 
35
33
  { args: %w(class other_service),
36
34
  commands: [{ args: ['police', 600_000_000, 1_000_000,
@@ -40,12 +38,9 @@ END
40
38
  commands: [], pos: 214 },
41
39
  { args: ['command_with_no_args'],
42
40
  commands: [], pos: 230 }],
43
- pos: 150
44
- }],
45
- pos: 128
46
- }],
47
- pos: 0
48
- }]
41
+ pos: 150 }],
42
+ pos: 128 }],
43
+ pos: 0 }]
49
44
  }
50
45
  end
51
46
 
@@ -98,8 +93,7 @@ END
98
93
  'policed-dscp-transmit'],
99
94
  commands: [{ args: %w(set dscp cs1),
100
95
  commands: [], pos: 114 }],
101
- pos: 50
102
- }]
96
+ pos: 50 }]
103
97
  end
104
98
 
105
99
  context 'integer query' do
@@ -37,8 +37,7 @@ END
37
37
  'police', 600_000_000, 1_000_000, 'exceed-action',
38
38
  'policed-dscp-transmit', :EOL,
39
39
  :INDENT,
40
- 'set', 'dscp', 'cs2', :EOL, :DEDENT, :DEDENT, :DEDENT
41
- ]
40
+ 'set', 'dscp', 'cs2', :EOL, :DEDENT, :DEDENT, :DEDENT]
42
41
  end
43
42
 
44
43
  subject { klass.new.call(input).map(&:last) }
@@ -71,8 +70,7 @@ END
71
70
  :DEDENT, :DEDENT, :DEDENT,
72
71
  'router', 'ospf', 12_345, :EOL,
73
72
  :INDENT, 'nsr', :EOL,
74
- :DEDENT
75
- ]
73
+ :DEDENT]
76
74
  end
77
75
 
78
76
  it 'pure' do
@@ -125,6 +123,18 @@ END
125
123
  it { expect(subject_pure.map(&:last)).to eq output }
126
124
  end
127
125
 
126
+ context 'complex eos banner' do
127
+ let(:input) { "banner motd\n'''\nEOF\n" }
128
+
129
+ let(:output) do
130
+ content = input.lines[1..-2].join
131
+ ['banner', 'motd', :BANNER_BEGIN, content, :BANNER_END, :EOL]
132
+ end
133
+
134
+ it { expect(subject.map(&:last)).to eq output }
135
+ it { expect(subject_pure.map(&:last)).to eq output }
136
+ end
137
+
128
138
  context 'decimal number' do
129
139
  let(:input) { 'boson levels at 93.2' }
130
140
  let(:output) { ['boson', 'levels', 'at', 93.2] }
@@ -164,8 +174,7 @@ END
164
174
  'DDDDDDDD DDDDDDDD DDDDDDDD AAAA'],
165
175
  [323, :CERTIFICATE_END],
166
176
  [323, :EOL],
167
- [323, :DEDENT]
168
- ]
177
+ [323, :DEDENT]]
169
178
  end
170
179
 
171
180
  subject { klass.new.call(input) }
@@ -26,10 +26,8 @@ END
26
26
  'policed-dscp-transmit'],
27
27
  commands: [{ args: %w(set dscp cs1),
28
28
  commands: [], pos: 114 }],
29
- pos: 50
30
- }],
31
- pos: 24
32
- },
29
+ pos: 50 }],
30
+ pos: 24 },
33
31
 
34
32
  { args: %w(class other_service),
35
33
  commands: [{ args: ['police', 600_000_000, 1_000_000,
@@ -39,12 +37,9 @@ END
39
37
  commands: [], pos: 214 },
40
38
  { args: ['command_with_no_args'],
41
39
  commands: [], pos: 230 }],
42
- pos: 150
43
- }],
44
- pos: 128
45
- }],
46
- pos: 0
47
- }]
40
+ pos: 150 }],
41
+ pos: 128 }],
42
+ pos: 0 }]
48
43
  }
49
44
  end
50
45
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: ios_parser
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.4.1
4
+ version: 0.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ben Miller
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-12-02 00:00:00.000000000 Z
11
+ date: 2017-04-26 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec
@@ -110,7 +110,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
110
110
  version: '0'
111
111
  requirements: []
112
112
  rubyforge_project:
113
- rubygems_version: 2.5.1
113
+ rubygems_version: 2.5.2
114
114
  signing_key:
115
115
  specification_version: 4
116
116
  summary: convert network switch and router config files to structured data
@@ -120,4 +120,3 @@ test_files:
120
120
  - spec/lib/ios_parser/lexer_spec.rb
121
121
  - spec/lib/ios_parser_spec.rb
122
122
  - spec/spec_helper.rb
123
- has_rdoc: