mustermann-shell 0.4.0
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 +7 -0
- data/README.md +63 -0
- data/lib/mustermann/shell.rb +55 -0
- data/mustermann-shell.gemspec +18 -0
- data/spec/shell_spec.rb +147 -0
- metadata +63 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 70b7a9e2e10df85b4f20be29bf3ef41935a2a73b
|
4
|
+
data.tar.gz: 047921a376ba9ae7317abee42b1044203b3acc6e
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 5f62850ed4adfa6e90b205c249a7790e2ef0fa4bdf43fe7e0bca7c8d88e4a1f8ad3180fd350866ddcbc2c951ed1e5149d098d1e01435867b5ba7fbadc412ddf3
|
7
|
+
data.tar.gz: 1ec90f73ab2938ea02a07b7eb5dc047e20b474e1392a3aa1f1228dc2a42b8d659a7409fcee116a46624291a87791f282d07b60e62ee04803c5f4c31181ba46dc
|
data/README.md
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
# Shell Syntax for Mustermann
|
2
|
+
|
3
|
+
This gem implements the `rails` pattern type for Mustermann. It is compatible with common Unix shells (like bash or zsh).
|
4
|
+
|
5
|
+
## Overview
|
6
|
+
|
7
|
+
**Supported options:** `uri_decode` and `ignore_unknown_options`.
|
8
|
+
|
9
|
+
**External documentation:** [Ruby's fnmatch](http://www.ruby-doc.org/core-2.1.4/File.html#method-c-fnmatch), [Wikipedia: Glob (programming)](http://en.wikipedia.org/wiki/Glob_(programming))
|
10
|
+
|
11
|
+
``` ruby
|
12
|
+
require 'mustermann'
|
13
|
+
|
14
|
+
pattern = Mustermann.new('/*', type: :shell)
|
15
|
+
pattern === "/foo.bar" # => true
|
16
|
+
pattern === "/foo/bar" # => false
|
17
|
+
|
18
|
+
pattern = Mustermann.new('/**/*', type: :shell)
|
19
|
+
pattern === "/foo.bar" # => true
|
20
|
+
pattern === "/foo/bar" # => true
|
21
|
+
|
22
|
+
pattern = Mustermann.new('/{foo,bar}', type: :shell)
|
23
|
+
pattern === "/foo" # => true
|
24
|
+
pattern === "/bar" # => true
|
25
|
+
pattern === "/baz" # => false
|
26
|
+
```
|
27
|
+
|
28
|
+
## Syntax
|
29
|
+
|
30
|
+
<table>
|
31
|
+
<thead>
|
32
|
+
<tr>
|
33
|
+
<th>Syntax Element</th>
|
34
|
+
<th>Description</th>
|
35
|
+
</tr>
|
36
|
+
</thead>
|
37
|
+
<tbody>
|
38
|
+
<tr>
|
39
|
+
<td><b>*</b></td>
|
40
|
+
<td>Matches anything but a slash.</td>
|
41
|
+
</tr>
|
42
|
+
<tr>
|
43
|
+
<td><b>**</b></td>
|
44
|
+
<td>Matches anything.</td>
|
45
|
+
</tr>
|
46
|
+
<tr>
|
47
|
+
<td><b>[</b><i>set</i><b>]</b></td>
|
48
|
+
<td>Matches one character in <i>set</i>.</td>
|
49
|
+
</tr>
|
50
|
+
<tr>
|
51
|
+
<td><b>{</b><i>a</i>,<i>b</i><b>}</b></td>
|
52
|
+
<td>Matches <i>a</i> or <i>b</i>.</td>
|
53
|
+
</tr>
|
54
|
+
<tr>
|
55
|
+
<td><b>\</b><i>x</i></td>
|
56
|
+
<td>Matches <i>x</i> or URI encoded version of <i>x</i>. For instance <tt>\*</tt> matches <tt>*</tt>.</td>
|
57
|
+
</tr>
|
58
|
+
<tr>
|
59
|
+
<td><i>any other character</i></td>
|
60
|
+
<td>Matches exactly that character or a URI encoded version of it.</td>
|
61
|
+
</tr>
|
62
|
+
</tbody>
|
63
|
+
</table>
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'mustermann'
|
2
|
+
require 'mustermann/pattern'
|
3
|
+
require 'mustermann/simple_match'
|
4
|
+
|
5
|
+
module Mustermann
|
6
|
+
# Matches strings that are identical to the pattern.
|
7
|
+
#
|
8
|
+
# @example
|
9
|
+
# Mustermann.new('/*.*', type: :shell) === '/bar' # => false
|
10
|
+
#
|
11
|
+
# @see Mustermann::Pattern
|
12
|
+
# @see file:README.md#shell Syntax description in the README
|
13
|
+
class Shell < Pattern
|
14
|
+
register :shell
|
15
|
+
|
16
|
+
# @!visibility private
|
17
|
+
# @return [#highlight, nil]
|
18
|
+
# highlighing logic for mustermann-visualizer,
|
19
|
+
# nil if mustermann-visualizer hasn't been loaded
|
20
|
+
def highlighter
|
21
|
+
return unless defined? Mustermann::Visualizer::Highlighter
|
22
|
+
@@highlighter ||= Mustermann::Visualizer::Highlighter.create do
|
23
|
+
on('\\') { |matched| escaped(matched, scanner.getch) }
|
24
|
+
on(/[\*\[\]]/, :special)
|
25
|
+
on("{") { nested(:union, ?{, ?}, ?,) }
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
# @param (see Mustermann::Pattern#initialize)
|
30
|
+
# @return (see Mustermann::Pattern#initialize)
|
31
|
+
# @see (see Mustermann::Pattern#initialize)
|
32
|
+
def initialize(string, **options)
|
33
|
+
@flags = File::FNM_PATHNAME | File::FNM_DOTMATCH | File::FNM_EXTGLOB
|
34
|
+
super(string, **options)
|
35
|
+
end
|
36
|
+
|
37
|
+
# @param (see Mustermann::Pattern#===)
|
38
|
+
# @return (see Mustermann::Pattern#===)
|
39
|
+
# @see (see Mustermann::Pattern#===)
|
40
|
+
def ===(string)
|
41
|
+
File.fnmatch? @string, unescape(string), @flags
|
42
|
+
end
|
43
|
+
|
44
|
+
# @param (see Mustermann::Pattern#peek_size)
|
45
|
+
# @return (see Mustermann::Pattern#peek_size)
|
46
|
+
# @see (see Mustermann::Pattern#peek_size)
|
47
|
+
def peek_size(string)
|
48
|
+
@peek_string ||= @string + "{**,/**,/**/*}"
|
49
|
+
super if File.fnmatch? @peek_string, unescape(string), @flags
|
50
|
+
end
|
51
|
+
|
52
|
+
# Used by {Mustermann::FileUtils} to not use a generic glob pattern.
|
53
|
+
alias_method :to_glob, :to_s
|
54
|
+
end
|
55
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
$:.unshift File.expand_path("../../mustermann/lib", __FILE__)
|
2
|
+
require "mustermann/version"
|
3
|
+
|
4
|
+
Gem::Specification.new do |s|
|
5
|
+
s.name = "mustermann-shell"
|
6
|
+
s.version = Mustermann::VERSION
|
7
|
+
s.author = "Konstantin Haase"
|
8
|
+
s.email = "konstantin.mailinglists@googlemail.com"
|
9
|
+
s.homepage = "https://github.com/rkh/mustermann"
|
10
|
+
s.summary = %q{Shell syntax for Mustermann}
|
11
|
+
s.description = %q{Adds Shell style patterns to Mustermman}
|
12
|
+
s.license = 'MIT'
|
13
|
+
s.required_ruby_version = '>= 2.1.0'
|
14
|
+
s.files = `git ls-files`.split("\n")
|
15
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
16
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
17
|
+
s.add_dependency 'mustermann', Mustermann::VERSION
|
18
|
+
end
|
data/spec/shell_spec.rb
ADDED
@@ -0,0 +1,147 @@
|
|
1
|
+
require 'support'
|
2
|
+
require 'mustermann/shell'
|
3
|
+
|
4
|
+
describe Mustermann::Shell do
|
5
|
+
extend Support::Pattern
|
6
|
+
|
7
|
+
pattern '' do
|
8
|
+
it { should match('') }
|
9
|
+
it { should_not match('/') }
|
10
|
+
|
11
|
+
it { should_not respond_to(:expand) }
|
12
|
+
it { should_not respond_to(:to_templates) }
|
13
|
+
end
|
14
|
+
|
15
|
+
pattern '/' do
|
16
|
+
it { should match('/') }
|
17
|
+
it { should_not match('/foo') }
|
18
|
+
|
19
|
+
example { pattern.params('/').should be == {} }
|
20
|
+
example { pattern.params('').should be_nil }
|
21
|
+
end
|
22
|
+
|
23
|
+
pattern '/foo' do
|
24
|
+
it { should match('/foo') }
|
25
|
+
it { should_not match('/bar') }
|
26
|
+
it { should_not match('/foo.bar') }
|
27
|
+
end
|
28
|
+
|
29
|
+
pattern '/foo/bar' do
|
30
|
+
it { should match('/foo/bar') }
|
31
|
+
it { should match('/foo%2Fbar') }
|
32
|
+
it { should match('/foo%2fbar') }
|
33
|
+
end
|
34
|
+
|
35
|
+
pattern '/*/bar' do
|
36
|
+
it { should match('/foo/bar') }
|
37
|
+
it { should match('/bar/bar') }
|
38
|
+
it { should match('/foo%2Fbar') }
|
39
|
+
it { should match('/foo%2fbar') }
|
40
|
+
it { should_not match('/foo/foo/bar') }
|
41
|
+
it { should_not match('/bar/foo') }
|
42
|
+
end
|
43
|
+
|
44
|
+
pattern '/**/foo' do
|
45
|
+
it { should match('/a/b/c/foo') }
|
46
|
+
it { should match('/a/b/c/foo') }
|
47
|
+
it { should match('/a/.b/c/foo') }
|
48
|
+
it { should match('/a/.b/c/foo') }
|
49
|
+
end
|
50
|
+
|
51
|
+
pattern '/:foo' do
|
52
|
+
it { should match('/:foo') }
|
53
|
+
it { should match('/%3Afoo') }
|
54
|
+
it { should_not match('/foo') }
|
55
|
+
it { should_not match('/foo?') }
|
56
|
+
it { should_not match('/foo/bar') }
|
57
|
+
it { should_not match('/') }
|
58
|
+
it { should_not match('/foo/') }
|
59
|
+
end
|
60
|
+
|
61
|
+
pattern '/föö' do
|
62
|
+
it { should match("/f%C3%B6%C3%B6") }
|
63
|
+
end
|
64
|
+
|
65
|
+
pattern '/test$/' do
|
66
|
+
it { should match('/test$/') }
|
67
|
+
end
|
68
|
+
|
69
|
+
pattern '/te+st/' do
|
70
|
+
it { should match('/te+st/') }
|
71
|
+
it { should_not match('/test/') }
|
72
|
+
it { should_not match('/teest/') }
|
73
|
+
end
|
74
|
+
|
75
|
+
pattern "/path with spaces" do
|
76
|
+
it { should match('/path%20with%20spaces') }
|
77
|
+
it { should_not match('/path%2Bwith%2Bspaces') }
|
78
|
+
it { should_not match('/path+with+spaces') }
|
79
|
+
end
|
80
|
+
|
81
|
+
pattern '/foo&bar' do
|
82
|
+
it { should match('/foo&bar') }
|
83
|
+
end
|
84
|
+
|
85
|
+
pattern '/test.bar' do
|
86
|
+
it { should match('/test.bar') }
|
87
|
+
it { should_not match('/test0bar') }
|
88
|
+
end
|
89
|
+
|
90
|
+
pattern '/{foo,bar}' do
|
91
|
+
it { should match('/foo') }
|
92
|
+
it { should match('/bar') }
|
93
|
+
it { should_not match('/foobar') }
|
94
|
+
end
|
95
|
+
|
96
|
+
pattern '/foo/bar', uri_decode: false do
|
97
|
+
it { should match('/foo/bar') }
|
98
|
+
it { should_not match('/foo%2Fbar') }
|
99
|
+
it { should_not match('/foo%2fbar') }
|
100
|
+
end
|
101
|
+
|
102
|
+
pattern "/path with spaces", uri_decode: false do
|
103
|
+
it { should_not match('/path%20with%20spaces') }
|
104
|
+
it { should_not match('/path%2Bwith%2Bspaces') }
|
105
|
+
it { should_not match('/path+with+spaces') }
|
106
|
+
end
|
107
|
+
|
108
|
+
describe :=~ do
|
109
|
+
example { '/foo'.should be =~ Mustermann::Shell.new('/foo') }
|
110
|
+
end
|
111
|
+
|
112
|
+
context "peeking" do
|
113
|
+
subject(:pattern) { Mustermann::Shell.new("foo*/") }
|
114
|
+
|
115
|
+
describe :peek_size do
|
116
|
+
example { pattern.peek_size("foo bar/blah") .should be == "foo bar/".size }
|
117
|
+
example { pattern.peek_size("foo%20bar/blah") .should be == "foo%20bar/".size }
|
118
|
+
example { pattern.peek_size("/foo bar") .should be_nil }
|
119
|
+
|
120
|
+
context 'with just * as pattern' do
|
121
|
+
subject(:pattern) { Mustermann::Shell.new('*') }
|
122
|
+
example { pattern.peek_size('foo') .should be == 3 }
|
123
|
+
example { pattern.peek_size('foo/bar') .should be == 3 }
|
124
|
+
example { pattern.peek_size('foo/bar/baz') .should be == 3 }
|
125
|
+
example { pattern.peek_size('foo/bar/baz/blah') .should be == 3 }
|
126
|
+
end
|
127
|
+
end
|
128
|
+
|
129
|
+
describe :peek_match do
|
130
|
+
example { pattern.peek_match("foo bar/blah") .to_s .should be == "foo bar/" }
|
131
|
+
example { pattern.peek_match("foo%20bar/blah") .to_s .should be == "foo%20bar/" }
|
132
|
+
example { pattern.peek_match("/foo bar") .should be_nil }
|
133
|
+
end
|
134
|
+
|
135
|
+
describe :peek_params do
|
136
|
+
example { pattern.peek_params("foo bar/blah") .should be == [{}, "foo bar/".size] }
|
137
|
+
example { pattern.peek_params("foo%20bar/blah") .should be == [{}, "foo%20bar/".size] }
|
138
|
+
example { pattern.peek_params("/foo bar") .should be_nil }
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
context "highlighting" do
|
143
|
+
let(:pattern) { Mustermann::Shell.new("/**,*/\\*/{a,b}") }
|
144
|
+
subject(:sexp) { Mustermann::Visualizer.highlight(pattern).to_sexp }
|
145
|
+
it { should be == '(root (separator /) (special *) (special *) (char ,) (special *) (separator /) (escaped "\\\\" (escaped_char *)) (separator /) (union { (root (char a)) ,(root (char b)) }))' }
|
146
|
+
end
|
147
|
+
end
|
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mustermann-shell
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.4.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Konstantin Haase
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2014-11-25 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: mustermann
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - '='
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: 0.4.0
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - '='
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: 0.4.0
|
27
|
+
description: Adds Shell style patterns to Mustermman
|
28
|
+
email: konstantin.mailinglists@googlemail.com
|
29
|
+
executables: []
|
30
|
+
extensions: []
|
31
|
+
extra_rdoc_files: []
|
32
|
+
files:
|
33
|
+
- README.md
|
34
|
+
- lib/mustermann/shell.rb
|
35
|
+
- mustermann-shell.gemspec
|
36
|
+
- spec/shell_spec.rb
|
37
|
+
homepage: https://github.com/rkh/mustermann
|
38
|
+
licenses:
|
39
|
+
- MIT
|
40
|
+
metadata: {}
|
41
|
+
post_install_message:
|
42
|
+
rdoc_options: []
|
43
|
+
require_paths:
|
44
|
+
- lib
|
45
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
46
|
+
requirements:
|
47
|
+
- - ">="
|
48
|
+
- !ruby/object:Gem::Version
|
49
|
+
version: 2.1.0
|
50
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '0'
|
55
|
+
requirements: []
|
56
|
+
rubyforge_project:
|
57
|
+
rubygems_version: 2.4.3
|
58
|
+
signing_key:
|
59
|
+
specification_version: 4
|
60
|
+
summary: Shell syntax for Mustermann
|
61
|
+
test_files:
|
62
|
+
- spec/shell_spec.rb
|
63
|
+
has_rdoc:
|