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 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