regexp-examples 0.5.1 → 0.5.2
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.
- checksums.yaml +4 -4
- data/README.md +4 -5
- data/lib/regexp-examples/groups.rb +2 -4
- data/lib/regexp-examples/parser.rb +46 -3
- data/lib/regexp-examples/version.rb +1 -1
- data/spec/regexp-examples_spec.rb +20 -0
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 0d34e8d62dc70d3b7b1ba17930f94a3799e9f669
|
4
|
+
data.tar.gz: 62b828f1e6207cf7198ad96a2b61ab5f08dea5d2
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 3e41e5d5a41dfaa44c67c3e99f28b0b37675774b3509f22d417f7bc2e9c664cccb9b480c8218a72ba63ce9876d2c7d09cbfc0bf8ab2c04d773f0e9e8d3818657
|
7
|
+
data.tar.gz: 82393a8ad2d76ebd853845a9f1de46cf1aa2175d56e0883004dc770fb9eaf5253dc23750a9eafb4cb36a8a751f5794071bd42fda0d8a2f4f68989486f31dccdc
|
data/README.md
CHANGED
@@ -38,6 +38,7 @@ For more detail on this, see [configuration options](#configuration-options).
|
|
38
38
|
* ...And backreferences(!!!), e.g. `/(this|that) \1/` `/(?<name>foo) \k<name>/`
|
39
39
|
* Groups work fine, even if nested or optional e.g. `/(even(this(works?))) \1 \2 \3/`, `/what about (this)? \1/`
|
40
40
|
* Non-capture groups, e.g. `/(?:foo)/`
|
41
|
+
* Comment groups, e.g. `/foo(?#comment)bar/`
|
41
42
|
* Control characters, e.g. `/\ca/`, `/\cZ/`, `/\C-9/`
|
42
43
|
* Escape sequences, e.g. `/\x42/`, `/\x5word/`, `/#{"\x80".force_encoding("ASCII-8BIT")}/`
|
43
44
|
* Unicode characters, e.g. `/\u0123/`, `/\uabcd/`, `/\u{789}/`
|
@@ -45,8 +46,9 @@ For more detail on this, see [configuration options](#configuration-options).
|
|
45
46
|
|
46
47
|
* Regexp options can also be used:
|
47
48
|
* Case insensitive examples: `/cool/i.examples #=> ["cool", "cooL", "coOl", "coOL", ...]`
|
48
|
-
* Multiline examples: `/./m.examples
|
49
|
+
* Multiline examples: `/./m.examples #=> ["\n", "a", "b", "c", "d"]`
|
49
50
|
* Extended form examples: `/line1 #comment \n line2/x.examples #=> ["line1line2"]`
|
51
|
+
* Options toggling supported: `/before(?imx-imx)after/`, `/before(?imx-imx:subexpr)after/`
|
50
52
|
|
51
53
|
## Bugs and Not-Yet-Supported syntax
|
52
54
|
|
@@ -54,10 +56,7 @@ For more detail on this, see [configuration options](#configuration-options).
|
|
54
56
|
* `/[[abc]]/.examples` (which _should_ return `["a", "b", "c"]`)
|
55
57
|
* `/[[a-d]&&[c-f]]/.examples` (which _should_ return: `["c", "d"]`)
|
56
58
|
|
57
|
-
*
|
58
|
-
* Including comments inside the pattern, i.e. `/(?#...)/`
|
59
|
-
* Conditional capture groups, such as `/(group1) (?(1)yes|no)`
|
60
|
-
* Options toggling, i.e. `/(?imx)/`, `/(?-imx)/`, `/(?imx: re)/` and `/(?-imx: re)/`
|
59
|
+
* Conditional capture groups, such as `/(group1) (?(1)yes|no)`
|
61
60
|
|
62
61
|
* The patterns: `/\10/` ... `/\77/` should match the octal representation of their character code, if there is no nth grouped subexpression. For example, `/\10/.examples` should return `["\x08"]`. Funnily enough, I did not think of this when writing my regexp parser.
|
63
62
|
|
@@ -126,7 +126,7 @@ module RegexpExamples
|
|
126
126
|
|
127
127
|
def result
|
128
128
|
chars = CharSets::Any
|
129
|
-
chars
|
129
|
+
chars = (["\n"] | chars) if multiline
|
130
130
|
chars.map do |result|
|
131
131
|
GroupResult.new(result)
|
132
132
|
end
|
@@ -134,12 +134,10 @@ module RegexpExamples
|
|
134
134
|
end
|
135
135
|
|
136
136
|
class MultiGroup
|
137
|
-
prepend GroupWithIgnoreCase
|
138
137
|
attr_reader :group_id
|
139
|
-
def initialize(groups, group_id
|
138
|
+
def initialize(groups, group_id)
|
140
139
|
@groups = groups
|
141
140
|
@group_id = group_id
|
142
|
-
@ignorecase = ignorecase
|
143
141
|
end
|
144
142
|
|
145
143
|
# Generates the result of each contained group
|
@@ -146,13 +146,44 @@ module RegexpExamples
|
|
146
146
|
@current_position += 1
|
147
147
|
@num_groups += 1
|
148
148
|
group_id = nil # init
|
149
|
-
|
149
|
+
previous_ignorecase = @ignorecase
|
150
|
+
previous_multiline = @multiline
|
151
|
+
previous_extended = @extended
|
152
|
+
rest_of_string.match(
|
153
|
+
/
|
154
|
+
\A
|
155
|
+
(\?)? # Is it a "special" group, i.e. starts with a "?"?
|
156
|
+
(
|
157
|
+
: # Non capture group
|
158
|
+
|! # Neglookahead
|
159
|
+
|= # Lookahead
|
160
|
+
|\# # Comment group
|
161
|
+
|< # Lookbehind or named capture
|
162
|
+
(
|
163
|
+
! # Neglookbehind
|
164
|
+
|= # Lookbehind
|
165
|
+
|[^>]+ # Named capture
|
166
|
+
)
|
167
|
+
|[mix]*-?[mix]* # Option toggle
|
168
|
+
)?
|
169
|
+
/x
|
170
|
+
) do |match|
|
150
171
|
case
|
151
172
|
when match[1].nil? # e.g. /(normal)/
|
152
173
|
group_id = @num_groups.to_s
|
153
174
|
when match[2] == ':' # e.g. /(?:nocapture)/
|
154
175
|
@current_position += 2
|
155
|
-
|
176
|
+
when match[2] == '#' # e.g. /(?#comment)/
|
177
|
+
comment_group = rest_of_string.match(/.*?[^\\](?:\\{2})*\)/)[0]
|
178
|
+
@current_position += comment_group.length
|
179
|
+
when match[2] =~ /\A(?=[mix-]+)([mix]*)-?([mix]*)/ # e.g. /(?i-mx)/
|
180
|
+
regexp_options_toggle($1, $2)
|
181
|
+
@current_position += $&.length + 1
|
182
|
+
if next_char == ':' # e.g. /(?i:subexpr)/
|
183
|
+
@current_position += 1
|
184
|
+
else
|
185
|
+
return parse_single_char_group('')
|
186
|
+
end
|
156
187
|
when %w(! =).include?(match[2]) # e.g. /(?=lookahead)/, /(?!neglookahead)/
|
157
188
|
raise IllegalSyntaxError, "Lookaheads are not regular; cannot generate examples"
|
158
189
|
when %w(! =).include?(match[3]) # e.g. /(?<=lookbehind)/, /(?<!neglookbehind)/
|
@@ -163,7 +194,19 @@ module RegexpExamples
|
|
163
194
|
end
|
164
195
|
end
|
165
196
|
groups = parse
|
166
|
-
|
197
|
+
@ignorecase = previous_ignorecase
|
198
|
+
@multiline = previous_multiline
|
199
|
+
@extended = previous_extended
|
200
|
+
MultiGroup.new(groups, group_id)
|
201
|
+
end
|
202
|
+
|
203
|
+
def regexp_options_toggle(on, off)
|
204
|
+
@ignorecase = true if (on.include? "i")
|
205
|
+
@ignorecase = false if (off.include? "i")
|
206
|
+
@multiline = true if (on.include? "m")
|
207
|
+
@multiline = false if (off.include? "m")
|
208
|
+
@extended = true if (on.include? "x")
|
209
|
+
@extended = false if (off.include? "x")
|
167
210
|
end
|
168
211
|
|
169
212
|
def parse_multi_end_group
|
@@ -231,6 +231,13 @@ RSpec.describe Regexp, "#examples" do
|
|
231
231
|
)
|
232
232
|
end
|
233
233
|
|
234
|
+
context "comment group" do
|
235
|
+
examples_exist_and_match(
|
236
|
+
/a(?#comment)b/,
|
237
|
+
/a(?#ugly backslashy\ comment\\\))b/
|
238
|
+
)
|
239
|
+
end
|
240
|
+
|
234
241
|
context "exact examples match" do
|
235
242
|
# More rigorous tests to assert that ALL examples are being listed
|
236
243
|
context "default config options" do
|
@@ -284,6 +291,19 @@ RSpec.describe Regexp, "#examples" do
|
|
284
291
|
).to eq %w(line1line2)
|
285
292
|
end
|
286
293
|
end
|
294
|
+
|
295
|
+
context "options toggling" do
|
296
|
+
context "rest of string" do
|
297
|
+
it { expect(/a(?i)b(?-i)c/.examples).to eq %w{abc aBc}}
|
298
|
+
it { expect(/a(?x) b(?-x) c/.examples).to eq %w{ab\ c}}
|
299
|
+
it { expect(/(?m)./.examples(max_group_results: 999)).to include "\n" }
|
300
|
+
end
|
301
|
+
context "subexpression" do
|
302
|
+
it { expect(/a(?i:b)c/.examples).to eq %w{abc aBc}}
|
303
|
+
it { expect(/a(?i:b(?-i:c))/.examples).to eq %w{abc aBc}}
|
304
|
+
it { expect(/a(?-i:b)c/i.examples).to eq %w{abc abC Abc AbC}}
|
305
|
+
end
|
306
|
+
end
|
287
307
|
end
|
288
308
|
|
289
309
|
end
|