list_matcher 1.0.4 → 1.0.5
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 +11 -1
- data/lib/list_matcher/version.rb +1 -1
- data/lib/list_matcher.rb +35 -18
- data/test/basic_test.rb +1 -1
- data/test/exception_test.rb +83 -0
- metadata +4 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 34630b608a56f9a22605ff55956ed8da7793ed73
|
|
4
|
+
data.tar.gz: 160a5e81d4c9e3bbd0ba2a516e97a0ec9048d27f
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 5a1523c2c3a36424bd76ba465345466993404c4e3b3e4e531b7ca2b9ea3765e392567df809f188af3bcb2ab8f58d1fe8c21b1dae3eed1087133f9d68767b922e
|
|
7
|
+
data.tar.gz: 917e5620134c0726880ba789db20bfe39f850ce11493d2cea17f690bbc5501ec18f5c66f72e41c8b745051e1776c341f86a8805c4e74b48db6486061c8706dc9
|
data/README.md
CHANGED
|
@@ -18,7 +18,7 @@ Or install it yourself as:
|
|
|
18
18
|
|
|
19
19
|
$ gem install list_matcher
|
|
20
20
|
|
|
21
|
-
##
|
|
21
|
+
## Synopsis
|
|
22
22
|
|
|
23
23
|
```ruby
|
|
24
24
|
require 'list_matcher'
|
|
@@ -36,6 +36,16 @@ puts m.pattern %w( cat catalog ) # (?:cat(?:alog)?)
|
|
|
36
36
|
puts m.pattern (1..31).to_a # (?:[4-9]|1\d?|2\d?|3[01]?)
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
+
## Usage
|
|
40
|
+
|
|
41
|
+
One provides a list of expressions to match and perhaps some options and receives in turn either a
|
|
42
|
+
compiled `Regexp` or a string from which such a regex can be compiled. The `rx` method provides a compiled
|
|
43
|
+
regex and `pattern`, a string. The latter is chiefly useful when composing a larger regex out of smaller
|
|
44
|
+
pieces.
|
|
45
|
+
|
|
46
|
+
The options one may provide to `List::Matcher` are all validated. Any errors cause it to raise a
|
|
47
|
+
`List::Matcher::Error` exception.
|
|
48
|
+
|
|
39
49
|
## Description
|
|
40
50
|
|
|
41
51
|
`List::Matcher` facilitates generating efficient regexen programmatically. This is useful, for example, when looking for
|
data/lib/list_matcher/version.rb
CHANGED
data/lib/list_matcher.rb
CHANGED
|
@@ -5,6 +5,9 @@ module List
|
|
|
5
5
|
attr_reader :atomic, :backtracking, :bound, :case_insensitive, :strip, :left_bound,
|
|
6
6
|
:right_bound, :word_test, :normalize_whitespace, :multiline, :name, :vet, :not_extended
|
|
7
7
|
|
|
8
|
+
# a special exception class for List::Matcher
|
|
9
|
+
class Error < ::StandardError; end
|
|
10
|
+
|
|
8
11
|
# convenience method for one-off regexen where there's no point in keeping
|
|
9
12
|
# around a pattern generator
|
|
10
13
|
def self.pattern(list, opts={})
|
|
@@ -44,9 +47,12 @@ module List
|
|
|
44
47
|
@normalize_whitespace = normalize_whitespace
|
|
45
48
|
@vet = vet
|
|
46
49
|
if name
|
|
47
|
-
raise "" unless name.is_a?(String) || name.is_a?(Symbol)
|
|
48
|
-
|
|
50
|
+
raise Error, "name must be a string or symbol" unless name.is_a?(String) || name.is_a?(Symbol)
|
|
51
|
+
begin
|
|
52
|
+
Regexp.new "(?<#{name}>.*)" # stir up any errors that might arise from using this name in a named capture
|
|
49
53
|
@name = name
|
|
54
|
+
rescue
|
|
55
|
+
raise Error, "#{name} does not work as the name of a named group"
|
|
50
56
|
end
|
|
51
57
|
end
|
|
52
58
|
case bound
|
|
@@ -70,7 +76,7 @@ module List
|
|
|
70
76
|
@left_bound = '\b'
|
|
71
77
|
@right_bound = '\b'
|
|
72
78
|
else
|
|
73
|
-
raise "unfamiliar value for :bound option: #{bound.inspect}"
|
|
79
|
+
raise Error, "unfamiliar value for :bound option: #{bound.inspect}"
|
|
74
80
|
end
|
|
75
81
|
if /_left/ === bound.to_s
|
|
76
82
|
@right_bound = nil
|
|
@@ -78,15 +84,25 @@ module List
|
|
|
78
84
|
@left_bound = nil
|
|
79
85
|
end
|
|
80
86
|
when Hash
|
|
81
|
-
@word_test = bound[:test] || raise('no boundary test provided')
|
|
87
|
+
@word_test = bound[:test] || raise( Error, 'no boundary test provided' )
|
|
82
88
|
@left_bound = bound[:left]
|
|
83
89
|
@right_bound = bound[:right]
|
|
84
|
-
raise 'neither bound provided' unless @left_bound || @right_bound
|
|
90
|
+
raise Error, 'neither bound provided' unless @left_bound || @right_bound
|
|
91
|
+
raise Error, 'test must be Regexp or String' unless @word_test.is_a?(Regexp) || @word_test.is_a?(String)
|
|
92
|
+
@word_test = Regexp.new @word_test unless @word_test.is_a?(Regexp)
|
|
93
|
+
[ @left_bound, @right_bound ].compact.each do |b|
|
|
94
|
+
raise Error, 'bounds must be strings' unless b.is_a?(String)
|
|
95
|
+
begin
|
|
96
|
+
Regexp.new b
|
|
97
|
+
rescue
|
|
98
|
+
raise Error, "bad boundary pattern: #{b}"
|
|
99
|
+
end
|
|
100
|
+
end
|
|
85
101
|
else
|
|
86
|
-
raise "unfamiliar value for :bound option: #{bound.inspect}"
|
|
102
|
+
raise Error, "unfamiliar value for :bound option: #{bound.inspect}"
|
|
87
103
|
end
|
|
88
104
|
symbols.keys.each do |k|
|
|
89
|
-
raise "symbols variable #{k} is neither a string, a symbol, nor a regex" unless k.is_a?(String) || k.is_a?(Symbol) || k.is_a?(Regexp)
|
|
105
|
+
raise Error, "symbols variable #{k.inspect} is neither a string, a symbol, nor a regex" unless k.is_a?(String) || k.is_a?(Symbol) || k.is_a?(Regexp)
|
|
90
106
|
end
|
|
91
107
|
if normalize_whitespace
|
|
92
108
|
@symbols[' '] = { pattern: '\s++' }
|
|
@@ -342,7 +358,7 @@ module List
|
|
|
342
358
|
c = ( max += 1 ).chr
|
|
343
359
|
sp = if opts.is_a? Hash
|
|
344
360
|
pat = opts.delete :pattern
|
|
345
|
-
raise "
|
|
361
|
+
raise Error, "symbol #{var} requires a pattern" unless pat || var.is_a?(Regexp)
|
|
346
362
|
pat ||= var.to_s
|
|
347
363
|
SpecialPattern.new engine, c, var, pat, **opts
|
|
348
364
|
elsif opts.is_a? String
|
|
@@ -350,7 +366,7 @@ module List
|
|
|
350
366
|
elsif var.is_a?(Regexp) && opts.nil?
|
|
351
367
|
SpecialPattern.new engine, c, var, nil
|
|
352
368
|
else
|
|
353
|
-
raise "
|
|
369
|
+
raise Error, "symbol #{var} requires a pattern"
|
|
354
370
|
end
|
|
355
371
|
ar << sp
|
|
356
372
|
end
|
|
@@ -375,7 +391,7 @@ module List
|
|
|
375
391
|
begin
|
|
376
392
|
Regexp.new s.pat
|
|
377
393
|
rescue
|
|
378
|
-
raise
|
|
394
|
+
raise Error, "the symbol #{s.symbol} has an ill-formed pattern: #{s.pat}"
|
|
379
395
|
end
|
|
380
396
|
end
|
|
381
397
|
end
|
|
@@ -440,8 +456,8 @@ module List
|
|
|
440
456
|
attr_accessor :engine, :optional, :symbols, :root
|
|
441
457
|
|
|
442
458
|
def initialize(engine, symbols)
|
|
443
|
-
@engine
|
|
444
|
-
@symbols
|
|
459
|
+
@engine = engine
|
|
460
|
+
@symbols = symbols
|
|
445
461
|
@children = []
|
|
446
462
|
end
|
|
447
463
|
|
|
@@ -507,15 +523,16 @@ module List
|
|
|
507
523
|
end
|
|
508
524
|
|
|
509
525
|
class SpecialPattern < Node
|
|
510
|
-
attr_accessor :char, :var, :left, :right, :pat
|
|
526
|
+
attr_accessor :char, :var, :left, :right, :pat, :symbol
|
|
511
527
|
def initialize(engine, char, var, pat, atomic: (var.is_a?(Regexp) && pat.nil?), word_left: false, word_right: false)
|
|
512
528
|
super(engine, nil)
|
|
513
|
-
@char
|
|
514
|
-
@
|
|
515
|
-
@
|
|
529
|
+
@char = char
|
|
530
|
+
@symbol = var.to_s
|
|
531
|
+
@var = var.is_a?(String) || var.is_a?(Symbol) ? Regexp.new(Regexp.quote(var.to_s)) : var
|
|
532
|
+
@pat = pat || var.to_s
|
|
516
533
|
@atomic = !!atomic
|
|
517
|
-
@left
|
|
518
|
-
@right
|
|
534
|
+
@left = !!word_left
|
|
535
|
+
@right = !!word_right
|
|
519
536
|
end
|
|
520
537
|
|
|
521
538
|
def dup
|
data/test/basic_test.rb
CHANGED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
require "minitest/autorun"
|
|
2
|
+
|
|
3
|
+
require "list_matcher"
|
|
4
|
+
|
|
5
|
+
class ExceptionTest < Minitest::Test
|
|
6
|
+
|
|
7
|
+
def test_bad_symbol
|
|
8
|
+
e = assert_raises List::Matcher::Error do
|
|
9
|
+
List::Matcher.pattern %w(cat), symbols: { foo: nil }
|
|
10
|
+
end
|
|
11
|
+
assert_equal 'symbol foo requires a pattern', e.message
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def test_bad_name
|
|
15
|
+
e = assert_raises List::Matcher::Error do
|
|
16
|
+
List::Matcher.pattern %w(cat), name: []
|
|
17
|
+
end
|
|
18
|
+
assert_equal 'name must be a string or symbol', e.message
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def test_bad_bound_symbol
|
|
22
|
+
e = assert_raises List::Matcher::Error do
|
|
23
|
+
List::Matcher.pattern %w(cat), bound: :foo
|
|
24
|
+
end
|
|
25
|
+
assert_equal 'unfamiliar value for :bound option: :foo', e.message
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
def test_bad_bound_no_test
|
|
29
|
+
e = assert_raises List::Matcher::Error do
|
|
30
|
+
List::Matcher.pattern %w(cat), bound: { left: '.' }
|
|
31
|
+
end
|
|
32
|
+
assert_equal 'no boundary test provided', e.message
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def test_bad_bound_neither
|
|
36
|
+
e = assert_raises List::Matcher::Error do
|
|
37
|
+
List::Matcher.pattern %w(cat), bound: { test: '.' }
|
|
38
|
+
end
|
|
39
|
+
assert_equal 'neither bound provided', e.message
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def test_bad_bound_strange_test
|
|
43
|
+
e = assert_raises List::Matcher::Error do
|
|
44
|
+
List::Matcher.pattern %w(cat), bound: { test: [], left: '.' }
|
|
45
|
+
end
|
|
46
|
+
assert_equal 'test must be Regexp or String', e.message
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
def test_bad_bound_not_string
|
|
50
|
+
e = assert_raises List::Matcher::Error do
|
|
51
|
+
List::Matcher.pattern %w(cat), bound: { test: /./, left: [] }
|
|
52
|
+
end
|
|
53
|
+
assert_equal 'bounds must be strings', e.message
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
def test_bad_symbol_no_pattern
|
|
57
|
+
e = assert_raises List::Matcher::Error do
|
|
58
|
+
List::Matcher.pattern %w(cat), symbols: { foo: {} }
|
|
59
|
+
end
|
|
60
|
+
assert_equal 'symbol foo requires a pattern', e.message
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def test_bad_group_name
|
|
64
|
+
e = assert_raises List::Matcher::Error do
|
|
65
|
+
List::Matcher.pattern %w(cat), name: '3'
|
|
66
|
+
end
|
|
67
|
+
assert_equal '3 does not work as the name of a named group', e.message
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
def test_bad_symbol_key
|
|
71
|
+
e = assert_raises List::Matcher::Error do
|
|
72
|
+
List::Matcher.pattern %w(cat), symbols: { [] => 'foo' }
|
|
73
|
+
end
|
|
74
|
+
assert_equal 'symbols variable [] is neither a string, a symbol, nor a regex', e.message
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def test_vetting
|
|
78
|
+
e = assert_raises List::Matcher::Error do
|
|
79
|
+
List::Matcher.pattern %w(cat), symbols: { foo: '++' }, vet: true
|
|
80
|
+
end
|
|
81
|
+
assert_equal 'the symbol foo has an ill-formed pattern: ++', e.message
|
|
82
|
+
end
|
|
83
|
+
end
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: list_matcher
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 1.0.
|
|
4
|
+
version: 1.0.5
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- dfhoughton
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2015-
|
|
11
|
+
date: 2015-09-02 00:00:00.000000000 Z
|
|
12
12
|
dependencies:
|
|
13
13
|
- !ruby/object:Gem::Dependency
|
|
14
14
|
name: bundler
|
|
@@ -57,6 +57,7 @@ files:
|
|
|
57
57
|
- test/basic_test.rb
|
|
58
58
|
- test/benchmarks.rb
|
|
59
59
|
- test/doc_test.rb
|
|
60
|
+
- test/exception_test.rb
|
|
60
61
|
- test/stress.rb
|
|
61
62
|
homepage: https://github.com/dfhoughton/list_matcher
|
|
62
63
|
licenses:
|
|
@@ -86,4 +87,5 @@ test_files:
|
|
|
86
87
|
- test/basic_test.rb
|
|
87
88
|
- test/benchmarks.rb
|
|
88
89
|
- test/doc_test.rb
|
|
90
|
+
- test/exception_test.rb
|
|
89
91
|
- test/stress.rb
|