regexp_parser 1.4.0 → 1.7.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 (171) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +66 -1
  3. data/Gemfile +3 -3
  4. data/README.md +11 -18
  5. data/Rakefile +3 -4
  6. data/lib/regexp_parser/expression.rb +28 -53
  7. data/lib/regexp_parser/expression/classes/backref.rb +18 -10
  8. data/lib/regexp_parser/expression/classes/conditional.rb +7 -2
  9. data/lib/regexp_parser/expression/classes/escape.rb +0 -4
  10. data/lib/regexp_parser/expression/classes/group.rb +4 -2
  11. data/lib/regexp_parser/expression/classes/keep.rb +1 -3
  12. data/lib/regexp_parser/expression/methods/match.rb +13 -0
  13. data/lib/regexp_parser/expression/methods/match_length.rb +172 -0
  14. data/lib/regexp_parser/expression/methods/options.rb +35 -0
  15. data/lib/regexp_parser/expression/methods/strfregexp.rb +0 -1
  16. data/lib/regexp_parser/expression/methods/tests.rb +6 -15
  17. data/lib/regexp_parser/expression/methods/traverse.rb +3 -1
  18. data/lib/regexp_parser/expression/quantifier.rb +2 -2
  19. data/lib/regexp_parser/expression/sequence.rb +3 -6
  20. data/lib/regexp_parser/expression/sequence_operation.rb +2 -6
  21. data/lib/regexp_parser/expression/subexpression.rb +3 -5
  22. data/lib/regexp_parser/lexer.rb +30 -44
  23. data/lib/regexp_parser/parser.rb +47 -24
  24. data/lib/regexp_parser/scanner.rb +1228 -1367
  25. data/lib/regexp_parser/scanner/char_type.rl +0 -3
  26. data/lib/regexp_parser/scanner/properties/long.yml +15 -1
  27. data/lib/regexp_parser/scanner/properties/short.yml +5 -0
  28. data/lib/regexp_parser/scanner/scanner.rl +101 -194
  29. data/lib/regexp_parser/syntax/tokens.rb +2 -10
  30. data/lib/regexp_parser/syntax/tokens/unicode_property.rb +30 -0
  31. data/lib/regexp_parser/syntax/versions/2.6.2.rb +10 -0
  32. data/lib/regexp_parser/syntax/versions/2.6.3.rb +10 -0
  33. data/lib/regexp_parser/version.rb +1 -1
  34. data/regexp_parser.gemspec +2 -2
  35. data/spec/expression/base_spec.rb +94 -0
  36. data/spec/expression/clone_spec.rb +120 -0
  37. data/spec/expression/conditional_spec.rb +89 -0
  38. data/spec/expression/free_space_spec.rb +27 -0
  39. data/spec/expression/methods/match_length_spec.rb +161 -0
  40. data/spec/expression/methods/match_spec.rb +25 -0
  41. data/spec/expression/methods/strfregexp_spec.rb +224 -0
  42. data/spec/expression/methods/tests_spec.rb +99 -0
  43. data/spec/expression/methods/traverse_spec.rb +161 -0
  44. data/spec/expression/options_spec.rb +128 -0
  45. data/spec/expression/root_spec.rb +9 -0
  46. data/spec/expression/sequence_spec.rb +9 -0
  47. data/spec/expression/subexpression_spec.rb +50 -0
  48. data/spec/expression/to_h_spec.rb +26 -0
  49. data/spec/expression/to_s_spec.rb +100 -0
  50. data/spec/lexer/all_spec.rb +22 -0
  51. data/spec/lexer/conditionals_spec.rb +53 -0
  52. data/spec/lexer/delimiters_spec.rb +68 -0
  53. data/spec/lexer/escapes_spec.rb +14 -0
  54. data/spec/lexer/keep_spec.rb +10 -0
  55. data/spec/lexer/literals_spec.rb +89 -0
  56. data/spec/lexer/nesting_spec.rb +99 -0
  57. data/spec/lexer/refcalls_spec.rb +55 -0
  58. data/spec/parser/all_spec.rb +43 -0
  59. data/spec/parser/alternation_spec.rb +88 -0
  60. data/spec/parser/anchors_spec.rb +17 -0
  61. data/spec/parser/conditionals_spec.rb +179 -0
  62. data/spec/parser/errors_spec.rb +30 -0
  63. data/spec/parser/escapes_spec.rb +121 -0
  64. data/spec/parser/free_space_spec.rb +130 -0
  65. data/spec/parser/groups_spec.rb +108 -0
  66. data/spec/parser/keep_spec.rb +6 -0
  67. data/spec/parser/posix_classes_spec.rb +8 -0
  68. data/spec/parser/properties_spec.rb +115 -0
  69. data/spec/parser/quantifiers_spec.rb +52 -0
  70. data/spec/parser/refcalls_spec.rb +112 -0
  71. data/spec/parser/set/intersections_spec.rb +127 -0
  72. data/spec/parser/set/ranges_spec.rb +111 -0
  73. data/spec/parser/sets_spec.rb +178 -0
  74. data/spec/parser/types_spec.rb +18 -0
  75. data/spec/scanner/all_spec.rb +18 -0
  76. data/spec/scanner/anchors_spec.rb +21 -0
  77. data/spec/scanner/conditionals_spec.rb +128 -0
  78. data/spec/scanner/delimiters_spec.rb +52 -0
  79. data/spec/scanner/errors_spec.rb +67 -0
  80. data/spec/scanner/escapes_spec.rb +53 -0
  81. data/spec/scanner/free_space_spec.rb +133 -0
  82. data/spec/scanner/groups_spec.rb +52 -0
  83. data/spec/scanner/keep_spec.rb +10 -0
  84. data/spec/scanner/literals_spec.rb +49 -0
  85. data/spec/scanner/meta_spec.rb +18 -0
  86. data/spec/scanner/properties_spec.rb +64 -0
  87. data/spec/scanner/quantifiers_spec.rb +20 -0
  88. data/spec/scanner/refcalls_spec.rb +36 -0
  89. data/spec/scanner/sets_spec.rb +102 -0
  90. data/spec/scanner/types_spec.rb +14 -0
  91. data/spec/spec_helper.rb +15 -0
  92. data/{test → spec}/support/runner.rb +9 -8
  93. data/spec/support/shared_examples.rb +77 -0
  94. data/{test → spec}/support/warning_extractor.rb +5 -7
  95. data/spec/syntax/syntax_spec.rb +48 -0
  96. data/spec/syntax/syntax_token_map_spec.rb +23 -0
  97. data/spec/syntax/versions/1.8.6_spec.rb +17 -0
  98. data/spec/syntax/versions/1.9.1_spec.rb +10 -0
  99. data/spec/syntax/versions/1.9.3_spec.rb +9 -0
  100. data/spec/syntax/versions/2.0.0_spec.rb +13 -0
  101. data/spec/syntax/versions/2.2.0_spec.rb +9 -0
  102. data/spec/syntax/versions/aliases_spec.rb +37 -0
  103. data/spec/token/token_spec.rb +85 -0
  104. metadata +149 -144
  105. data/test/expression/test_all.rb +0 -12
  106. data/test/expression/test_base.rb +0 -90
  107. data/test/expression/test_clone.rb +0 -89
  108. data/test/expression/test_conditionals.rb +0 -113
  109. data/test/expression/test_free_space.rb +0 -35
  110. data/test/expression/test_set.rb +0 -84
  111. data/test/expression/test_strfregexp.rb +0 -230
  112. data/test/expression/test_subexpression.rb +0 -58
  113. data/test/expression/test_tests.rb +0 -99
  114. data/test/expression/test_to_h.rb +0 -59
  115. data/test/expression/test_to_s.rb +0 -104
  116. data/test/expression/test_traverse.rb +0 -161
  117. data/test/helpers.rb +0 -10
  118. data/test/lexer/test_all.rb +0 -41
  119. data/test/lexer/test_conditionals.rb +0 -127
  120. data/test/lexer/test_keep.rb +0 -24
  121. data/test/lexer/test_literals.rb +0 -130
  122. data/test/lexer/test_nesting.rb +0 -132
  123. data/test/lexer/test_refcalls.rb +0 -56
  124. data/test/parser/set/test_intersections.rb +0 -127
  125. data/test/parser/set/test_ranges.rb +0 -111
  126. data/test/parser/test_all.rb +0 -64
  127. data/test/parser/test_alternation.rb +0 -92
  128. data/test/parser/test_anchors.rb +0 -34
  129. data/test/parser/test_conditionals.rb +0 -187
  130. data/test/parser/test_errors.rb +0 -63
  131. data/test/parser/test_escapes.rb +0 -134
  132. data/test/parser/test_free_space.rb +0 -139
  133. data/test/parser/test_groups.rb +0 -289
  134. data/test/parser/test_keep.rb +0 -21
  135. data/test/parser/test_posix_classes.rb +0 -27
  136. data/test/parser/test_properties.rb +0 -134
  137. data/test/parser/test_quantifiers.rb +0 -301
  138. data/test/parser/test_refcalls.rb +0 -186
  139. data/test/parser/test_sets.rb +0 -179
  140. data/test/parser/test_types.rb +0 -50
  141. data/test/scanner/test_all.rb +0 -38
  142. data/test/scanner/test_anchors.rb +0 -38
  143. data/test/scanner/test_conditionals.rb +0 -184
  144. data/test/scanner/test_errors.rb +0 -91
  145. data/test/scanner/test_escapes.rb +0 -56
  146. data/test/scanner/test_free_space.rb +0 -200
  147. data/test/scanner/test_groups.rb +0 -79
  148. data/test/scanner/test_keep.rb +0 -35
  149. data/test/scanner/test_literals.rb +0 -89
  150. data/test/scanner/test_meta.rb +0 -40
  151. data/test/scanner/test_properties.rb +0 -312
  152. data/test/scanner/test_quantifiers.rb +0 -37
  153. data/test/scanner/test_refcalls.rb +0 -52
  154. data/test/scanner/test_scripts.rb +0 -53
  155. data/test/scanner/test_sets.rb +0 -119
  156. data/test/scanner/test_types.rb +0 -35
  157. data/test/scanner/test_unicode_blocks.rb +0 -30
  158. data/test/support/disable_autotest.rb +0 -8
  159. data/test/syntax/test_all.rb +0 -6
  160. data/test/syntax/test_syntax.rb +0 -61
  161. data/test/syntax/test_syntax_token_map.rb +0 -25
  162. data/test/syntax/versions/test_1.8.rb +0 -55
  163. data/test/syntax/versions/test_1.9.1.rb +0 -36
  164. data/test/syntax/versions/test_1.9.3.rb +0 -32
  165. data/test/syntax/versions/test_2.0.0.rb +0 -37
  166. data/test/syntax/versions/test_2.2.0.rb +0 -32
  167. data/test/syntax/versions/test_aliases.rb +0 -129
  168. data/test/syntax/versions/test_all.rb +0 -5
  169. data/test/test_all.rb +0 -5
  170. data/test/token/test_all.rb +0 -2
  171. data/test/token/test_token.rb +0 -107
@@ -0,0 +1,161 @@
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
@@ -0,0 +1,25 @@
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
@@ -0,0 +1,224 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe('Expression#strfregexp') do
4
+ specify('#strfre alias') do
5
+ expect(RP.parse(/a/)).to respond_to(:strfre)
6
+ end
7
+
8
+ specify('#strfregexp level') do
9
+ root = RP.parse(/a(b(c))/)
10
+
11
+ expect(root.strfregexp('%l')).to eq 'root'
12
+
13
+ a = root.first
14
+ expect(a.strfregexp('%%l')).to eq '%0'
15
+
16
+ b = root[1].first
17
+ expect(b.strfregexp('<%l>')).to eq '<1>'
18
+
19
+ c = root[1][1].first
20
+ expect(c.strfregexp('[at: %l]')).to eq '[at: 2]'
21
+ end
22
+
23
+ specify('#strfregexp start end') do
24
+ root = RP.parse(/a(b(c))/)
25
+
26
+ expect(root.strfregexp('%s')).to eq '0'
27
+ expect(root.strfregexp('%e')).to eq '7'
28
+
29
+ a = root.first
30
+ expect(a.strfregexp('%%s')).to eq '%0'
31
+ expect(a.strfregexp('%e')).to eq '1'
32
+
33
+ group_1 = root[1]
34
+ expect(group_1.strfregexp('GRP:%s')).to eq 'GRP:1'
35
+ expect(group_1.strfregexp('%e')).to eq '7'
36
+
37
+ b = group_1.first
38
+ expect(b.strfregexp('<@%s>')).to eq '<@2>'
39
+ expect(b.strfregexp('%e')).to eq '3'
40
+
41
+ c = group_1.last.first
42
+ expect(c.strfregexp('[at: %s]')).to eq '[at: 4]'
43
+ expect(c.strfregexp('%e')).to eq '5'
44
+ end
45
+
46
+ specify('#strfregexp length') do
47
+ root = RP.parse(/a[b]c/)
48
+
49
+ expect(root.strfregexp('%S')).to eq '5'
50
+
51
+ a = root.first
52
+ expect(a.strfregexp('%S')).to eq '1'
53
+
54
+ set = root[1]
55
+ expect(set.strfregexp('%S')).to eq '3'
56
+ end
57
+
58
+ specify('#strfregexp coded offset') do
59
+ root = RP.parse(/a[b]c/)
60
+
61
+ expect(root.strfregexp('%o')).to eq '@0+5'
62
+
63
+ a = root.first
64
+ expect(a.strfregexp('%o')).to eq '@0+1'
65
+
66
+ set = root[1]
67
+ expect(set.strfregexp('%o')).to eq '@1+3'
68
+ end
69
+
70
+ specify('#strfregexp type token') do
71
+ root = RP.parse(/a[b](c)/)
72
+
73
+ expect(root.strfregexp('%y')).to eq 'expression'
74
+ expect(root.strfregexp('%k')).to eq 'root'
75
+ expect(root.strfregexp('%i')).to eq 'expression:root'
76
+ expect(root.strfregexp('%c')).to eq 'Regexp::Expression::Root'
77
+
78
+ a = root.first
79
+ expect(a.strfregexp('%y')).to eq 'literal'
80
+ expect(a.strfregexp('%k')).to eq 'literal'
81
+ expect(a.strfregexp('%i')).to eq 'literal:literal'
82
+ expect(a.strfregexp('%c')).to eq 'Regexp::Expression::Literal'
83
+
84
+ set = root[1]
85
+ expect(set.strfregexp('%y')).to eq 'set'
86
+ expect(set.strfregexp('%k')).to eq 'character'
87
+ expect(set.strfregexp('%i')).to eq 'set:character'
88
+ expect(set.strfregexp('%c')).to eq 'Regexp::Expression::CharacterSet'
89
+
90
+ group = root.last
91
+ expect(group.strfregexp('%y')).to eq 'group'
92
+ expect(group.strfregexp('%k')).to eq 'capture'
93
+ expect(group.strfregexp('%i')).to eq 'group:capture'
94
+ expect(group.strfregexp('%c')).to eq 'Regexp::Expression::Group::Capture'
95
+ end
96
+
97
+ specify('#strfregexp quantifier') do
98
+ root = RP.parse(/a+[b](c)?d{3,4}/)
99
+
100
+ expect(root.strfregexp('%q')).to eq '{1}'
101
+ expect(root.strfregexp('%Q')).to eq ''
102
+ expect(root.strfregexp('%z, %Z')).to eq '1, 1'
103
+
104
+ a = root.first
105
+ expect(a.strfregexp('%q')).to eq '{1, or-more}'
106
+ expect(a.strfregexp('%Q')).to eq '+'
107
+ expect(a.strfregexp('%z, %Z')).to eq '1, -1'
108
+
109
+ set = root[1]
110
+ expect(set.strfregexp('%q')).to eq '{1}'
111
+ expect(set.strfregexp('%Q')).to eq ''
112
+ expect(set.strfregexp('%z, %Z')).to eq '1, 1'
113
+
114
+ group = root[2]
115
+ expect(group.strfregexp('%q')).to eq '{0, 1}'
116
+ expect(group.strfregexp('%Q')).to eq '?'
117
+ expect(group.strfregexp('%z, %Z')).to eq '0, 1'
118
+
119
+ d = root.last
120
+ expect(d.strfregexp('%q')).to eq '{3, 4}'
121
+ expect(d.strfregexp('%Q')).to eq '{3,4}'
122
+ expect(d.strfregexp('%z, %Z')).to eq '3, 4'
123
+ end
124
+
125
+ specify('#strfregexp text') do
126
+ root = RP.parse(/a(b(c))|[d-gk-p]+/)
127
+
128
+ expect(root.strfregexp('%t')).to eq 'a(b(c))|[d-gk-p]+'
129
+ expect(root.strfregexp('%~t')).to eq 'expression:root'
130
+
131
+ alt = root.first
132
+ expect(alt.strfregexp('%t')).to eq 'a(b(c))|[d-gk-p]+'
133
+ expect(alt.strfregexp('%T')).to eq 'a(b(c))|[d-gk-p]+'
134
+ expect(alt.strfregexp('%~t')).to eq 'meta:alternation'
135
+
136
+ seq_1 = alt.first
137
+ expect(seq_1.strfregexp('%t')).to eq 'a(b(c))'
138
+ expect(seq_1.strfregexp('%T')).to eq 'a(b(c))'
139
+ expect(seq_1.strfregexp('%~t')).to eq 'expression:sequence'
140
+
141
+ group = seq_1[1]
142
+ expect(group.strfregexp('%t')).to eq '(b(c))'
143
+ expect(group.strfregexp('%T')).to eq '(b(c))'
144
+ expect(group.strfregexp('%~t')).to eq 'group:capture'
145
+
146
+ seq_2 = alt.last
147
+ expect(seq_2.strfregexp('%t')).to eq '[d-gk-p]+'
148
+ expect(seq_2.strfregexp('%T')).to eq '[d-gk-p]+'
149
+
150
+ set = seq_2.first
151
+ expect(set.strfregexp('%t')).to eq '[d-gk-p]'
152
+ expect(set.strfregexp('%T')).to eq '[d-gk-p]+'
153
+ expect(set.strfregexp('%~t')).to eq 'set:character'
154
+ end
155
+
156
+ specify('#strfregexp combined') do
157
+ root = RP.parse(/a{5}|[b-d]+/)
158
+
159
+ expect(root.strfregexp('%b')).to eq '@0+11 expression:root'
160
+ expect(root.strfregexp('%b')).to eq root.strfregexp('%o %i')
161
+
162
+ expect(root.strfregexp('%m')).to eq '@0+11 expression:root {1}'
163
+ expect(root.strfregexp('%m')).to eq root.strfregexp('%b %q')
164
+
165
+ expect(root.strfregexp('%a')).to eq '@0+11 expression:root {1} a{5}|[b-d]+'
166
+ expect(root.strfregexp('%a')).to eq root.strfregexp('%m %t')
167
+ end
168
+
169
+ specify('#strfregexp conditional') do
170
+ root = RP.parse('(?<A>a)(?(<A>)b|c)', 'ruby/2.0')
171
+
172
+ expect { root.strfregexp }.not_to(raise_error)
173
+ end
174
+
175
+ specify('#strfregexp_tree') do
176
+ root = RP.parse(/a[b-d]*(e(f+))?/)
177
+
178
+ expect(root.strfregexp_tree('%>%o %~t')).to eq(
179
+ "@0+15 expression:root\n" +
180
+ " @0+1 a\n" +
181
+ " @1+6 set:character\n" +
182
+ " @2+3 set:range\n" +
183
+ " @2+1 b\n" +
184
+ " @4+1 d\n" +
185
+ " @7+8 group:capture\n" +
186
+ " @8+1 e\n" +
187
+ " @9+4 group:capture\n" +
188
+ " @10+2 f+"
189
+ )
190
+ end
191
+
192
+ specify('#strfregexp_tree separator') do
193
+ root = RP.parse(/a[b-d]*(e(f+))?/)
194
+
195
+ expect(root.strfregexp_tree('%>%o %~t', true, '-SEP-')).to eq(
196
+ "@0+15 expression:root-SEP-" +
197
+ " @0+1 a-SEP-" +
198
+ " @1+6 set:character-SEP-" +
199
+ " @2+3 set:range-SEP-" +
200
+ " @2+1 b-SEP-" +
201
+ " @4+1 d-SEP-" +
202
+ " @7+8 group:capture-SEP-" +
203
+ " @8+1 e-SEP-" +
204
+ " @9+4 group:capture-SEP-" +
205
+ " @10+2 f+"
206
+ )
207
+ end
208
+
209
+ specify('#strfregexp_tree excluding self') do
210
+ root = RP.parse(/a[b-d]*(e(f+))?/)
211
+
212
+ expect(root.strfregexp_tree('%>%o %~t', false)).to eq(
213
+ "@0+1 a\n" +
214
+ "@1+6 set:character\n" +
215
+ " @2+3 set:range\n" +
216
+ " @2+1 b\n" +
217
+ " @4+1 d\n" +
218
+ "@7+8 group:capture\n" +
219
+ " @8+1 e\n" +
220
+ " @9+4 group:capture\n" +
221
+ " @10+2 f+"
222
+ )
223
+ end
224
+ end
@@ -0,0 +1,99 @@
1
+ require 'spec_helper'
2
+
3
+ RSpec.describe('ExpressionTests') do
4
+ specify('#type?') do
5
+ root = RP.parse(/abcd|(ghij)|[klmn]/)
6
+
7
+ alt = root.first
8
+
9
+ expect(alt.type?(:meta)).to be true
10
+ expect(alt.type?(:escape)).to be false
11
+ expect(alt.type?(%i[meta escape])).to be true
12
+ expect(alt.type?(%i[literal escape])).to be false
13
+ expect(alt.type?(:*)).to be true
14
+ expect(alt.type?([:*])).to be true
15
+ expect(alt.type?(%i[literal escape *])).to be true
16
+
17
+ seq_1 = alt[0]
18
+ expect(seq_1.type?(:expression)).to be true
19
+ expect(seq_1.first.type?(:literal)).to be true
20
+
21
+ seq_2 = alt[1]
22
+ expect(seq_2.type?(:*)).to be true
23
+ expect(seq_2.first.type?(:group)).to be true
24
+
25
+ seq_3 = alt[2]
26
+ expect(seq_3.first.type?(:set)).to be true
27
+ end
28
+
29
+ specify('#is?') do
30
+ root = RP.parse(/.+|\.?/)
31
+
32
+ expect(root.is?(:*)).to be true
33
+
34
+ alt = root.first
35
+ expect(alt.is?(:*)).to be true
36
+ expect(alt.is?(:alternation)).to be true
37
+ expect(alt.is?(:alternation, :meta)).to be true
38
+
39
+ seq_1 = alt[0]
40
+ expect(seq_1.is?(:sequence)).to be true
41
+ expect(seq_1.is?(:sequence, :expression)).to be true
42
+
43
+ expect(seq_1.first.is?(:dot)).to be true
44
+ expect(seq_1.first.is?(:dot, :escape)).to be false
45
+ expect(seq_1.first.is?(:dot, :meta)).to be true
46
+ expect(seq_1.first.is?(:dot, %i[escape meta])).to be true
47
+
48
+ seq_2 = alt[1]
49
+ expect(seq_2.first.is?(:dot)).to be true
50
+ expect(seq_2.first.is?(:dot, :escape)).to be true
51
+ expect(seq_2.first.is?(:dot, :meta)).to be false
52
+ expect(seq_2.first.is?(:dot, %i[meta escape])).to be true
53
+ end
54
+
55
+ specify('#one_of?') do
56
+ root = RP.parse(/\Aab(c[\w])d|e.\z/)
57
+
58
+ expect(root.one_of?(:*)).to be true
59
+ expect(root.one_of?(:* => :*)).to be true
60
+ expect(root.one_of?(:* => [:*])).to be true
61
+
62
+ alt = root.first
63
+ expect(alt.one_of?(:*)).to be true
64
+ expect(alt.one_of?(:meta)).to be true
65
+ expect(alt.one_of?(:meta, :alternation)).to be true
66
+ expect(alt.one_of?(meta: %i[dot bogus])).to be false
67
+ expect(alt.one_of?(meta: %i[dot alternation])).to be true
68
+
69
+ seq_1 = alt[0]
70
+ expect(seq_1.one_of?(:expression)).to be true
71
+ expect(seq_1.one_of?(expression: :sequence)).to be true
72
+
73
+ expect(seq_1.first.one_of?(:anchor)).to be true
74
+ expect(seq_1.first.one_of?(anchor: :bos)).to be true
75
+ expect(seq_1.first.one_of?(anchor: :eos)).to be false
76
+ expect(seq_1.first.one_of?(anchor: %i[escape meta bos])).to be true
77
+ expect(seq_1.first.one_of?(anchor: %i[escape meta eos])).to be false
78
+
79
+ seq_2 = alt[1]
80
+ expect(seq_2.first.one_of?(:literal)).to be true
81
+
82
+ expect(seq_2[1].one_of?(:meta)).to be true
83
+ expect(seq_2[1].one_of?(meta: :dot)).to be true
84
+ expect(seq_2[1].one_of?(meta: :alternation)).to be false
85
+ expect(seq_2[1].one_of?(meta: [:dot])).to be true
86
+
87
+ expect(seq_2.last.one_of?(:group)).to be false
88
+ expect(seq_2.last.one_of?(group: [:*])).to be false
89
+ expect(seq_2.last.one_of?(group: [:*], meta: :*)).to be false
90
+
91
+ expect(seq_2.last.one_of?(:meta => [:*], :* => :*)).to be true
92
+ expect(seq_2.last.one_of?(meta: [:*], anchor: :*)).to be true
93
+ expect(seq_2.last.one_of?(meta: [:*], anchor: :eos)).to be true
94
+ expect(seq_2.last.one_of?(meta: [:*], anchor: [:bos])).to be false
95
+ expect(seq_2.last.one_of?(meta: [:*], anchor: %i[bos eos])).to be true
96
+
97
+ expect { root.one_of?(Object.new) }.to raise_error(ArgumentError)
98
+ end
99
+ end