pathspec 0.0.2 → 0.1.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 +4 -4
- data/CHANGELOG.md +15 -1
- data/README.md +7 -2
- data/lib/pathspec/gitignorespec.rb +22 -3
- data/spec/spec_helper.rb +9 -0
- data/spec/unit/pathspec/gitignorespec_spec.rb +305 -0
- data/spec/unit/pathspec/spec_spec.rb +12 -0
- data/spec/unit/pathspec_spec.rb +322 -0
- metadata +12 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3241bfa1371172a86936a49ce7f977ab8c8d9edb
|
4
|
+
data.tar.gz: 9c1e2d50895f2c65943e2158b63e818b80c8d2e3
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 66082a9cf1cd342c1e636c5243e424c6649418193ce34fe65b1e1b8e62c9f241c289baf3c5a0c48cc3b870bbb7650540e833fd0400454537f8ec1c9f76ba5f8d
|
7
|
+
data.tar.gz: 6fbca7071256e9024293d6e0ed69eed42bb7118cc95e80d8f359a81e32e3d6cbf7e520270ad7ca94127936ec7c925efddfcba0ce3b3224a7c2f32bbeb459d0f9
|
data/CHANGELOG.md
CHANGED
@@ -1 +1,15 @@
|
|
1
|
-
|
1
|
+
# pathspec-ruby CHANGELOG
|
2
|
+
|
3
|
+
## 0.1.0
|
4
|
+
- Port new edgecase handling from [python-path-specification](https://github.com/cpburnz/python-path-specification/pull/8). Many thanks to @jdpace! :)
|
5
|
+
- Removed EOL Ruby support
|
6
|
+
- Added current Ruby stable to Travis testing
|
7
|
+
|
8
|
+
## 0.0.2
|
9
|
+
- Fixed issues with Ruby 1.8.7/2.1.1
|
10
|
+
- Added more testing scripts
|
11
|
+
- Fixed Windows path related issues
|
12
|
+
- Cleanup unnecessary things in gem
|
13
|
+
|
14
|
+
## 0.0.1
|
15
|
+
- Initial version.
|
data/README.md
CHANGED
@@ -1,14 +1,19 @@
|
|
1
1
|
pathspec-ruby
|
2
2
|
=============
|
3
3
|
|
4
|
+
[](https://travis-ci.org/highb/pathspec-ruby) [](https://codecov.io/gh/highb/pathspec-ruby)
|
5
|
+
|
6
|
+
Supported Rubies:
|
7
|
+
- 2.2.7 (Maintenance)
|
8
|
+
- 2.3.4 (Stable)
|
9
|
+
- 2.4.1 (Stable)
|
10
|
+
|
4
11
|
Match Path Specifications, such as .gitignore, in Ruby!
|
5
12
|
|
6
13
|
Follows .gitignore syntax defined on [gitscm](http://git-scm.com/docs/gitignore)
|
7
14
|
|
8
15
|
.gitignore functionality ported from [Python pathspec](https://pypi.python.org/pypi/pathspec/0.2.2) by [@cpburnz](https://github.com/cpburnz/python-path-specification)
|
9
16
|
|
10
|
-
[Travis Status](https://travis-ci.org/highb/pathspec-ruby) 
|
11
|
-
|
12
17
|
## Build/Install from Rubygems
|
13
18
|
```shell
|
14
19
|
gem install pathspec
|
@@ -27,6 +27,12 @@ class GitIgnoreSpec < RegexSpec
|
|
27
27
|
@regex = nil
|
28
28
|
@inclusive = nil
|
29
29
|
|
30
|
+
# EDGE CASE: According to git check-ignore (v2.4.1)), a single '/'
|
31
|
+
# does not match any file
|
32
|
+
elsif pattern == '/'
|
33
|
+
@regex = nil
|
34
|
+
@inclusive = nil
|
35
|
+
|
30
36
|
# We have a valid pattern!
|
31
37
|
else
|
32
38
|
# A pattern starting with an exclamation mark ('!') negates the
|
@@ -58,12 +64,15 @@ class GitIgnoreSpec < RegexSpec
|
|
58
64
|
# to root.
|
59
65
|
if pattern_segs[0].empty?
|
60
66
|
pattern_segs.shift
|
61
|
-
|
67
|
+
elsif pattern_segs.length == 1 ||
|
68
|
+
pattern_segs.length == 2 && pattern_segs[-1].empty?
|
62
69
|
# A pattern without a beginning slash ('/') will match any
|
63
70
|
# descendant path. This is equivilent to "**/{pattern}". So,
|
64
71
|
# prepend with double-asterisks to make pattern relative to
|
65
72
|
# root.
|
66
|
-
|
73
|
+
# EDGE CASE: This also holds for a single pattern with a
|
74
|
+
# trailing slash (e.g. dir/).
|
75
|
+
if pattern_segs[0] != '**'
|
67
76
|
pattern_segs.insert(0, '**')
|
68
77
|
end
|
69
78
|
end
|
@@ -72,7 +81,7 @@ class GitIgnoreSpec < RegexSpec
|
|
72
81
|
# paths of if it is a directory but not if it is a regular file.
|
73
82
|
# This is equivilent to "{pattern}/**". So, set last segment to
|
74
83
|
# double asterisks to include all descendants.
|
75
|
-
if pattern_segs[-1].empty?
|
84
|
+
if pattern_segs[-1].empty? && pattern_segs.length > 1
|
76
85
|
pattern_segs[-1] = '**'
|
77
86
|
end
|
78
87
|
|
@@ -131,6 +140,16 @@ class GitIgnoreSpec < RegexSpec
|
|
131
140
|
end
|
132
141
|
|
133
142
|
regex.concat(translate_segment_glob(seg))
|
143
|
+
|
144
|
+
if i == regex_end && @inclusive
|
145
|
+
# A pattern ending without a slash ('/') will match a file
|
146
|
+
# or a directory (with paths underneath it).
|
147
|
+
# e.g. foo matches: foo, foo/bar, foo/bar/baz, etc.
|
148
|
+
# EDGE CASE: However, this does not hold for exclusion cases
|
149
|
+
# according to `git check-ignore` (v2.4.1).
|
150
|
+
regex.concat("(?:#{path_sep}.*)?")
|
151
|
+
end
|
152
|
+
|
134
153
|
need_slash = true
|
135
154
|
end
|
136
155
|
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,305 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'pathspec/gitignorespec'
|
3
|
+
|
4
|
+
describe 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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 { 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
|
+
|
304
|
+
|
305
|
+
end
|
@@ -0,0 +1,322 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fakefs/safe'
|
3
|
+
require 'pathspec'
|
4
|
+
require 'fakefs/spec_helpers'
|
5
|
+
|
6
|
+
describe PathSpec do
|
7
|
+
shared_examples "standard gitignore negation" do
|
8
|
+
it { is_expected.to_not match('important.txt') }
|
9
|
+
it { is_expected.to_not match('foo/important.txt') }
|
10
|
+
it { is_expected.to match('foo/bar/') }
|
11
|
+
end
|
12
|
+
|
13
|
+
context "initialization" do
|
14
|
+
context "from multilines" do
|
15
|
+
context "#new" do
|
16
|
+
subject { PathSpec.new <<-IGNORELINES
|
17
|
+
!important.txt
|
18
|
+
foo/**
|
19
|
+
/bar/baz
|
20
|
+
IGNORELINES
|
21
|
+
}
|
22
|
+
|
23
|
+
it_behaves_like "standard gitignore negation"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context "from a string with no newlines" do
|
28
|
+
let(:str) { "foo/**" }
|
29
|
+
|
30
|
+
context "#new" do
|
31
|
+
subject { PathSpec.new str }
|
32
|
+
|
33
|
+
it { is_expected.to match('foo/important.txt') }
|
34
|
+
it { is_expected.to match('foo/bar/') }
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
context "from a non-string/non-enumerable" do
|
39
|
+
it "throws an exception" do
|
40
|
+
expect { PathSpec.new Object.new }.to raise_error
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
context "from array of gitignore strings" do
|
45
|
+
let(:arr) { ["!important.txt", "foo/**", "/bar/baz"] }
|
46
|
+
|
47
|
+
context "#new" do
|
48
|
+
subject { PathSpec.new arr }
|
49
|
+
|
50
|
+
it_behaves_like "standard gitignore negation"
|
51
|
+
end
|
52
|
+
|
53
|
+
context "#from_lines" do
|
54
|
+
subject {
|
55
|
+
PathSpec.from_lines(arr)
|
56
|
+
}
|
57
|
+
|
58
|
+
it_behaves_like "standard gitignore negation"
|
59
|
+
end
|
60
|
+
|
61
|
+
context "#add array" do
|
62
|
+
subject {
|
63
|
+
ps = PathSpec.new []
|
64
|
+
ps.add arr
|
65
|
+
}
|
66
|
+
|
67
|
+
it_behaves_like "standard gitignore negation"
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
context "from linedelimited gitignore string" do
|
72
|
+
let(:line) { "!important.txt\nfoo/**\n/bar/baz\n" }
|
73
|
+
|
74
|
+
context "#new" do
|
75
|
+
subject { PathSpec.new line }
|
76
|
+
|
77
|
+
it_behaves_like "standard gitignore negation"
|
78
|
+
end
|
79
|
+
|
80
|
+
context "#from_lines" do
|
81
|
+
subject {
|
82
|
+
PathSpec.from_lines(line)
|
83
|
+
}
|
84
|
+
|
85
|
+
it_behaves_like "standard gitignore negation"
|
86
|
+
end
|
87
|
+
|
88
|
+
context "#add" do
|
89
|
+
subject {
|
90
|
+
ps = PathSpec.new
|
91
|
+
ps.add line
|
92
|
+
}
|
93
|
+
|
94
|
+
it_behaves_like "standard gitignore negation"
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
context "from a gitignore file" do
|
99
|
+
include FakeFS::SpecHelpers
|
100
|
+
|
101
|
+
let(:filename) { '.gitignore' }
|
102
|
+
before(:each) do
|
103
|
+
file = File.open(filename, 'w') { |f|
|
104
|
+
f << "!important.txt\n"
|
105
|
+
f << "foo/**\n"
|
106
|
+
f << "/bar/baz\n"
|
107
|
+
}
|
108
|
+
end
|
109
|
+
|
110
|
+
context "#new" do
|
111
|
+
subject {
|
112
|
+
PathSpec.new File.open(filename, 'r')
|
113
|
+
}
|
114
|
+
|
115
|
+
it_behaves_like "standard gitignore negation"
|
116
|
+
end
|
117
|
+
|
118
|
+
context "#from_filename" do
|
119
|
+
subject {
|
120
|
+
PathSpec.from_filename(filename)
|
121
|
+
}
|
122
|
+
|
123
|
+
it_behaves_like "standard gitignore negation"
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
context "from multiple gitignore files" do
|
128
|
+
include FakeFS::SpecHelpers
|
129
|
+
|
130
|
+
let(:filenames) { ['.gitignore', '.otherignore'] }
|
131
|
+
before(:each) do
|
132
|
+
file = File.open('.gitignore', 'w') { |f|
|
133
|
+
f << "!important.txt\n"
|
134
|
+
f << "foo/**\n"
|
135
|
+
f << "/bar/baz\n"
|
136
|
+
}
|
137
|
+
|
138
|
+
file = File.open('.otherignore', 'w') { |f|
|
139
|
+
f << "ban*na\n"
|
140
|
+
f << "!banana\n"
|
141
|
+
}
|
142
|
+
end
|
143
|
+
|
144
|
+
context "#new" do
|
145
|
+
subject {
|
146
|
+
arr = filenames.collect { |f| File.open(f, 'r') }
|
147
|
+
PathSpec.new arr
|
148
|
+
}
|
149
|
+
|
150
|
+
it_behaves_like "standard gitignore negation"
|
151
|
+
|
152
|
+
it { is_expected.to_not match('banana') }
|
153
|
+
it { is_expected.to match('banananananana') }
|
154
|
+
end
|
155
|
+
|
156
|
+
context "#add" do
|
157
|
+
subject {
|
158
|
+
arr = filenames.collect { |f| File.open(f, 'r') }
|
159
|
+
ps = PathSpec.new
|
160
|
+
ps.add arr
|
161
|
+
}
|
162
|
+
|
163
|
+
it_behaves_like "standard gitignore negation"
|
164
|
+
|
165
|
+
it { is_expected.to_not match('banana') }
|
166
|
+
it { is_expected.to match('banananananana') }
|
167
|
+
end
|
168
|
+
end
|
169
|
+
end
|
170
|
+
|
171
|
+
context "#match_tree" do
|
172
|
+
include FakeFS::SpecHelpers
|
173
|
+
|
174
|
+
context "unix" do
|
175
|
+
let(:root) {'/tmp/project'}
|
176
|
+
let(:gitignore) { <<-GITIGNORE
|
177
|
+
!**/important.txt
|
178
|
+
abc/**
|
179
|
+
GITIGNORE
|
180
|
+
}
|
181
|
+
|
182
|
+
before(:each) {
|
183
|
+
FileUtils.mkdir_p root
|
184
|
+
FileUtils.mkdir_p "#{root}/abc"
|
185
|
+
FileUtils.touch "#{root}/abc/1"
|
186
|
+
FileUtils.touch "#{root}/abc/2"
|
187
|
+
FileUtils.touch "#{root}/abc/important.txt"
|
188
|
+
}
|
189
|
+
|
190
|
+
subject {
|
191
|
+
PathSpec.new(gitignore).match_tree(root)
|
192
|
+
}
|
193
|
+
|
194
|
+
it { is_expected.to include "#{root}/abc".to_s }
|
195
|
+
it { is_expected.to include "#{root}/abc/1".to_s }
|
196
|
+
it { is_expected.not_to include "#{root}/abc/important.txt".to_s }
|
197
|
+
it { is_expected.not_to include "#{root}".to_s }
|
198
|
+
end
|
199
|
+
|
200
|
+
context "windows" do
|
201
|
+
let(:root) {'C:/project'}
|
202
|
+
let(:gitignore) { <<-GITIGNORE
|
203
|
+
!**/important.txt
|
204
|
+
abc/**
|
205
|
+
GITIGNORE
|
206
|
+
}
|
207
|
+
|
208
|
+
before(:each) {
|
209
|
+
FileUtils.mkdir_p root
|
210
|
+
FileUtils.mkdir_p "#{root}/abc"
|
211
|
+
FileUtils.touch "#{root}/abc/1"
|
212
|
+
FileUtils.touch "#{root}/abc/2"
|
213
|
+
FileUtils.touch "#{root}/abc/important.txt"
|
214
|
+
}
|
215
|
+
|
216
|
+
subject {
|
217
|
+
PathSpec.new(gitignore).match_tree(root)
|
218
|
+
}
|
219
|
+
|
220
|
+
it { is_expected.to include "#{root}/abc".to_s }
|
221
|
+
it { is_expected.to include "#{root}/abc/1".to_s }
|
222
|
+
it { is_expected.not_to include "#{root}/abc/important.txt".to_s }
|
223
|
+
it { is_expected.not_to include "#{root}".to_s }
|
224
|
+
end
|
225
|
+
end
|
226
|
+
|
227
|
+
context "#match_paths" do
|
228
|
+
let(:gitignore) { <<-GITIGNORE
|
229
|
+
!**/important.txt
|
230
|
+
/abc/**
|
231
|
+
GITIGNORE
|
232
|
+
}
|
233
|
+
|
234
|
+
context "with no root arg" do
|
235
|
+
subject { PathSpec.new(gitignore).match_paths(['/abc/important.txt', '/abc/', '/abc/1']) }
|
236
|
+
|
237
|
+
it { is_expected.to include "/abc/" }
|
238
|
+
it { is_expected.to include "/abc/1" }
|
239
|
+
it { is_expected.not_to include "/abc/important.txt" }
|
240
|
+
end
|
241
|
+
|
242
|
+
context 'relative to non-root dir' do
|
243
|
+
subject { PathSpec.new(gitignore).match_paths([
|
244
|
+
'/def/abc/important.txt',
|
245
|
+
'/def/abc/',
|
246
|
+
'/def/abc/1'], '/def') }
|
247
|
+
|
248
|
+
it { is_expected.to include "/def/abc/" }
|
249
|
+
it { is_expected.to include "/def/abc/1" }
|
250
|
+
it { is_expected.not_to include "/def/abc/important.txt" }
|
251
|
+
end
|
252
|
+
|
253
|
+
context 'relative to windows drive letter' do
|
254
|
+
subject { PathSpec.new(gitignore).match_paths([
|
255
|
+
'C:/def/abc/important.txt',
|
256
|
+
'C:/def/abc/',
|
257
|
+
'C:/def/abc/1'], 'C:/def/') }
|
258
|
+
|
259
|
+
it { is_expected.to include "C:/def/abc/" }
|
260
|
+
it { is_expected.to include "C:/def/abc/1" }
|
261
|
+
it { is_expected.not_to include "C:/def/abc/important.txt" }
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
# Example to exclude everything except a specific directory foo/bar (note
|
266
|
+
# the /* - without the slash, the wildcard would also exclude everything
|
267
|
+
# within foo/bar): (from git-scm.com)
|
268
|
+
context "very specific gitignore" do
|
269
|
+
let(:gitignore) { <<-GITIGNORE
|
270
|
+
# exclude everything except directory foo/bar
|
271
|
+
/*
|
272
|
+
!/foo
|
273
|
+
/foo/*
|
274
|
+
!/foo/bar
|
275
|
+
GITIGNORE
|
276
|
+
}
|
277
|
+
|
278
|
+
subject { PathSpec.new(gitignore) }
|
279
|
+
|
280
|
+
it { is_expected.not_to match("foo/bar") }
|
281
|
+
it { is_expected.to match("anything") }
|
282
|
+
it { is_expected.to match("foo/otherthing") }
|
283
|
+
end
|
284
|
+
|
285
|
+
context "#empty" do
|
286
|
+
let(:gitignore) { <<-GITIGNORE
|
287
|
+
# A comment
|
288
|
+
GITIGNORE
|
289
|
+
}
|
290
|
+
|
291
|
+
subject { PathSpec.new gitignore }
|
292
|
+
|
293
|
+
it 'is empty when there are no valid lines' do
|
294
|
+
expect(subject.empty?).to be true
|
295
|
+
end
|
296
|
+
end
|
297
|
+
|
298
|
+
context "regex file" do
|
299
|
+
let(:regexfile) { <<-REGEX
|
300
|
+
ab*a
|
301
|
+
REGEX
|
302
|
+
}
|
303
|
+
|
304
|
+
subject { PathSpec.new regexfile, :regex}
|
305
|
+
|
306
|
+
it "matches the regex" do
|
307
|
+
expect(subject.match('anna')).to be false
|
308
|
+
expect(subject.match('abba')).to be true
|
309
|
+
end
|
310
|
+
end
|
311
|
+
|
312
|
+
context "unsuppored spec type" do
|
313
|
+
let(:file) { <<-REGEX
|
314
|
+
This is some kind of nonsense.
|
315
|
+
REGEX
|
316
|
+
}
|
317
|
+
|
318
|
+
it "does not allow an unknown spec type" do
|
319
|
+
expect { PathSpec.new file, :foo}.to raise_error
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: pathspec
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Brandon High
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2017-06-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -51,7 +51,11 @@ files:
|
|
51
51
|
- lib/pathspec/gitignorespec.rb
|
52
52
|
- lib/pathspec/regexspec.rb
|
53
53
|
- lib/pathspec/spec.rb
|
54
|
-
|
54
|
+
- spec/spec_helper.rb
|
55
|
+
- spec/unit/pathspec/gitignorespec_spec.rb
|
56
|
+
- spec/unit/pathspec/spec_spec.rb
|
57
|
+
- spec/unit/pathspec_spec.rb
|
58
|
+
homepage: https://github.com/highb/pathspec-ruby
|
55
59
|
licenses:
|
56
60
|
- Apache
|
57
61
|
metadata: {}
|
@@ -75,4 +79,8 @@ rubygems_version: 2.2.2
|
|
75
79
|
signing_key:
|
76
80
|
specification_version: 4
|
77
81
|
summary: 'PathSpec: for matching path patterns'
|
78
|
-
test_files:
|
82
|
+
test_files:
|
83
|
+
- spec/spec_helper.rb
|
84
|
+
- spec/unit/pathspec/gitignorespec_spec.rb
|
85
|
+
- spec/unit/pathspec/spec_spec.rb
|
86
|
+
- spec/unit/pathspec_spec.rb
|