globby 0.0.1

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.
Files changed (6) hide show
  1. data/LICENSE.txt +20 -0
  2. data/README.md +34 -0
  3. data/Rakefile +9 -0
  4. data/lib/globby.rb +54 -0
  5. data/spec/globby_spec.rb +157 -0
  6. metadata +74 -0
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2012 Jon Jensen
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
@@ -0,0 +1,34 @@
1
+ # globby
2
+
3
+ globby is a [.gitignore](http://www.kernel.org/pub/software/scm/git/docs/gitignore.html)-compatible file globber for ruby
4
+
5
+ ## Usage
6
+
7
+ Globby.new(rules).matches
8
+
9
+ ### An example:
10
+
11
+ > rules = File.read('.gitignore').split(/\n/)
12
+ > pp Globby.new(rules).matches
13
+ ["Gemfile.lock",
14
+ "doc/Foreigner.html",
15
+ "doc/Foreigner/Adapter.html",
16
+ "doc/Gemfile.html",
17
+ "doc/Immigrant.html",
18
+ ...
19
+ "immigrant-0.1.3.gem",
20
+ "immigrant-0.1.4.gem"]
21
+ => nil
22
+
23
+ ## Why on earth would I ever use this?
24
+
25
+ * You're curious what is getting `.gitignore`'d and/or you want to do something
26
+ with those files.
27
+ * You're writing a library/tool that will have its own list of ignored/tracked
28
+ files. My use case is for an I18n library that extracts strings from ruby
29
+ files... I need to provide users a nice configurable way to whitelist given
30
+ files/directories/patterns.
31
+
32
+ ## License
33
+
34
+ Copyright (c) 2012 Jon Jensen, released under the MIT license
@@ -0,0 +1,9 @@
1
+ require 'rake'
2
+
3
+ require 'rspec/core'
4
+ require 'rspec/core/rake_task'
5
+ RSpec::Core::RakeTask.new(:spec) do |spec|
6
+ spec.pattern = FileList['spec/**/*_spec.rb']
7
+ end
8
+
9
+ task :default => :spec
@@ -0,0 +1,54 @@
1
+ require 'set'
2
+
3
+ class Globby
4
+ def initialize(patterns = [])
5
+ @patterns = patterns
6
+ end
7
+
8
+ def matches
9
+ result = Set.new
10
+ @patterns.each do |pattern|
11
+ if pattern[0, 1] == '!'
12
+ result.subtract matches_for(pattern[1..-1])
13
+ else
14
+ result.merge matches_for(pattern)
15
+ end
16
+ end
17
+ result.to_a.sort
18
+ end
19
+
20
+ def matches_for(pattern)
21
+ return [] unless pattern = normalize(pattern)
22
+ expects_dir = pattern.sub!(/\/\z/, '')
23
+
24
+ files = Dir.glob(pattern, File::FNM_PATHNAME)
25
+ result = []
26
+ files.each do |file|
27
+ next if ['.', '..'].include?(File.basename(file))
28
+ if directory?(file)
29
+ result.concat matches_for("/" + file + "/**/{*,.*}")
30
+ elsif !expects_dir
31
+ result << file
32
+ end
33
+ end
34
+ result
35
+ end
36
+
37
+ def normalize(pattern)
38
+ pattern = pattern.strip
39
+ first = pattern[0, 1]
40
+ if pattern.empty? || first == '#'
41
+ nil
42
+ elsif first == '/'
43
+ pattern[1..-1]
44
+ else
45
+ "**/" + pattern # could be anywhere
46
+ end
47
+ end
48
+
49
+ protected
50
+
51
+ def directory?(pattern)
52
+ File.directory?(pattern) && !File.symlink?(pattern)
53
+ end
54
+ end
@@ -0,0 +1,157 @@
1
+ require 'globby'
2
+ RSpec.configure { |config| config.mock_framework = :mocha }
3
+
4
+ # A blank line matches no files, so it can serve as a separator for
5
+ # readability.
6
+ #
7
+ # A line starting with # serves as a comment.
8
+ #
9
+ # An optional prefix ! which negates the pattern; any matching file excluded by
10
+ # a previous pattern will become included again. If a negated pattern matches,
11
+ # this will override lower precedence patterns sources.
12
+ #
13
+ # If the pattern ends with a slash, it is removed for the purpose of the
14
+ # following description, but it would only find a match with a directory. In
15
+ # other words, foo/ will match a directory foo and paths underneath it, but
16
+ # will not match a regular file or a symbolic link foo (this is consistent with
17
+ # the way how pathspec works in general in git).
18
+ #
19
+ # If the pattern does not contain a slash /, git treats it as a shell glob
20
+ # pattern and checks for a match against the pathname relative to the location
21
+ # of the .gitignore file (relative to the toplevel of the work tree if not from
22
+ # a .gitignore file).
23
+ #
24
+ # Otherwise, git treats the pattern as a shell glob suitable for consumption by
25
+ # fnmatch(3) with the FNM_PATHNAME flag: wildcards in the pattern will not
26
+ # match a / in the pathname. For example, "Documentation/*.html" matches
27
+ # "Documentation/git.html" but not "Documentation/ppc/ppc.html" or
28
+ # "tools/perf/Documentation/perf.html".
29
+ #
30
+ # A leading slash matches the beginning of the pathname. For example, "/*.c"
31
+ # matches "cat-file.c" but not "mozilla-sha1/sha1.c".
32
+
33
+ describe Globby do
34
+ describe "#matches_for" do
35
+
36
+ let(:globby) { Globby.new }
37
+
38
+ context "a blank line" do
39
+ it "should return nothing" do
40
+ Dir.expects(:glob).never
41
+ globby.matches_for("").should == []
42
+ end
43
+ end
44
+
45
+ context "a comment" do
46
+ it "should return nothing" do
47
+ Dir.expects(:glob).never
48
+ globby.matches_for("#comment").should == []
49
+ end
50
+ end
51
+
52
+ context "a pattern ending in a slash" do
53
+ it "should return a matching directory's contents" do
54
+ globby.stubs(:directory?).returns true, false
55
+ Dir.expects(:glob).twice.returns ["foo"], ['foo/bar']
56
+ globby.matches_for("foo/").should == ['foo/bar']
57
+ end
58
+
59
+ it "should ignore symlinks and regular files" do
60
+ globby.stubs(:directory?).returns false
61
+ Dir.expects(:glob).once.returns ["foo"]
62
+ globby.matches_for("foo/").should == []
63
+ end
64
+ end
65
+
66
+ context "a pattern without a slash" do
67
+ it "should return all glob matches" do
68
+ Dir.expects(:glob).with{ |*args| args.first == "**/*rb"}.returns []
69
+ globby.matches_for("*rb")
70
+ end
71
+ end
72
+
73
+ context "a pattern with a slash" do
74
+ it "should return all glob matches" do
75
+ Dir.expects(:glob).with{ |*args| args.first == "**/foo/bar"}.returns []
76
+ globby.matches_for("foo/bar")
77
+ end
78
+ end
79
+
80
+ context "a pattern starting in a slash" do
81
+ it "should return all root glob matches" do
82
+ Dir.expects(:glob).with{ |*args| args.first == "foo/bar"}.returns []
83
+ globby.matches_for("/foo/bar")
84
+ end
85
+ end
86
+ end
87
+
88
+ describe "#matches" do
89
+ it "should match gitignore perfectly" do
90
+ require 'tmpdir'
91
+ require 'fileutils'
92
+
93
+ files = <<-FILES.strip.split(/\s+/)
94
+ .gitignore
95
+ foo.rb
96
+ foo.html
97
+ bar
98
+ baz/lol.txt
99
+ foo/.hidden
100
+ foo/bar.rb
101
+ foo/bar.html
102
+ foo/bar/baz.pdf
103
+ foobar/.hidden
104
+ foobar/baz.txt
105
+ foobar/baz.rb
106
+ foobar/baz/lol.wut
107
+ FILES
108
+
109
+ ignore = <<-IGNORE.gsub(/^ +/, '')
110
+ # here we go...
111
+
112
+ # some dotfiles
113
+ .hidden
114
+
115
+ # html, but just in the root
116
+ /*.html
117
+
118
+ # all rb files anywhere
119
+ *.rb
120
+
121
+ # except rb files immediately under foobar
122
+ !foobar/*.rb
123
+
124
+ # this will match foo/bar but not bar
125
+ bar/
126
+
127
+ # this will match nothing
128
+ foo*bar/baz.pdf
129
+
130
+ # this will match baz/ and foobar/baz/
131
+ baz
132
+ IGNORE
133
+
134
+ Dir.mktmpdir do |dir|
135
+ Dir.chdir(dir) do
136
+ File.open('.gitignore', 'w'){ |f| f.write ignore }
137
+ files.each do |file|
138
+ FileUtils.mkdir_p File.dirname(file)
139
+ FileUtils.touch file
140
+ end
141
+
142
+ `git init .`
143
+ untracked = `git status -uall`.gsub(/.*#\n|#\s+|^nothing.*/m, '').split(/\n/)
144
+
145
+ globby = Globby.new(ignore.split(/\n/))
146
+ ignored = globby.matches
147
+
148
+ all_files = Dir.glob('**/*', File::FNM_DOTMATCH | File::FNM_PATHNAME).
149
+ reject{ |f| f =~ /^\.git\// }.
150
+ select{ |f| File.symlink?(f) || File.file?(f) }
151
+
152
+ all_files.sort.should == (untracked + ignored).sort
153
+ end
154
+ end
155
+ end
156
+ end
157
+ end
metadata ADDED
@@ -0,0 +1,74 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: globby
3
+ version: !ruby/object:Gem::Version
4
+ hash: 29
5
+ prerelease:
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 1
10
+ version: 0.0.1
11
+ platform: ruby
12
+ authors:
13
+ - Jon Jensen
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2013-01-16 00:00:00 Z
19
+ dependencies: []
20
+
21
+ description: find files using .gitignore-style globs
22
+ email: jenseng@gmail.com
23
+ executables: []
24
+
25
+ extensions: []
26
+
27
+ extra_rdoc_files: []
28
+
29
+ files:
30
+ - LICENSE.txt
31
+ - Rakefile
32
+ - README.md
33
+ - lib/globby.rb
34
+ - spec/globby_spec.rb
35
+ homepage: http://github.com/jenseng/globby
36
+ licenses: []
37
+
38
+ post_install_message:
39
+ rdoc_options: []
40
+
41
+ require_paths:
42
+ - lib
43
+ required_ruby_version: !ruby/object:Gem::Requirement
44
+ none: false
45
+ requirements:
46
+ - - ">="
47
+ - !ruby/object:Gem::Version
48
+ hash: 57
49
+ segments:
50
+ - 1
51
+ - 8
52
+ - 7
53
+ version: 1.8.7
54
+ required_rubygems_version: !ruby/object:Gem::Requirement
55
+ none: false
56
+ requirements:
57
+ - - ">="
58
+ - !ruby/object:Gem::Version
59
+ hash: 17
60
+ segments:
61
+ - 1
62
+ - 3
63
+ - 5
64
+ version: 1.3.5
65
+ requirements: []
66
+
67
+ rubyforge_project:
68
+ rubygems_version: 1.8.24
69
+ signing_key:
70
+ specification_version: 3
71
+ summary: .gitignore-compatible file globber
72
+ test_files: []
73
+
74
+ has_rdoc: