mustermann-shell 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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
@@ -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>&#123;</b><i>a</i>,<i>b</i><b>&#125;</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
@@ -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: