regexp_parser 1.7.1 → 2.2.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 (139) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +157 -1
  3. data/Gemfile +6 -1
  4. data/LICENSE +1 -1
  5. data/README.md +38 -32
  6. data/Rakefile +18 -27
  7. data/lib/regexp_parser/error.rb +4 -0
  8. data/lib/regexp_parser/expression/base.rb +123 -0
  9. data/lib/regexp_parser/expression/classes/anchor.rb +0 -2
  10. data/lib/regexp_parser/expression/classes/{backref.rb → backreference.rb} +5 -0
  11. data/lib/regexp_parser/expression/classes/{set → character_set}/intersection.rb +0 -0
  12. data/lib/regexp_parser/expression/classes/{set → character_set}/range.rb +2 -1
  13. data/lib/regexp_parser/expression/classes/{set.rb → character_set.rb} +0 -0
  14. data/lib/regexp_parser/expression/classes/conditional.rb +11 -1
  15. data/lib/regexp_parser/expression/classes/{escape.rb → escape_sequence.rb} +13 -7
  16. data/lib/regexp_parser/expression/classes/free_space.rb +2 -4
  17. data/lib/regexp_parser/expression/classes/group.rb +28 -3
  18. data/lib/regexp_parser/expression/classes/literal.rb +1 -5
  19. data/lib/regexp_parser/expression/classes/property.rb +1 -3
  20. data/lib/regexp_parser/expression/classes/root.rb +4 -17
  21. data/lib/regexp_parser/expression/classes/type.rb +0 -2
  22. data/lib/regexp_parser/expression/methods/match_length.rb +2 -2
  23. data/lib/regexp_parser/expression/methods/strfregexp.rb +1 -1
  24. data/lib/regexp_parser/expression/methods/traverse.rb +2 -2
  25. data/lib/regexp_parser/expression/quantifier.rb +11 -2
  26. data/lib/regexp_parser/expression/sequence.rb +3 -20
  27. data/lib/regexp_parser/expression/subexpression.rb +1 -2
  28. data/lib/regexp_parser/expression.rb +7 -139
  29. data/lib/regexp_parser/lexer.rb +13 -11
  30. data/lib/regexp_parser/parser.rb +325 -344
  31. data/lib/regexp_parser/scanner/char_type.rl +11 -11
  32. data/lib/regexp_parser/scanner/properties/long.csv +604 -0
  33. data/lib/regexp_parser/scanner/properties/short.csv +242 -0
  34. data/lib/regexp_parser/scanner/property.rl +2 -2
  35. data/lib/regexp_parser/scanner/scanner.rl +235 -255
  36. data/lib/regexp_parser/scanner.rb +1324 -1387
  37. data/lib/regexp_parser/syntax/any.rb +4 -6
  38. data/lib/regexp_parser/syntax/base.rb +13 -15
  39. data/lib/regexp_parser/syntax/token/anchor.rb +15 -0
  40. data/lib/regexp_parser/syntax/{tokens → token}/assertion.rb +2 -2
  41. data/lib/regexp_parser/syntax/token/backreference.rb +30 -0
  42. data/lib/regexp_parser/syntax/{tokens → token}/character_set.rb +2 -2
  43. data/lib/regexp_parser/syntax/{tokens → token}/character_type.rb +3 -3
  44. data/lib/regexp_parser/syntax/{tokens → token}/conditional.rb +3 -3
  45. data/lib/regexp_parser/syntax/token/escape.rb +31 -0
  46. data/lib/regexp_parser/syntax/{tokens → token}/group.rb +7 -7
  47. data/lib/regexp_parser/syntax/{tokens → token}/keep.rb +1 -1
  48. data/lib/regexp_parser/syntax/{tokens → token}/meta.rb +2 -2
  49. data/lib/regexp_parser/syntax/{tokens → token}/posix_class.rb +3 -3
  50. data/lib/regexp_parser/syntax/token/quantifier.rb +35 -0
  51. data/lib/regexp_parser/syntax/token/unicode_property.rb +696 -0
  52. data/lib/regexp_parser/syntax/token.rb +45 -0
  53. data/lib/regexp_parser/syntax/version_lookup.rb +4 -4
  54. data/lib/regexp_parser/syntax/versions/1.8.6.rb +2 -2
  55. data/lib/regexp_parser/syntax/versions/1.9.1.rb +1 -1
  56. data/lib/regexp_parser/syntax/versions/3.1.0.rb +10 -0
  57. data/lib/regexp_parser/syntax.rb +8 -6
  58. data/lib/regexp_parser/token.rb +9 -20
  59. data/lib/regexp_parser/version.rb +1 -1
  60. data/lib/regexp_parser.rb +0 -2
  61. data/regexp_parser.gemspec +20 -22
  62. metadata +34 -165
  63. data/lib/regexp_parser/scanner/properties/long.yml +0 -594
  64. data/lib/regexp_parser/scanner/properties/short.yml +0 -237
  65. data/lib/regexp_parser/syntax/tokens/anchor.rb +0 -15
  66. data/lib/regexp_parser/syntax/tokens/backref.rb +0 -24
  67. data/lib/regexp_parser/syntax/tokens/escape.rb +0 -30
  68. data/lib/regexp_parser/syntax/tokens/quantifier.rb +0 -35
  69. data/lib/regexp_parser/syntax/tokens/unicode_property.rb +0 -675
  70. data/lib/regexp_parser/syntax/tokens.rb +0 -45
  71. data/spec/expression/base_spec.rb +0 -94
  72. data/spec/expression/clone_spec.rb +0 -120
  73. data/spec/expression/conditional_spec.rb +0 -89
  74. data/spec/expression/free_space_spec.rb +0 -27
  75. data/spec/expression/methods/match_length_spec.rb +0 -161
  76. data/spec/expression/methods/match_spec.rb +0 -25
  77. data/spec/expression/methods/strfregexp_spec.rb +0 -224
  78. data/spec/expression/methods/tests_spec.rb +0 -99
  79. data/spec/expression/methods/traverse_spec.rb +0 -161
  80. data/spec/expression/options_spec.rb +0 -128
  81. data/spec/expression/root_spec.rb +0 -9
  82. data/spec/expression/sequence_spec.rb +0 -9
  83. data/spec/expression/subexpression_spec.rb +0 -50
  84. data/spec/expression/to_h_spec.rb +0 -26
  85. data/spec/expression/to_s_spec.rb +0 -100
  86. data/spec/lexer/all_spec.rb +0 -22
  87. data/spec/lexer/conditionals_spec.rb +0 -53
  88. data/spec/lexer/delimiters_spec.rb +0 -68
  89. data/spec/lexer/escapes_spec.rb +0 -14
  90. data/spec/lexer/keep_spec.rb +0 -10
  91. data/spec/lexer/literals_spec.rb +0 -89
  92. data/spec/lexer/nesting_spec.rb +0 -99
  93. data/spec/lexer/refcalls_spec.rb +0 -55
  94. data/spec/parser/all_spec.rb +0 -43
  95. data/spec/parser/alternation_spec.rb +0 -88
  96. data/spec/parser/anchors_spec.rb +0 -17
  97. data/spec/parser/conditionals_spec.rb +0 -179
  98. data/spec/parser/errors_spec.rb +0 -30
  99. data/spec/parser/escapes_spec.rb +0 -121
  100. data/spec/parser/free_space_spec.rb +0 -130
  101. data/spec/parser/groups_spec.rb +0 -108
  102. data/spec/parser/keep_spec.rb +0 -6
  103. data/spec/parser/posix_classes_spec.rb +0 -8
  104. data/spec/parser/properties_spec.rb +0 -115
  105. data/spec/parser/quantifiers_spec.rb +0 -52
  106. data/spec/parser/refcalls_spec.rb +0 -112
  107. data/spec/parser/set/intersections_spec.rb +0 -127
  108. data/spec/parser/set/ranges_spec.rb +0 -111
  109. data/spec/parser/sets_spec.rb +0 -178
  110. data/spec/parser/types_spec.rb +0 -18
  111. data/spec/scanner/all_spec.rb +0 -18
  112. data/spec/scanner/anchors_spec.rb +0 -21
  113. data/spec/scanner/conditionals_spec.rb +0 -128
  114. data/spec/scanner/delimiters_spec.rb +0 -52
  115. data/spec/scanner/errors_spec.rb +0 -67
  116. data/spec/scanner/escapes_spec.rb +0 -53
  117. data/spec/scanner/free_space_spec.rb +0 -133
  118. data/spec/scanner/groups_spec.rb +0 -52
  119. data/spec/scanner/keep_spec.rb +0 -10
  120. data/spec/scanner/literals_spec.rb +0 -49
  121. data/spec/scanner/meta_spec.rb +0 -18
  122. data/spec/scanner/properties_spec.rb +0 -64
  123. data/spec/scanner/quantifiers_spec.rb +0 -20
  124. data/spec/scanner/refcalls_spec.rb +0 -36
  125. data/spec/scanner/sets_spec.rb +0 -102
  126. data/spec/scanner/types_spec.rb +0 -14
  127. data/spec/spec_helper.rb +0 -15
  128. data/spec/support/runner.rb +0 -42
  129. data/spec/support/shared_examples.rb +0 -77
  130. data/spec/support/warning_extractor.rb +0 -60
  131. data/spec/syntax/syntax_spec.rb +0 -48
  132. data/spec/syntax/syntax_token_map_spec.rb +0 -23
  133. data/spec/syntax/versions/1.8.6_spec.rb +0 -17
  134. data/spec/syntax/versions/1.9.1_spec.rb +0 -10
  135. data/spec/syntax/versions/1.9.3_spec.rb +0 -9
  136. data/spec/syntax/versions/2.0.0_spec.rb +0 -13
  137. data/spec/syntax/versions/2.2.0_spec.rb +0 -9
  138. data/spec/syntax/versions/aliases_spec.rb +0 -37
  139. data/spec/token/token_spec.rb +0 -85
@@ -1,94 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe(Regexp::Expression::Base) do
4
- specify('#to_re') do
5
- re_text = '^a*(b([cde]+))+f?$'
6
-
7
- re = RP.parse(re_text).to_re
8
-
9
- expect(re).to be_a(::Regexp)
10
- expect(re_text).to eq re.source
11
- end
12
-
13
- specify('#level') do
14
- regexp = /^a(b(c(d)))e$/
15
- root = RP.parse(regexp)
16
-
17
- ['^', 'a', '(b(c(d)))', 'e', '$'].each_with_index do |t, i|
18
- expect(root[i].to_s).to eq t
19
- expect(root[i].level).to eq 0
20
- end
21
-
22
- expect(root[2][0].to_s).to eq 'b'
23
- expect(root[2][0].level).to eq 1
24
-
25
- expect(root[2][1][0].to_s).to eq 'c'
26
- expect(root[2][1][0].level).to eq 2
27
-
28
- expect(root[2][1][1][0].to_s).to eq 'd'
29
- expect(root[2][1][1][0].level).to eq 3
30
- end
31
-
32
- specify('#terminal?') do
33
- root = RP.parse('^a([b]+)c$')
34
-
35
- expect(root).not_to be_terminal
36
-
37
- expect(root[0]).to be_terminal
38
- expect(root[1]).to be_terminal
39
- expect(root[2]).not_to be_terminal
40
- expect(root[2][0]).not_to be_terminal
41
- expect(root[2][0][0]).to be_terminal
42
- expect(root[3]).to be_terminal
43
- expect(root[4]).to be_terminal
44
- end
45
-
46
- specify('alt #terminal?') do
47
- root = RP.parse('^(ab|cd)$')
48
-
49
- expect(root).not_to be_terminal
50
-
51
- expect(root[0]).to be_terminal
52
- expect(root[1]).not_to be_terminal
53
- expect(root[1][0]).not_to be_terminal
54
- expect(root[1][0][0]).not_to be_terminal
55
- expect(root[1][0][0][0]).to be_terminal
56
- expect(root[1][0][1]).not_to be_terminal
57
- expect(root[1][0][1][0]).to be_terminal
58
- end
59
-
60
- specify('#coded_offset') do
61
- root = RP.parse('^a*(b+(c?))$')
62
-
63
- expect(root.coded_offset).to eq '@0+12'
64
-
65
- [
66
- ['@0+1', '^'],
67
- ['@1+2', 'a*'],
68
- ['@3+8', '(b+(c?))'],
69
- ['@11+1', '$'],
70
- ].each_with_index do |check, i|
71
- against = [root[i].coded_offset, root[i].to_s]
72
-
73
- expect(against).to eq check
74
- end
75
-
76
- expect([root[2][0].coded_offset, root[2][0].to_s]).to eq ['@4+2', 'b+']
77
- expect([root[2][1].coded_offset, root[2][1].to_s]).to eq ['@6+4', '(c?)']
78
- expect([root[2][1][0].coded_offset, root[2][1][0].to_s]).to eq ['@7+2', 'c?']
79
- end
80
-
81
- specify('#quantity') do
82
- expect(RP.parse(/aa/)[0].quantity).to eq [nil, nil]
83
- expect(RP.parse(/a?/)[0].quantity).to eq [0, 1]
84
- expect(RP.parse(/a*/)[0].quantity).to eq [0, -1]
85
- expect(RP.parse(/a+/)[0].quantity).to eq [1, -1]
86
- end
87
-
88
- specify('#repetitions') do
89
- expect(RP.parse(/aa/)[0].repetitions).to eq 1..1
90
- expect(RP.parse(/a?/)[0].repetitions).to eq 0..1
91
- expect(RP.parse(/a*/)[0].repetitions).to eq 0..(Float::INFINITY)
92
- expect(RP.parse(/a+/)[0].repetitions).to eq 1..(Float::INFINITY)
93
- end
94
- end
@@ -1,120 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe('Expression#clone') do
4
- specify('Base#clone') do
5
- root = RP.parse(/^(?i:a)b+$/i)
6
- copy = root.clone
7
-
8
- expect(copy.to_s).to eq root.to_s
9
-
10
- expect(root.object_id).not_to eq copy.object_id
11
- expect(root.text).to eq copy.text
12
- expect(root.text.object_id).not_to eq copy.text.object_id
13
-
14
- root_1 = root[1]
15
- copy_1 = copy[1]
16
-
17
- expect(root_1.options).to eq copy_1.options
18
- expect(root_1.options.object_id).not_to eq copy_1.options.object_id
19
-
20
- root_2 = root[2]
21
- copy_2 = copy[2]
22
-
23
- expect(root_2).to be_quantified
24
- expect(copy_2).to be_quantified
25
- expect(root_2.quantifier.text).to eq copy_2.quantifier.text
26
- expect(root_2.quantifier.text.object_id).not_to eq copy_2.quantifier.text.object_id
27
- expect(root_2.quantifier.object_id).not_to eq copy_2.quantifier.object_id
28
-
29
- # regression test
30
- expect { root_2.clone }.not_to change { root_2.quantifier.object_id }
31
- expect { root_2.clone }.not_to change { root_2.quantifier.text.object_id }
32
- end
33
-
34
- specify('Subexpression#clone') do
35
- root = RP.parse(/^a(b([cde])f)g$/)
36
- copy = root.clone
37
-
38
- expect(copy.to_s).to eq root.to_s
39
-
40
- expect(root).to respond_to(:expressions)
41
- expect(copy).to respond_to(:expressions)
42
- expect(root.expressions.object_id).not_to eq copy.expressions.object_id
43
- copy.expressions.each_with_index do |exp, index|
44
- expect(root[index].object_id).not_to eq exp.object_id
45
- end
46
- copy[2].each_with_index do |exp, index|
47
- expect(root[2][index].object_id).not_to eq exp.object_id
48
- end
49
-
50
- # regression test
51
- expect { root.clone }.not_to change { root.expressions.object_id }
52
- end
53
-
54
- specify('Group::Named#clone') do
55
- root = RP.parse('^(?<somename>a)+bc$')
56
- copy = root.clone
57
-
58
- expect(copy.to_s).to eq root.to_s
59
-
60
- root_1 = root[1]
61
- copy_1 = copy[1]
62
-
63
- expect(root_1.name).to eq copy_1.name
64
- expect(root_1.name.object_id).not_to eq copy_1.name.object_id
65
- expect(root_1.text).to eq copy_1.text
66
- expect(root_1.expressions.object_id).not_to eq copy_1.expressions.object_id
67
- copy_1.expressions.each_with_index do |exp, index|
68
- expect(root_1[index].object_id).not_to eq exp.object_id
69
- end
70
-
71
- # regression test
72
- expect { root_1.clone }.not_to change { root_1.name.object_id }
73
- end
74
-
75
- specify('Sequence#clone') do
76
- root = RP.parse(/(a|b)/)
77
- copy = root.clone
78
-
79
- # regression test
80
- expect(copy.to_s).to eq root.to_s
81
-
82
- root_seq_op = root[0][0]
83
- copy_seq_op = copy[0][0]
84
- root_seq_1 = root[0][0][0]
85
- copy_seq_1 = copy[0][0][0]
86
-
87
- expect(root_seq_op.object_id).not_to eq copy_seq_op.object_id
88
- expect(root_seq_1.object_id).not_to eq copy_seq_1.object_id
89
- copy_seq_1.expressions.each_with_index do |exp, index|
90
- expect(root_seq_1[index].object_id).not_to eq exp.object_id
91
- end
92
- end
93
-
94
- describe('Base#unquantified_clone') do
95
- it 'produces a clone' do
96
- root = RP.parse(/^a(b([cde])f)g$/)
97
- copy = root.unquantified_clone
98
-
99
- expect(copy.to_s).to eq root.to_s
100
-
101
- expect(copy.object_id).not_to eq root.object_id
102
- end
103
-
104
- it 'does not carry over the callee quantifier' do
105
- expect(RP.parse(/a{3}/)[0]).to be_quantified
106
- expect(RP.parse(/a{3}/)[0].unquantified_clone).not_to be_quantified
107
-
108
- expect(RP.parse(/[a]{3}/)[0]).to be_quantified
109
- expect(RP.parse(/[a]{3}/)[0].unquantified_clone).not_to be_quantified
110
-
111
- expect(RP.parse(/(a|b){3}/)[0]).to be_quantified
112
- expect(RP.parse(/(a|b){3}/)[0].unquantified_clone).not_to be_quantified
113
- end
114
-
115
- it 'keeps quantifiers of callee children' do
116
- expect(RP.parse(/(a{3}){3}/)[0][0]).to be_quantified
117
- expect(RP.parse(/(a{3}){3}/)[0].unquantified_clone[0]).to be_quantified
118
- end
119
- end
120
- end
@@ -1,89 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe(Regexp::Expression::Conditional) do
4
- let(:root) { RP.parse('^(a(b))(b(?(1)c|(?(2)d|(?(3)e|f)))g)$') }
5
- let(:cond_1) { root[2][1] }
6
- let(:cond_2) { root[2][1][2][0] }
7
- let(:cond_3) { root[2][1][2][0][2][0] }
8
-
9
- specify('root level') do
10
- [
11
- '^',
12
- '(a(b))',
13
- '(b(?(1)c|(?(2)d|(?(3)e|f)))g)',
14
- '$'
15
- ].each_with_index do |t, i|
16
- expect(root[i].conditional_level).to eq 0
17
- expect(root[i].to_s).to eq t
18
- end
19
-
20
- expect(root[2][0].to_s).to eq 'b'
21
- expect(root[2][0].conditional_level).to eq 0
22
- end
23
-
24
- specify('level one') do
25
- condition = cond_1.condition
26
- branch_1 = cond_1.branches.first
27
-
28
- expect(condition).to be_a Conditional::Condition
29
- expect(condition.to_s).to eq '(1)'
30
- expect(condition.conditional_level).to eq 1
31
-
32
- expect(branch_1).to be_a Conditional::Branch
33
- expect(branch_1.to_s).to eq 'c'
34
- expect(branch_1.conditional_level).to eq 1
35
-
36
- expect(branch_1.first.to_s).to eq 'c'
37
- expect(branch_1.first.conditional_level).to eq 1
38
- end
39
-
40
- specify('level two') do
41
- condition = cond_2.condition
42
- branch_1 = cond_2.branches.first
43
- branch_2 = cond_2.branches.last
44
-
45
- expect(cond_2.to_s).to start_with '(?'
46
- expect(cond_2.conditional_level).to eq 1
47
-
48
- expect(condition).to be_a Conditional::Condition
49
- expect(condition.to_s).to eq '(2)'
50
- expect(condition.conditional_level).to eq 2
51
-
52
- expect(branch_1).to be_a Conditional::Branch
53
- expect(branch_1.to_s).to eq 'd'
54
- expect(branch_1.conditional_level).to eq 2
55
-
56
- expect(branch_1.first.to_s).to eq 'd'
57
- expect(branch_1.first.conditional_level).to eq 2
58
-
59
- expect(branch_2.first.to_s).to start_with '(?'
60
- expect(branch_2.first.conditional_level).to eq 2
61
- end
62
-
63
- specify('level three') do
64
- condition = cond_3.condition
65
- branch_1 = cond_3.branches.first
66
- branch_2 = cond_3.branches.last
67
-
68
- expect(condition).to be_a Conditional::Condition
69
- expect(condition.to_s).to eq '(3)'
70
- expect(condition.conditional_level).to eq 3
71
-
72
- expect(cond_3.to_s).to eq '(?(3)e|f)'
73
- expect(cond_3.conditional_level).to eq 2
74
-
75
- expect(branch_1).to be_a Conditional::Branch
76
- expect(branch_1.to_s).to eq 'e'
77
- expect(branch_1.conditional_level).to eq 3
78
-
79
- expect(branch_1.first.to_s).to eq 'e'
80
- expect(branch_1.first.conditional_level).to eq 3
81
-
82
- expect(branch_2).to be_a Conditional::Branch
83
- expect(branch_2.to_s).to eq 'f'
84
- expect(branch_2.conditional_level).to eq 3
85
-
86
- expect(branch_2.first.to_s).to eq 'f'
87
- expect(branch_2.first.conditional_level).to eq 3
88
- end
89
- end
@@ -1,27 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe(Regexp::Expression::FreeSpace) do
4
- specify('white space quantify raises error') do
5
- regexp = /
6
- a # Comment
7
- /x
8
-
9
- root = RP.parse(regexp)
10
- space = root[0]
11
-
12
- expect(space).to be_instance_of(FreeSpace::WhiteSpace)
13
- expect { space.quantify(:dummy, '#') }.to raise_error(RuntimeError)
14
- end
15
-
16
- specify('comment quantify raises error') do
17
- regexp = /
18
- a # Comment
19
- /x
20
-
21
- root = RP.parse(regexp)
22
- comment = root[3]
23
-
24
- expect(comment).to be_instance_of(FreeSpace::Comment)
25
- expect { comment.quantify(:dummy, '#') }.to raise_error(RuntimeError)
26
- end
27
- end
@@ -1,161 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe(Regexp::MatchLength) do
4
- ML = described_class
5
-
6
- specify('literal') { expect(ML.of(/a/).minmax).to eq [1, 1] }
7
- specify('literal sequence') { expect(ML.of(/abc/).minmax).to eq [3, 3] }
8
- specify('dot') { expect(ML.of(/./).minmax).to eq [1, 1] }
9
- specify('set') { expect(ML.of(/[abc]/).minmax).to eq [1, 1] }
10
- specify('type') { expect(ML.of(/\d/).minmax).to eq [1, 1] }
11
- specify('escape') { expect(ML.of(/\n/).minmax).to eq [1, 1] }
12
- specify('property') { expect(ML.of(/\p{ascii}/).minmax).to eq [1, 1] }
13
- specify('codepoint list') { expect(ML.of(/\u{61 62 63}/).minmax).to eq [3, 3] }
14
- specify('multi-char literal') { expect(ML.of(/abc/).minmax).to eq [3, 3] }
15
- specify('fixed quantified') { expect(ML.of(/a{5}/).minmax).to eq [5, 5] }
16
- specify('range quantified') { expect(ML.of(/a{5,9}/).minmax).to eq [5, 9] }
17
- specify('nested quantified') { expect(ML.of(/(a{2}){3,4}/).minmax).to eq [6, 8] }
18
- specify('open-end quantified') { expect(ML.of(/a*/).minmax).to eq [0, Float::INFINITY] }
19
- specify('empty subexpression') { expect(ML.of(//).minmax).to eq [0, 0] }
20
- specify('anchor') { expect(ML.of(/^$/).minmax).to eq [0, 0] }
21
- specify('lookaround') { expect(ML.of(/(?=abc)/).minmax).to eq [0, 0] }
22
- specify('free space') { expect(ML.of(/ /x).minmax).to eq [0, 0] }
23
- specify('comment') { expect(ML.of(/(?#comment)/x).minmax).to eq [0, 0] }
24
- specify('backreference') { expect(ML.of(/(abc){2}\1/).minmax).to eq [9, 9] }
25
- specify('subexp call') { expect(ML.of(/(abc){2}\g<-1>/).minmax).to eq [9, 9] }
26
- specify('alternation') { expect(ML.of(/a|bcde/).minmax).to eq [1, 4] }
27
- specify('nested alternation') { expect(ML.of(/a|bc(d|efg)/).minmax).to eq [1, 5] }
28
- specify('quantified alternation') { expect(ML.of(/a|bcde?/).minmax).to eq [1, 4] }
29
- if ruby_version_at_least('2.4.1')
30
- specify('absence group') { expect(ML.of('(?~abc)').minmax).to eq [0, Float::INFINITY] }
31
- end
32
-
33
- specify('raises for missing references') do
34
- exp = RP.parse(/(a)\1/).last
35
- exp.referenced_expression = nil
36
- expect { exp.match_length }.to raise_error(ArgumentError)
37
- end
38
-
39
- describe('::of') do
40
- it('works with Regexps') { expect(ML.of(/foo/).minmax).to eq [3, 3] }
41
- it('works with Strings') { expect(ML.of('foo').minmax).to eq [3, 3] }
42
- it('works with Expressions') { expect(ML.of(RP.parse(/foo/)).minmax).to eq [3, 3] }
43
- end
44
-
45
- describe('Expression#match_length') do
46
- it('returns the MatchLength') { expect(RP.parse(/abc/).match_length.minmax).to eq [3, 3] }
47
- end
48
-
49
- describe('Expression#inner_match_length') do
50
- it 'returns the MatchLength of an expression that does not count towards parent match_length' do
51
- exp = RP.parse(/(?=ab|cdef)/)[0]
52
- expect(exp).to be_a Regexp::Expression::Assertion::Base
53
- expect(exp.match_length.minmax).to eq [0, 0]
54
- expect(exp.inner_match_length.minmax).to eq [2, 4]
55
- end
56
- end
57
-
58
- describe('#include?') do
59
- specify('unquantified') do
60
- expect(ML.of(/a/)).to include 1
61
- expect(ML.of(/a/)).not_to include 0
62
- expect(ML.of(/a/)).not_to include 2
63
- end
64
-
65
- specify('fixed quantified') do
66
- expect(ML.of(/a{5}/)).to include 5
67
- expect(ML.of(/a{5}/)).not_to include 0
68
- expect(ML.of(/a{5}/)).not_to include 4
69
- expect(ML.of(/a{5}/)).not_to include 6
70
- end
71
-
72
- specify('variably quantified') do
73
- expect(ML.of(/a?/)).to include 0
74
- expect(ML.of(/a?/)).to include 1
75
- expect(ML.of(/a?/)).not_to include 2
76
- end
77
-
78
- specify('nested quantified') do
79
- expect(ML.of(/(a{2}){3,4}/)).to include 6
80
- expect(ML.of(/(a{2}){3,4}/)).to include 8
81
- expect(ML.of(/(a{2}){3,4}/)).not_to include 0
82
- expect(ML.of(/(a{2}){3,4}/)).not_to include 5
83
- expect(ML.of(/(a{2}){3,4}/)).not_to include 7
84
- expect(ML.of(/(a{2}){3,4}/)).not_to include 9
85
- end
86
-
87
- specify('branches') do
88
- expect(ML.of(/ab|cdef/)).to include 2
89
- expect(ML.of(/ab|cdef/)).to include 4
90
- expect(ML.of(/ab|cdef/)).not_to include 0
91
- expect(ML.of(/ab|cdef/)).not_to include 3
92
- expect(ML.of(/ab|cdef/)).not_to include 5
93
- end
94
-
95
- specify('called on leaf node') do
96
- expect(ML.of(RP.parse(/a{2}/)[0])).to include 2
97
- expect(ML.of(RP.parse(/a{2}/)[0])).not_to include 0
98
- expect(ML.of(RP.parse(/a{2}/)[0])).not_to include 1
99
- expect(ML.of(RP.parse(/a{2}/)[0])).not_to include 3
100
- end
101
- end
102
-
103
- describe('#fixed?') do
104
- specify('unquantified') { expect(ML.of(/a/)).to be_fixed }
105
- specify('fixed quantified') { expect(ML.of(/a{5}/)).to be_fixed }
106
- specify('variably quantified') { expect(ML.of(/a?/)).not_to be_fixed }
107
- specify('equal branches') { expect(ML.of(/ab|cd/)).to be_fixed }
108
- specify('unequal branches') { expect(ML.of(/ab|cdef/)).not_to be_fixed }
109
- specify('equal quantified branches') { expect(ML.of(/a{2}|cd/)).to be_fixed }
110
- specify('unequal quantified branches') { expect(ML.of(/a{3}|cd/)).not_to be_fixed }
111
- specify('empty') { expect(ML.of(//)).to be_fixed }
112
- end
113
-
114
- describe('#each') do
115
- it 'returns an Enumerator if called without a block' do
116
- result = ML.of(/a?/).each
117
- expect(result).to be_a(Enumerator)
118
- expect(result.next).to eq 0
119
- expect(result.next).to eq 1
120
- expect { result.next }.to raise_error(StopIteration)
121
- end
122
-
123
- it 'is aware of limit option even if called without a block' do
124
- result = ML.of(/a?/).each(limit: 1)
125
- expect(result).to be_a(Enumerator)
126
- expect(result.next).to eq 0
127
- expect { result.next }.to raise_error(StopIteration)
128
- end
129
-
130
- it 'is limited to 1000 iterations in case there are infinite match lengths' do
131
- expect(ML.of(/a*/).first(3000).size).to eq 1000
132
- end
133
-
134
- it 'scaffolds the Enumerable interface' do
135
- expect(ML.of(/abc|defg/).count).to eq 2
136
- expect(ML.of(/(ab)*/).first(5)).to eq [0, 2, 4, 6, 8]
137
- expect(ML.of(/a{,10}/).any? { |len| len > 20 }).to be false
138
- end
139
- end
140
-
141
- describe('#endless_each') do
142
- it 'returns an Enumerator if called without a block' do
143
- result = ML.of(/a?/).endless_each
144
- expect(result).to be_a(Enumerator)
145
- expect(result.next).to eq 0
146
- expect(result.next).to eq 1
147
- expect { result.next }.to raise_error(StopIteration)
148
- end
149
-
150
- it 'never stops iterating for infinite match lengths' do
151
- expect(ML.of(/a*/).endless_each.first(3000).size).to eq 3000
152
- end
153
- end
154
-
155
- describe('#inspect') do
156
- it 'is nice' do
157
- result = RP.parse(/a{2,4}/)[0].match_length
158
- expect(result.inspect).to eq '#<Regexp::MatchLength<Literal> min=2 max=4>'
159
- end
160
- end
161
- end
@@ -1,25 +0,0 @@
1
- require 'spec_helper'
2
-
3
- RSpec.describe('Expression#match') do
4
- it 'returns the #match result of the respective Regexp' do
5
- expect(RP.parse(/a/).match('a')[0]).to eq 'a'
6
- end
7
-
8
- it 'can be given an offset, just like Regexp#match' do
9
- expect(RP.parse(/./).match('ab', 1)[0]).to eq 'b'
10
- end
11
-
12
- it 'works with the #=~ alias' do
13
- expect(RP.parse(/a/) =~ 'a').to be_a MatchData
14
- end
15
- end
16
-
17
- RSpec.describe('Expression#match?') do
18
- it 'returns true if the Respective Regexp matches' do
19
- expect(RP.parse(/a/).match?('a')).to be true
20
- end
21
-
22
- it 'returns false if the Respective Regexp does not match' do
23
- expect(RP.parse(/a/).match?('b')).to be false
24
- end
25
- end