regexp-examples 0.5.1 → 0.5.2

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ff205ed61ad0ca0c2dc2383afd17930110763b44
4
- data.tar.gz: a13f23a7d56b9b7d7e4323380d705276793e6e4f
3
+ metadata.gz: 0d34e8d62dc70d3b7b1ba17930f94a3799e9f669
4
+ data.tar.gz: 62b828f1e6207cf7198ad96a2b61ab5f08dea5d2
5
5
  SHA512:
6
- metadata.gz: 068c7dbd13945c0487b91c61e9cae304323775adc82cd4e80092ab32505eb46f31aaf98736f5a353eb1ad06a471864f9432ce3d203097f2dcfc6e696dba07e12
7
- data.tar.gz: c2014a4055874af1edbdc3fbee60e58b3f182ba37278f5f0738f4699256a0669b84e8b7d731494c5493e04fb249c3135cb31e5a716e687cd677fd3f9fa1a8da9
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(max_group_results: 999) #=> ["a", "b", "c", ..., "\n"]`
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
- * Extended groups are not yet supported, such as:
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 |= ["\n"] if multiline
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, ignorecase)
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
- rest_of_string.match(/\A(\?)?(:|!|=|<(!|=|[^!=][^>]*))?/) do |match|
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
- group_id = nil
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
- MultiGroup.new(groups, group_id, @ignorecase)
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
@@ -1,3 +1,3 @@
1
1
  module RegexpExamples
2
- VERSION = '0.5.1'
2
+ VERSION = '0.5.2'
3
3
  end
@@ -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
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: regexp-examples
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.5.1
4
+ version: 0.5.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Tom Lord