fast_ignore 0.12.1 → 0.13.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/README.md +140 -68
- data/lib/fast_ignore.rb +4 -12
- data/lib/fast_ignore/rule_builder.rb +1 -1
- data/lib/fast_ignore/rule_set.rb +3 -2
- data/lib/fast_ignore/rule_set_builder.rb +5 -5
- data/lib/fast_ignore/shebang_rule.rb +1 -2
- data/lib/fast_ignore/version.rb +1 -1
- metadata +2 -20
- data/.gitignore +0 -6
- data/.leftovers.yml +0 -5
- data/.rspec +0 -3
- data/.rubocop.yml +0 -216
- data/.simplecov +0 -12
- data/.spellr.yml +0 -5
- data/.spellr_wordlists/english.txt +0 -62
- data/.spellr_wordlists/ruby.txt +0 -1
- data/.spellr_wordlists/shell.txt +0 -3
- data/.travis.yml +0 -11
- data/Gemfile +0 -9
- data/Rakefile +0 -18
- data/bin/console +0 -8
- data/bin/ls +0 -6
- data/bin/ls_seconds +0 -21
- data/bin/setup +0 -8
- data/bin/time +0 -21
- data/fast_ignore.gemspec +0 -41
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: ee7e9eb231ff6441ca703c935e9c270e4cb6c2f8f3216d993d4fc891807e77f6
|
4
|
+
data.tar.gz: 68f1ace7ab6420ce140a43a747a969f29401eba718dd9d1e94b9538774b0ac6d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 83609a93cf79d3d4063e69d213450d85f81c4b9bb7c1200468e46fa7fce01602c751c4afd6dbaef652d1761c0f180fa5806ff29d0913ca184a5e41850875a8d0
|
7
|
+
data.tar.gz: dbf3e341e671fa1a51dce4c885c04e1eadf0717d78ffd94f1746c63b1024f78bd9d4b6915e7b892ca3af21d27ef2566df980be41101573c3dd586384b6f6d7c6
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# v0.13.0
|
2
|
+
- Attempt to improve documentation structure
|
3
|
+
- 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.
|
4
|
+
- Don't ignore `.git` if `gitignore: false`.
|
5
|
+
|
1
6
|
# v0.12.1
|
2
7
|
- Reads all relevant git config files when finding a global .gitignore
|
3
8
|
|
data/README.md
CHANGED
@@ -1,6 +1,7 @@
|
|
1
1
|
# FastIgnore
|
2
2
|
|
3
|
-
[![travis](https://travis-ci.
|
3
|
+
[![travis](https://travis-ci.com/robotdana/fast_ignore.svg?branch=master)](https://travis-ci.com/robotdana/fast_ignore)
|
4
|
+
[![Gem Version](https://badge.fury.io/rb/fast_ignore.svg)](https://rubygems.org/gems/fast_ignore)
|
4
5
|
|
5
6
|
This started as a way to quickly and natively ruby-ly parse gitignore files and find matching files.
|
6
7
|
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.
|
@@ -14,13 +15,15 @@ FastIgnore.new(relative: true).sort == `git ls-files`.split("\n").sort
|
|
14
15
|
## Features
|
15
16
|
|
16
17
|
- Fast (faster than using `` `git ls-files`.split("\n") `` for small repos (because it avoids the overhead of ``` `` ```))
|
17
|
-
- Supports ruby 2.4
|
18
|
-
- supports all gitignore rule patterns
|
18
|
+
- Supports ruby 2.4-2.7 & jruby
|
19
|
+
- supports all [gitignore rule patterns](https://git-scm.com/docs/gitignore#_pattern_format)
|
19
20
|
- doesn't require git to be installed
|
20
|
-
- supports a gitignore-esque "include" patterns. (`include_rules
|
21
|
-
- supports an expansion of include patterns,
|
22
|
-
- supports matching by shebang rather than filename for extensionless files: `#!:`
|
23
|
-
-
|
21
|
+
- supports a gitignore-esque "include" patterns. ([`include_rules:`](#include_rules)/[`include_files:`](#include_files))
|
22
|
+
- supports an expansion of include patterns, expanding and anchoring paths ([`argv_rules:`](#argv_rules))
|
23
|
+
- supports [matching by shebang](#shebang_rules) rather than filename for extensionless files: `#!:`
|
24
|
+
- reads .gitignore in all subdirectories
|
25
|
+
- reads .git/info/excludes
|
26
|
+
- reads the ignore file mentioned in your git config
|
24
27
|
|
25
28
|
## Installation
|
26
29
|
|
@@ -47,22 +50,26 @@ FastIgnore.new.each { |file| puts "#{file} is not ignored by the .gitignore file
|
|
47
50
|
|
48
51
|
### `#each`, `#map` etc
|
49
52
|
|
50
|
-
|
53
|
+
This yields paths that are _not_ ignored by the gitignore, i.e. the paths that would be returned by `git ls-files`.
|
54
|
+
|
55
|
+
A FastIgnore instance is an Enumerable and responds to all Enumerable methods:
|
51
56
|
|
52
57
|
```ruby
|
53
58
|
FastIgnore.new.to_a
|
54
59
|
FastIgnore.new.map { |file| file.upcase }
|
55
60
|
```
|
56
61
|
|
57
|
-
Like other enumerables, `FastIgnore#each` can return an enumerator
|
62
|
+
Like other enumerables, `FastIgnore#each` can return an enumerator:
|
58
63
|
|
59
64
|
```ruby
|
60
65
|
FastIgnore.new.each.with_index { |file, index| puts "#{file}#{index}" }
|
61
66
|
```
|
62
67
|
|
68
|
+
**Warning: Do not change directory (e.g. `Dir.chdir`) in the block.**
|
69
|
+
|
63
70
|
### `#allowed?`
|
64
71
|
|
65
|
-
To check if a single
|
72
|
+
To check if a single path is allowed, use
|
66
73
|
```ruby
|
67
74
|
FastIgnore.new.allowed?('relative/path')
|
68
75
|
FastIgnore.new.allowed?('./relative/path')
|
@@ -70,7 +77,9 @@ FastIgnore.new.allowed?('/absolute/path')
|
|
70
77
|
FastIgnore.new.allowed?('~/home/path')
|
71
78
|
```
|
72
79
|
|
73
|
-
|
80
|
+
Relative paths will be considered relative to the [`root:`](#root) directory, not the current directory.
|
81
|
+
|
82
|
+
This is aliased as `===` so you can use a FastIgnore instance in case statements.
|
74
83
|
```ruby
|
75
84
|
case my_path
|
76
85
|
when FastIgnore.new
|
@@ -78,18 +87,34 @@ when FastIgnore.new
|
|
78
87
|
end
|
79
88
|
```
|
80
89
|
|
81
|
-
It's recommended to
|
90
|
+
It's recommended to save the FastIgnore instance to a variable to avoid having to read and parse the gitignore file and gitconfig files repeatedly.
|
91
|
+
|
92
|
+
See [Optimising allowed](#optimising_allowed) for ways to make this even faster
|
93
|
+
|
94
|
+
**Note: A file must exist at that path and not be a directory for it to be considered allowed.**
|
95
|
+
Essentially it can be thought of as `` `git ls-files`.include?(path) `` but much faster.
|
96
|
+
This excludes all directories and all possible path names that don't exist.
|
97
|
+
|
82
98
|
|
83
99
|
### `relative: true`
|
84
|
-
|
100
|
+
|
101
|
+
**Default: false**
|
102
|
+
|
103
|
+
When `relative: false`: FastIgnore#each will yield full paths.
|
104
|
+
When `relative: true`: FastIgnore#each will yield paths relative to the [`root:`](#root) directory
|
85
105
|
|
86
106
|
```ruby
|
87
107
|
FastIgnore.new(relative: true).to_a
|
88
108
|
```
|
89
109
|
|
90
110
|
### `follow_symlinks: true`
|
91
|
-
|
92
|
-
|
111
|
+
|
112
|
+
**Default: false**
|
113
|
+
|
114
|
+
When `follow_symlinks: false`: FastIgnore#each will match git's behaviour and not follow symbolic links.
|
115
|
+
When `follow_symlinks: true`: FastIgnore#each will check if a symlink points to a directory, and files in linked directories must also match rules using the symlink path as the directory location, not the real directory location.
|
116
|
+
|
117
|
+
**This doesn't use the real path for matching or yield or return it.**
|
93
118
|
|
94
119
|
```ruby
|
95
120
|
FastIgnore.new(follow_symlinks: true).to_a
|
@@ -97,14 +122,16 @@ FastIgnore.new(follow_symlinks: true).to_a
|
|
97
122
|
|
98
123
|
### `root:`
|
99
124
|
|
100
|
-
|
125
|
+
**Default: Dir.pwd ($PWD, the current working directory)**
|
126
|
+
|
101
127
|
This directory is used for:
|
102
|
-
- the location of
|
103
|
-
- the
|
104
|
-
- the root directory for array rules
|
105
|
-
-
|
106
|
-
- the ancestor of
|
107
|
-
- the
|
128
|
+
- the location of `.git/core/exclude`
|
129
|
+
- the ancestor of all non-global [automatically loaded `.gitignore` files](#gitignore_false)
|
130
|
+
- the root directory for array rules ([`ignore_rules:`](#ignore_rules), [`include_rules:`](#include_rules), [`argv_rules:`](#argv_rules)) containing `/`
|
131
|
+
- the path that [`relative:`](#relative_true) is relative to
|
132
|
+
- the ancestor of all paths yielded by [`#each`](#each_map_etc)
|
133
|
+
- the path that [`#allowed?`](#allowed) considers relative paths relative to
|
134
|
+
- the ancestor of all [`include_files:`](#include_files) and [`ignore_files:`](#ignore_files)
|
108
135
|
|
109
136
|
To use a different directory:
|
110
137
|
```ruby
|
@@ -112,37 +139,49 @@ FastIgnore.new(root: '/absolute/path/to/root').to_a
|
|
112
139
|
FastIgnore.new(root: '../relative/path/to/root').to_a
|
113
140
|
```
|
114
141
|
|
142
|
+
A relative root will be found relative to the current working directory when the FastIgnore instance is initialized, and that will be the last time the current working directory is relevant.
|
143
|
+
|
144
|
+
**Note: Changes to the current working directory (e.g. with `Dir.chdir`), after initialising a FastIgnore instance, will _not_ affect the FastIgnore instance. `root:` will always be what it was when the instance was initialized.**
|
145
|
+
|
115
146
|
### `gitignore:`
|
116
147
|
|
117
|
-
|
148
|
+
**Default: true**
|
149
|
+
|
150
|
+
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`.
|
151
|
+
When `gitignore: false`: no ignore files or git config files are automatically read, and `.git` will not be automatically excluded.
|
118
152
|
|
119
|
-
To not do this use
|
120
153
|
```ruby
|
121
154
|
FastIgnore.new(gitignore: false).to_a
|
122
155
|
```
|
123
156
|
|
124
|
-
|
125
|
-
```ruby
|
126
|
-
FastIgnore.new(gitignore: true).to_a
|
127
|
-
```
|
157
|
+
### `ignore_files:`
|
128
158
|
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
```
|
133
|
-
Note that the location of the .gitignore file will affect rules beginning with `/` or ending in `/**`
|
159
|
+
**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)
|
160
|
+
|
161
|
+
Additional gitignore-style files, either as a path or an array of paths.
|
134
162
|
|
135
|
-
### `ignore_files:`
|
136
163
|
You can specify other gitignore-style files to ignore as well.
|
137
164
|
Missing files will raise an `Errno::ENOENT` error.
|
138
165
|
|
166
|
+
Relative paths are relative to the [`root:`](#root) directory.
|
167
|
+
Absolute paths also need to be within the [`root:`](#root) directory.
|
168
|
+
|
169
|
+
|
139
170
|
```ruby
|
140
171
|
FastIgnore.new(ignore_files: 'relative/path/to/my/ignore/file').to_a
|
141
172
|
FastIgnore.new(ignore_files: ['/absolute/path/to/my/ignore/file', '/and/another']).to_a
|
142
173
|
```
|
143
174
|
|
175
|
+
Note: the location of the files will affect rules beginning with or containing `/`.
|
176
|
+
|
177
|
+
To avoid raising `Errno::ENOENT` when the file doesn't exist:
|
178
|
+
```ruby
|
179
|
+
FastIgnore.new(ignore_files: ['/ignore/file'].select { |f| File.exist?(f) }).to_a
|
180
|
+
```
|
181
|
+
|
144
182
|
### `ignore_rules:`
|
145
|
-
|
183
|
+
|
184
|
+
This can be a string, or an array of strings, and multiline strings can be used with one rule per line.
|
146
185
|
|
147
186
|
```ruby
|
148
187
|
FastIgnore.new(ignore_rules: '.DS_Store').to_a
|
@@ -150,84 +189,110 @@ FastIgnore.new(ignore_rules: ['.git', '.gitkeep']).to_a
|
|
150
189
|
FastIgnore.new(ignore_rules: ".git\n.gitkeep").to_a
|
151
190
|
```
|
152
191
|
|
153
|
-
|
192
|
+
These rules use the [`root:`](#root) argument to resolve rules containing `/`.
|
154
193
|
|
155
|
-
|
194
|
+
### `include_files:`
|
156
195
|
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
196
|
+
**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).
|
197
|
+
|
198
|
+
Building on the gitignore format, FastIgnore 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
|
+
These rules can be provided in files either as absolute or relative paths, or an array of paths.
|
202
|
+
Relative paths are relative to the [`root:`](#root) directory.
|
203
|
+
Absolute paths also need to be within the [`root:`](#root) directory.
|
204
|
+
|
205
|
+
```ruby
|
206
|
+
FastIgnore.new(include_files: 'my_include_file').to_a
|
207
|
+
FastIgnore.new(include_files: ['/absolute/include/file', './relative/include/file']).to_a
|
208
|
+
```
|
209
|
+
|
210
|
+
Missing files will raise an `Errno::ENOENT` error.
|
211
|
+
|
212
|
+
To avoid raising `Errno::ENOENT` when the file doesn't exist:
|
213
|
+
```ruby
|
214
|
+
FastIgnore.new(include_files: ['include/file'].select { |f| File.exist?(f) }).to_a
|
169
215
|
```
|
170
216
|
|
171
|
-
|
217
|
+
**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.**
|
218
|
+
|
219
|
+
### `include_rules:`
|
220
|
+
|
221
|
+
Building on the gitignore format, FastIgnore also accepts rules to include matching paths (rather than ignoring them).
|
222
|
+
A rule matching a directory will include all descendants of that directory.
|
223
|
+
|
224
|
+
This can be a string, or an array of strings, and multiline strings can be used with one rule per line.
|
172
225
|
```ruby
|
173
|
-
FastIgnore.new(include_files: '/absolute/path/to/my/include/file', gitignore: false).to_a
|
174
226
|
FastIgnore.new(include_rules: %w{my*rule /and/another !rule}, gitignore: false).to_a
|
175
227
|
```
|
176
228
|
|
177
|
-
|
229
|
+
Rules use the [`root:`](#root) argument to resolve rules containing `/`.
|
230
|
+
|
231
|
+
**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.**
|
232
|
+
|
233
|
+
### `argv_rules:`
|
234
|
+
This is like [`include_rules:`](#include_rules) with additional features meant for dealing with humans and `ARGV` values.
|
235
|
+
|
236
|
+
It expands rules that are absolute paths, and paths beginning with `~`, `../` and `./` (with and without `!`).
|
237
|
+
This means rules beginning with `/` are absolute. Not relative to [`root:`](#root).
|
238
|
+
|
239
|
+
Additionally it assumes all rules are relative to the [`root:`](#root) directory (after resolving absolute paths) unless they begin with `*` (or `!*`).
|
240
|
+
|
241
|
+
This can be a string, or an array of strings, and multiline strings can be used with one rule per line.
|
178
242
|
|
179
243
|
```ruby
|
180
244
|
FastIgnore.new(argv_rules: ['./a/pasted/path', '/or/a/path/from/stdin', 'an/argument', '*.txt']).to_a
|
181
245
|
```
|
182
246
|
|
183
|
-
|
184
|
-
It assumes all rules are anchored unless they begin with `*` or `!*`.
|
247
|
+
**Warning: it will *not* expand e.g. `/../` in the middle of a rule that doesn't begin with any of `~`,`../`,`./`,`/`.**
|
185
248
|
|
186
|
-
Note:
|
249
|
+
**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.**
|
187
250
|
|
188
251
|
### shebang rules
|
189
252
|
|
190
|
-
Sometimes you need to match files by their shebang rather than their path or filename
|
191
|
-
|
192
|
-
To match extensionless files by shebang/hashbang/etc:
|
253
|
+
Sometimes you need to match files by their shebang/hashbang/etc rather than their path or filename
|
193
254
|
|
194
|
-
|
255
|
+
Rules beginning with `#!:` will match whole words in the shebang line of extensionless files.
|
195
256
|
e.g.
|
196
257
|
```gitignore
|
197
258
|
#!:ruby
|
198
259
|
```
|
199
260
|
will match shebang lines: `#!/usr/bin/env ruby` or `#!/usr/bin/ruby` or `#!/usr/bin/ruby -w`
|
261
|
+
|
200
262
|
e.g.
|
201
263
|
```gitignore
|
202
264
|
#!:bin/ruby
|
203
265
|
```
|
204
266
|
will match `#!/bin/ruby` or `#!/usr/bin/ruby` or `#!/usr/bin/ruby -w`
|
205
|
-
|
267
|
+
Only exact substring matches are available, There's no special handling of * or / or etc.
|
206
268
|
|
269
|
+
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)
|
207
270
|
```ruby
|
208
271
|
FastIgnore.new(include_rules: ['*.rb', '#!:ruby']).to_a
|
209
272
|
FastIgnore.new(ignore_rules: ['*.sh', '#!:sh', '#!:bash', '#!:zsh']).to_a
|
210
273
|
```
|
211
274
|
|
275
|
+
**Note: git considers rules like this as a comment and will ignore them.**
|
276
|
+
|
212
277
|
## Combinations
|
213
278
|
|
214
|
-
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
|
279
|
+
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`.
|
215
280
|
|
216
281
|
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:
|
217
|
-
provide the files as strings to `include_rules:` or `ignore_rules:`
|
282
|
+
provide the files as strings to [`include_rules:`](#include_rules) or [`ignore_rules:`](#ignore_rules)
|
218
283
|
```ruby
|
219
284
|
FastIgnore.new(include_rules: [File.read('/my/path'), File.read('/another/path')])).to_a
|
220
285
|
```
|
221
|
-
This does unfortunately lose the file path as the root for
|
222
|
-
If that's important, combine the files in the file system and use `include_files:` or `ignore_files:` as normal.
|
286
|
+
This does unfortunately lose the file path as the root for rules containing `/`.
|
287
|
+
If that's important, combine the files in the file system and use [`include_files:`](#include_files) or [`ignore_files:`](#ignore_files) as normal.
|
223
288
|
|
224
|
-
To use the additional ARGV handling
|
289
|
+
To use the additional `ARGV` handling of [`argv_rules:`](#argv_rules) on a file, read the file into the array.
|
225
290
|
|
226
291
|
```ruby
|
227
292
|
FastIgnore.new(argv_rules: ["my/rule", File.read('/my/path')]).to_a
|
228
293
|
```
|
229
294
|
|
230
|
-
This does unfortunately lose the file path as the root
|
295
|
+
This does unfortunately lose the file path as the root `/` and there is no workaround except setting the [`root:`](#root) for the whole FastIgnore instance.
|
231
296
|
|
232
297
|
### optimising #allowed?
|
233
298
|
|
@@ -239,10 +304,11 @@ This is not required, and if FastIgnore does have to go to the filesystem for th
|
|
239
304
|
|
240
305
|
|
241
306
|
## Known issues
|
242
|
-
- Doesn't know what to do if you change the current working directory inside the `FastIgnore#each` block.
|
307
|
+
- Doesn't know what to do if you change the current working directory inside the [`FastIgnore#each`](#each_map_etc) block.
|
243
308
|
So don't do that.
|
244
309
|
|
245
|
-
(It does handle changing the current working directory between `FastIgnore#allowed?` calls.)
|
310
|
+
(It does handle changing the current working directory between [`FastIgnore#allowed?`](#allowed) calls) (changing directories doesn't affect the [`root:`](#root) directory, that's frozen at FastIgnore.new (this is a design decision, not an issue)).
|
311
|
+
- FastIgnore always matches patterns case-insensitively. (git varies by filesystem).
|
246
312
|
|
247
313
|
## Development
|
248
314
|
|
@@ -254,6 +320,12 @@ This repo is too small to stress bin/time more than 0.01s, switch to a large rep
|
|
254
320
|
|
255
321
|
To install this gem onto your local machine, run `bundle exec rake install`.
|
256
322
|
|
323
|
+
### Goals
|
324
|
+
|
325
|
+
1. Match `git ls-files` behaviour quirk for quirk.
|
326
|
+
2. Provide a convenient interface for allowlist/denylist files in ruby.
|
327
|
+
3. Be fast.
|
328
|
+
|
257
329
|
## Contributing
|
258
330
|
|
259
331
|
Bug reports and pull requests are welcome on GitHub at https://github.com/robotdana/fast_ignore.
|
data/lib/fast_ignore.rb
CHANGED
@@ -22,9 +22,9 @@ class FastIgnore
|
|
22
22
|
|
23
23
|
def initialize(relative: false, root: nil, gitignore: :auto, follow_symlinks: false, **rule_set_builder_args)
|
24
24
|
@relative = relative
|
25
|
-
@
|
25
|
+
@follow_symlinks_method = ::File.method(follow_symlinks ? :stat : :lstat)
|
26
26
|
@gitignore_enabled = gitignore
|
27
|
-
@loaded_gitignore_files = Set[''] if gitignore
|
27
|
+
@loaded_gitignore_files = ::Set[''] if gitignore
|
28
28
|
@root = "#{::File.expand_path(root.to_s, Dir.pwd)}/"
|
29
29
|
@rule_sets = ::FastIgnore::RuleSetBuilder.build(root: @root, gitignore: gitignore, **rule_set_builder_args)
|
30
30
|
|
@@ -43,7 +43,7 @@ class FastIgnore
|
|
43
43
|
def allowed?(path, directory: nil, content: nil)
|
44
44
|
full_path = ::File.expand_path(path, @root)
|
45
45
|
return false unless full_path.start_with?(@root)
|
46
|
-
return false if directory.nil? ?
|
46
|
+
return false if directory.nil? ? @follow_symlinks_method.call(full_path).directory? : directory
|
47
47
|
|
48
48
|
relative_path = full_path.delete_prefix(@root)
|
49
49
|
load_gitignore_recursive(relative_path) if @gitignore_enabled
|
@@ -58,14 +58,6 @@ class FastIgnore
|
|
58
58
|
|
59
59
|
private
|
60
60
|
|
61
|
-
def directory?(path)
|
62
|
-
if @follow_symlinks
|
63
|
-
::File.stat(path).directory?
|
64
|
-
else
|
65
|
-
::File.lstat(path).directory?
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
61
|
def load_gitignore_recursive(path)
|
70
62
|
paths = []
|
71
63
|
while (path = ::File.dirname(path)) != '.'
|
@@ -93,7 +85,7 @@ class FastIgnore
|
|
93
85
|
begin
|
94
86
|
full_path = parent_full_path + filename
|
95
87
|
relative_path = parent_relative_path + filename
|
96
|
-
dir =
|
88
|
+
dir = @follow_symlinks_method.call(full_path).directory?
|
97
89
|
|
98
90
|
next unless @rule_sets.all? { |r| r.allowed_unrecursive?(relative_path, dir, full_path, filename, nil) }
|
99
91
|
|
@@ -32,7 +32,7 @@ class FastIgnore
|
|
32
32
|
end
|
33
33
|
|
34
34
|
def shebang_rules(rule, allow)
|
35
|
-
rules = [::FastIgnore::ShebangRule.new(/\A#!.*\b#{Regexp.escape(rule)}\b
|
35
|
+
rules = [::FastIgnore::ShebangRule.new(/\A#!.*\b#{Regexp.escape(rule)}\b/i.freeze, allow)]
|
36
36
|
return rules unless allow
|
37
37
|
|
38
38
|
rules << ::FastIgnore::Rule.new('**/*', true, true, true)
|
data/lib/fast_ignore/rule_set.rb
CHANGED
@@ -46,9 +46,10 @@ class FastIgnore
|
|
46
46
|
|
47
47
|
def squash_rules(rules)
|
48
48
|
out = rules.chunk_while { |a, b| a.type == b.type }.map do |chunk|
|
49
|
-
|
49
|
+
first = chunk.first
|
50
|
+
next first if chunk.length == 1
|
50
51
|
|
51
|
-
|
52
|
+
first.class.new(Regexp.union(chunk.map(&:rule)), first.negation?)
|
52
53
|
end
|
53
54
|
|
54
55
|
out
|
@@ -11,7 +11,7 @@ class FastIgnore
|
|
11
11
|
root:,
|
12
12
|
ignore_rules: nil,
|
13
13
|
ignore_files: nil,
|
14
|
-
gitignore:
|
14
|
+
gitignore: true,
|
15
15
|
include_rules: nil,
|
16
16
|
include_files: nil,
|
17
17
|
argv_rules: nil
|
@@ -19,7 +19,7 @@ class FastIgnore
|
|
19
19
|
prepare [
|
20
20
|
from_array(ignore_rules),
|
21
21
|
*from_files(ignore_files, project_root: root),
|
22
|
-
from_array('.git'),
|
22
|
+
(from_array('.git') if gitignore),
|
23
23
|
from_gitignore_arg(gitignore, project_root: root),
|
24
24
|
from_array(include_rules, allow: true),
|
25
25
|
*from_files(include_files, allow: true, project_root: root),
|
@@ -72,12 +72,12 @@ class FastIgnore
|
|
72
72
|
gi = ::FastIgnore::RuleSet.new([], false, true)
|
73
73
|
gi << from_root_gitignore_file(global_gitignore_path(root: project_root))
|
74
74
|
gi << from_root_gitignore_file(::File.join(project_root, '.git/info/exclude'))
|
75
|
-
gi << from_root_gitignore_file(::File.join(project_root, '.gitignore')
|
75
|
+
gi << from_root_gitignore_file(::File.join(project_root, '.gitignore'))
|
76
76
|
gi
|
77
77
|
end
|
78
78
|
|
79
|
-
def from_root_gitignore_file(path
|
80
|
-
return
|
79
|
+
def from_root_gitignore_file(path)
|
80
|
+
return unless ::File.exist?(path)
|
81
81
|
|
82
82
|
build_rule_set(::File.readlines(path), false, file_root: '', gitignore: true)
|
83
83
|
end
|
data/lib/fast_ignore/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: fast_ignore
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.13.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dana Sherson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-06-06 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -143,27 +143,9 @@ executables: []
|
|
143
143
|
extensions: []
|
144
144
|
extra_rdoc_files: []
|
145
145
|
files:
|
146
|
-
- ".gitignore"
|
147
|
-
- ".leftovers.yml"
|
148
|
-
- ".rspec"
|
149
|
-
- ".rubocop.yml"
|
150
|
-
- ".simplecov"
|
151
|
-
- ".spellr.yml"
|
152
|
-
- ".spellr_wordlists/english.txt"
|
153
|
-
- ".spellr_wordlists/ruby.txt"
|
154
|
-
- ".spellr_wordlists/shell.txt"
|
155
|
-
- ".travis.yml"
|
156
146
|
- CHANGELOG.md
|
157
|
-
- Gemfile
|
158
147
|
- LICENSE.txt
|
159
148
|
- README.md
|
160
|
-
- Rakefile
|
161
|
-
- bin/console
|
162
|
-
- bin/ls
|
163
|
-
- bin/ls_seconds
|
164
|
-
- bin/setup
|
165
|
-
- bin/time
|
166
|
-
- fast_ignore.gemspec
|
167
149
|
- lib/fast_ignore.rb
|
168
150
|
- lib/fast_ignore/backports.rb
|
169
151
|
- lib/fast_ignore/fn_match_to_re.rb
|
data/.gitignore
DELETED
data/.leftovers.yml
DELETED
data/.rspec
DELETED
data/.rubocop.yml
DELETED
@@ -1,216 +0,0 @@
|
|
1
|
-
require: rubocop-rspec
|
2
|
-
|
3
|
-
# Reference:
|
4
|
-
# https://rubocop.readthedocs.io/en/latest/
|
5
|
-
|
6
|
-
# Keep this in alphabetical order.
|
7
|
-
# Each override should have a comment (even if it's just "default is bad")
|
8
|
-
|
9
|
-
AllCops:
|
10
|
-
NewCops: enable
|
11
|
-
Exclude:
|
12
|
-
- db/schema*
|
13
|
-
- .bundle/**/*
|
14
|
-
- tmp/**/*
|
15
|
-
- vendor/**/*
|
16
|
-
DisplayCopNames: true
|
17
|
-
DisplayStyleGuide: true
|
18
|
-
TargetRubyVersion: 2.4
|
19
|
-
|
20
|
-
# all of our layout customisations are because we prefer indentation to be
|
21
|
-
# always consistently 2 spaces, for blocks, scopes, multiline expressions, etc
|
22
|
-
# e.g.
|
23
|
-
# class Klass
|
24
|
-
# def method(arg1,
|
25
|
-
# arg2)
|
26
|
-
# value = if arg1 == 'value' && arg2 == 'value'
|
27
|
-
# method2
|
28
|
-
# .method(arg_a, arg_b,
|
29
|
-
# arg_c, arg_d, keyword1: true,
|
30
|
-
# keyword2: true) do
|
31
|
-
# @last = [
|
32
|
-
# arg_a, arg_b,
|
33
|
-
# arg_c, arg_d
|
34
|
-
# ]
|
35
|
-
# end
|
36
|
-
# end
|
37
|
-
# value
|
38
|
-
# end
|
39
|
-
# end
|
40
|
-
|
41
|
-
# to match our preference for consistent indentation
|
42
|
-
Layout/HashAlignment:
|
43
|
-
EnforcedLastArgumentHashStyle: always_ignore
|
44
|
-
|
45
|
-
# to match our preference for consistent indentation
|
46
|
-
Layout/ParameterAlignment:
|
47
|
-
EnforcedStyle: with_fixed_indentation
|
48
|
-
|
49
|
-
# to match our preference for consistent indentation
|
50
|
-
Layout/BlockAlignment:
|
51
|
-
EnforcedStyleAlignWith: start_of_block
|
52
|
-
|
53
|
-
# to match our preference for consistent indentation
|
54
|
-
Layout/CaseIndentation:
|
55
|
-
EnforcedStyle: end
|
56
|
-
|
57
|
-
# to match our preference for consistent indentation
|
58
|
-
Layout/EndAlignment:
|
59
|
-
EnforcedStyleAlignWith: start_of_line
|
60
|
-
|
61
|
-
# Aligning Assignments, etc makes diffs noisy
|
62
|
-
Layout/ExtraSpacing:
|
63
|
-
AllowForAlignment: false
|
64
|
-
|
65
|
-
# to match our preference for consistent indentation
|
66
|
-
Layout/FirstArrayElementLineBreak:
|
67
|
-
Enabled: true
|
68
|
-
|
69
|
-
# to match our preference for consistent indentation
|
70
|
-
Layout/FirstHashElementLineBreak:
|
71
|
-
Enabled: true
|
72
|
-
|
73
|
-
# to match our preference for consistent indentation
|
74
|
-
Layout/FirstArgumentIndentation:
|
75
|
-
EnforcedStyle: consistent
|
76
|
-
|
77
|
-
# to match our preference for consistent indentation
|
78
|
-
Layout/FirstArrayElementIndentation:
|
79
|
-
EnforcedStyle: consistent
|
80
|
-
|
81
|
-
# to match our preference for consistent indentation
|
82
|
-
Layout/FirstHashElementIndentation:
|
83
|
-
EnforcedStyle: consistent
|
84
|
-
|
85
|
-
Layout/LineLength:
|
86
|
-
Max: 120
|
87
|
-
|
88
|
-
# to match our preference for consistent indentation
|
89
|
-
# and hanging assignment looks lost
|
90
|
-
Layout/MultilineAssignmentLayout:
|
91
|
-
EnforcedStyle: same_line
|
92
|
-
|
93
|
-
# this changes our preferred:
|
94
|
-
# value = if thing1 &&
|
95
|
-
# thing2
|
96
|
-
# to:
|
97
|
-
# value = if thing1 &&
|
98
|
-
# thing2
|
99
|
-
# even though the IndentationWidth is 2
|
100
|
-
# but it's right most of the time so I put up with it
|
101
|
-
Layout/MultilineOperationIndentation:
|
102
|
-
EnforcedStyle: indented
|
103
|
-
|
104
|
-
Layout/MultilineMethodCallIndentation:
|
105
|
-
EnforcedStyle: indented
|
106
|
-
|
107
|
-
# Temporarily disable this spec as a recent change has broken it for us:
|
108
|
-
# https://github.com/rubocop-hq/rubocop/issues/6254
|
109
|
-
Layout/RescueEnsureAlignment:
|
110
|
-
Enabled: false
|
111
|
-
|
112
|
-
Metrics:
|
113
|
-
CountComments: false
|
114
|
-
|
115
|
-
Metrics/BlockLength:
|
116
|
-
ExcludedMethods:
|
117
|
-
- configure
|
118
|
-
- describe
|
119
|
-
- context
|
120
|
-
- shared_examples
|
121
|
-
|
122
|
-
Metrics/CyclomaticComplexity:
|
123
|
-
Enabled: false
|
124
|
-
|
125
|
-
Metrics/PerceivedComplexity:
|
126
|
-
Enabled: false
|
127
|
-
|
128
|
-
RSpec:
|
129
|
-
Enabled: true
|
130
|
-
Include:
|
131
|
-
- 'spec/**/*.rb'
|
132
|
-
|
133
|
-
RSpec/DescribeClass:
|
134
|
-
Enabled: false
|
135
|
-
|
136
|
-
# I misuse matchers often
|
137
|
-
RSpec/ExpectActual:
|
138
|
-
Enabled: false
|
139
|
-
|
140
|
-
RSpec/FilePath:
|
141
|
-
Enabled: false
|
142
|
-
|
143
|
-
# Multiple expectations are useful
|
144
|
-
# checking you've partially achieved something on the way to completely achieving it is useful for debugging failures
|
145
|
-
RSpec/MultipleExpectations:
|
146
|
-
Enabled: false
|
147
|
-
|
148
|
-
# It should be obvious from context. Chill out rubocop
|
149
|
-
RSpec/NamedSubject:
|
150
|
-
Enabled: false
|
151
|
-
|
152
|
-
RSpec/NestedGroups:
|
153
|
-
Max: 7
|
154
|
-
|
155
|
-
# This matches the style we've been using all along (ever so slightly more frequently)
|
156
|
-
Style/Alias:
|
157
|
-
EnforcedStyle: prefer_alias_method
|
158
|
-
|
159
|
-
Style/CollectionMethods:
|
160
|
-
Enabled: true
|
161
|
-
|
162
|
-
# we don't rdoc
|
163
|
-
Style/Documentation:
|
164
|
-
Enabled: false
|
165
|
-
|
166
|
-
# this can mess with the balance of symmetric cases
|
167
|
-
Style/IfInsideElse:
|
168
|
-
Enabled: false
|
169
|
-
|
170
|
-
# [a, b].include?(x) is more unclear than a == x || b == x
|
171
|
-
Style/MultipleComparison:
|
172
|
-
Enabled: false
|
173
|
-
|
174
|
-
# it's microscopically faster
|
175
|
-
Style/Not:
|
176
|
-
Enabled: false
|
177
|
-
|
178
|
-
# we use %w{} pretty frequently
|
179
|
-
Style/PercentLiteralDelimiters:
|
180
|
-
PreferredDelimiters:
|
181
|
-
default: '{}'
|
182
|
-
'%w': '{}'
|
183
|
-
'%W': '{}'
|
184
|
-
'%i': '{}'
|
185
|
-
'%I': '{}'
|
186
|
-
'%r': '{}'
|
187
|
-
|
188
|
-
# We want this to warn to force consistency within the codebase.
|
189
|
-
Style/SafeNavigation:
|
190
|
-
Enabled: true
|
191
|
-
|
192
|
-
# different methods calls that do exactly the same thing are a smell, regardless of semantics
|
193
|
-
Style/SignalException:
|
194
|
-
EnforcedStyle: only_raise
|
195
|
-
|
196
|
-
# this wants less descriptive names
|
197
|
-
Style/SingleLineBlockParams:
|
198
|
-
Enabled: false
|
199
|
-
|
200
|
-
Style/SymbolArray:
|
201
|
-
Enabled: false
|
202
|
-
|
203
|
-
Style/WordArray:
|
204
|
-
Enabled: false
|
205
|
-
|
206
|
-
Style/HashEachMethods:
|
207
|
-
Enabled: true
|
208
|
-
|
209
|
-
Style/HashTransformKeys:
|
210
|
-
Enabled: true
|
211
|
-
|
212
|
-
Style/HashTransformValues:
|
213
|
-
Enabled: true
|
214
|
-
|
215
|
-
Style/CommentedKeyword:
|
216
|
-
Enabled: false
|
data/.simplecov
DELETED
@@ -1,12 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
SimpleCov.start do
|
4
|
-
add_filter '/backports'
|
5
|
-
add_filter '/spec/'
|
6
|
-
if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.5')
|
7
|
-
enable_coverage(:branch)
|
8
|
-
minimum_coverage line: 100, branch: 100
|
9
|
-
else
|
10
|
-
minimum_coverage 100
|
11
|
-
end
|
12
|
-
end
|
data/.spellr.yml
DELETED
@@ -1,62 +0,0 @@
|
|
1
|
-
argv
|
2
|
-
backports
|
3
|
-
baz
|
4
|
-
changelog
|
5
|
-
codebase
|
6
|
-
config
|
7
|
-
cov
|
8
|
-
cyclomatic
|
9
|
-
enoent
|
10
|
-
enumerables
|
11
|
-
env
|
12
|
-
errno
|
13
|
-
esque
|
14
|
-
excludesfile
|
15
|
-
extensionless
|
16
|
-
fancyignore
|
17
|
-
filesystem
|
18
|
-
fnmatch
|
19
|
-
frotz
|
20
|
-
gemfile
|
21
|
-
gitconfig
|
22
|
-
github
|
23
|
-
gitignore
|
24
|
-
gitkeep
|
25
|
-
hashbang
|
26
|
-
includefile
|
27
|
-
janky
|
28
|
-
jruby
|
29
|
-
klass
|
30
|
-
llo
|
31
|
-
memoize
|
32
|
-
nocov
|
33
|
-
noninfringement
|
34
|
-
params
|
35
|
-
pathspec
|
36
|
-
pwd
|
37
|
-
rdoc
|
38
|
-
regexp
|
39
|
-
rspec
|
40
|
-
rubo
|
41
|
-
rubocop
|
42
|
-
rubygems
|
43
|
-
rubyish
|
44
|
-
rulesets
|
45
|
-
rvm
|
46
|
-
sherson
|
47
|
-
simplecov
|
48
|
-
stdin
|
49
|
-
subdir
|
50
|
-
substring
|
51
|
-
sudo
|
52
|
-
symlinks
|
53
|
-
tmp
|
54
|
-
toplevel
|
55
|
-
txt
|
56
|
-
unrecursive
|
57
|
-
upcase
|
58
|
-
usr
|
59
|
-
webpack
|
60
|
-
xconfig
|
61
|
-
xdg
|
62
|
-
zsh
|
data/.spellr_wordlists/ruby.txt
DELETED
@@ -1 +0,0 @@
|
|
1
|
-
rspec
|
data/.spellr_wordlists/shell.txt
DELETED
data/.travis.yml
DELETED
data/Gemfile
DELETED
data/Rakefile
DELETED
@@ -1,18 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require 'bundler/gem_tasks'
|
4
|
-
require 'rspec/core/rake_task'
|
5
|
-
require 'rubocop/rake_task'
|
6
|
-
require 'spellr/rake_task'
|
7
|
-
require 'leftovers/rake_task'
|
8
|
-
|
9
|
-
RuboCop::RakeTask.new
|
10
|
-
RSpec::Core::RakeTask.new(:spec)
|
11
|
-
Spellr::RakeTask.generate_task
|
12
|
-
Leftovers::RakeTask.generate_task
|
13
|
-
|
14
|
-
if RUBY_PLATFORM == 'java'
|
15
|
-
task default: :spec
|
16
|
-
else
|
17
|
-
task default: [:spec, :rubocop, :spellr, :leftovers]
|
18
|
-
end
|
data/bin/console
DELETED
data/bin/ls
DELETED
data/bin/ls_seconds
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby --disable-all
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
require_relative '../lib/fast_ignore'
|
5
|
-
|
6
|
-
t1 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
7
|
-
new_a = FastIgnore.new(relative: true, argv_rules: ARGV).to_a
|
8
|
-
t2 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
9
|
-
puts "new #{new_a.count}: #{t2 - t1}"
|
10
|
-
fi = FastIgnore.new(relative: true, argv_rules: ARGV)
|
11
|
-
fi.to_a
|
12
|
-
t3 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
13
|
-
cached_a = fi.to_a
|
14
|
-
t4 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
15
|
-
puts "cached #{cached_a.count}: #{t4 - t3}"
|
16
|
-
t5 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
17
|
-
git_a = `git ls-files`.split("\n")
|
18
|
-
t6 = Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
19
|
-
puts "git ls-files #{git_a.count}: #{t6 - t5}"
|
20
|
-
|
21
|
-
exit 1 unless new_a.length == cached_a.length && new_a.length == git_a.length
|
data/bin/setup
DELETED
data/bin/time
DELETED
@@ -1,21 +0,0 @@
|
|
1
|
-
#!/usr/bin/env ruby
|
2
|
-
# frozen_string_literal: true
|
3
|
-
|
4
|
-
# use mac terminal not vs code terminal
|
5
|
-
# ensure nothing else is watching that dir in the filesystem e.g. webpack
|
6
|
-
|
7
|
-
require 'open3'
|
8
|
-
require 'shellwords'
|
9
|
-
RUNS = 30
|
10
|
-
SCRIPT = "time #{__dir__}/ls #{Shellwords.join(ARGV)}"
|
11
|
-
|
12
|
-
times = Array.new(RUNS).map do
|
13
|
-
run_times = Open3.capture3(SCRIPT)[1]
|
14
|
-
puts run_times.lstrip
|
15
|
-
run_times.scan(/(?:\d+(?:.\d+)?)/)
|
16
|
-
end
|
17
|
-
|
18
|
-
puts format(
|
19
|
-
"\e[1mAverage:\n\e[32m%0.2f real %0.2f user %0.2f sys\e[0m", # rubocop:disable Style/FormatStringToken
|
20
|
-
*times.transpose.map { |n| (n.map(&:to_f).sum / RUNS) }
|
21
|
-
)
|
data/fast_ignore.gemspec
DELETED
@@ -1,41 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
lib = File.expand_path('lib', __dir__)
|
4
|
-
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
5
|
-
require 'fast_ignore/version'
|
6
|
-
|
7
|
-
Gem::Specification.new do |spec|
|
8
|
-
spec.name = 'fast_ignore'
|
9
|
-
spec.version = FastIgnore::VERSION
|
10
|
-
spec.authors = ['Dana Sherson']
|
11
|
-
spec.email = ['robot@dana.sh']
|
12
|
-
|
13
|
-
spec.summary = 'Parse gitignore files, quickly'
|
14
|
-
spec.homepage = 'https://github.com/robotdana/fast_ignore'
|
15
|
-
spec.license = 'MIT'
|
16
|
-
|
17
|
-
spec.required_ruby_version = '~> 2.4'
|
18
|
-
|
19
|
-
if spec.respond_to?(:metadata)
|
20
|
-
spec.metadata['homepage_uri'] = spec.homepage
|
21
|
-
spec.metadata['source_code_uri'] = 'https://github.com/robotdana/fast_ignore'
|
22
|
-
spec.metadata['changelog_uri'] = 'https://github.com/robotdana/fast_ignore/blob/master/CHANGELOG.md'
|
23
|
-
end
|
24
|
-
|
25
|
-
# Specify which files should be added to the gem when it is released.
|
26
|
-
# The `git ls-files -z` loads the files in the RubyGem that have been added into git.
|
27
|
-
spec.files = Dir.chdir(File.expand_path(__dir__)) do
|
28
|
-
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
29
|
-
end
|
30
|
-
spec.require_paths = ['lib']
|
31
|
-
|
32
|
-
spec.add_development_dependency 'bundler', '>= 1.17'
|
33
|
-
spec.add_development_dependency 'leftovers', '>= 0.2.2'
|
34
|
-
spec.add_development_dependency 'pry', '> 0'
|
35
|
-
spec.add_development_dependency 'rake', '>= 12.3.3'
|
36
|
-
spec.add_development_dependency 'rspec', '~> 3.0'
|
37
|
-
spec.add_development_dependency 'rubocop', '>= 0.74.0'
|
38
|
-
spec.add_development_dependency 'rubocop-rspec', '~> 1'
|
39
|
-
spec.add_development_dependency 'simplecov', '~> 0.18.5'
|
40
|
-
spec.add_development_dependency 'spellr', '>= 0.8.3'
|
41
|
-
end
|