pathspec 0.0.2 → 1.0.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.
@@ -1,17 +1,21 @@
1
1
  require 'pathspec/spec'
2
2
 
3
- class RegexSpec < Spec
4
- def initialize(regex)
5
- @regex = Regexp.compile regex
3
+ class PathSpec
4
+ # Simple regex-based spec
5
+ class RegexSpec < Spec
6
+ def initialize(pattern)
7
+ @pattern = pattern.dup
8
+ @regex = Regexp.compile pattern
6
9
 
7
- super
8
- end
10
+ super
11
+ end
9
12
 
10
- def inclusive?
11
- true
12
- end
13
+ def inclusive?
14
+ true
15
+ end
13
16
 
14
- def match(path)
15
- @regex.match(path) if @regex
17
+ def match(path)
18
+ @regex&.match(path)
19
+ end
16
20
  end
17
21
  end
@@ -1,14 +1,20 @@
1
- class Spec
2
- attr_reader :regex
1
+ class PathSpec
2
+ # Abstract spec
3
+ class Spec
4
+ attr_reader :regex, :pattern
3
5
 
4
- def initialize(*_)
5
- end
6
+ def initialize(*_); end
6
7
 
7
- def match(files)
8
- raise "Unimplemented"
9
- end
8
+ def match(files)
9
+ raise 'Unimplemented'
10
+ end
11
+
12
+ def inclusive?
13
+ true
14
+ end
10
15
 
11
- def inclusive?
12
- true
16
+ def to_s
17
+ @pattern
18
+ end
13
19
  end
14
20
  end
@@ -0,0 +1,2 @@
1
+ !**/important.txt
2
+ abc/**
@@ -0,0 +1,51 @@
1
+ # Source: https://github.com/github/gitignore/blob/master/Ruby.gitignore
2
+ *.gem
3
+ *.rbc
4
+ /.config
5
+ /coverage/
6
+ /InstalledFiles
7
+ /pkg/
8
+ /spec/reports/
9
+ /spec/examples.txt
10
+ /test/tmp/
11
+ /test/version_tmp/
12
+ /tmp/
13
+
14
+ # Used by dotenv library to load environment variables.
15
+ # .env
16
+
17
+ ## Specific to RubyMotion:
18
+ .dat*
19
+ .repl_history
20
+ build/
21
+ *.bridgesupport
22
+ build-iPhoneOS/
23
+ build-iPhoneSimulator/
24
+
25
+ ## Specific to RubyMotion (use of CocoaPods):
26
+ #
27
+ # We recommend against adding the Pods directory to your .gitignore. However
28
+ # you should judge for yourself, the pros and cons are mentioned at:
29
+ # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
30
+ #
31
+ # vendor/Pods/
32
+
33
+ ## Documentation cache and generated files:
34
+ /.yardoc/
35
+ /_yardoc/
36
+ /doc/
37
+ /rdoc/
38
+
39
+ ## Environment normalization:
40
+ /.bundle/
41
+ /vendor/bundle
42
+ /lib/bundler/man/
43
+
44
+ # for a library or gem, you might want to ignore these files since the code is
45
+ # intended to run in multiple environments; otherwise, check them in:
46
+ # Gemfile.lock
47
+ # .ruby-version
48
+ # .ruby-gemset
49
+
50
+ # unless supporting rvm < 1.11.0 or doing something fancy, ignore this:
51
+ .rvmrc
@@ -0,0 +1 @@
1
+ *.md
@@ -0,0 +1 @@
1
+ .*\.md
@@ -0,0 +1,6 @@
1
+ begin
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+ rescue StandardError
5
+ puts 'SimpleCov failed to start, most likely this due to running Ruby 1.8.7'
6
+ end
@@ -0,0 +1,303 @@
1
+ require 'spec_helper'
2
+ require 'pathspec/gitignorespec'
3
+
4
+ describe PathSpec::GitIgnoreSpec do
5
+ # Original specification by http://git-scm.com/docs/gitignore
6
+
7
+ # A blank line matches no files, so it can serve as a separator for
8
+ # readability.
9
+ describe 'does nothing for newlines' do
10
+ subject { PathSpec::GitIgnoreSpec.new "\n" }
11
+ it { is_expected.to_not match('foo.tmp') }
12
+ it { is_expected.to_not match(' ') }
13
+ it { is_expected.to_not be_inclusive }
14
+ end
15
+
16
+ describe 'does nothing for blank strings' do
17
+ subject { PathSpec::GitIgnoreSpec.new '' }
18
+ it { is_expected.to_not match 'foo.tmp' }
19
+ it { is_expected.to_not match ' ' }
20
+ it { is_expected.to_not be_inclusive }
21
+ end
22
+
23
+ # A line starting with # serves as a comment. Put a backslash ("\") in front
24
+ # of the first hash for patterns that begin with a hash.
25
+ describe 'does nothing for comments' do
26
+ subject { PathSpec::GitIgnoreSpec.new '# this is a gitignore style comment' }
27
+ it { is_expected.to_not match('foo.tmp') }
28
+ it { is_expected.to_not match(' ') }
29
+ it { is_expected.to_not be_inclusive }
30
+ end
31
+
32
+ describe 'ignores comment char with a slash' do
33
+ subject { PathSpec::GitIgnoreSpec.new '\#averystrangefile' }
34
+ it { is_expected.to match('#averystrangefile') }
35
+ it { is_expected.to_not match('foobar') }
36
+ it { is_expected.to be_inclusive }
37
+ end
38
+
39
+ describe 'escapes characters with slashes' do
40
+ subject { PathSpec::GitIgnoreSpec.new 'twinkletwinkle\*' }
41
+ it { is_expected.to match('twinkletwinkle*') }
42
+ it { is_expected.to_not match('twinkletwinkletwinkle') }
43
+ it { is_expected.to be_inclusive }
44
+ end
45
+
46
+ # Trailing spaces are ignored unless they are quoted with backlash ("\").
47
+ describe 'ignores trailing spaces' do
48
+ subject { PathSpec::GitIgnoreSpec.new 'foo ' }
49
+ it { is_expected.to match('foo') }
50
+ it { is_expected.to_not match('foo ') }
51
+ it { is_expected.to be_inclusive }
52
+ end
53
+
54
+ # This is not handled properly yet
55
+ describe 'does not ignore escaped trailing spaces'
56
+
57
+ # An optional prefix "!" which negates the pattern; any matching file excluded
58
+ # by a previous pattern will become included again. It is not possible to
59
+ # re-include a file if a parent directory of that file is excluded. Git
60
+ # doesn't list excluded directories for performance reasons, so any patterns
61
+ # on contained files have no effect, no matter where they are defined. Put a
62
+ # backslash ("\") in front of the first "!" for patterns that begin with a
63
+ # literal "!", for example, "\!important!.txt".
64
+ describe 'is exclusive of !' do
65
+ subject { PathSpec::GitIgnoreSpec.new '!important.txt' }
66
+ it { is_expected.to match('important.txt') }
67
+ it { is_expected.to_not be_inclusive }
68
+ it { is_expected.to_not match('!important.txt') }
69
+ end
70
+
71
+ # If the pattern ends with a slash, it is removed for the purpose of the
72
+ # following description, but it would only find a match with a directory. In
73
+ # other words, foo/ will match a directory foo and paths underneath it, but
74
+ # will not match a regular file or a symbolic link foo (this is consistent
75
+ # with the way how pathspec works in general in Git).
76
+ describe 'trailing slashes match directories and their contents but not regular files or symlinks' do
77
+ subject { PathSpec::GitIgnoreSpec.new 'foo/' }
78
+ it { is_expected.to match('foo/') }
79
+ it { is_expected.to match('foo/bar') }
80
+ it { is_expected.to match('baz/foo/bar') }
81
+ it { is_expected.to_not match('foo') }
82
+ it { is_expected.to be_inclusive }
83
+ end
84
+
85
+ # If the pattern does not contain a slash '/', Git treats it as a shell glob
86
+ # pattern and checks for a match against the pathname relative to the location
87
+ # of the .gitignore file (relative to the toplevel of the work tree if not
88
+ # from a .gitignore file).
89
+ describe 'handles basic globbing' do
90
+ subject { PathSpec::GitIgnoreSpec.new '*.tmp' }
91
+ it { is_expected.to match('foo.tmp') }
92
+ it { is_expected.to match('foo/bar.tmp') }
93
+ it { is_expected.to match('foo/bar.tmp/baz') }
94
+ it { is_expected.to_not match('foo.rb') }
95
+ it { is_expected.to be_inclusive }
96
+ end
97
+
98
+ describe 'handles inner globs' do
99
+ subject { PathSpec::GitIgnoreSpec.new 'foo-*-bar' }
100
+ it { is_expected.to match('foo--bar') }
101
+ it { is_expected.to match('foo-hello-bar') }
102
+ it { is_expected.to match('a/foo-hello-bar') }
103
+ it { is_expected.to match('foo-hello-bar/b') }
104
+ it { is_expected.to match('a/foo-hello-bar/b') }
105
+ it { is_expected.to_not match('foo.tmp') }
106
+ end
107
+
108
+ describe 'handles postfix globs' do
109
+ subject { PathSpec::GitIgnoreSpec.new '~temp-*' }
110
+ it { is_expected.to match('~temp-') }
111
+ it { is_expected.to match('~temp-foo') }
112
+ it { is_expected.to match('foo/~temp-bar') }
113
+ it { is_expected.to match('foo/~temp-bar/baz') }
114
+ it { is_expected.to_not match('~temp') }
115
+ end
116
+
117
+ describe 'handles multiple globs' do
118
+ subject { PathSpec::GitIgnoreSpec.new '*.middle.*' }
119
+ it { is_expected.to match('hello.middle.rb') }
120
+ it { is_expected.to_not match('foo.rb') }
121
+ it { is_expected.to be_inclusive }
122
+ end
123
+
124
+ describe 'handles dir globs' do
125
+ subject { PathSpec::GitIgnoreSpec.new 'dir/*' }
126
+ it { is_expected.to match('dir/foo') }
127
+ it { is_expected.to_not match('foo/') }
128
+ it { is_expected.to be_inclusive }
129
+ end
130
+
131
+ # Otherwise, Git treats the pattern as a shell glob suitable for consumption
132
+ # by fnmatch(3) with the FNM_PATHNAME flag: wildcards in the pattern will not
133
+ # match a / in the pathname. For example, "Documentation/*.html" matches
134
+ # "Documentation/git.html" but not "Documentation/ppc/ppc.html" or
135
+ # "tools/perf/Documentation/perf.html".
136
+ describe 'handles dir globs' do
137
+ subject { PathSpec::GitIgnoreSpec.new 'dir/*' }
138
+ it { is_expected.to match('dir/foo') }
139
+ it { is_expected.to_not match('foo/') }
140
+ it { is_expected.to be_inclusive }
141
+ end
142
+
143
+ describe 'handles globs inside of dirs' do
144
+ subject { PathSpec::GitIgnoreSpec.new 'Documentation/*.html' }
145
+ it { is_expected.to match('Documentation/git.html') }
146
+ it { is_expected.to_not match('Documentation/ppc/ppc.html') }
147
+ it { is_expected.to_not match('tools/perf/Documentation/perf.html') } # TODO: Or is it? Git 2 weirdness?
148
+ it { is_expected.to be_inclusive }
149
+ end
150
+
151
+ describe 'handles wildcards' do
152
+ subject { PathSpec::GitIgnoreSpec.new 'jokeris????' }
153
+ it { is_expected.to match('jokeriswild') }
154
+ it { is_expected.to_not match('jokerisfat') }
155
+ it { is_expected.to be_inclusive }
156
+ end
157
+
158
+ describe 'handles brackets' do
159
+ subject { PathSpec::GitIgnoreSpec.new '*[eu][xl]*' }
160
+ it { is_expected.to match('youknowregex') }
161
+ it { is_expected.to match('youknowregularexpressions') }
162
+ it { is_expected.to_not match('youknownothing') }
163
+ it { is_expected.to be_inclusive }
164
+ end
165
+
166
+ describe 'handles unmatched brackets' do
167
+ subject { PathSpec::GitIgnoreSpec.new '*[*[*' }
168
+ it { is_expected.to match('bracket[oh[wow') }
169
+ it { is_expected.to be_inclusive }
170
+ end
171
+
172
+ describe 'handles brackets with carats' do
173
+ subject { PathSpec::GitIgnoreSpec.new '*[^]' }
174
+ it { is_expected.to match('myfavorite^') }
175
+ it { is_expected.to be_inclusive }
176
+ end
177
+
178
+ describe 'handles brackets for brackets' do
179
+ subject { PathSpec::GitIgnoreSpec.new '*[]]' }
180
+ it { is_expected.to match('yodawg[]]') }
181
+ it { is_expected.to be_inclusive }
182
+ end
183
+
184
+ describe 'handles brackets with escaped characters' do
185
+ # subject { GitIgnoreSpec.new 'back[\\]slash' }
186
+ # it { is_expected.to match('back\\slash') }
187
+ # it { is_expected.to_not match('back\\\\slash') }
188
+ # it { is_expected.to be_inclusive }
189
+ end
190
+
191
+ describe 'handles negated brackets' do
192
+ subject { PathSpec::GitIgnoreSpec.new 'ab[!cd]ef' }
193
+ it { is_expected.to_not match('abcef') }
194
+ it { is_expected.to match('abzef') }
195
+ it { is_expected.to be_inclusive }
196
+ end
197
+
198
+ # A leading slash matches the beginning of the pathname. For example, "/*.c"
199
+ # matches "cat-file.c" but not "mozilla-sha1/sha1.c".
200
+ describe 'handles leading / as relative to base directory' do
201
+ subject { PathSpec::GitIgnoreSpec.new '/*.c' }
202
+ it { is_expected.to match('cat-file.c') }
203
+ it { is_expected.to_not match('mozilla-sha1/sha1.c') }
204
+ it { is_expected.to be_inclusive }
205
+ end
206
+
207
+ describe 'handles simple single paths' do
208
+ subject { PathSpec::GitIgnoreSpec.new 'spam' }
209
+ it { is_expected.to match('spam') }
210
+ it { is_expected.to match('spam/') }
211
+ it { is_expected.to match('foo/spam') }
212
+ it { is_expected.to match('spam/foo') }
213
+ it { is_expected.to match('foo/spam/bar') }
214
+ it { is_expected.to_not match('foo') }
215
+ end
216
+
217
+ # Two consecutive asterisks ("**") in patterns matched against full pathname
218
+ # may have special meaning:
219
+
220
+ # A leading "**" followed by a slash means match in all directories. For
221
+ # example, "**/foo" matches file or directory "foo" anywhere, the same as
222
+ # pattern "foo". "**/foo/bar" matches file or directory "bar" anywhere that is
223
+ # directly under directory "foo".
224
+ describe 'handles prefixed ** as searching any location' do
225
+ subject { PathSpec::GitIgnoreSpec.new '**/foo' }
226
+ it { is_expected.to match('foo') }
227
+ it { is_expected.to match('bar/foo') }
228
+ it { is_expected.to match('baz/bar/foo') }
229
+ it { is_expected.to_not match('baz/bar/foo.rb') }
230
+ it { is_expected.to be_inclusive }
231
+ end
232
+
233
+ describe 'handles prefixed ** with a directory as searching a file under a directory in any location' do
234
+ subject { PathSpec::GitIgnoreSpec.new '**/foo/bar' }
235
+ it { is_expected.to_not match('foo') }
236
+ it { is_expected.to match('foo/bar') }
237
+ it { is_expected.to match('baz/foo/bar') }
238
+ it { is_expected.to match('baz/foo/bar/sub') }
239
+ it { is_expected.to_not match('baz/foo/bar.rb') }
240
+ it { is_expected.to_not match('baz/bananafoo/bar') }
241
+ it { is_expected.to be_inclusive }
242
+ end
243
+
244
+ # A trailing "/**" matches everything inside. For example, "abc/**" matches
245
+ # all files inside directory "abc", relative to the location of the .gitignore
246
+ # file, with infinite depth.
247
+ describe 'handles leading /** as all files inside a directory' do
248
+ subject { PathSpec::GitIgnoreSpec.new 'abc/**' }
249
+ it { is_expected.to match('abc/') }
250
+ it { is_expected.to match('abc/def') }
251
+ it { is_expected.to_not match('123/abc/def') }
252
+ it { is_expected.to_not match('123/456/abc/') }
253
+ it { is_expected.to be_inclusive }
254
+ end
255
+
256
+ # A slash followed by two consecutive asterisks then a slash matches zero or
257
+ # more directories. For example, "a/**/b" matches "a/b", "a/x/b", "a/x/y/b"
258
+ # and so on.
259
+ describe 'handles /** in the middle of a path' do
260
+ subject { PathSpec::GitIgnoreSpec.new 'a/**/b' }
261
+ it { is_expected.to match('a/b') }
262
+ it { is_expected.to match('a/x/b') }
263
+ it { is_expected.to match('a/x/y/b') }
264
+ it { is_expected.to_not match('123/a/b') }
265
+ it { is_expected.to_not match('123/a/x/b') }
266
+ it { is_expected.to be_inclusive }
267
+ end
268
+
269
+ describe 'matches all paths when given **' do
270
+ subject { PathSpec::GitIgnoreSpec.new '**' }
271
+
272
+ it { is_expected.to match('a/b') }
273
+ it { is_expected.to match('a/x/b') }
274
+ it { is_expected.to match('a/x/y/b') }
275
+ it { is_expected.to match('123/a/b') }
276
+ it { is_expected.to match('123/a/x/b') }
277
+ end
278
+
279
+ # Other consecutive asterisks are considered invalid.
280
+ describe 'considers other consecutive asterisks invalid' do
281
+ subject { PathSpec::GitIgnoreSpec.new 'a/***/b' }
282
+ it { is_expected.to_not match('a/b') }
283
+ it { is_expected.to_not match('a/x/b') }
284
+ it { is_expected.to_not match('a/x/y/b') }
285
+ it { is_expected.to_not match('123/a/b') }
286
+ it { is_expected.to_not match('123/a/x/b') }
287
+ it { is_expected.to_not be_inclusive }
288
+ end
289
+
290
+ describe 'does not match single absolute paths' do
291
+ subject { PathSpec::GitIgnoreSpec.new '/' }
292
+ it { is_expected.to_not match('foo.tmp') }
293
+ it { is_expected.to_not match(' ') }
294
+ it { is_expected.to_not match('a/b') }
295
+ end
296
+
297
+ describe 'nested paths are relative to the file' do
298
+ subject { PathSpec::GitIgnoreSpec.new 'foo/spam' }
299
+ it { is_expected.to match('foo/spam') }
300
+ it { is_expected.to match('foo/spam/bar') }
301
+ it { is_expected.to_not match('bar/foo/spam') }
302
+ end
303
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ require 'pathspec/spec'
3
+
4
+ describe PathSpec::Spec do
5
+ subject { PathSpec::Spec.new }
6
+
7
+ it 'does not allow matching' do
8
+ expect { subject.match 'anything' }.to raise_error(/Unimplemented/)
9
+ end
10
+
11
+ it { is_expected.to be_inclusive }
12
+ end