regexp_parser 1.4.0 → 1.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.
Files changed (133) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +27 -1
  3. data/Gemfile +1 -1
  4. data/README.md +9 -13
  5. data/lib/regexp_parser/expression.rb +33 -21
  6. data/lib/regexp_parser/expression/classes/backref.rb +18 -10
  7. data/lib/regexp_parser/expression/classes/conditional.rb +4 -0
  8. data/lib/regexp_parser/expression/classes/group.rb +4 -2
  9. data/lib/regexp_parser/expression/classes/keep.rb +1 -3
  10. data/lib/regexp_parser/expression/methods/match_length.rb +172 -0
  11. data/lib/regexp_parser/expression/quantifier.rb +2 -2
  12. data/lib/regexp_parser/expression/sequence.rb +0 -4
  13. data/lib/regexp_parser/expression/subexpression.rb +3 -5
  14. data/lib/regexp_parser/lexer.rb +31 -24
  15. data/lib/regexp_parser/parser.rb +25 -3
  16. data/lib/regexp_parser/syntax/tokens.rb +2 -10
  17. data/lib/regexp_parser/version.rb +1 -1
  18. data/regexp_parser.gemspec +2 -2
  19. data/spec/expression/base_spec.rb +80 -0
  20. data/spec/expression/clone_spec.rb +120 -0
  21. data/spec/expression/conditional_spec.rb +89 -0
  22. data/spec/expression/free_space_spec.rb +27 -0
  23. data/spec/expression/methods/match_length_spec.rb +141 -0
  24. data/spec/expression/methods/strfregexp_spec.rb +224 -0
  25. data/spec/expression/methods/tests_spec.rb +97 -0
  26. data/spec/expression/methods/traverse_spec.rb +140 -0
  27. data/spec/expression/subexpression_spec.rb +50 -0
  28. data/spec/expression/to_h_spec.rb +26 -0
  29. data/spec/expression/to_s_spec.rb +100 -0
  30. data/spec/lexer/all_spec.rb +22 -0
  31. data/{test/lexer/test_conditionals.rb → spec/lexer/conditionals_spec.rb} +31 -35
  32. data/spec/lexer/escapes_spec.rb +38 -0
  33. data/spec/lexer/keep_spec.rb +22 -0
  34. data/{test/lexer/test_literals.rb → spec/lexer/literals_spec.rb} +20 -24
  35. data/{test/lexer/test_nesting.rb → spec/lexer/nesting_spec.rb} +11 -13
  36. data/spec/lexer/refcalls_spec.rb +54 -0
  37. data/spec/parser/all_spec.rb +31 -0
  38. data/spec/parser/alternation_spec.rb +88 -0
  39. data/{test/parser/test_anchors.rb → spec/parser/anchors_spec.rb} +7 -10
  40. data/spec/parser/conditionals_spec.rb +179 -0
  41. data/spec/parser/errors_spec.rb +51 -0
  42. data/spec/parser/escapes_spec.rb +132 -0
  43. data/spec/parser/free_space_spec.rb +130 -0
  44. data/spec/parser/groups_spec.rb +267 -0
  45. data/spec/parser/keep_spec.rb +19 -0
  46. data/spec/parser/posix_classes_spec.rb +27 -0
  47. data/spec/parser/properties_spec.rb +127 -0
  48. data/spec/parser/quantifiers_spec.rb +293 -0
  49. data/spec/parser/refcalls_spec.rb +237 -0
  50. data/spec/parser/set/intersections_spec.rb +127 -0
  51. data/spec/parser/set/ranges_spec.rb +111 -0
  52. data/spec/parser/sets_spec.rb +178 -0
  53. data/{test/parser/test_types.rb → spec/parser/types_spec.rb} +13 -20
  54. data/spec/scanner/all_spec.rb +18 -0
  55. data/{test/scanner/test_anchors.rb → spec/scanner/anchors_spec.rb} +8 -10
  56. data/{test/scanner/test_conditionals.rb → spec/scanner/conditionals_spec.rb} +49 -53
  57. data/spec/scanner/errors_spec.rb +90 -0
  58. data/{test/scanner/test_escapes.rb → spec/scanner/escapes_spec.rb} +8 -10
  59. data/{test/scanner/test_free_space.rb → spec/scanner/free_space_spec.rb} +48 -52
  60. data/{test/scanner/test_groups.rb → spec/scanner/groups_spec.rb} +33 -41
  61. data/spec/scanner/keep_spec.rb +33 -0
  62. data/{test/scanner/test_literals.rb → spec/scanner/literals_spec.rb} +8 -12
  63. data/{test/scanner/test_meta.rb → spec/scanner/meta_spec.rb} +8 -10
  64. data/{test/scanner/test_properties.rb → spec/scanner/properties_spec.rb} +14 -19
  65. data/{test/scanner/test_quantifiers.rb → spec/scanner/quantifiers_spec.rb} +7 -9
  66. data/{test/scanner/test_refcalls.rb → spec/scanner/refcalls_spec.rb} +9 -9
  67. data/{test/scanner/test_scripts.rb → spec/scanner/scripts_spec.rb} +8 -12
  68. data/{test/scanner/test_sets.rb → spec/scanner/sets_spec.rb} +14 -17
  69. data/spec/scanner/types_spec.rb +29 -0
  70. data/spec/scanner/unicode_blocks_spec.rb +28 -0
  71. data/spec/spec_helper.rb +14 -0
  72. data/{test → spec}/support/runner.rb +9 -8
  73. data/{test → spec}/support/warning_extractor.rb +5 -7
  74. data/spec/syntax/syntax_spec.rb +44 -0
  75. data/spec/syntax/syntax_token_map_spec.rb +23 -0
  76. data/spec/syntax/versions/1.8.6_spec.rb +38 -0
  77. data/spec/syntax/versions/1.9.1_spec.rb +23 -0
  78. data/spec/syntax/versions/1.9.3_spec.rb +22 -0
  79. data/spec/syntax/versions/2.0.0_spec.rb +28 -0
  80. data/spec/syntax/versions/2.2.0_spec.rb +22 -0
  81. data/spec/syntax/versions/aliases_spec.rb +119 -0
  82. data/spec/token/token_spec.rb +85 -0
  83. metadata +131 -140
  84. data/test/expression/test_all.rb +0 -12
  85. data/test/expression/test_base.rb +0 -90
  86. data/test/expression/test_clone.rb +0 -89
  87. data/test/expression/test_conditionals.rb +0 -113
  88. data/test/expression/test_free_space.rb +0 -35
  89. data/test/expression/test_set.rb +0 -84
  90. data/test/expression/test_strfregexp.rb +0 -230
  91. data/test/expression/test_subexpression.rb +0 -58
  92. data/test/expression/test_tests.rb +0 -99
  93. data/test/expression/test_to_h.rb +0 -59
  94. data/test/expression/test_to_s.rb +0 -104
  95. data/test/expression/test_traverse.rb +0 -161
  96. data/test/helpers.rb +0 -10
  97. data/test/lexer/test_all.rb +0 -41
  98. data/test/lexer/test_keep.rb +0 -24
  99. data/test/lexer/test_refcalls.rb +0 -56
  100. data/test/parser/set/test_intersections.rb +0 -127
  101. data/test/parser/set/test_ranges.rb +0 -111
  102. data/test/parser/test_all.rb +0 -64
  103. data/test/parser/test_alternation.rb +0 -92
  104. data/test/parser/test_conditionals.rb +0 -187
  105. data/test/parser/test_errors.rb +0 -63
  106. data/test/parser/test_escapes.rb +0 -134
  107. data/test/parser/test_free_space.rb +0 -139
  108. data/test/parser/test_groups.rb +0 -289
  109. data/test/parser/test_keep.rb +0 -21
  110. data/test/parser/test_posix_classes.rb +0 -27
  111. data/test/parser/test_properties.rb +0 -134
  112. data/test/parser/test_quantifiers.rb +0 -301
  113. data/test/parser/test_refcalls.rb +0 -186
  114. data/test/parser/test_sets.rb +0 -179
  115. data/test/scanner/test_all.rb +0 -38
  116. data/test/scanner/test_errors.rb +0 -91
  117. data/test/scanner/test_keep.rb +0 -35
  118. data/test/scanner/test_types.rb +0 -35
  119. data/test/scanner/test_unicode_blocks.rb +0 -30
  120. data/test/support/disable_autotest.rb +0 -8
  121. data/test/syntax/test_all.rb +0 -6
  122. data/test/syntax/test_syntax.rb +0 -61
  123. data/test/syntax/test_syntax_token_map.rb +0 -25
  124. data/test/syntax/versions/test_1.8.rb +0 -55
  125. data/test/syntax/versions/test_1.9.1.rb +0 -36
  126. data/test/syntax/versions/test_1.9.3.rb +0 -32
  127. data/test/syntax/versions/test_2.0.0.rb +0 -37
  128. data/test/syntax/versions/test_2.2.0.rb +0 -32
  129. data/test/syntax/versions/test_aliases.rb +0 -129
  130. data/test/syntax/versions/test_all.rb +0 -5
  131. data/test/test_all.rb +0 -5
  132. data/test/token/test_all.rb +0 -2
  133. data/test/token/test_token.rb +0 -107
@@ -0,0 +1,19 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe('Keep parsing') do
4
+ specify('parse keep') do
5
+ regexp = /ab\Kcd/
6
+ root = RP.parse(regexp)
7
+
8
+ expect(root[1]).to be_instance_of(Keep::Mark)
9
+ expect(root[1].text).to eq '\\K'
10
+ end
11
+
12
+ specify('parse keep nested') do
13
+ regexp = /(a\\\Kb)/
14
+ root = RP.parse(regexp)
15
+
16
+ expect(root[0][2]).to be_instance_of(Keep::Mark)
17
+ expect(root[0][2].text).to eq '\\K'
18
+ end
19
+ end
@@ -0,0 +1,27 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe('PosixClasse parsing') do
4
+ specify('parse posix class') do
5
+ root = RP.parse('[[:word:]]')
6
+ exp = root[0][0]
7
+
8
+ expect(exp).to be_instance_of(PosixClass)
9
+ expect(exp.type).to eq :posixclass
10
+ expect(exp.token).to eq :word
11
+ expect(exp.name).to eq 'word'
12
+ expect(exp.text).to eq '[:word:]'
13
+ expect(exp).not_to be_negative
14
+ end
15
+
16
+ specify('parse negative posix class') do
17
+ root = RP.parse('[[:^word:]]')
18
+ exp = root[0][0]
19
+
20
+ expect(exp).to be_instance_of(PosixClass)
21
+ expect(exp.type).to eq :nonposixclass
22
+ expect(exp.token).to eq :word
23
+ expect(exp.name).to eq 'word'
24
+ expect(exp.text).to eq '[:^word:]'
25
+ expect(exp).to be_negative
26
+ end
27
+ end
@@ -0,0 +1,127 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe('Property parsing') do
4
+ modes = %w[p P]
5
+ example_props = [
6
+ 'Alnum',
7
+ 'Any',
8
+ 'Age=1.1',
9
+ 'Dash',
10
+ 'di',
11
+ 'Default_Ignorable_Code_Point',
12
+ 'Math',
13
+ 'Noncharacter-Code_Point', # test dash
14
+ 'sd',
15
+ 'Soft Dotted', # test whitespace
16
+ 'sterm',
17
+ 'xidc',
18
+ 'XID_Continue',
19
+ 'Emoji',
20
+ 'InChessSymbols'
21
+ ]
22
+
23
+ modes.each do |mode|
24
+ token_type = mode == 'p' ? :property : :nonproperty
25
+
26
+ example_props.each do |property|
27
+ specify("parse_#{token_type}_#{property}") do
28
+ t = RP.parse("ab\\#{mode}{#{property}}", '*')
29
+
30
+ expect(t.expressions.last).to be_a(UnicodeProperty::Base)
31
+
32
+ expect(t.expressions.last.type).to eq token_type
33
+ expect(t.expressions.last.name).to eq property
34
+ end
35
+ end
36
+ end
37
+
38
+ specify('parse all properties of current ruby') do
39
+ unsupported = RegexpPropertyValues.all_for_current_ruby.reject do |prop|
40
+ begin
41
+ RP.parse("\\p{#{prop}}")
42
+ rescue SyntaxError, StandardError
43
+ nil
44
+ end
45
+ end
46
+ expect(unsupported).to be_empty
47
+ end
48
+
49
+ specify('parse property negative') do
50
+ t = RP.parse('ab\\p{L}cd', 'ruby/1.9')
51
+
52
+ expect(t[1]).not_to be_negative
53
+ end
54
+
55
+ specify('parse nonproperty negative') do
56
+ t = RP.parse('ab\\P{L}cd', 'ruby/1.9')
57
+
58
+ expect(t[1]).to be_negative
59
+ end
60
+
61
+ specify('parse caret nonproperty negative') do
62
+ t = RP.parse('ab\\p{^L}cd', 'ruby/1.9')
63
+
64
+ expect(t[1]).to be_negative
65
+ end
66
+
67
+ specify('parse double negated property negative') do
68
+ t = RP.parse('ab\\P{^L}cd', 'ruby/1.9')
69
+
70
+ expect(t[1]).not_to be_negative
71
+ end
72
+
73
+ specify('parse property shortcut') do
74
+ expect(RP.parse('\\p{mark}')[0].shortcut).to eq 'm'
75
+ expect(RP.parse('\\p{sc}')[0].shortcut).to eq 'sc'
76
+ expect(RP.parse('\\p{in_bengali}')[0].shortcut).to be_nil
77
+ end
78
+
79
+ specify('parse property age') do
80
+ t = RP.parse('ab\\p{age=5.2}cd', 'ruby/1.9')
81
+
82
+ expect(t[1]).to be_a(UnicodeProperty::Age)
83
+ end
84
+
85
+ specify('parse property derived') do
86
+ t = RP.parse('ab\\p{Math}cd', 'ruby/1.9')
87
+
88
+ expect(t[1]).to be_a(UnicodeProperty::Derived)
89
+ end
90
+
91
+ specify('parse property script') do
92
+ t = RP.parse('ab\\p{Hiragana}cd', 'ruby/1.9')
93
+
94
+ expect(t[1]).to be_a(UnicodeProperty::Script)
95
+ end
96
+
97
+ specify('parse property script V1 9 3') do
98
+ t = RP.parse('ab\\p{Brahmi}cd', 'ruby/1.9.3')
99
+
100
+ expect(t[1]).to be_a(UnicodeProperty::Script)
101
+ end
102
+
103
+ specify('parse property script V2 2 0') do
104
+ t = RP.parse('ab\\p{Caucasian_Albanian}cd', 'ruby/2.2')
105
+
106
+ expect(t[1]).to be_a(UnicodeProperty::Script)
107
+ end
108
+
109
+ specify('parse property block') do
110
+ t = RP.parse('ab\\p{InArmenian}cd', 'ruby/1.9')
111
+
112
+ expect(t[1]).to be_a(UnicodeProperty::Block)
113
+ end
114
+
115
+ specify('parse property following literal') do
116
+ t = RP.parse('ab\\p{Lu}cd', 'ruby/1.9')
117
+
118
+ expect(t[2]).to be_a(Literal)
119
+ end
120
+
121
+ specify('parse abandoned newline property') do
122
+ t = RP.parse('\\p{newline}', 'ruby/1.9')
123
+ expect(t.expressions.last).to be_a(UnicodeProperty::Base)
124
+
125
+ expect { RP.parse('\\p{newline}', 'ruby/2.0') }.to raise_error(Regexp::Syntax::NotImplementedError)
126
+ end
127
+ end
@@ -0,0 +1,293 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe('Quantifier parsing') do
4
+ specify('parse zero or one greedy') do
5
+ root = RP.parse('a?bc')
6
+ exp = root.expressions.first
7
+
8
+ expect(exp).to be_quantified
9
+ expect(exp.quantifier.token).to eq :zero_or_one
10
+ expect(exp.quantifier.min).to eq 0
11
+ expect(exp.quantifier.max).to eq 1
12
+ expect(exp.quantifier.mode).to eq :greedy
13
+ expect(exp.quantifier).to be_greedy
14
+ expect(exp).to be_greedy
15
+
16
+ expect(exp.quantifier).not_to be_reluctant
17
+ expect(exp).not_to be_reluctant
18
+ expect(exp.quantifier).not_to be_possessive
19
+ expect(exp).not_to be_possessive
20
+ end
21
+
22
+ specify('parse zero or one reluctant') do
23
+ root = RP.parse('a??bc')
24
+ exp = root.expressions.first
25
+
26
+ expect(exp).to be_quantified
27
+ expect(exp.quantifier.token).to eq :zero_or_one
28
+ expect(exp.quantifier.min).to eq 0
29
+ expect(exp.quantifier.max).to eq 1
30
+ expect(exp.quantifier.mode).to eq :reluctant
31
+ expect(exp.quantifier).to be_reluctant
32
+ expect(exp).to be_reluctant
33
+
34
+ expect(exp.quantifier).not_to be_greedy
35
+ expect(exp).not_to be_greedy
36
+ expect(exp.quantifier).not_to be_possessive
37
+ expect(exp).not_to be_possessive
38
+ end
39
+
40
+ specify('parse zero or one possessive') do
41
+ root = RP.parse('a?+bc', 'ruby/1.9')
42
+ exp = root.expressions.first
43
+
44
+ expect(exp).to be_quantified
45
+ expect(exp.quantifier.token).to eq :zero_or_one
46
+ expect(exp.quantifier.min).to eq 0
47
+ expect(exp.quantifier.max).to eq 1
48
+ expect(exp.quantifier.mode).to eq :possessive
49
+ expect(exp.quantifier).to be_possessive
50
+ expect(exp).to be_possessive
51
+
52
+ expect(exp.quantifier).not_to be_greedy
53
+ expect(exp).not_to be_greedy
54
+ expect(exp.quantifier).not_to be_reluctant
55
+ expect(exp).not_to be_reluctant
56
+ end
57
+
58
+ specify('parse zero or more greedy') do
59
+ root = RP.parse('a*bc')
60
+ exp = root.expressions.first
61
+
62
+ expect(exp).to be_quantified
63
+ expect(exp.quantifier.token).to eq :zero_or_more
64
+ expect(exp.quantifier.min).to eq 0
65
+ expect(exp.quantifier.max).to eq(-1)
66
+ expect(exp.quantifier.mode).to eq :greedy
67
+ expect(exp.quantifier).to be_greedy
68
+ expect(exp).to be_greedy
69
+ end
70
+
71
+ specify('parse zero or more reluctant') do
72
+ root = RP.parse('a*?bc')
73
+ exp = root.expressions.first
74
+
75
+ expect(exp).to be_quantified
76
+ expect(exp.quantifier.token).to eq :zero_or_more
77
+ expect(exp.quantifier.min).to eq 0
78
+ expect(exp.quantifier.max).to eq(-1)
79
+ expect(exp.quantifier.mode).to eq :reluctant
80
+ expect(exp.quantifier).to be_reluctant
81
+ expect(exp).to be_reluctant
82
+ end
83
+
84
+ specify('parse zero or more possessive') do
85
+ root = RP.parse('a*+bc', 'ruby/1.9')
86
+ exp = root.expressions.first
87
+
88
+ expect(exp).to be_quantified
89
+ expect(exp.quantifier.token).to eq :zero_or_more
90
+ expect(exp.quantifier.min).to eq 0
91
+ expect(exp.quantifier.max).to eq(-1)
92
+ expect(exp.quantifier.mode).to eq :possessive
93
+ expect(exp.quantifier).to be_possessive
94
+ expect(exp).to be_possessive
95
+ end
96
+
97
+ specify('parse one or more greedy') do
98
+ root = RP.parse('a+bc')
99
+ exp = root.expressions.first
100
+
101
+ expect(exp).to be_quantified
102
+ expect(exp.quantifier.token).to eq :one_or_more
103
+ expect(exp.quantifier.min).to eq 1
104
+ expect(exp.quantifier.max).to eq(-1)
105
+ expect(exp.quantifier.mode).to eq :greedy
106
+ expect(exp.quantifier).to be_greedy
107
+ expect(exp).to be_greedy
108
+ end
109
+
110
+ specify('parse one or more reluctant') do
111
+ root = RP.parse('a+?bc')
112
+ exp = root.expressions.first
113
+
114
+ expect(exp).to be_quantified
115
+ expect(exp.quantifier.token).to eq :one_or_more
116
+ expect(exp.quantifier.min).to eq 1
117
+ expect(exp.quantifier.max).to eq(-1)
118
+ expect(exp.quantifier.mode).to eq :reluctant
119
+ expect(exp.quantifier).to be_reluctant
120
+ expect(exp).to be_reluctant
121
+ end
122
+
123
+ specify('parse one or more possessive') do
124
+ root = RP.parse('a++bc', 'ruby/1.9')
125
+ exp = root.expressions.first
126
+
127
+ expect(exp).to be_quantified
128
+ expect(exp.quantifier.token).to eq :one_or_more
129
+ expect(exp.quantifier.min).to eq 1
130
+ expect(exp.quantifier.max).to eq(-1)
131
+ expect(exp.quantifier.mode).to eq :possessive
132
+ expect(exp.quantifier).to be_possessive
133
+ expect(exp).to be_possessive
134
+ end
135
+
136
+ specify('parse intervals min max greedy') do
137
+ root = RP.parse('a{2,4}bc')
138
+ exp = root.expressions.first
139
+
140
+ expect(exp).to be_quantified
141
+ expect(exp.quantifier.token).to eq :interval
142
+ expect(exp.quantifier.min).to eq 2
143
+ expect(exp.quantifier.max).to eq 4
144
+ expect(exp.quantifier.mode).to eq :greedy
145
+ expect(exp.quantifier).to be_greedy
146
+ expect(exp).to be_greedy
147
+ end
148
+
149
+ specify('parse intervals min max reluctant') do
150
+ root = RP.parse('a{3,5}?bc')
151
+ exp = root.expressions.first
152
+
153
+ expect(exp).to be_quantified
154
+ expect(exp.quantifier.token).to eq :interval
155
+ expect(exp.quantifier.min).to eq 3
156
+ expect(exp.quantifier.max).to eq 5
157
+ expect(exp.quantifier.mode).to eq :reluctant
158
+ expect(exp.quantifier).to be_reluctant
159
+ expect(exp).to be_reluctant
160
+ end
161
+
162
+ specify('parse intervals min max possessive') do
163
+ root = RP.parse('a{2,4}+bc', 'ruby/1.9')
164
+ exp = root.expressions.first
165
+
166
+ expect(exp).to be_quantified
167
+ expect(exp.quantifier.token).to eq :interval
168
+ expect(exp.quantifier.min).to eq 2
169
+ expect(exp.quantifier.max).to eq 4
170
+ expect(exp.quantifier.mode).to eq :possessive
171
+ expect(exp.quantifier).to be_possessive
172
+ expect(exp).to be_possessive
173
+ end
174
+
175
+ specify('parse intervals min only greedy') do
176
+ root = RP.parse('a{2,}bc')
177
+ exp = root.expressions.first
178
+
179
+ expect(exp).to be_quantified
180
+ expect(exp.quantifier.token).to eq :interval
181
+ expect(exp.quantifier.min).to eq 2
182
+ expect(exp.quantifier.max).to eq(-1)
183
+ expect(exp.quantifier.mode).to eq :greedy
184
+ expect(exp.quantifier).to be_greedy
185
+ expect(exp).to be_greedy
186
+ end
187
+
188
+ specify('parse intervals min only reluctant') do
189
+ root = RP.parse('a{2,}?bc')
190
+ exp = root.expressions.first
191
+
192
+ expect(exp).to be_quantified
193
+ expect(exp.quantifier.token).to eq :interval
194
+ expect(exp.quantifier.text).to eq '{2,}?'
195
+ expect(exp.quantifier.min).to eq 2
196
+ expect(exp.quantifier.max).to eq(-1)
197
+ expect(exp.quantifier.mode).to eq :reluctant
198
+ expect(exp.quantifier).to be_reluctant
199
+ expect(exp).to be_reluctant
200
+ end
201
+
202
+ specify('parse intervals min only possessive') do
203
+ root = RP.parse('a{3,}+bc', 'ruby/1.9')
204
+ exp = root.expressions.first
205
+
206
+ expect(exp).to be_quantified
207
+ expect(exp.quantifier.token).to eq :interval
208
+ expect(exp.quantifier.text).to eq '{3,}+'
209
+ expect(exp.quantifier.min).to eq 3
210
+ expect(exp.quantifier.max).to eq(-1)
211
+ expect(exp.quantifier.mode).to eq :possessive
212
+ expect(exp.quantifier).to be_possessive
213
+ expect(exp).to be_possessive
214
+ end
215
+
216
+ specify('parse intervals max only greedy') do
217
+ root = RP.parse('a{,2}bc')
218
+ exp = root.expressions.first
219
+
220
+ expect(exp).to be_quantified
221
+ expect(exp.quantifier.token).to eq :interval
222
+ expect(exp.quantifier.min).to eq 0
223
+ expect(exp.quantifier.max).to eq 2
224
+ expect(exp.quantifier.mode).to eq :greedy
225
+ expect(exp.quantifier).to be_greedy
226
+ expect(exp).to be_greedy
227
+ end
228
+
229
+ specify('parse intervals max only reluctant') do
230
+ root = RP.parse('a{,4}?bc')
231
+ exp = root.expressions.first
232
+
233
+ expect(exp).to be_quantified
234
+ expect(exp.quantifier.token).to eq :interval
235
+ expect(exp.quantifier.min).to eq 0
236
+ expect(exp.quantifier.max).to eq 4
237
+ expect(exp.quantifier.mode).to eq :reluctant
238
+ expect(exp.quantifier).to be_reluctant
239
+ expect(exp).to be_reluctant
240
+ end
241
+
242
+ specify('parse intervals max only possessive') do
243
+ root = RP.parse('a{,3}+bc', 'ruby/1.9')
244
+ exp = root.expressions.first
245
+
246
+ expect(exp).to be_quantified
247
+ expect(exp.quantifier.token).to eq :interval
248
+ expect(exp.quantifier.min).to eq 0
249
+ expect(exp.quantifier.max).to eq 3
250
+ expect(exp.quantifier.mode).to eq :possessive
251
+ expect(exp.quantifier).to be_possessive
252
+ expect(exp).to be_possessive
253
+ end
254
+
255
+ specify('parse intervals exact greedy') do
256
+ root = RP.parse('a{2}bc')
257
+ exp = root.expressions.first
258
+
259
+ expect(exp).to be_quantified
260
+ expect(exp.quantifier.token).to eq :interval
261
+ expect(exp.quantifier.min).to eq 2
262
+ expect(exp.quantifier.max).to eq 2
263
+ expect(exp.quantifier.mode).to eq :greedy
264
+ expect(exp.quantifier).to be_greedy
265
+ expect(exp).to be_greedy
266
+ end
267
+
268
+ specify('parse intervals exact reluctant') do
269
+ root = RP.parse('a{3}?bc')
270
+ exp = root.expressions.first
271
+
272
+ expect(exp).to be_quantified
273
+ expect(exp.quantifier.token).to eq :interval
274
+ expect(exp.quantifier.min).to eq 3
275
+ expect(exp.quantifier.max).to eq 3
276
+ expect(exp.quantifier.mode).to eq :reluctant
277
+ expect(exp.quantifier).to be_reluctant
278
+ expect(exp).to be_reluctant
279
+ end
280
+
281
+ specify('parse intervals exact possessive') do
282
+ root = RP.parse('a{3}+bc', 'ruby/1.9')
283
+ exp = root.expressions.first
284
+
285
+ expect(exp).to be_quantified
286
+ expect(exp.quantifier.token).to eq :interval
287
+ expect(exp.quantifier.min).to eq 3
288
+ expect(exp.quantifier.max).to eq 3
289
+ expect(exp.quantifier.mode).to eq :possessive
290
+ expect(exp.quantifier).to be_possessive
291
+ expect(exp).to be_possessive
292
+ end
293
+ end