regexp_parser 1.5.0 → 1.5.1

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.
Files changed (71) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +14 -0
  3. data/lib/regexp_parser/expression.rb +6 -43
  4. data/lib/regexp_parser/expression/classes/conditional.rb +3 -2
  5. data/lib/regexp_parser/expression/classes/escape.rb +0 -4
  6. data/lib/regexp_parser/expression/methods/match.rb +13 -0
  7. data/lib/regexp_parser/expression/methods/options.rb +35 -0
  8. data/lib/regexp_parser/expression/methods/strfregexp.rb +0 -1
  9. data/lib/regexp_parser/expression/methods/tests.rb +6 -15
  10. data/lib/regexp_parser/expression/sequence.rb +3 -2
  11. data/lib/regexp_parser/expression/sequence_operation.rb +2 -6
  12. data/lib/regexp_parser/lexer.rb +0 -21
  13. data/lib/regexp_parser/parser.rb +22 -21
  14. data/lib/regexp_parser/scanner.rb +1159 -1329
  15. data/lib/regexp_parser/scanner/char_type.rl +0 -3
  16. data/lib/regexp_parser/scanner/scanner.rl +82 -190
  17. data/lib/regexp_parser/version.rb +1 -1
  18. data/spec/expression/base_spec.rb +14 -0
  19. data/spec/expression/methods/match_length_spec.rb +13 -0
  20. data/spec/expression/methods/match_spec.rb +25 -0
  21. data/spec/expression/methods/tests_spec.rb +2 -0
  22. data/spec/expression/options_spec.rb +128 -0
  23. data/spec/expression/root_spec.rb +9 -0
  24. data/spec/expression/sequence_spec.rb +9 -0
  25. data/spec/lexer/conditionals_spec.rb +49 -119
  26. data/spec/lexer/escapes_spec.rb +8 -32
  27. data/spec/lexer/keep_spec.rb +5 -17
  28. data/spec/lexer/literals_spec.rb +73 -110
  29. data/spec/lexer/nesting_spec.rb +86 -117
  30. data/spec/lexer/refcalls_spec.rb +51 -50
  31. data/spec/parser/all_spec.rb +13 -1
  32. data/spec/parser/anchors_spec.rb +9 -23
  33. data/spec/parser/conditionals_spec.rb +9 -9
  34. data/spec/parser/errors_spec.rb +22 -43
  35. data/spec/parser/escapes_spec.rb +33 -44
  36. data/spec/parser/groups_spec.rb +98 -257
  37. data/spec/parser/keep_spec.rb +2 -15
  38. data/spec/parser/posix_classes_spec.rb +5 -24
  39. data/spec/parser/properties_spec.rb +42 -54
  40. data/spec/parser/quantifiers_spec.rb +41 -283
  41. data/spec/parser/refcalls_spec.rb +60 -185
  42. data/spec/parser/set/intersections_spec.rb +17 -17
  43. data/spec/parser/set/ranges_spec.rb +17 -17
  44. data/spec/parser/sets_spec.rb +5 -5
  45. data/spec/parser/types_spec.rb +11 -36
  46. data/spec/scanner/anchors_spec.rb +13 -28
  47. data/spec/scanner/conditionals_spec.rb +121 -173
  48. data/spec/scanner/errors_spec.rb +65 -87
  49. data/spec/scanner/escapes_spec.rb +49 -50
  50. data/spec/scanner/free_space_spec.rb +102 -165
  51. data/spec/scanner/groups_spec.rb +45 -64
  52. data/spec/scanner/keep_spec.rb +5 -28
  53. data/spec/scanner/literals_spec.rb +45 -81
  54. data/spec/scanner/meta_spec.rb +13 -33
  55. data/spec/scanner/properties_spec.rb +43 -286
  56. data/spec/scanner/quantifiers_spec.rb +13 -28
  57. data/spec/scanner/refcalls_spec.rb +32 -48
  58. data/spec/scanner/sets_spec.rb +88 -102
  59. data/spec/scanner/types_spec.rb +10 -25
  60. data/spec/spec_helper.rb +1 -0
  61. data/spec/support/shared_examples.rb +77 -0
  62. data/spec/syntax/syntax_spec.rb +4 -0
  63. data/spec/syntax/versions/1.8.6_spec.rb +12 -33
  64. data/spec/syntax/versions/1.9.1_spec.rb +5 -18
  65. data/spec/syntax/versions/1.9.3_spec.rb +4 -17
  66. data/spec/syntax/versions/2.0.0_spec.rb +8 -23
  67. data/spec/syntax/versions/2.2.0_spec.rb +4 -17
  68. data/spec/syntax/versions/aliases_spec.rb +25 -109
  69. metadata +14 -6
  70. data/spec/scanner/scripts_spec.rb +0 -49
  71. data/spec/scanner/unicode_blocks_spec.rb +0 -28
@@ -2,7 +2,11 @@ require 'spec_helper'
2
2
 
3
3
  RSpec.describe(Regexp::Parser) do
4
4
  specify('parse returns a root expression') do
5
- expect(RP.parse('abc')).to be_instance_of(Regexp::Expression::Root)
5
+ expect(RP.parse('abc')).to be_instance_of(Root)
6
+ end
7
+
8
+ specify('parse can be called with block') do
9
+ expect(RP.parse('abc') { |root| root.class }).to eq Root
6
10
  end
7
11
 
8
12
  specify('parse root contains expressions') do
@@ -10,6 +14,14 @@ RSpec.describe(Regexp::Parser) do
10
14
  expect(root.expressions).to all(be_a Regexp::Expression::Base)
11
15
  end
12
16
 
17
+ specify('parse root options mi') do
18
+ root = RP.parse(/[abc]/mi, 'ruby/1.8')
19
+
20
+ expect(root.m?).to be true
21
+ expect(root.i?).to be true
22
+ expect(root.x?).to be false
23
+ end
24
+
13
25
  specify('parse node types') do
14
26
  root = RP.parse('^(one){2,3}([^d\\]efm-qz\\,\\-]*)(ghi)+$')
15
27
 
@@ -1,31 +1,17 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe('Anchor parsing') do
4
- tests = {
5
- '^a' => [0, :anchor, :bol, Anchor::BOL],
6
- 'a$' => [1, :anchor, :eol, Anchor::EOL],
4
+ include_examples 'parse', /^a/, 0 => [:anchor, :bol, Anchor::BOL]
5
+ include_examples 'parse', /a$/, 1 => [:anchor, :eol, Anchor::EOL]
7
6
 
8
- '\Aa' => [0, :anchor, :bos, Anchor::BOS],
9
- 'a\z' => [1, :anchor, :eos, Anchor::EOS],
10
- 'a\Z' => [1, :anchor, :eos_ob_eol, Anchor::EOSobEOL],
7
+ include_examples 'parse', /\Aa/, 0 => [:anchor, :bos, Anchor::BOS]
8
+ include_examples 'parse', /a\z/, 1 => [:anchor, :eos, Anchor::EOS]
9
+ include_examples 'parse', /a\Z/, 1 => [:anchor, :eos_ob_eol, Anchor::EOSobEOL]
11
10
 
12
- 'a\b' => [1, :anchor, :word_boundary, Anchor::WordBoundary],
13
- 'a\B' => [1, :anchor, :nonword_boundary, Anchor::NonWordBoundary],
11
+ include_examples 'parse', /a\b/, 1 => [:anchor, :word_boundary, Anchor::WordBoundary]
12
+ include_examples 'parse', /a\B/, 1 => [:anchor, :nonword_boundary, Anchor::NonWordBoundary]
14
13
 
15
- 'a\G' => [1, :anchor, :match_start, Anchor::MatchStart],
14
+ include_examples 'parse', /a\G/, 1 => [:anchor, :match_start, Anchor::MatchStart]
16
15
 
17
- "\\\\Aa" => [0, :escape, :backslash, EscapeSequence::Literal],
18
- }
19
-
20
- tests.each_with_index do |(pattern, (index, type, token, klass)), count|
21
- specify("parse_anchor_#{token}_#{count}") do
22
- root = RP.parse(pattern, 'ruby/1.9')
23
- exp = root.expressions.at(index)
24
-
25
- expect(exp).to be_a(klass)
26
-
27
- expect(exp.type).to eq type
28
- expect(exp.token).to eq token
29
- end
30
- end
16
+ include_examples 'parse', /\\A/, 0 => [:escape, :backslash, EscapeSequence::Literal]
31
17
  end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  RSpec.describe('Conditional parsing') do
4
4
  specify('parse conditional') do
5
- regexp = Regexp.new('(?<A>a)(?(<A>)T|F)/')
5
+ regexp = /(?<A>a)(?(<A>)T|F)/
6
6
 
7
7
  root = RP.parse(regexp, 'ruby/2.0')
8
8
  exp = root[1]
@@ -16,7 +16,7 @@ RSpec.describe('Conditional parsing') do
16
16
  end
17
17
 
18
18
  specify('parse conditional condition') do
19
- regexp = Regexp.new('(?<A>a)(?(<A>)T|F)/')
19
+ regexp = /(?<A>a)(?(<A>)T|F)/
20
20
 
21
21
  root = RP.parse(regexp, 'ruby/2.0')
22
22
  exp = root[1].condition
@@ -31,7 +31,7 @@ RSpec.describe('Conditional parsing') do
31
31
  end
32
32
 
33
33
  specify('parse conditional condition with number ref') do
34
- regexp = Regexp.new('(a)(?(1)T|F)/')
34
+ regexp = /(a)(?(1)T|F)/
35
35
 
36
36
  root = RP.parse(regexp, 'ruby/2.0')
37
37
  exp = root[1].condition
@@ -46,7 +46,7 @@ RSpec.describe('Conditional parsing') do
46
46
  end
47
47
 
48
48
  specify('parse conditional nested groups') do
49
- regexp = Regexp.new('((a)|(b)|((?(2)(c(d|e)+)?|(?(3)f|(?(4)(g|(h)(i)))))))/')
49
+ regexp = /((a)|(b)|((?(2)(c(d|e)+)?|(?(3)f|(?(4)(g|(h)(i)))))))/
50
50
 
51
51
  root = RP.parse(regexp, 'ruby/2.0')
52
52
 
@@ -80,7 +80,7 @@ RSpec.describe('Conditional parsing') do
80
80
  end
81
81
 
82
82
  specify('parse conditional nested') do
83
- regexp = Regexp.new('(a(b(c(d)(e))))(?(1)(?(2)d|(?(3)e|f))|(?(4)(?(5)g|h)))/')
83
+ regexp = /(a(b(c(d)(e))))(?(1)(?(2)d|(?(3)e|f))|(?(4)(?(5)g|h)))/
84
84
 
85
85
  root = RP.parse(regexp, 'ruby/2.0')
86
86
 
@@ -102,7 +102,7 @@ RSpec.describe('Conditional parsing') do
102
102
  end
103
103
 
104
104
  specify('parse conditional nested alternation') do
105
- regexp = Regexp.new('(a)(?(1)(b|c|d)|(e|f|g))(h)(?(2)(i|j|k)|(l|m|n))|o|p/')
105
+ regexp = /(a)(?(1)(b|c|d)|(e|f|g))(h)(?(2)(i|j|k)|(l|m|n))|o|p/
106
106
 
107
107
  root = RP.parse(regexp, 'ruby/2.0')
108
108
 
@@ -125,7 +125,7 @@ RSpec.describe('Conditional parsing') do
125
125
  end
126
126
 
127
127
  specify('parse conditional extra separator') do
128
- regexp = Regexp.new('(?<A>a)(?(<A>)T|)/')
128
+ regexp = /(?<A>a)(?(<A>)T|)/
129
129
 
130
130
  root = RP.parse(regexp, 'ruby/2.0')
131
131
  branches = root[1].branches
@@ -146,7 +146,7 @@ RSpec.describe('Conditional parsing') do
146
146
  end
147
147
 
148
148
  specify('parse conditional quantified') do
149
- regexp = Regexp.new('(foo)(?(1)\d|(\w)){42}/')
149
+ regexp = /(foo)(?(1)\d|(\w)){42}/
150
150
 
151
151
  root = RP.parse(regexp, 'ruby/2.0')
152
152
  conditional = root[1]
@@ -158,7 +158,7 @@ RSpec.describe('Conditional parsing') do
158
158
  end
159
159
 
160
160
  specify('parse conditional branch content quantified') do
161
- regexp = Regexp.new('(foo)(?(1)\d{23}|(\w){42})/')
161
+ regexp = /(foo)(?(1)\d{23}|(\w){42})/
162
162
 
163
163
  root = RP.parse(regexp, 'ruby/2.0')
164
164
  conditional = root[1]
@@ -1,51 +1,30 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe('Parsing errors') do
4
- let(:rp) { Regexp::Parser.new }
5
- before { rp.parse(/foo/) }
4
+ let(:parser) { Regexp::Parser.new }
5
+ before { parser.parse(/foo/) } # initializes ivars
6
6
 
7
- specify('parser unknown token type') do
8
- expect { rp.send(:parse_token, Regexp::Token.new(:foo, :bar)) }
7
+ it('raises UnknownTokenTypeError for unknown token types') do
8
+ expect { parser.send(:parse_token, Regexp::Token.new(:foo, :bar)) }
9
9
  .to raise_error(Regexp::Parser::UnknownTokenTypeError)
10
10
  end
11
11
 
12
- specify('parser unknown set token') do
13
- expect { rp.send(:parse_token, Regexp::Token.new(:set, :foo)) }
14
- .to raise_error(Regexp::Parser::UnknownTokenError)
15
- end
16
-
17
- specify('parser unknown meta token') do
18
- expect { rp.send(:parse_token, Regexp::Token.new(:meta, :foo)) }
19
- .to raise_error(Regexp::Parser::UnknownTokenError)
20
- end
21
-
22
- specify('parser unknown character type token') do
23
- expect { rp.send(:parse_token, Regexp::Token.new(:type, :foo)) }
24
- .to raise_error(Regexp::Parser::UnknownTokenError)
25
- end
26
-
27
- specify('parser unknown unicode property token') do
28
- expect { rp.send(:parse_token, Regexp::Token.new(:property, :foo)) }
29
- .to raise_error(Regexp::Parser::UnknownTokenError)
30
- end
31
-
32
- specify('parser unknown unicode nonproperty token') do
33
- expect { rp.send(:parse_token, Regexp::Token.new(:nonproperty, :foo)) }
34
- .to raise_error(Regexp::Parser::UnknownTokenError)
35
- end
36
-
37
- specify('parser unknown anchor token') do
38
- expect { rp.send(:parse_token, Regexp::Token.new(:anchor, :foo)) }
39
- .to raise_error(Regexp::Parser::UnknownTokenError)
40
- end
41
-
42
- specify('parser unknown quantifier token') do
43
- expect { rp.send(:parse_token, Regexp::Token.new(:quantifier, :foo)) }
44
- .to raise_error(Regexp::Parser::UnknownTokenError)
45
- end
46
-
47
- specify('parser unknown group open token') do
48
- expect { rp.send(:parse_token, Regexp::Token.new(:group, :foo)) }
49
- .to raise_error(Regexp::Parser::UnknownTokenError)
50
- end
12
+ RSpec.shared_examples 'UnknownTokenError' do |type, token|
13
+ it "raises for unkown tokens of type #{type}" do
14
+ expect { parser.send(:parse_token, Regexp::Token.new(type, :foo)) }
15
+ .to raise_error(Regexp::Parser::UnknownTokenError)
16
+ end
17
+ end
18
+
19
+ include_examples 'UnknownTokenError', :anchor
20
+ include_examples 'UnknownTokenError', :backref
21
+ include_examples 'UnknownTokenError', :conditional
22
+ include_examples 'UnknownTokenError', :free_space
23
+ include_examples 'UnknownTokenError', :group
24
+ include_examples 'UnknownTokenError', :meta
25
+ include_examples 'UnknownTokenError', :nonproperty
26
+ include_examples 'UnknownTokenError', :property
27
+ include_examples 'UnknownTokenError', :quantifier
28
+ include_examples 'UnknownTokenError', :set
29
+ include_examples 'UnknownTokenError', :type
51
30
  end
@@ -1,49 +1,35 @@
1
1
  require 'spec_helper'
2
2
 
3
- RSpec.describe('Escape parsing') do
4
- tests = {
5
- /a\ac/ => [1, :escape, :bell, EscapeSequence::Bell],
6
- /a\ec/ => [1, :escape, :escape, EscapeSequence::AsciiEscape],
7
- /a\fc/ => [1, :escape, :form_feed, EscapeSequence::FormFeed],
8
- /a\nc/ => [1, :escape, :newline, EscapeSequence::Newline],
9
- /a\rc/ => [1, :escape, :carriage, EscapeSequence::Return],
10
- /a\tc/ => [1, :escape, :tab, EscapeSequence::Tab],
11
- /a\vc/ => [1, :escape, :vertical_tab, EscapeSequence::VerticalTab],
12
-
13
- # meta character escapes
14
- /a\.c/ => [1, :escape, :dot, EscapeSequence::Literal],
15
- /a\?c/ => [1, :escape, :zero_or_one, EscapeSequence::Literal],
16
- /a\*c/ => [1, :escape, :zero_or_more, EscapeSequence::Literal],
17
- /a\+c/ => [1, :escape, :one_or_more, EscapeSequence::Literal],
18
- /a\|c/ => [1, :escape, :alternation, EscapeSequence::Literal],
19
- /a\(c/ => [1, :escape, :group_open, EscapeSequence::Literal],
20
- /a\)c/ => [1, :escape, :group_close, EscapeSequence::Literal],
21
- /a\{c/ => [1, :escape, :interval_open, EscapeSequence::Literal],
22
- /a\}c/ => [1, :escape, :interval_close, EscapeSequence::Literal],
23
-
24
- # unicode escapes
25
- /a\u0640/ => [1, :escape, :codepoint, EscapeSequence::Codepoint],
26
- /a\u{41 1F60D}/ => [1, :escape, :codepoint_list, EscapeSequence::CodepointList],
27
- /a\u{10FFFF}/ => [1, :escape, :codepoint_list, EscapeSequence::CodepointList],
28
-
29
- # hex escapes
30
- /a\xFF/n => [1, :escape, :hex, EscapeSequence::Hex],
31
-
32
- # octal escapes
33
- /a\177/n => [1, :escape, :octal, EscapeSequence::Octal],
34
- }
35
-
36
- tests.each_with_index do |(pattern, (index, type, token, klass)), count|
37
- specify("parse_escape_#{token}_#{count = (count + 1)}") do
38
- root = RP.parse(pattern, 'ruby/1.9')
39
- exp = root.expressions.at(index)
40
-
41
- expect(exp).to be_a(klass)
42
-
43
- expect(exp.type).to eq type
44
- expect(exp.token).to eq token
45
- end
46
- end
3
+ RSpec.describe('EscapeSequence parsing') do
4
+ include_examples 'parse', /a\ac/, 1 => [:escape, :bell, EscapeSequence::Bell]
5
+ include_examples 'parse', /a\ec/, 1 => [:escape, :escape, EscapeSequence::AsciiEscape]
6
+ include_examples 'parse', /a\fc/, 1 => [:escape, :form_feed, EscapeSequence::FormFeed]
7
+ include_examples 'parse', /a\nc/, 1 => [:escape, :newline, EscapeSequence::Newline]
8
+ include_examples 'parse', /a\rc/, 1 => [:escape, :carriage, EscapeSequence::Return]
9
+ include_examples 'parse', /a\tc/, 1 => [:escape, :tab, EscapeSequence::Tab]
10
+ include_examples 'parse', /a\vc/, 1 => [:escape, :vertical_tab, EscapeSequence::VerticalTab]
11
+
12
+ # meta character escapes
13
+ include_examples 'parse', /a\.c/, 1 => [:escape, :dot, EscapeSequence::Literal]
14
+ include_examples 'parse', /a\?c/, 1 => [:escape, :zero_or_one, EscapeSequence::Literal]
15
+ include_examples 'parse', /a\*c/, 1 => [:escape, :zero_or_more, EscapeSequence::Literal]
16
+ include_examples 'parse', /a\+c/, 1 => [:escape, :one_or_more, EscapeSequence::Literal]
17
+ include_examples 'parse', /a\|c/, 1 => [:escape, :alternation, EscapeSequence::Literal]
18
+ include_examples 'parse', /a\(c/, 1 => [:escape, :group_open, EscapeSequence::Literal]
19
+ include_examples 'parse', /a\)c/, 1 => [:escape, :group_close, EscapeSequence::Literal]
20
+ include_examples 'parse', /a\{c/, 1 => [:escape, :interval_open, EscapeSequence::Literal]
21
+ include_examples 'parse', /a\}c/, 1 => [:escape, :interval_close, EscapeSequence::Literal]
22
+
23
+ # unicode escapes
24
+ include_examples 'parse', /a\u0640/, 1 => [:escape, :codepoint, EscapeSequence::Codepoint]
25
+ include_examples 'parse', /a\u{41 1F60D}/, 1 => [:escape, :codepoint_list, EscapeSequence::CodepointList]
26
+ include_examples 'parse', /a\u{10FFFF}/, 1 => [:escape, :codepoint_list, EscapeSequence::CodepointList]
27
+
28
+ # hex escapes
29
+ include_examples 'parse', /a\xFF/n, 1 => [:escape, :hex, EscapeSequence::Hex]
30
+
31
+ # octal escapes
32
+ include_examples 'parse', /a\177/n, 1 => [:escape, :octal, EscapeSequence::Octal]
47
33
 
48
34
  specify('parse chars and codepoints') do
49
35
  root = RP.parse(/\n\?\101\x42\u0043\u{44 45}/)
@@ -65,6 +51,9 @@ RSpec.describe('Escape parsing') do
65
51
 
66
52
  expect(root[5].chars).to eq %w[D E]
67
53
  expect(root[5].codepoints).to eq [68, 69]
54
+
55
+ expect { root[5].char }.to raise_error(/#chars/)
56
+ expect { root[5].codepoint }.to raise_error(/#codepoints/)
68
57
  end
69
58
 
70
59
  specify('parse escape control sequence lower') do
@@ -1,267 +1,108 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe('Group parsing') do
4
- specify('parse root options mi') do
5
- t = RP.parse(/[abc]/mi, 'ruby/1.8')
6
-
7
- expect(t.m?).to be true
8
- expect(t.i?).to be true
9
- expect(t.x?).to be false
10
- end
11
-
12
- specify('parse option group') do
13
- t = RP.parse(/(?m:a)/, 'ruby/1.8')
14
-
15
- expect(t[0]).to be_instance_of(Group::Options)
16
- expect(t[0].token).to eq :options
17
-
18
- expect(t[0].m?).to be true
19
- expect(t[0].i?).to be false
20
- expect(t[0].x?).to be false
21
-
22
- expect(t[0].option_changes[:m]).to be true
23
- expect(t[0].option_changes[:i]).to be_nil
24
- end
25
-
26
- specify('parse self defeating option group') do
27
- t = RP.parse(/(?m-m:a)/, 'ruby/1.8')
28
-
29
- expect(t[0].m?).to be false
30
- expect(t[0].i?).to be false
31
- expect(t[0].x?).to be false
32
-
33
- expect(t[0].option_changes[:m]).to be false
34
- expect(t[0].option_changes[:i]).to be_nil
35
- end
36
-
37
- specify('parse nested options activate one') do
38
- t = RP.parse(/(?x-mi:a(?m:b))/, 'ruby/1.8')
39
-
40
- expect(t[0].m?).to be false
41
- expect(t[0].i?).to be false
42
- expect(t[0].x?).to be true
43
-
44
- expect(t[0][1].m?).to be true
45
- expect(t[0][1].i?).to be false
46
- expect(t[0][1].x?).to be true
47
-
48
- expect(t[0][1].option_changes[:m]).to be true
49
- expect(t[0][1].option_changes[:i]).to be_nil
50
- expect(t[0][1].option_changes[:x]).to be_nil
51
- end
52
-
53
- specify('parse nested options deactivate one') do
54
- t = RP.parse(/(?ix-m:a(?-i:b))/, 'ruby/1.8')
55
-
56
- expect(t[0].m?).to be false
57
- expect(t[0].i?).to be true
58
- expect(t[0].x?).to be true
59
-
60
- expect(t[0][1].m?).to be false
61
- expect(t[0][1].i?).to be false
62
- expect(t[0][1].x?).to be true
63
-
64
- expect(t[0][1].option_changes[:i]).to be false
65
- expect(t[0][1].option_changes[:m]).to be_nil
66
- expect(t[0][1].option_changes[:x]).to be_nil
67
- end
68
-
69
- specify('parse nested options invert all') do
70
- t = RP.parse('(?xi-m:a(?m-ix:b))', 'ruby/1.8')
71
-
72
- expect(t[0].m?).to be false
73
- expect(t[0].i?).to be true
74
- expect(t[0].x?).to be true
75
-
76
- expect(t[0][1].m?).to be true
77
- expect(t[0][1].i?).to be false
78
- expect(t[0][1].x?).to be false
79
-
80
- expect(t[0][1].option_changes[:m]).to be true
81
- expect(t[0][1].option_changes[:i]).to be false
82
- expect(t[0][1].option_changes[:x]).to be false
83
- end
84
-
85
- specify('parse nested options affect literal subexpressions') do
86
- t = RP.parse(/(?x-mi:a(?m:b))/, 'ruby/1.8')
87
-
88
- expect(t[0][0].m?).to be false
89
- expect(t[0][0].i?).to be false
90
- expect(t[0][0].x?).to be true
91
-
92
- expect(t[0][1][0].m?).to be true
93
- expect(t[0][1][0].i?).to be false
94
- expect(t[0][1][0].x?).to be true
95
- end
96
-
97
- specify('parse option switch group') do
98
- t = RP.parse(/a(?i-m)b/m, 'ruby/1.8')
99
-
100
- expect(t[1]).to be_instance_of(Group::Options)
101
- expect(t[1].token).to eq :options_switch
102
-
103
- expect(t[1].m?).to be false
104
- expect(t[1].i?).to be true
105
- expect(t[1].x?).to be false
106
-
107
- expect(t[1].option_changes[:i]).to be true
108
- expect(t[1].option_changes[:m]).to be false
109
- expect(t[1].option_changes[:x]).to be_nil
110
- end
111
-
112
- specify('parse option switch affects following expressions') do
113
- t = RP.parse(/a(?i-m)b/m, 'ruby/1.8')
114
-
115
- expect(t[0].m?).to be true
116
- expect(t[0].i?).to be false
117
- expect(t[0].x?).to be false
118
-
119
- expect(t[2].m?).to be false
120
- expect(t[2].i?).to be true
121
- expect(t[2].x?).to be false
122
- end
123
-
124
- specify('parse option switch in group') do
125
- t = RP.parse(/(a(?i-m)b)c/m, 'ruby/1.8')
126
-
127
- group1 = t[0]
128
-
129
- expect(group1.m?).to be true
130
- expect(group1.i?).to be false
131
- expect(group1.x?).to be false
132
-
133
- expect(group1[0].m?).to be true
134
- expect(group1[0].i?).to be false
135
- expect(group1[0].x?).to be false
136
-
137
- expect(group1[1].m?).to be false
138
- expect(group1[1].i?).to be true
139
- expect(group1[1].x?).to be false
140
-
141
- expect(group1[2].m?).to be false
142
- expect(group1[2].i?).to be true
143
- expect(group1[2].x?).to be false
144
-
145
- expect(t[1].m?).to be true
146
- expect(t[1].i?).to be false
147
- expect(t[1].x?).to be false
148
- end
149
-
150
- specify('parse nested option switch in group') do
151
- t = RP.parse(/((?i-m)(a(?-i)b))/m, 'ruby/1.8')
152
-
153
- group2 = t[0][1]
154
-
155
- expect(group2.m?).to be false
156
- expect(group2.i?).to be true
157
- expect(group2.x?).to be false
158
-
159
- expect(group2[0].m?).to be false
160
- expect(group2[0].i?).to be true
161
- expect(group2[0].x?).to be false
162
-
163
- expect(group2[1].m?).to be false
164
- expect(group2[1].i?).to be false
165
- expect(group2[1].x?).to be false
166
-
167
- expect(group2[2].m?).to be false
168
- expect(group2[2].i?).to be false
169
- expect(group2[2].x?).to be false
170
- end
171
-
172
- specify('parse options dau') do
173
- t = RP.parse('(?dua:abc)')
174
-
175
- expect(t[0].d?).to be false
176
- expect(t[0].a?).to be true
177
- expect(t[0].u?).to be false
178
- end
179
-
180
- specify('parse nested options dau') do
181
- t = RP.parse('(?u:a(?d:b))')
182
-
183
- expect(t[0].u?).to be true
184
- expect(t[0].d?).to be false
185
- expect(t[0].a?).to be false
186
-
187
- expect(t[0][1].d?).to be true
188
- expect(t[0][1].a?).to be false
189
- expect(t[0][1].u?).to be false
190
- end
191
-
192
- specify('parse nested options da') do
193
- t = RP.parse('(?di-xm:a(?da-x:b))')
194
-
195
- expect(t[0].d?).to be true
196
- expect(t[0].i?).to be true
197
- expect(t[0].m?).to be false
198
- expect(t[0].x?).to be false
199
- expect(t[0].a?).to be false
200
- expect(t[0].u?).to be false
201
-
202
- expect(t[0][1].d?).to be false
203
- expect(t[0][1].a?).to be true
204
- expect(t[0][1].u?).to be false
205
- expect(t[0][1].x?).to be false
206
- expect(t[0][1].m?).to be false
207
- expect(t[0][1].i?).to be true
208
- end
209
-
210
- specify('parse lookahead') do
211
- t = RP.parse('(?=abc)(?!def)', 'ruby/1.8')
212
-
213
- expect(t[0]).to be_a(Assertion::Lookahead)
214
-
215
- expect(t[1]).to be_a(Assertion::NegativeLookahead)
216
- end
217
-
218
- specify('parse lookbehind') do
219
- t = RP.parse('(?<=abc)(?<!def)', 'ruby/1.9')
220
-
221
- expect(t[0]).to be_a(Assertion::Lookbehind)
222
-
223
- expect(t[1]).to be_a(Assertion::NegativeLookbehind)
224
- end
225
-
226
- specify('parse comment') do
227
- t = RP.parse('a(?# is for apple)b(?# for boy)c(?# cat)')
228
-
229
- [1, 3, 5].each do |i|
230
- expect(t[i]).to be_a(Group::Comment)
231
-
232
- expect(t[i].type).to eq :group
233
- expect(t[i].token).to eq :comment
234
- end
235
- end
236
-
237
- specify('parse absence group', if: ruby_version_at_least('2.4.1')) do
238
- t = RP.parse('a(?~b)c(?~d)e')
239
-
240
- [1, 3].each do |i|
241
- expect(t[i]).to be_a(Group::Absence)
242
-
243
- expect(t[i].type).to eq :group
244
- expect(t[i].token).to eq :absence
245
- end
246
- end
4
+ include_examples 'parse', /(?=abc)(?!def)/,
5
+ 0 => [:assertion, :lookahead, Assertion::Lookahead],
6
+ 1 => [:assertion, :nlookahead, Assertion::NegativeLookahead]
7
+
8
+ include_examples 'parse', /(?<=abc)(?<!def)/,
9
+ 0 => [:assertion, :lookbehind, Assertion::Lookbehind],
10
+ 1 => [:assertion, :nlookbehind, Assertion::NegativeLookbehind]
11
+
12
+ include_examples 'parse', /a(?# is for apple)b(?# for boy)c(?# cat)/,
13
+ 1 => [:group, :comment, Group::Comment],
14
+ 3 => [:group, :comment, Group::Comment],
15
+ 5 => [:group, :comment, Group::Comment]
16
+
17
+ if ruby_version_at_least('2.4.1')
18
+ include_examples 'parse', 'a(?~b)c(?~d)e',
19
+ 1 => [:group, :absence, Group::Absence],
20
+ 3 => [:group, :absence, Group::Absence]
21
+ end
22
+
23
+ include_examples 'parse', /(?m:a)/,
24
+ 0 => [:group, :options, Group::Options, options: { m: true }, option_changes: { m: true }]
25
+
26
+ # self-defeating group option
27
+ include_examples 'parse', /(?m-m:a)/,
28
+ 0 => [:group, :options, Group::Options, options: {}, option_changes: { m: false }]
29
+
30
+ # activate one option in nested group
31
+ include_examples 'parse', /(?x-mi:a(?m:b))/,
32
+ 0 => [:group, :options, Group::Options, options: { x: true }, option_changes: { i: false, m: false, x: true }],
33
+ [0, 1] => [:group, :options, Group::Options, options: { m: true, x: true }, option_changes: { m: true }]
34
+
35
+ # deactivate one option in nested group
36
+ include_examples 'parse', /(?ix-m:a(?-i:b))/,
37
+ 0 => [:group, :options, Group::Options, options: { i: true, x: true }, option_changes: { i: true, m: false, x: true }],
38
+ [0, 1] => [:group, :options, Group::Options, options: { x: true }, option_changes: { i: false }]
39
+
40
+ # invert all options in nested group
41
+ include_examples 'parse', /(?xi-m:a(?m-ix:b))/,
42
+ 0 => [:group, :options, Group::Options, options: { i: true, x: true }, option_changes: { i: true, m: false, x: true }],
43
+ [0, 1] => [:group, :options, Group::Options, options: { m: true }, option_changes: { i: false, m: true, x: false }]
44
+
45
+ # nested options affect literal subexpressions
46
+ include_examples 'parse', /(?x-mi:a(?m:b))/,
47
+ [0, 0] => [:literal, :literal, Literal, text: 'a', options: { x: true }],
48
+ [0, 1, 0] => [:literal, :literal, Literal, text: 'b', options: { m: true, x: true }]
49
+
50
+ # option switching group
51
+ include_examples 'parse', /a(?i-m)b/m,
52
+ 0 => [:literal, :literal, Literal, text: 'a', options: { m: true }],
53
+ 1 => [:group, :options_switch, Group::Options, options: { i: true }, option_changes: { i: true, m: false }],
54
+ 2 => [:literal, :literal, Literal, text: 'b', options: { i: true }]
55
+
56
+ # option switch in group
57
+ include_examples 'parse', /(a(?i-m)b)c/m,
58
+ 0 => [:group, :capture, Group::Capture, options: { m: true }],
59
+ [0, 0] => [:literal, :literal, Literal, text: 'a', options: { m: true }],
60
+ [0, 1] => [:group, :options_switch, Group::Options, options: { i: true }, option_changes: { i: true, m: false }],
61
+ [0, 2] => [:literal, :literal, Literal, text: 'b', options: { i: true }],
62
+ 1 => [:literal, :literal, Literal, text: 'c', options: { m: true }]
63
+
64
+ # nested option switch in group
65
+ include_examples 'parse', /((?i-m)(a(?-i)b))/m,
66
+ [0, 1] => [:group, :capture, Group::Capture, options: { i: true }],
67
+ [0, 1, 0] => [:literal, :literal, Literal, text: 'a', options: { i: true }],
68
+ [0, 1, 1] => [:group, :options_switch, Group::Options, options: {}, option_changes: { i: false }],
69
+ [0, 1, 2] => [:literal, :literal, Literal, text: 'b', options: {}]
70
+
71
+ # options dau
72
+ include_examples 'parse', /(?dua:abc)/,
73
+ 0 => [:group, :options, Group::Options, options: { a: true }, option_changes: { a: true }]
74
+
75
+ # nested options dau
76
+ include_examples 'parse', /(?u:a(?d:b))/,
77
+ 0 => [:group, :options, Group::Options, options: { u: true }, option_changes: { u: true }],
78
+ [0, 1] => [:group, :options, Group::Options, options: { d: true }, option_changes: { d: true, u: false }],
79
+ [0, 1, 0] => [:literal, :literal, Literal, text: 'b', options: { d: true }]
80
+
81
+ # nested options da
82
+ include_examples 'parse', /(?di-xm:a(?da-x:b))/,
83
+ 0 => [:group, :options, Group::Options, options: { d: true, i:true }],
84
+ [0, 1] => [:group, :options, Group::Options, options: { a: true, i: true }, option_changes: { a: true, d: false, x: false}],
85
+ [0, 1, 0] => [:literal, :literal, Literal, text: 'b', options: { a: true, i: true }]
247
86
 
248
87
  specify('parse group number') do
249
- t = RP.parse('(a)(?=b)((?:c)(d|(e)))')
250
- expect(t[0].number).to eq 1
251
- expect(t[1]).not_to respond_to(:number)
252
- expect(t[2].number).to eq 2
253
- expect(t[2][0]).not_to respond_to(:number)
254
- expect(t[2][1].number).to eq 3
255
- expect(t[2][1][0][1][0].number).to eq 4
88
+ root = RP.parse(/(a)(?=b)((?:c)(d|(e)))/)
89
+
90
+ expect(root[0].number).to eq 1
91
+ expect(root[1]).not_to respond_to(:number)
92
+ expect(root[2].number).to eq 2
93
+ expect(root[2][0]).not_to respond_to(:number)
94
+ expect(root[2][1].number).to eq 3
95
+ expect(root[2][1][0][1][0].number).to eq 4
256
96
  end
257
97
 
258
98
  specify('parse group number at level') do
259
- t = RP.parse('(a)(?=b)((?:c)(d|(e)))')
260
- expect(t[0].number_at_level).to eq 1
261
- expect(t[1]).not_to respond_to(:number_at_level)
262
- expect(t[2].number_at_level).to eq 2
263
- expect(t[2][0]).not_to respond_to(:number_at_level)
264
- expect(t[2][1].number_at_level).to eq 1
265
- expect(t[2][1][0][1][0].number_at_level).to eq 1
99
+ root = RP.parse(/(a)(?=b)((?:c)(d|(e)))/)
100
+
101
+ expect(root[0].number_at_level).to eq 1
102
+ expect(root[1]).not_to respond_to(:number_at_level)
103
+ expect(root[2].number_at_level).to eq 2
104
+ expect(root[2][0]).not_to respond_to(:number_at_level)
105
+ expect(root[2][1].number_at_level).to eq 1
106
+ expect(root[2][1][0][1][0].number_at_level).to eq 1
266
107
  end
267
108
  end