path_list 0.16

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA256:
3
+ metadata.gz: 91d6f384f20b71300e57606743061284dc17782a28cea3526ca68cc27787cc62
4
+ data.tar.gz: 355fd59a3a051fab5408d1fb3c7533d869c56b2619384dd60cfc6f688f44b6e5
5
+ SHA512:
6
+ metadata.gz: 67ff7ebb50d8a66ac2305f5bf3ba911af59fce623313f4a2868cdee18445bdf3e21a6445ddb3b5ebfcd0c80accedfa2ada5fb017a156b7846367cfd0ca936cda
7
+ data.tar.gz: 7b558aaa6c071d63122c29238fb1ae9742d21f3c49171762f3eee94d6d5e45d90e6d6b2e7edf2d4afdc67ac8c86d7db19e4e83f5d1b9e76e064416e234c8e2f5
data/CHANGELOG.md ADDED
@@ -0,0 +1,125 @@
1
+ # v0.16.0
2
+ - Remove relative: true/false, always return relative paths like git does, its the only way i've ever used this gem
3
+ - Remove follow_symlinks: true/false. it's inaccuurately named and unnecessary
4
+ - relative paths to allowed? are expanded relative to the current dir not the PathList.root dir.
5
+ - each starts at the current directory, or optionally a given directory
6
+ - rename gem to path_list with everything in the constant PathList. I've renamed the gem because there's going to be a LOT of api changes soon.
7
+
8
+ # v0.15.2
9
+ - Updated methods with multiple `_` arguments to have different names to make sorbet happy
10
+
11
+ # v0.15.1
12
+ - Updated dependencies to allow running on ruby 3.0.0.preview1
13
+
14
+ # v0.15.0
15
+ - fixed a handful of character class edge cases to match git behavior
16
+ - mostly ranges with - or / as one end of the range
17
+ - major refactoring of the regexp builder that shouldn't have any behaviour implications but should make development easier (e.g. seeing those unhandled edge cases).
18
+ - improved speed of repos with many sub-gitignore files
19
+ - mentioned submodules & sparse checkout in the readme as yet another thing git does that this project doesn't because submodule details are hidden in the git index.
20
+
21
+ # v0.14.0
22
+ - significant performance improvements ~50% faster
23
+ - add `PathList#to_proc` for no good reason
24
+
25
+ # v0.13.0
26
+ - Attempt to improve documentation structure
27
+ - Remove `gitignore: true` raising `Errno::ENOENT` if root:/.gitignore didn't exist. I can't think of a use. Now `gitignore: true` is just the default behaviour.
28
+ - Don't ignore `.git` if `gitignore: false`.
29
+
30
+ # v0.12.1
31
+ - Reads all relevant git config files when finding a global .gitignore
32
+
33
+ # v0.12.0
34
+ - Reads all relevant gitignore files (nested .gitignore files, global .gitignore referred to in .gitconfig, and .git/info/exclude)
35
+
36
+ # v0.11.0
37
+ - major performance improvement (use regexp rather than fnmatch)
38
+ - optionally pass directory: and content: into allowed? if these are already loaded.
39
+
40
+ # v0.10.2
41
+ - add PathList#=== as an alias for PathList#allowed? so that PathList objects can be used for case statements.
42
+ - Fix shebangs in non-pwd-root situations
43
+
44
+ # v0.10.1
45
+ - Add option to follow symlinks (turns out i needed it)
46
+ - performance improvements
47
+
48
+ # v0.10.0
49
+ - patterns with middle slashes are anchored to the root (like the gitignore documentation, now that it more clearly explains)
50
+ - new shebang pattern (#!:), the previous version was extremely janky.
51
+ - now you can ignore by shebang pattern
52
+ - symlinks aren't followed when deciding if a path is a directory or not (this now matches git)
53
+ - documentation improvements
54
+ - root can be given as a path relative to PWD
55
+ - includes with 'a/**/d' now matches a/b/c/d properly
56
+
57
+ # v0.9.0
58
+ - speed improvements, which may break things (Specifically, only using relative paths internally, is about 30% faster (depending on root depth))
59
+ - using a `ignore_files:` or `include_files:` that are outside the `root: (default $PWD)` will now raise an error.
60
+ - remove deprecated `gitignore:` a path (e.g. `gitignore: '/path/to/gitignore'`). please use `gitignore: false, ignore_files: '/path/to/gitignore'` instead.
61
+
62
+ # v0.8.3
63
+ - fix `ignore_rules` not matching directories when using `include_shebangs:`
64
+
65
+ # v0.8.2
66
+ - fix `include_rules` not matching filenames with no extension when using `include_shebangs:`
67
+
68
+ # v0.8.1
69
+ - `include_shebangs:` can be given non array value
70
+
71
+ # v0.8.0
72
+ - drop support for ruby 2.3. My plan is to only support supported ruby versions
73
+ - add coverage to the pipeline. removed some methods, added some tests, and now we have 100% test coverage
74
+ - deprecate using `gitignore: '/path/to/gitignore'`. please use `gitignore: false, ignore_files: '/path/to/gitignore'` instead.
75
+
76
+ # v0.7.0
77
+ - add `include_shebangs:` which filters by shebangs
78
+
79
+ # v0.6.0
80
+ - nicer argv handling
81
+ - add `argv_rules:` option, which resolves paths and considers everything that doesn't start with a `*` to start with a `/`
82
+ - combine the different includes methods and files using AND
83
+ - slightly more realistic version comparison just in case someone releases ruby 2.10
84
+ - can be run with --disable-gems
85
+ - `.allowed?` now more exactly matches `.each`, it returns false for directories and unreadable files.
86
+
87
+ # v0.5.2
88
+ - performance improvements
89
+
90
+ # v0.5.1
91
+ - restore `.allowed?`. now i have tests for it. oops
92
+
93
+ # v0.5.0
94
+ - remove deprecated `:rules` and `:files` arguments
95
+ - ! is now evaluated in sequence for include_rules
96
+ - it's a big refactor, sorry if i broke something
97
+ - some performance improvements
98
+
99
+ # v0.4.1
100
+ - oops i did a regexp wrong
101
+
102
+ # v0.4.0
103
+ - include_rules support
104
+ - to make room for this, `:rules` and `:files` keyword arguments are deprecated.
105
+ Please use `:ignore_rules` and `:ignore_files` instead.
106
+
107
+ # v0.3.3
108
+ - some performance improvements. maybe
109
+
110
+ # v0.3.2
111
+ - handle soft links to nowhere
112
+
113
+ # v0.3.1
114
+ - upgrade rubocop version requirement to avoid github security warning
115
+
116
+ # v0.3.0
117
+ - Supports 2.3 - 2.6
118
+
119
+ # v0.2.0
120
+ - Considers rules relative to the location of the gitignore file instead of just relative to PWD
121
+ - Can override the path to the gitignore file, using `PathList.new(gitignore: path)`
122
+ - Mention PathList#allowed? in the documentation.
123
+
124
+ # v0.1.0
125
+ Initial Release
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Dana Sherson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,317 @@
1
+ # PathList
2
+
3
+ # This is undergoing a major API redesign and when i'm done it'll be 1.0.0, please pin the exact version 0.whatever number in your gemfile
4
+
5
+ [![travis](https://travis-ci.com/robotdana/path_list.svg?branch=main)](https://travis-ci.com/robotdana/path_list)
6
+ [![Gem Version](https://badge.fury.io/rb/path_list.svg)](https://rubygems.org/gems/path_list)
7
+
8
+ This started as a way to quickly and natively ruby-ly parse gitignore files and find matching files.
9
+ It's now gained an equivalent includes file functionality, ARGV awareness, and some shebang matching, while still being extremely fast, to be a one-stop file-list for your linter.
10
+
11
+ Filter a directory tree using a .gitignore file. Recognises all of the [gitignore rules](https://www.git-scm.com/docs/gitignore#_pattern_format)
12
+
13
+ ```ruby
14
+ PathList.new.sort == `git ls-files`.split("\n").sort
15
+ ```
16
+
17
+ ## Features
18
+
19
+ - Fast (faster than using `` `git ls-files`.split("\n") `` for small repos (because it avoids the overhead of ``` `` ```))
20
+ - Supports ruby 2.4-3.0.0.preview1 & jruby
21
+ - supports all [gitignore rule patterns](https://git-scm.com/docs/gitignore#_pattern_format)
22
+ - doesn't require git to be installed
23
+ - supports a gitignore-esque "include" patterns. ([`include_rules:`](#include_rules)/[`include_files:`](#include_files))
24
+ - supports an expansion of include patterns, expanding and anchoring paths ([`argv_rules:`](#argv_rules))
25
+ - supports [matching by shebang](#shebang_rules) rather than filename for extensionless files: `#!:`
26
+ - reads .gitignore in all subdirectories
27
+ - reads .git/info/excludes
28
+ - reads the global gitignore file mentioned in your git config
29
+
30
+ ## Installation
31
+
32
+ Add this line to your application's Gemfile:
33
+
34
+ ```ruby
35
+ gem 'path_list'
36
+ ```
37
+
38
+ And then execute:
39
+ ```sh
40
+ $ bundle
41
+ ```
42
+ Or install it yourself as:
43
+ ```sh
44
+ $ gem install path_list
45
+ ```
46
+
47
+ ## Usage
48
+
49
+ ```ruby
50
+ PathList.new.each { |file| puts "#{file} is not ignored by the .gitignore file" }
51
+ ```
52
+
53
+ ### `#each`, `#map` etc
54
+
55
+ This yields paths that are _not_ ignored by the gitignore, i.e. the paths that would be returned by `git ls-files`.
56
+
57
+ A PathList instance is an Enumerable and responds to all Enumerable methods:
58
+
59
+ ```ruby
60
+ PathList.new.to_a
61
+ PathList.new.map { |file| file.upcase }
62
+ ```
63
+
64
+ Like other enumerables, `PathList#each` can return an enumerator:
65
+
66
+ ```ruby
67
+ PathList.new.each.with_index { |file, index| puts "#{file}#{index}" }
68
+ ```
69
+
70
+ **Warning: Do not change directory (e.g. `Dir.chdir`) in the block.**
71
+
72
+ ### `#allowed?`
73
+
74
+ To check if a single path is allowed, use
75
+ ```ruby
76
+ PathList.new.allowed?('relative/path')
77
+ PathList.new.allowed?('./relative/path')
78
+ PathList.new.allowed?('/absolute/path')
79
+ PathList.new.allowed?('~/home/path')
80
+ ```
81
+
82
+ Relative paths will be considered relative to the [`root:`](#root) directory, not the current directory.
83
+
84
+ This is aliased as `===` so you can use a PathList instance in case statements.
85
+ ```ruby
86
+ case my_path
87
+ when PathList.new
88
+ puts(my_path)
89
+ end
90
+ ```
91
+
92
+ It's recommended to save the PathList instance to a variable to avoid having to read and parse the gitignore file and gitconfig files repeatedly.
93
+
94
+ See [Optimising allowed](#optimising_allowed) for ways to make this even faster
95
+
96
+ **Note: A file must exist at that path and not be a directory for it to be considered allowed.**
97
+ Essentially it can be thought of as `` `git ls-files`.include?(path) `` but much faster.
98
+ This excludes all directories and all possible path names that don't exist.
99
+
100
+ ### `root:`
101
+
102
+ **Default: Dir.pwd ($PWD, the current working directory)**
103
+
104
+ This directory is used for:
105
+ - the location of `.git/core/exclude`
106
+ - the ancestor of all non-global [automatically loaded `.gitignore` files](#gitignore_false)
107
+ - the root directory for array rules ([`ignore_rules:`](#ignore_rules), [`include_rules:`](#include_rules), [`argv_rules:`](#argv_rules)) containing `/`
108
+ - the path that yielded paths are relative to
109
+ - the ancestor of all paths yielded by [`#each`](#each_map_etc)
110
+ - the path that [`#allowed?`](#allowed) considers relative paths relative to
111
+ - the ancestor of all [`include_files:`](#include_files) and [`ignore_files:`](#ignore_files)
112
+
113
+ To use a different directory:
114
+ ```ruby
115
+ PathList.new(root: '/absolute/path/to/root').to_a
116
+ PathList.new(root: '../relative/path/to/root').to_a
117
+ ```
118
+
119
+ A relative root will be found relative to the current working directory when the PathList instance is initialized, and that will be the last time the current working directory is relevant.
120
+
121
+ **Note: Changes to the current working directory (e.g. with `Dir.chdir`), after initialising a PathList instance, will _not_ affect the PathList instance. `root:` will always be what it was when the instance was initialized, even as a default value.**
122
+
123
+ ### `gitignore:`
124
+
125
+ **Default: true**
126
+
127
+ When `gitignore: true`: the .gitignore file in the [`root:`](#root) directory is loaded, plus any .gitignore files in its subdirectories, the global git ignore file as described in git config, and .git/info/exclude. `.git` directories are also excluded to match the behaviour of `git ls-files`.
128
+ When `gitignore: false`: no ignore files or git config files are automatically read, and `.git` will not be automatically excluded.
129
+
130
+ ```ruby
131
+ PathList.new(gitignore: false).to_a
132
+ ```
133
+
134
+ ### `ignore_files:`
135
+
136
+ **This is a list of files in the gitignore format to parse and match paths against, not a list of files to ignore** If you want an array of files use [`ignore_rules:`](#ignore_rules)
137
+
138
+ Additional gitignore-style files, either as a path or an array of paths.
139
+
140
+ You can specify other gitignore-style files to ignore as well.
141
+ Missing files will raise an `Errno::ENOENT` error.
142
+
143
+ Relative paths are relative to the [`root:`](#root) directory.
144
+ Absolute paths also need to be within the [`root:`](#root) directory.
145
+
146
+
147
+ ```ruby
148
+ PathList.new(ignore_files: 'relative/path/to/my/ignore/file').to_a
149
+ PathList.new(ignore_files: ['/absolute/path/to/my/ignore/file', '/and/another']).to_a
150
+ ```
151
+
152
+ Note: the location of the files will affect rules beginning with or containing `/`.
153
+
154
+ To avoid raising `Errno::ENOENT` when the file doesn't exist:
155
+ ```ruby
156
+ PathList.new(ignore_files: ['/ignore/file'].select { |f| File.exist?(f) }).to_a
157
+ ```
158
+
159
+ ### `ignore_rules:`
160
+
161
+ This can be a string, or an array of strings, and multiline strings can be used with one rule per line.
162
+
163
+ ```ruby
164
+ PathList.new(ignore_rules: '.DS_Store').to_a
165
+ PathList.new(ignore_rules: ['.git', '.gitkeep']).to_a
166
+ PathList.new(ignore_rules: ".git\n.gitkeep").to_a
167
+ ```
168
+
169
+ These rules use the [`root:`](#root) argument to resolve rules containing `/`.
170
+
171
+ ### `include_files:`
172
+
173
+ **This is an array of files in the gitignore format to parse and match paths against, not a list of files to include.** If you want an array of files use [`include_rules:`](#include_rules).
174
+
175
+ Building on the gitignore format, PathList also accepts rules to include matching paths (rather than ignoring them).
176
+ A rule matching a directory will include all descendants of that directory.
177
+
178
+ These rules can be provided in files either as absolute or relative paths, or an array of paths.
179
+ Relative paths are relative to the [`root:`](#root) directory.
180
+ Absolute paths also need to be within the [`root:`](#root) directory.
181
+
182
+ ```ruby
183
+ PathList.new(include_files: 'my_include_file').to_a
184
+ PathList.new(include_files: ['/absolute/include/file', './relative/include/file']).to_a
185
+ ```
186
+
187
+ Missing files will raise an `Errno::ENOENT` error.
188
+
189
+ To avoid raising `Errno::ENOENT` when the file doesn't exist:
190
+ ```ruby
191
+ PathList.new(include_files: ['include/file'].select { |f| File.exist?(f) }).to_a
192
+ ```
193
+
194
+ **Note: All paths checked must not be excluded by any ignore files AND each included by include file separately AND the [`include_rules:`](#include_rules) AND the [`argv_rules:`](#argv_rules). see [Combinations](#combinations) for solutions to using OR.**
195
+
196
+ ### `include_rules:`
197
+
198
+ Building on the gitignore format, PathList also accepts rules to include matching paths (rather than ignoring them).
199
+ A rule matching a directory will include all descendants of that directory.
200
+
201
+ This can be a string, or an array of strings, and multiline strings can be used with one rule per line.
202
+ ```ruby
203
+ PathList.new(include_rules: %w{my*rule /and/another !rule}, gitignore: false).to_a
204
+ ```
205
+
206
+ Rules use the [`root:`](#root) argument to resolve rules containing `/`.
207
+
208
+ **Note: All paths checked must not be excluded by any ignore files AND each included by [include file](#include_files) separately AND the `include_rules:` AND the [`argv_rules:`](#argv_rules). see [Combinations](#combinations) for solutions to using OR.**
209
+
210
+ ### `argv_rules:`
211
+ This is like [`include_rules:`](#include_rules) with additional features meant for dealing with humans and `ARGV` values.
212
+
213
+ It expands rules that are absolute paths, and paths beginning with `~`, `../` and `./` (with and without `!`).
214
+ This means rules beginning with `/` are absolute. Not relative to [`root:`](#root).
215
+
216
+ Additionally it assumes all rules are relative to the [`root:`](#root) directory (after resolving absolute paths) unless they begin with `*` (or `!*`).
217
+
218
+ This can be a string, or an array of strings, and multiline strings can be used with one rule per line.
219
+
220
+ ```ruby
221
+ PathList.new(argv_rules: ['./a/pasted/path', '/or/a/path/from/stdin', 'an/argument', '*.txt']).to_a
222
+ ```
223
+
224
+ **Warning: it will *not* expand e.g. `/../` in the middle of a rule that doesn't begin with any of `~`,`../`,`./`,`/`.**
225
+
226
+ **Note: All paths checked must not be excluded by any ignore files AND each included by [include file](#include_files) separately AND the [`include_rules:`](#include_rules) AND the `argv_rules:`. see [Combinations](#combinations) for solutions to using OR.**
227
+
228
+ ### shebang rules
229
+
230
+ Sometimes you need to match files by their shebang/hashbang/etc rather than their path or filename
231
+
232
+ Rules beginning with `#!:` will match whole words in the shebang line of extensionless files.
233
+ e.g.
234
+ ```gitignore
235
+ #!:ruby
236
+ ```
237
+ will match shebang lines: `#!/usr/bin/env ruby` or `#!/usr/bin/ruby` or `#!/usr/bin/ruby -w`
238
+
239
+ e.g.
240
+ ```gitignore
241
+ #!:bin/ruby
242
+ ```
243
+ will match `#!/bin/ruby` or `#!/usr/bin/ruby` or `#!/usr/bin/ruby -w`
244
+ Only exact substring matches are available, There's no special handling of * or / or etc.
245
+
246
+ These rules can be supplied any way regular rules are, whether in a .gitignore file or files mentioned in [`include_files:`](#include_files) or [`ignore_files:`](#ignore_files) or [`include_rules:`](#include_rules) or [`ignore_rules:`](#ignore_rules) or [`argv_rules:`](#argv_rules)
247
+ ```ruby
248
+ PathList.new(include_rules: ['*.rb', '#!:ruby']).to_a
249
+ PathList.new(ignore_rules: ['*.sh', '#!:sh', '#!:bash', '#!:zsh']).to_a
250
+ ```
251
+
252
+ **Note: git considers rules like this as a comment and will ignore them.**
253
+
254
+ ## Combinations
255
+
256
+ In the simplest case a file must be allowed by each ignore file, each include file, and each array of rules. That is, they are combined using `AND`.
257
+
258
+ To combine files using `OR`, that is, a file may be matched by either file it doesn't have to be referred to in both:
259
+ provide the files as strings to [`include_rules:`](#include_rules) or [`ignore_rules:`](#ignore_rules)
260
+ ```ruby
261
+ PathList.new(include_rules: [File.read('/my/path'), File.read('/another/path')])).to_a
262
+ ```
263
+ This does unfortunately lose the file path as the root for rules containing `/`.
264
+ If that's important, combine the files in the file system and use [`include_files:`](#include_files) or [`ignore_files:`](#ignore_files) as normal.
265
+
266
+ To use the additional `ARGV` handling of [`argv_rules:`](#argv_rules) on a file, read the file into the array.
267
+
268
+ ```ruby
269
+ PathList.new(argv_rules: ["my/rule", File.read('/my/path')]).to_a
270
+ ```
271
+
272
+ This does unfortunately lose the file path as the root `/` and there is no workaround except setting the [`root:`](#root) for the whole PathList instance.
273
+
274
+ ### optimising #allowed?
275
+
276
+ To avoid unnecessary calls to the filesystem, if your code already knows whether or not it's a directory, or if you're checking shebangs and you have already read the content of the file: use
277
+ ```ruby
278
+ PathList.new.allowed?('relative/path', directory: false, content: "#!/usr/bin/ruby\n\nputs 'ok'\n")
279
+ ```
280
+ This is not required, and if PathList does have to go to the filesystem for this information it's well optimised to only read what is necessary.
281
+
282
+ ## Limitations
283
+ - Doesn't know what to do if you change the current working directory inside the [`PathList#each`](#each_map_etc) block.
284
+ So don't do that.
285
+
286
+ (It does handle changing the current working directory between [`PathList#allowed?`](#allowed) calls)
287
+ - PathList always matches patterns case-insensitively. (git varies by filesystem).
288
+ - PathList always outputs paths as literal UTF-8 characters. (git depends on your core.quotepath setting but by default outputs non ascii paths with octal escapes surrounded by quotes).
289
+ - Because git looks at its own index objects and PathList looks at the file system there may be some differences between PathList and `git ls-files`. To avoid these differences you may want to use the [`git_ls`](https://github.com/robotdana/git_ls) gem instead
290
+ - Tracked files that were committed before the matching ignore rule was committed will be returned by `git ls-files`, but not by PathList.
291
+ - Untracked files will be returned by PathList, but not by `git ls-files`
292
+ - Deleted files whose deletions haven't been committed will be returned by `git ls-files`, but not by PathList
293
+ - On a case insensitive file system, with files that differ only by case, `git ls-files` will include all case variations, while PathList will only include whichever variation git placed in the file system.
294
+ - PathList is unaware of submodules and just treats them like regular directories. For example: `git ls-files --recurse-submodules` won't use the parent repo's gitignore on a submodule, while PathList doesn't know it's a submodule and will.
295
+ - PathList will only return the files actually on the file system when using `git sparse-checkout`.
296
+
297
+ ## Contributing
298
+
299
+ Bug reports and pull requests are welcome on GitHub at https://github.com/robotdana/path_list.
300
+
301
+ Some tools that may help:
302
+
303
+ - `bin/setup`: install development dependencies
304
+ - `bundle exec rspec`: run all tests
305
+ - `bundle exec rake`: run all tests and linters
306
+ - `bin/console`: open a `pry` console with everything required for experimenting
307
+ - `bin/ls [argv_rules]`: the equivalent of `git ls-files`
308
+ - `bin/prof/ls [argv_rules]`: ruby-prof report for `bin/ls`
309
+ - `bin/prof/parse [argv_rules]`: ruby-prof report for parsing root and global gitignore files and any arguments.
310
+ - `bin/time [argv_rules]`: the average time for 30 runs of `bin/ls`<br>
311
+ This repo is too small to stress bin/time more than 0.01s, switch to a large repo and find the average time before and after changes.
312
+ - `bin/compare`: compare the speed and output of PathList and `git ls-files`.
313
+ (suppressing differences that are because of known [limitations](#limitations))
314
+
315
+ ## License
316
+
317
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).