regexp_parser 1.5.0 → 1.8.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 (87) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +59 -0
  3. data/Gemfile +3 -3
  4. data/README.md +14 -6
  5. data/Rakefile +3 -4
  6. data/lib/regexp_parser/expression.rb +6 -43
  7. data/lib/regexp_parser/expression/classes/conditional.rb +3 -2
  8. data/lib/regexp_parser/expression/classes/escape.rb +0 -4
  9. data/lib/regexp_parser/expression/methods/match.rb +13 -0
  10. data/lib/regexp_parser/expression/methods/match_length.rb +1 -1
  11. data/lib/regexp_parser/expression/methods/options.rb +35 -0
  12. data/lib/regexp_parser/expression/methods/strfregexp.rb +0 -1
  13. data/lib/regexp_parser/expression/methods/tests.rb +6 -15
  14. data/lib/regexp_parser/expression/methods/traverse.rb +3 -1
  15. data/lib/regexp_parser/expression/sequence.rb +3 -2
  16. data/lib/regexp_parser/expression/sequence_operation.rb +2 -6
  17. data/lib/regexp_parser/lexer.rb +4 -25
  18. data/lib/regexp_parser/parser.rb +40 -33
  19. data/lib/regexp_parser/scanner.rb +1208 -1353
  20. data/lib/regexp_parser/scanner/char_type.rl +0 -3
  21. data/lib/regexp_parser/scanner/properties/long.yml +15 -1
  22. data/lib/regexp_parser/scanner/properties/short.yml +5 -0
  23. data/lib/regexp_parser/scanner/scanner.rl +116 -202
  24. data/lib/regexp_parser/syntax/tokens/unicode_property.rb +30 -0
  25. data/lib/regexp_parser/syntax/versions/2.6.2.rb +10 -0
  26. data/lib/regexp_parser/syntax/versions/2.6.3.rb +10 -0
  27. data/lib/regexp_parser/version.rb +1 -1
  28. data/spec/expression/base_spec.rb +14 -0
  29. data/spec/expression/methods/match_length_spec.rb +20 -0
  30. data/spec/expression/methods/match_spec.rb +25 -0
  31. data/spec/expression/methods/tests_spec.rb +2 -0
  32. data/spec/expression/methods/traverse_spec.rb +21 -0
  33. data/spec/expression/options_spec.rb +128 -0
  34. data/spec/expression/root_spec.rb +9 -0
  35. data/spec/expression/sequence_spec.rb +9 -0
  36. data/spec/lexer/conditionals_spec.rb +49 -119
  37. data/spec/lexer/delimiters_spec.rb +68 -0
  38. data/spec/lexer/escapes_spec.rb +8 -32
  39. data/spec/lexer/keep_spec.rb +5 -17
  40. data/spec/lexer/literals_spec.rb +73 -110
  41. data/spec/lexer/nesting_spec.rb +86 -117
  42. data/spec/lexer/refcalls_spec.rb +51 -50
  43. data/spec/parser/all_spec.rb +13 -1
  44. data/spec/parser/anchors_spec.rb +9 -23
  45. data/spec/parser/conditionals_spec.rb +9 -9
  46. data/spec/parser/errors_spec.rb +22 -43
  47. data/spec/parser/escapes_spec.rb +33 -44
  48. data/spec/parser/free_space_spec.rb +25 -4
  49. data/spec/parser/groups_spec.rb +98 -257
  50. data/spec/parser/keep_spec.rb +2 -15
  51. data/spec/parser/options_spec.rb +28 -0
  52. data/spec/parser/posix_classes_spec.rb +5 -24
  53. data/spec/parser/properties_spec.rb +42 -54
  54. data/spec/parser/quantifiers_spec.rb +42 -283
  55. data/spec/parser/refcalls_spec.rb +60 -185
  56. data/spec/parser/set/intersections_spec.rb +17 -17
  57. data/spec/parser/set/ranges_spec.rb +17 -17
  58. data/spec/parser/sets_spec.rb +5 -5
  59. data/spec/parser/types_spec.rb +11 -36
  60. data/spec/scanner/anchors_spec.rb +13 -28
  61. data/spec/scanner/conditionals_spec.rb +121 -173
  62. data/spec/scanner/delimiters_spec.rb +52 -0
  63. data/spec/scanner/errors_spec.rb +64 -87
  64. data/spec/scanner/escapes_spec.rb +53 -50
  65. data/spec/scanner/free_space_spec.rb +102 -165
  66. data/spec/scanner/groups_spec.rb +45 -64
  67. data/spec/scanner/keep_spec.rb +5 -28
  68. data/spec/scanner/literals_spec.rb +45 -81
  69. data/spec/scanner/meta_spec.rb +13 -33
  70. data/spec/scanner/options_spec.rb +36 -0
  71. data/spec/scanner/properties_spec.rb +43 -286
  72. data/spec/scanner/quantifiers_spec.rb +13 -28
  73. data/spec/scanner/refcalls_spec.rb +32 -48
  74. data/spec/scanner/sets_spec.rb +88 -102
  75. data/spec/scanner/types_spec.rb +10 -25
  76. data/spec/spec_helper.rb +1 -0
  77. data/spec/support/shared_examples.rb +77 -0
  78. data/spec/syntax/syntax_spec.rb +4 -0
  79. data/spec/syntax/versions/1.8.6_spec.rb +12 -33
  80. data/spec/syntax/versions/1.9.1_spec.rb +5 -18
  81. data/spec/syntax/versions/1.9.3_spec.rb +4 -17
  82. data/spec/syntax/versions/2.0.0_spec.rb +8 -23
  83. data/spec/syntax/versions/2.2.0_spec.rb +4 -17
  84. data/spec/syntax/versions/aliases_spec.rb +27 -109
  85. metadata +28 -10
  86. data/spec/scanner/scripts_spec.rb +0 -49
  87. data/spec/scanner/unicode_blocks_spec.rb +0 -28
@@ -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
@@ -1,19 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
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
4
+ include_examples 'parse', /ab\Kcd/, 1 => [:keep, :mark, Keep::Mark, text: '\K']
5
+ include_examples 'parse', /(a\K)/, [0, 1] => [:keep, :mark, Keep::Mark, text: '\K']
19
6
  end
@@ -0,0 +1,28 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe('passing options to parse') do
4
+ it 'raises if if parsing from a Regexp and options are passed' do
5
+ expect { RP.parse(/a+/, options: ::Regexp::EXTENDED) }.to raise_error(
6
+ ArgumentError,
7
+ 'options cannot be supplied unless parsing a String'
8
+ )
9
+ end
10
+
11
+ it 'sets options if parsing from a String' do
12
+ root = RP.parse('a+', options: ::Regexp::MULTILINE | ::Regexp::EXTENDED)
13
+
14
+ expect(root.options).to eq(m: true, x: true)
15
+ end
16
+
17
+ it 'allows options to not be supplied when parsing from a Regexp' do
18
+ root = RP.parse(/a+/ix)
19
+
20
+ expect(root.options).to eq(i: true, x: true)
21
+ end
22
+
23
+ it 'has an empty option-hash when parsing from a String and passing no options' do
24
+ root = RP.parse('a+')
25
+
26
+ expect(root.options).to be_empty
27
+ end
28
+ end
@@ -1,27 +1,8 @@
1
1
  require 'spec_helper'
2
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
3
+ RSpec.describe('PosixClass parsing') do
4
+ include_examples 'parse', /[[:word:]]/, [0, 0] => [:posixclass, :word, PosixClass,
5
+ name: 'word', text: '[:word:]', negative?: false]
6
+ include_examples 'parse', /[[:^word:]]/, [0, 0] => [:nonposixclass, :word, PosixClass,
7
+ name: 'word', text: '[:^word:]', negative?: true]
27
8
  end
@@ -1,7 +1,6 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  RSpec.describe('Property parsing') do
4
- modes = %w[p P]
5
4
  example_props = [
6
5
  'Alnum',
7
6
  'Any',
@@ -20,108 +19,97 @@ RSpec.describe('Property parsing') do
20
19
  'InChessSymbols'
21
20
  ]
22
21
 
23
- modes.each do |mode|
24
- token_type = mode == 'p' ? :property : :nonproperty
22
+ example_props.each do |name|
23
+ it("parses property #{name}") do
24
+ exp = RP.parse("ab\\p{#{name}}", '*').last
25
25
 
26
- example_props.each do |property|
27
- specify("parse_#{token_type}_#{property}") do
28
- t = RP.parse("ab\\#{mode}{#{property}}", '*')
26
+ expect(exp).to be_a(UnicodeProperty::Base)
27
+ expect(exp.type).to eq :property
28
+ expect(exp.name).to eq name
29
+ end
29
30
 
30
- expect(t.expressions.last).to be_a(UnicodeProperty::Base)
31
+ it("parses nonproperty #{name}") do
32
+ exp = RP.parse("ab\\P{#{name}}", '*').last
31
33
 
32
- expect(t.expressions.last.type).to eq token_type
33
- expect(t.expressions.last.name).to eq property
34
- end
34
+ expect(exp).to be_a(UnicodeProperty::Base)
35
+ expect(exp.type).to eq :nonproperty
36
+ expect(exp.name).to eq name
35
37
  end
36
38
  end
37
39
 
38
40
  specify('parse all properties of current ruby') do
39
41
  unsupported = RegexpPropertyValues.all_for_current_ruby.reject do |prop|
40
- begin
41
- RP.parse("\\p{#{prop}}")
42
- rescue SyntaxError, StandardError
43
- nil
44
- end
42
+ RP.parse("\\p{#{prop}}") rescue false
45
43
  end
46
44
  expect(unsupported).to be_empty
47
45
  end
48
46
 
49
47
  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
48
+ root = RP.parse('ab\p{L}cd', 'ruby/1.9')
49
+ expect(root[1]).not_to be_negative
53
50
  end
54
51
 
55
52
  specify('parse nonproperty negative') do
56
- t = RP.parse('ab\\P{L}cd', 'ruby/1.9')
57
-
58
- expect(t[1]).to be_negative
53
+ root = RP.parse('ab\P{L}cd', 'ruby/1.9')
54
+ expect(root[1]).to be_negative
59
55
  end
60
56
 
61
57
  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
58
+ root = RP.parse('ab\p{^L}cd', 'ruby/1.9')
59
+ expect(root[1]).to be_negative
65
60
  end
66
61
 
67
62
  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
63
+ root = RP.parse('ab\P{^L}cd', 'ruby/1.9')
64
+ expect(root[1]).not_to be_negative
71
65
  end
72
66
 
73
67
  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
68
+ expect(RP.parse('\p{lowercase_letter}')[0].shortcut).to eq 'll'
69
+ expect(RP.parse('\p{sc}')[0].shortcut).to eq 'sc'
70
+ expect(RP.parse('\p{in_bengali}')[0].shortcut).to be_nil
77
71
  end
78
72
 
79
73
  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)
74
+ root = RP.parse('ab\p{age=5.2}cd', 'ruby/1.9')
75
+ expect(root[1]).to be_a(UnicodeProperty::Age)
83
76
  end
84
77
 
85
78
  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)
79
+ root = RP.parse('ab\p{Math}cd', 'ruby/1.9')
80
+ expect(root[1]).to be_a(UnicodeProperty::Derived)
89
81
  end
90
82
 
91
83
  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)
84
+ root = RP.parse('ab\p{Hiragana}cd', 'ruby/1.9')
85
+ expect(root[1]).to be_a(UnicodeProperty::Script)
95
86
  end
96
87
 
97
88
  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)
89
+ root = RP.parse('ab\p{Brahmi}cd', 'ruby/1.9.3')
90
+ expect(root[1]).to be_a(UnicodeProperty::Script)
101
91
  end
102
92
 
103
93
  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)
94
+ root = RP.parse('ab\p{Caucasian_Albanian}cd', 'ruby/2.2')
95
+ expect(root[1]).to be_a(UnicodeProperty::Script)
107
96
  end
108
97
 
109
98
  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)
99
+ root = RP.parse('ab\p{InArmenian}cd', 'ruby/1.9')
100
+ expect(root[1]).to be_a(UnicodeProperty::Block)
113
101
  end
114
102
 
115
103
  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)
104
+ root = RP.parse('ab\p{Lu}cd', 'ruby/1.9')
105
+ expect(root[2]).to be_a(Literal)
119
106
  end
120
107
 
121
108
  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)
109
+ root = RP.parse('\p{newline}', 'ruby/1.9')
110
+ expect(root.expressions.last).to be_a(UnicodeProperty::Base)
124
111
 
125
- expect { RP.parse('\\p{newline}', 'ruby/2.0') }.to raise_error(Regexp::Syntax::NotImplementedError)
112
+ expect { RP.parse('\p{newline}', 'ruby/2.0') }
113
+ .to raise_error(Regexp::Syntax::NotImplementedError)
126
114
  end
127
115
  end