regexp_parser 2.1.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 (129) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +19 -1
  3. data/LICENSE +1 -1
  4. data/README.md +17 -23
  5. data/Rakefile +10 -19
  6. data/lib/regexp_parser/expression/base.rb +123 -0
  7. data/lib/regexp_parser/expression/classes/anchor.rb +0 -2
  8. data/lib/regexp_parser/expression/classes/{backref.rb → backreference.rb} +0 -0
  9. data/lib/regexp_parser/expression/classes/{set → character_set}/intersection.rb +0 -0
  10. data/lib/regexp_parser/expression/classes/{set → character_set}/range.rb +0 -0
  11. data/lib/regexp_parser/expression/classes/{set.rb → character_set.rb} +0 -0
  12. data/lib/regexp_parser/expression/classes/{escape.rb → escape_sequence.rb} +13 -7
  13. data/lib/regexp_parser/expression/classes/free_space.rb +0 -2
  14. data/lib/regexp_parser/expression/classes/literal.rb +1 -5
  15. data/lib/regexp_parser/expression/classes/property.rb +0 -2
  16. data/lib/regexp_parser/expression/classes/root.rb +0 -1
  17. data/lib/regexp_parser/expression/classes/type.rb +0 -2
  18. data/lib/regexp_parser/expression/methods/strfregexp.rb +1 -1
  19. data/lib/regexp_parser/expression/quantifier.rb +1 -1
  20. data/lib/regexp_parser/expression/sequence.rb +0 -1
  21. data/lib/regexp_parser/expression/subexpression.rb +0 -1
  22. data/lib/regexp_parser/expression.rb +6 -130
  23. data/lib/regexp_parser/lexer.rb +7 -5
  24. data/lib/regexp_parser/scanner/properties/long.csv +604 -0
  25. data/lib/regexp_parser/scanner/properties/short.csv +242 -0
  26. data/lib/regexp_parser/scanner/scanner.rl +6 -4
  27. data/lib/regexp_parser/scanner.rb +126 -124
  28. data/lib/regexp_parser/syntax/any.rb +1 -3
  29. data/lib/regexp_parser/syntax/base.rb +12 -14
  30. data/lib/regexp_parser/syntax/token/anchor.rb +15 -0
  31. data/lib/regexp_parser/syntax/{tokens → token}/assertion.rb +2 -2
  32. data/lib/regexp_parser/syntax/token/backreference.rb +30 -0
  33. data/lib/regexp_parser/syntax/{tokens → token}/character_set.rb +2 -2
  34. data/lib/regexp_parser/syntax/{tokens → token}/character_type.rb +3 -3
  35. data/lib/regexp_parser/syntax/{tokens → token}/conditional.rb +3 -3
  36. data/lib/regexp_parser/syntax/token/escape.rb +31 -0
  37. data/lib/regexp_parser/syntax/{tokens → token}/group.rb +7 -7
  38. data/lib/regexp_parser/syntax/{tokens → token}/keep.rb +1 -1
  39. data/lib/regexp_parser/syntax/{tokens → token}/meta.rb +2 -2
  40. data/lib/regexp_parser/syntax/{tokens → token}/posix_class.rb +3 -3
  41. data/lib/regexp_parser/syntax/token/quantifier.rb +35 -0
  42. data/lib/regexp_parser/syntax/token/unicode_property.rb +696 -0
  43. data/lib/regexp_parser/syntax/token.rb +45 -0
  44. data/lib/regexp_parser/syntax/versions/1.8.6.rb +2 -2
  45. data/lib/regexp_parser/syntax/versions/1.9.1.rb +1 -1
  46. data/lib/regexp_parser/syntax/versions/3.1.0.rb +10 -0
  47. data/lib/regexp_parser/syntax.rb +1 -1
  48. data/lib/regexp_parser/token.rb +9 -20
  49. data/lib/regexp_parser/version.rb +1 -1
  50. data/lib/regexp_parser.rb +0 -2
  51. data/regexp_parser.gemspec +20 -22
  52. metadata +32 -164
  53. data/lib/regexp_parser/scanner/properties/long.yml +0 -594
  54. data/lib/regexp_parser/scanner/properties/short.yml +0 -237
  55. data/lib/regexp_parser/syntax/tokens/anchor.rb +0 -15
  56. data/lib/regexp_parser/syntax/tokens/backref.rb +0 -24
  57. data/lib/regexp_parser/syntax/tokens/escape.rb +0 -30
  58. data/lib/regexp_parser/syntax/tokens/quantifier.rb +0 -35
  59. data/lib/regexp_parser/syntax/tokens/unicode_property.rb +0 -675
  60. data/lib/regexp_parser/syntax/tokens.rb +0 -45
  61. data/spec/expression/base_spec.rb +0 -104
  62. data/spec/expression/clone_spec.rb +0 -152
  63. data/spec/expression/conditional_spec.rb +0 -89
  64. data/spec/expression/free_space_spec.rb +0 -27
  65. data/spec/expression/methods/match_length_spec.rb +0 -161
  66. data/spec/expression/methods/match_spec.rb +0 -25
  67. data/spec/expression/methods/strfregexp_spec.rb +0 -224
  68. data/spec/expression/methods/tests_spec.rb +0 -99
  69. data/spec/expression/methods/traverse_spec.rb +0 -161
  70. data/spec/expression/options_spec.rb +0 -128
  71. data/spec/expression/subexpression_spec.rb +0 -50
  72. data/spec/expression/to_h_spec.rb +0 -26
  73. data/spec/expression/to_s_spec.rb +0 -108
  74. data/spec/lexer/all_spec.rb +0 -22
  75. data/spec/lexer/conditionals_spec.rb +0 -53
  76. data/spec/lexer/delimiters_spec.rb +0 -68
  77. data/spec/lexer/escapes_spec.rb +0 -14
  78. data/spec/lexer/keep_spec.rb +0 -10
  79. data/spec/lexer/literals_spec.rb +0 -64
  80. data/spec/lexer/nesting_spec.rb +0 -99
  81. data/spec/lexer/refcalls_spec.rb +0 -60
  82. data/spec/parser/all_spec.rb +0 -43
  83. data/spec/parser/alternation_spec.rb +0 -88
  84. data/spec/parser/anchors_spec.rb +0 -17
  85. data/spec/parser/conditionals_spec.rb +0 -179
  86. data/spec/parser/errors_spec.rb +0 -30
  87. data/spec/parser/escapes_spec.rb +0 -121
  88. data/spec/parser/free_space_spec.rb +0 -130
  89. data/spec/parser/groups_spec.rb +0 -108
  90. data/spec/parser/keep_spec.rb +0 -6
  91. data/spec/parser/options_spec.rb +0 -28
  92. data/spec/parser/posix_classes_spec.rb +0 -8
  93. data/spec/parser/properties_spec.rb +0 -115
  94. data/spec/parser/quantifiers_spec.rb +0 -68
  95. data/spec/parser/refcalls_spec.rb +0 -117
  96. data/spec/parser/set/intersections_spec.rb +0 -127
  97. data/spec/parser/set/ranges_spec.rb +0 -111
  98. data/spec/parser/sets_spec.rb +0 -178
  99. data/spec/parser/types_spec.rb +0 -18
  100. data/spec/scanner/all_spec.rb +0 -18
  101. data/spec/scanner/anchors_spec.rb +0 -21
  102. data/spec/scanner/conditionals_spec.rb +0 -128
  103. data/spec/scanner/delimiters_spec.rb +0 -52
  104. data/spec/scanner/errors_spec.rb +0 -67
  105. data/spec/scanner/escapes_spec.rb +0 -64
  106. data/spec/scanner/free_space_spec.rb +0 -165
  107. data/spec/scanner/groups_spec.rb +0 -61
  108. data/spec/scanner/keep_spec.rb +0 -10
  109. data/spec/scanner/literals_spec.rb +0 -39
  110. data/spec/scanner/meta_spec.rb +0 -18
  111. data/spec/scanner/options_spec.rb +0 -36
  112. data/spec/scanner/properties_spec.rb +0 -64
  113. data/spec/scanner/quantifiers_spec.rb +0 -25
  114. data/spec/scanner/refcalls_spec.rb +0 -55
  115. data/spec/scanner/sets_spec.rb +0 -151
  116. data/spec/scanner/types_spec.rb +0 -14
  117. data/spec/spec_helper.rb +0 -16
  118. data/spec/support/runner.rb +0 -42
  119. data/spec/support/shared_examples.rb +0 -77
  120. data/spec/support/warning_extractor.rb +0 -60
  121. data/spec/syntax/syntax_spec.rb +0 -48
  122. data/spec/syntax/syntax_token_map_spec.rb +0 -23
  123. data/spec/syntax/versions/1.8.6_spec.rb +0 -17
  124. data/spec/syntax/versions/1.9.1_spec.rb +0 -10
  125. data/spec/syntax/versions/1.9.3_spec.rb +0 -9
  126. data/spec/syntax/versions/2.0.0_spec.rb +0 -13
  127. data/spec/syntax/versions/2.2.0_spec.rb +0 -9
  128. data/spec/syntax/versions/aliases_spec.rb +0 -37
  129. data/spec/token/token_spec.rb +0 -85
@@ -1,104 +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
-
95
- specify('#base_length') do
96
- expect(RP.parse(/(aa)/)[0].base_length).to eq 4
97
- expect(RP.parse(/(aa){42}/)[0].base_length).to eq 4
98
- end
99
-
100
- specify('#full_length') do
101
- expect(RP.parse(/(aa)/)[0].full_length).to eq 4
102
- expect(RP.parse(/(aa){42}/)[0].full_length).to eq 8
103
- end
104
- end
@@ -1,152 +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('Group::Options#clone') do
76
- root = RP.parse('foo(?i)bar')
77
- copy = root.clone
78
-
79
- expect(copy.to_s).to eq root.to_s
80
-
81
- root_1 = root[1]
82
- copy_1 = copy[1]
83
-
84
- expect(root_1.option_changes).to eq copy_1.option_changes
85
- expect(root_1.option_changes.object_id).not_to eq copy_1.option_changes.object_id
86
-
87
- # regression test
88
- expect { root_1.clone }.not_to(change { root_1.option_changes.object_id })
89
- end
90
-
91
- specify('Backreference::Base#clone') do
92
- root = RP.parse('(foo)\1')
93
- copy = root.clone
94
-
95
- expect(copy.to_s).to eq root.to_s
96
-
97
- root_1 = root[1]
98
- copy_1 = copy[1]
99
-
100
- expect(root_1.referenced_expression.to_s).to eq copy_1.referenced_expression.to_s
101
- expect(root_1.referenced_expression.object_id).not_to eq copy_1.referenced_expression.object_id
102
-
103
- # regression test
104
- expect { root_1.clone }.not_to(change { root_1.referenced_expression.object_id })
105
- end
106
-
107
- specify('Sequence#clone') do
108
- root = RP.parse(/(a|b)/)
109
- copy = root.clone
110
-
111
- # regression test
112
- expect(copy.to_s).to eq root.to_s
113
-
114
- root_seq_op = root[0][0]
115
- copy_seq_op = copy[0][0]
116
- root_seq_1 = root[0][0][0]
117
- copy_seq_1 = copy[0][0][0]
118
-
119
- expect(root_seq_op.object_id).not_to eq copy_seq_op.object_id
120
- expect(root_seq_1.object_id).not_to eq copy_seq_1.object_id
121
- copy_seq_1.expressions.each_with_index do |exp, index|
122
- expect(root_seq_1[index].object_id).not_to eq exp.object_id
123
- end
124
- end
125
-
126
- describe('Base#unquantified_clone') do
127
- it 'produces a clone' do
128
- root = RP.parse(/^a(b([cde])f)g$/)
129
- copy = root.unquantified_clone
130
-
131
- expect(copy.to_s).to eq root.to_s
132
-
133
- expect(copy.object_id).not_to eq root.object_id
134
- end
135
-
136
- it 'does not carry over the callee quantifier' do
137
- expect(RP.parse(/a{3}/)[0]).to be_quantified
138
- expect(RP.parse(/a{3}/)[0].unquantified_clone).not_to be_quantified
139
-
140
- expect(RP.parse(/[a]{3}/)[0]).to be_quantified
141
- expect(RP.parse(/[a]{3}/)[0].unquantified_clone).not_to be_quantified
142
-
143
- expect(RP.parse(/(a|b){3}/)[0]).to be_quantified
144
- expect(RP.parse(/(a|b){3}/)[0].unquantified_clone).not_to be_quantified
145
- end
146
-
147
- it 'keeps quantifiers of callee children' do
148
- expect(RP.parse(/(a{3}){3}/)[0][0]).to be_quantified
149
- expect(RP.parse(/(a{3}){3}/)[0].unquantified_clone[0]).to be_quantified
150
- end
151
- end
152
- 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(Regexp::Parser::Error)
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(Regexp::Parser::Error)
26
- end
27
- end
@@ -1,161 +0,0 @@
1
- require 'spec_helper'
2
-
3
- ML = Regexp::MatchLength
4
-
5
- RSpec.describe(Regexp::MatchLength) do
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