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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: a0eb87d15ea86cb98dce7e2ca41f6939418c3b57
4
- data.tar.gz: 084dc186f9fbf2f8c4a7ed8268cfa1c78e296728
3
+ metadata.gz: 3241bfa1371172a86936a49ce7f977ab8c8d9edb
4
+ data.tar.gz: 9c1e2d50895f2c65943e2158b63e818b80c8d2e3
5
5
  SHA512:
6
- metadata.gz: 17ccc33fba7022b67fe0da1f9c02fbb6bd4e2d6d8e40fcb0d8ed0420f9733ace1692de35e69151e948b788cf007d7ea49f8c1760809ab02b672e61af16aac9e0
7
- data.tar.gz: a1d2fa238ea0fbc47083c25a4372a6d55848e200b1b850701e63ef12a191c06141b00f0a1871c14b46fe3e8366dcf1dfcf3b588a99f81b2d48117fbefe6eadd5
6
+ metadata.gz: 66082a9cf1cd342c1e636c5243e424c6649418193ce34fe65b1e1b8e62c9f241c289baf3c5a0c48cc3b870bbb7650540e833fd0400454537f8ec1c9f76ba5f8d
7
+ data.tar.gz: 6fbca7071256e9024293d6e0ed69eed42bb7118cc95e80d8f359a81e32e3d6cbf7e520270ad7ca94127936ec7c925efddfcba0ce3b3224a7c2f32bbeb459d0f9
@@ -1 +1,15 @@
1
- 0.0.1: Initial version.
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
+ [![Build Status](https://travis-ci.org/highb/pathspec-ruby.svg?branch=master)](https://travis-ci.org/highb/pathspec-ruby) [![codecov](https://codecov.io/gh/highb/pathspec-ruby/branch/master/graph/badge.svg)](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) ![Travis CI Status](https://travis-ci.org/highb/pathspec-ruby.svg?branch=master)
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
- else
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
- if pattern_segs.length == 1 && pattern_segs[0] != '**'
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
@@ -0,0 +1,9 @@
1
+ begin
2
+ require 'simplecov'
3
+ SimpleCov.start
4
+
5
+ require 'codecov'
6
+ SimpleCov.formatter = SimpleCov::Formatter::Codecov
7
+ rescue
8
+ puts 'SimpleCov failed to start, most likely this due to running Ruby 1.8.7'
9
+ end
@@ -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,12 @@
1
+ require 'spec_helper'
2
+ require 'pathspec/spec'
3
+
4
+ describe Spec do
5
+ subject { Spec.new }
6
+
7
+ it "does not allow matching" do
8
+ expect { subject.match "anything" }.to raise_error
9
+ end
10
+
11
+ it { is_expected.to be_inclusive }
12
+ 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.2
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: 2014-08-11 00:00:00.000000000 Z
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
- homepage: http://rubygems.org/gems/pathspec
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