spellr 0.9.0 → 0.10.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +40 -23
- data/exe/spellr +3 -0
- data/lib/spellr/autocorrect_reporter.rb +39 -0
- data/lib/spellr/backports.rb +1 -44
- data/lib/spellr/base_reporter.rb +8 -0
- data/lib/spellr/check.rb +39 -13
- data/lib/spellr/cli_options.rb +8 -13
- data/lib/spellr/config.rb +11 -3
- data/lib/spellr/config_loader.rb +1 -1
- data/lib/spellr/config_validator.rb +6 -6
- data/lib/spellr/file.rb +5 -1
- data/lib/spellr/file_list.rb +1 -2
- data/lib/spellr/interactive.rb +56 -19
- data/lib/spellr/interactive_add.rb +2 -2
- data/lib/spellr/interactive_replacement.rb +2 -2
- data/lib/spellr/key_tuner/possible_key.rb +1 -1
- data/lib/spellr/key_tuner/stats.rb +1 -1
- data/lib/spellr/line_tokenizer.rb +1 -1
- data/lib/spellr/rake_task.rb +17 -5
- data/lib/spellr/reporter.rb +2 -2
- data/lib/spellr/suggester.rb +60 -0
- data/lib/spellr/token.rb +9 -0
- data/lib/spellr/tokenizer.rb +7 -9
- data/lib/spellr/version.rb +1 -1
- data/lib/spellr/wordlist.rb +16 -3
- data/spellr.gemspec +3 -1
- metadata +33 -6
- data/lib/spellr/check_interactive.rb +0 -24
- data/lib/spellr/check_parallel.rb +0 -23
- data/lib/spellr/stringio_with_encoding.rb +0 -11
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 21ab4e433d233e14066dd74202d26ce302ea6b61807b06c74d5418f0351f576a
|
4
|
+
data.tar.gz: 865fe94e51e2ad6b819eef675b2075eaaf15214bc599e14de2c76b376169ad3a
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ff244a207751f57b402c1c5080487205935a4c80fd0b2481cd8a58a12ba717412596714c1684fde3e28aac6caff182e8985855243dc02c720463d17e1e533bc8
|
7
|
+
data.tar.gz: bf87a587fd6cf7ab5ef907645cfc68b627f65098b9e771c09a9fb19360467817c05cb3d61bda17bb01296f81a71e23048f42ec4054e1cd8a96703332571f1ff1
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
# v0.10.1
|
2
|
+
- Resolve fast_ignore follow_symlinks deprecation
|
3
|
+
|
4
|
+
# v0.10.0
|
5
|
+
- Drop ruby 2.4 support, to allow for...
|
6
|
+
- Spelling suggestions while using `spellr --interactive`
|
7
|
+
- And a new, probably frequently wrong, `spellr --autocorrect`
|
8
|
+
|
9
|
+
# v0.9.1
|
10
|
+
- Assume all files are utf8, more comprehensively. (Sets ::Encoding.default_external and default_internal while running)
|
11
|
+
|
1
12
|
# v0.9.0
|
2
13
|
- Recognize url with _ in query string and zero length path
|
3
14
|
- Assume all files are utf8
|
data/README.md
CHANGED
@@ -27,7 +27,7 @@ However, in a programming context spelling things _consistently_ is useful, wher
|
|
27
27
|
|
28
28
|
## Installation
|
29
29
|
|
30
|
-
This is tested against ruby 2.
|
30
|
+
This is tested against ruby 2.5-3.0.
|
31
31
|
|
32
32
|
### With Bundler
|
33
33
|
|
@@ -66,6 +66,7 @@ $ spellr # will run the spell checker
|
|
66
66
|
$ spellr --interactive # will run the spell checker, interactively
|
67
67
|
$ spellr --wordlist # will output all words that fail the spell checker in spellr wordlist format
|
68
68
|
$ spellr --quiet # will suppress all output
|
69
|
+
$ spellr --autocorrect # for if you're feeling lucky
|
69
70
|
```
|
70
71
|
|
71
72
|
To check a single file or subset of files, just add paths or globs:
|
@@ -123,14 +124,16 @@ To start an interactive spell checking session:
|
|
123
124
|
$ spellr --interactive
|
124
125
|
```
|
125
126
|
|
126
|
-
You'll be shown each word that's not found in a dictionary, it's location (path:line:column), along with a prompt.
|
127
|
+
You'll be shown each word that's not found in a dictionary, it's location (path:line:column), along with suggestions, and a prompt.
|
127
128
|
```
|
128
129
|
file.rb:1:0 notaword
|
130
|
+
Did you mean: [1] notwork, [2] nonword
|
129
131
|
[a]dd, [r]eplace, [s]kip, [h]elp, [^C] to exit: [ ]
|
130
132
|
```
|
131
133
|
|
132
134
|
Type `h` for this list of what each letter command does
|
133
135
|
```
|
136
|
+
[1]...[2] Replace notaword with the numbered suggestion
|
134
137
|
[a] Add notaword to a word list
|
135
138
|
[r] Replace notaword
|
136
139
|
[R] Replace this and all future instances of notaword
|
@@ -144,9 +147,20 @@ What do you want to do? [ ]
|
|
144
147
|
|
145
148
|
---
|
146
149
|
|
150
|
+
If you type a numeral the word will be replaced with that numbered suggestion
|
151
|
+
```
|
152
|
+
file.txt:1:0 notaword
|
153
|
+
Did you mean: [1] notwork, [2] nonword
|
154
|
+
[a]dd, [r]eplace, [s]kip, [h]elp, [^C] to exit: [2]
|
155
|
+
Replaced notaword with nonword
|
156
|
+
```
|
157
|
+
|
158
|
+
---
|
159
|
+
|
147
160
|
If you type `r` or `R` you'll be shown a prompt with the original word and it prefilled ready for correcting:
|
148
161
|
```
|
149
162
|
file.txt:1:0 notaword
|
163
|
+
Did you mean: [1] notwork, [2] nonword
|
150
164
|
[a]dd, [r]eplace, [s]kip, [h]elp, [^C] to exit: [r]
|
151
165
|
|
152
166
|
[^C] to go back
|
@@ -167,6 +181,7 @@ Lowercase `s` will skip this particular use of the word, uppercase `S` will also
|
|
167
181
|
If you instead type `a` you'll be shown a list of possible wordlists to add to. This list is based on the file path, and is configurable in `.spellr.yml`.
|
168
182
|
```
|
169
183
|
file.txt:1:0 notaword
|
184
|
+
Did you mean: [1] notwork, [2] nonword
|
170
185
|
[a]dd, [r]eplace, [s]kip, [h]elp, [^C] to exit: [a]
|
171
186
|
|
172
187
|
[e] english
|
@@ -247,7 +262,7 @@ languages:
|
|
247
262
|
- path/to/logstash/file
|
248
263
|
```
|
249
264
|
|
250
|
-
## Rake
|
265
|
+
## Rake
|
251
266
|
|
252
267
|
Create or open a file in the root of your project named `Rakefile`.
|
253
268
|
adding the following lines
|
@@ -260,7 +275,27 @@ Spellr::RakeTask.generate_task
|
|
260
275
|
This will add the `rake spellr` task. To provide arguments like the cli, use square brackets. (ensure you escape the `[]` if you're using zsh)
|
261
276
|
`rake 'spellr[--interactive]'`
|
262
277
|
|
263
|
-
To
|
278
|
+
To provide default cli arguments, the first argument is the name, and subsequent arguments are the cli arguments.
|
279
|
+
```ruby
|
280
|
+
# Rakefile
|
281
|
+
require 'spellr/rake_task'
|
282
|
+
Spellr::RakeTask.generate_task(:spellr_quiet, '--quiet')
|
283
|
+
|
284
|
+
task default: :spellr_quiet
|
285
|
+
```
|
286
|
+
or `rake spellr` will be in interactive mode unless the CI env variable is set.
|
287
|
+
```ruby
|
288
|
+
# Rakefile
|
289
|
+
require 'spellr/rake_task'
|
290
|
+
spellr_arguments = ENV['CI'] ? [] : ['--interactive']
|
291
|
+
Spellr::RakeTask.generate_task(:spellr, **spellr_arguments)
|
292
|
+
|
293
|
+
task default: :spellr
|
294
|
+
```
|
295
|
+
|
296
|
+
## Travis
|
297
|
+
|
298
|
+
To have this automatically run on travis, add `:spellr` to the default rake task.
|
264
299
|
```ruby
|
265
300
|
# Rakefile
|
266
301
|
require 'spellr/rake_task'
|
@@ -284,28 +319,10 @@ sudo: false
|
|
284
319
|
language: ruby
|
285
320
|
cache: bundler
|
286
321
|
rvm:
|
287
|
-
-
|
322
|
+
- 3.0
|
288
323
|
before_install: gem install bundler
|
289
324
|
```
|
290
325
|
|
291
|
-
To provide default cli arguments, the first argument is the name, and subsequent arguments are the cli arguments.
|
292
|
-
```ruby
|
293
|
-
# Rakefile
|
294
|
-
require 'spellr/rake_task'
|
295
|
-
Spellr::RakeTask.generate_task(:spellr_quiet, '--quiet')
|
296
|
-
|
297
|
-
task default: :spellr_quiet
|
298
|
-
```
|
299
|
-
or `rake spellr` will be in interactive mode unless the CI env variable is set.
|
300
|
-
```ruby
|
301
|
-
# Rakefile
|
302
|
-
require 'spellr/rake_task'
|
303
|
-
spellr_arguments = ENV['CI'] ? [] : ['--interactive']
|
304
|
-
Spellr::RakeTask.generate_task(:spellr, **spellr_arguments)
|
305
|
-
|
306
|
-
task default: :spellr
|
307
|
-
```
|
308
|
-
|
309
326
|
## Ignoring the configured patterns
|
310
327
|
|
311
328
|
Sometimes you'll want to spell check something that would usually be ignored,
|
data/exe/spellr
CHANGED
@@ -0,0 +1,39 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative '../spellr'
|
4
|
+
require_relative 'base_reporter'
|
5
|
+
require_relative 'suggester'
|
6
|
+
|
7
|
+
module Spellr
|
8
|
+
class AutocorrectReporter < BaseReporter
|
9
|
+
def finish
|
10
|
+
puts "\n"
|
11
|
+
print_count(:checked, 'file')
|
12
|
+
print_value(total, 'error', 'found')
|
13
|
+
print_count(:total_fixed, 'error', 'fixed', hide_zero: true)
|
14
|
+
print_count(:total_unfixed, 'error', 'unfixed', hide_zero: true)
|
15
|
+
end
|
16
|
+
|
17
|
+
def call(token)
|
18
|
+
super
|
19
|
+
|
20
|
+
handle_replace(token)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def total
|
26
|
+
counts[:total_unfixed] + counts[:total_fixed]
|
27
|
+
end
|
28
|
+
|
29
|
+
def handle_replace(token)
|
30
|
+
replacement = ::Spellr::Suggester.suggestions(token).first
|
31
|
+
return increment(:total_unfixed) unless replacement
|
32
|
+
|
33
|
+
token.replace(replacement)
|
34
|
+
increment(:total_fixed)
|
35
|
+
puts "Replaced #{red(token)} with #{green(replacement)}"
|
36
|
+
throw :check_file_from, token
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
data/lib/spellr/backports.rb
CHANGED
@@ -1,50 +1,7 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
module Spellr
|
4
|
-
|
5
|
-
unless ruby_version >= Gem::Version.new('2.5')
|
6
|
-
module HashSlice
|
7
|
-
refine Hash do
|
8
|
-
def slice!(*keys)
|
9
|
-
delete_if { |k| !keys.include?(k) }
|
10
|
-
end
|
11
|
-
|
12
|
-
def slice(*keys)
|
13
|
-
dup.slice!(*keys)
|
14
|
-
end
|
15
|
-
end
|
16
|
-
end
|
17
|
-
|
18
|
-
require 'yaml'
|
19
|
-
module YAMLSymbolizeNames
|
20
|
-
refine YAML.singleton_class do
|
21
|
-
alias_method :safe_load_without_symbolize_names, :safe_load
|
22
|
-
def safe_load(path, *args, symbolize_names: false, **kwargs)
|
23
|
-
if symbolize_names
|
24
|
-
symbolize_names!(safe_load_without_symbolize_names(path, *args, **kwargs))
|
25
|
-
else
|
26
|
-
safe_load_without_symbolize_names(path, *args, **kwargs)
|
27
|
-
end
|
28
|
-
end
|
29
|
-
|
30
|
-
private
|
31
|
-
|
32
|
-
def symbolize_names!(obj) # rubocop:disable Metrics/MethodLength
|
33
|
-
case obj
|
34
|
-
when Hash
|
35
|
-
obj.keys.each do |key| # rubocop:disable Style/HashEachMethods # each_key never finishes.
|
36
|
-
obj[key.to_sym] = symbolize_names!(obj.delete(key))
|
37
|
-
end
|
38
|
-
when Array
|
39
|
-
obj.map! { |ea| symbolize_names!(ea) }
|
40
|
-
end
|
41
|
-
obj
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
|
47
|
-
unless ruby_version >= Gem::Version.new('2.6')
|
4
|
+
unless Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6')
|
48
5
|
require 'yaml'
|
49
6
|
module YAMLPermittedClasses
|
50
7
|
refine YAML.singleton_class do
|
data/lib/spellr/base_reporter.rb
CHANGED
@@ -46,5 +46,13 @@ module Spellr
|
|
46
46
|
def counts
|
47
47
|
output.counts
|
48
48
|
end
|
49
|
+
|
50
|
+
def print_count(stat, noun, verb = stat, hide_zero: false)
|
51
|
+
print_value(counts[stat], noun, verb, hide_zero: hide_zero)
|
52
|
+
end
|
53
|
+
|
54
|
+
def print_value(value, noun, verb, hide_zero: false)
|
55
|
+
puts "#{pluralize noun, value} #{verb}" if !hide_zero || value.positive?
|
56
|
+
end
|
49
57
|
end
|
50
58
|
end
|
data/lib/spellr/check.rb
CHANGED
@@ -3,6 +3,7 @@
|
|
3
3
|
require_relative '../spellr'
|
4
4
|
require_relative 'tokenizer'
|
5
5
|
require_relative 'string_format'
|
6
|
+
require_relative 'output_stubbed'
|
6
7
|
|
7
8
|
module Spellr
|
8
9
|
class Check
|
@@ -21,8 +22,10 @@ module Spellr
|
|
21
22
|
end
|
22
23
|
|
23
24
|
def check
|
24
|
-
|
25
|
-
|
25
|
+
if Spellr.config.parallel
|
26
|
+
parallel_check
|
27
|
+
else
|
28
|
+
files.each { |file| check_and_count_file(file, reporter) }
|
26
29
|
end
|
27
30
|
|
28
31
|
reporter.finish
|
@@ -30,24 +33,47 @@ module Spellr
|
|
30
33
|
|
31
34
|
private
|
32
35
|
|
33
|
-
def
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
36
|
+
def parallel_check
|
37
|
+
require 'parallel'
|
38
|
+
|
39
|
+
Parallel.each(files, finish: ->(_, _, result) { reporter.output << result }) do |file|
|
40
|
+
sub_reporter = reporter.class.new(Spellr::OutputStubbed.new)
|
41
|
+
check_and_count_file(file, sub_reporter)
|
42
|
+
sub_reporter.output
|
43
|
+
end
|
39
44
|
end
|
40
45
|
|
41
|
-
def
|
46
|
+
def check_and_count_file(file, current_reporter)
|
47
|
+
check_file(file, current_reporter)
|
48
|
+
current_reporter.output.increment(:checked)
|
49
|
+
rescue Spellr::InvalidByteSequence, ::Errno::ENOENT, ::Errno::EISDIR, ::Errno::EACCES
|
50
|
+
current_reporter.warn "Skipped unreadable file: #{aqua file.relative_path}"
|
51
|
+
end
|
52
|
+
|
53
|
+
def check_file(file, curr_reporter, start_at = nil, wordlist_proc = wordlist_proc_for(file))
|
54
|
+
restart_token = catch(:check_file_from) do
|
55
|
+
report_file(file, curr_reporter, start_at, wordlist_proc)
|
56
|
+
nil
|
57
|
+
end
|
58
|
+
check_file_from_restart(file, curr_reporter, restart_token, wordlist_proc) if restart_token
|
59
|
+
end
|
60
|
+
|
61
|
+
def report_file(file, curr_reporter, start_at = nil, wordlist_proc = wordlist_proc_for(file))
|
42
62
|
Spellr::Tokenizer.new(file, start_at: start_at)
|
43
|
-
.each_token(skip_term_proc:
|
44
|
-
|
45
|
-
|
63
|
+
.each_token(skip_term_proc: wordlist_proc) do |token|
|
64
|
+
curr_reporter.call(token)
|
65
|
+
curr_reporter.output.exit_code = 1
|
46
66
|
end
|
47
67
|
end
|
48
68
|
|
69
|
+
def check_file_from_restart(file, current_reporter, restart_token, wordlist_proc)
|
70
|
+
# new wordlist cache when adding a word
|
71
|
+
wordlist_proc = wordlist_proc_for(file) unless restart_token.replacement
|
72
|
+
check_file(file, current_reporter, restart_token.location, wordlist_proc)
|
73
|
+
end
|
74
|
+
|
49
75
|
def wordlist_proc_for(file)
|
50
|
-
wordlists =
|
76
|
+
wordlists = file.wordlists
|
51
77
|
|
52
78
|
->(term) { wordlists.any? { |w| w.include?(term) } }
|
53
79
|
end
|
data/lib/spellr/cli_options.rb
CHANGED
@@ -9,8 +9,6 @@ module Spellr
|
|
9
9
|
class Options
|
10
10
|
class << self
|
11
11
|
def parse(argv)
|
12
|
-
@parallel_option = false
|
13
|
-
|
14
12
|
options.parse!(argv)
|
15
13
|
end
|
16
14
|
|
@@ -25,6 +23,7 @@ module Spellr
|
|
25
23
|
opts.on('-w', '--wordlist', 'Outputs errors in wordlist format', &method(:wordlist_option))
|
26
24
|
opts.on('-q', '--quiet', 'Silences output', &method(:quiet_option))
|
27
25
|
opts.on('-i', '--interactive', 'Runs the spell check interactively', &method(:interactive_option))
|
26
|
+
opts.on('-a', '--autocorrect', 'Autocorrect errors', &method(:autocorrect_option))
|
28
27
|
opts.separator('')
|
29
28
|
opts.on('--[no-]parallel', 'Run in parallel or not, default --parallel', &method(:parallel_option))
|
30
29
|
opts.on('-d', '--dry-run', 'List files to be checked', &method(:dry_run_option))
|
@@ -54,9 +53,12 @@ module Spellr
|
|
54
53
|
|
55
54
|
def interactive_option(_)
|
56
55
|
require_relative 'interactive'
|
57
|
-
require_relative 'check_interactive'
|
58
56
|
Spellr.config.reporter = Spellr::Interactive.new
|
59
|
-
|
57
|
+
end
|
58
|
+
|
59
|
+
def autocorrect_option(_)
|
60
|
+
require_relative 'autocorrect_reporter'
|
61
|
+
Spellr.config.reporter = Spellr::AutocorrectReporter.new
|
60
62
|
end
|
61
63
|
|
62
64
|
def suppress_file_rules(_)
|
@@ -73,15 +75,8 @@ module Spellr
|
|
73
75
|
Spellr.config.config_file = file
|
74
76
|
end
|
75
77
|
|
76
|
-
def parallel_option(parallel)
|
77
|
-
|
78
|
-
Spellr.config.checker = if parallel
|
79
|
-
require_relative 'check_parallel'
|
80
|
-
Spellr::CheckParallel
|
81
|
-
else
|
82
|
-
require_relative 'check'
|
83
|
-
Spellr::Check
|
84
|
-
end
|
78
|
+
def parallel_option(parallel)
|
79
|
+
Spellr.config.parallel = parallel
|
85
80
|
end
|
86
81
|
|
87
82
|
def dry_run_option(_)
|
data/lib/spellr/config.rb
CHANGED
@@ -10,7 +10,7 @@ require 'pathname'
|
|
10
10
|
|
11
11
|
module Spellr
|
12
12
|
class Config
|
13
|
-
attr_writer :reporter, :
|
13
|
+
attr_writer :reporter, :parallel
|
14
14
|
|
15
15
|
attr_accessor :suppress_file_rules, :dry_run
|
16
16
|
|
@@ -68,6 +68,10 @@ module Spellr
|
|
68
68
|
@reporter ||= default_reporter
|
69
69
|
end
|
70
70
|
|
71
|
+
def parallel
|
72
|
+
defined?(@parallel) ? @parallel : default_parallel
|
73
|
+
end
|
74
|
+
|
71
75
|
def checker
|
72
76
|
return dry_run_checker if dry_run?
|
73
77
|
|
@@ -101,8 +105,12 @@ module Spellr
|
|
101
105
|
end
|
102
106
|
|
103
107
|
def default_checker
|
104
|
-
require_relative '
|
105
|
-
Spellr::
|
108
|
+
require_relative 'check'
|
109
|
+
Spellr::Check
|
110
|
+
end
|
111
|
+
|
112
|
+
def default_parallel
|
113
|
+
reporter.class.name != 'Spellr::Interactive'
|
106
114
|
end
|
107
115
|
end
|
108
116
|
end
|
data/lib/spellr/config_loader.rb
CHANGED
@@ -32,7 +32,7 @@ module Spellr
|
|
32
32
|
def load_yaml(path)
|
33
33
|
return {} unless ::File.exist?(path)
|
34
34
|
|
35
|
-
YAML.safe_load(::File.read(path
|
35
|
+
YAML.safe_load(::File.read(path), symbolize_names: true)
|
36
36
|
end
|
37
37
|
|
38
38
|
def merge_config(default, project) # rubocop:disable Metrics/MethodLength
|
@@ -8,7 +8,7 @@ module Spellr
|
|
8
8
|
class ConfigValidator
|
9
9
|
include Spellr::Validations
|
10
10
|
|
11
|
-
validate :
|
11
|
+
validate :not_interactive_and_parallel
|
12
12
|
validate :interactive_is_interactive
|
13
13
|
validate :only_has_one_key_per_language
|
14
14
|
validate :languages_with_conflicting_keys
|
@@ -31,11 +31,11 @@ module Spellr
|
|
31
31
|
nil
|
32
32
|
end
|
33
33
|
|
34
|
-
def
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
34
|
+
def not_interactive_and_parallel
|
35
|
+
return unless Spellr.config.reporter.class.name == 'Spellr::Interactive' &&
|
36
|
+
Spellr.config.parallel
|
37
|
+
|
38
|
+
errors << 'CLI error: --interactive is incompatible with --parallel'
|
39
39
|
end
|
40
40
|
|
41
41
|
def only_has_one_key_per_language
|
data/lib/spellr/file.rb
CHANGED
@@ -34,7 +34,11 @@ module Spellr
|
|
34
34
|
end
|
35
35
|
|
36
36
|
def read_write
|
37
|
-
write(yield
|
37
|
+
write(yield read)
|
38
|
+
end
|
39
|
+
|
40
|
+
def wordlists
|
41
|
+
::Spellr.config.wordlists_for(self).sort_by { |wordlist| -wordlist.length }
|
38
42
|
end
|
39
43
|
end
|
40
44
|
end
|
data/lib/spellr/file_list.rb
CHANGED
data/lib/spellr/interactive.rb
CHANGED
@@ -5,18 +5,17 @@ require_relative '../spellr'
|
|
5
5
|
require_relative 'interactive_add'
|
6
6
|
require_relative 'interactive_replacement'
|
7
7
|
require_relative 'base_reporter'
|
8
|
+
require_relative 'suggester'
|
8
9
|
|
9
10
|
module Spellr
|
10
11
|
class Interactive < BaseReporter # rubocop:disable Metrics/ClassLength
|
11
|
-
def finish
|
12
|
+
def finish
|
12
13
|
puts "\n"
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
puts "#{pluralize 'error', counts[:total_fixed]} fixed" if counts[:total_fixed].positive?
|
19
|
-
puts "#{pluralize 'word', counts[:total_added]} added" if counts[:total_added].positive?
|
14
|
+
print_count(:checked, 'file')
|
15
|
+
print_value(total, 'error', 'found')
|
16
|
+
print_count(:total_skipped, 'error', 'skipped', hide_zero: true)
|
17
|
+
print_count(:total_fixed, 'error', 'fixed', hide_zero: true)
|
18
|
+
print_count(:total_added, 'word', 'added', hide_zero: true)
|
20
19
|
end
|
21
20
|
|
22
21
|
def global_replacements
|
@@ -27,22 +26,25 @@ module Spellr
|
|
27
26
|
@global_skips ||= counts[:global_skips] = []
|
28
27
|
end
|
29
28
|
|
30
|
-
def call(token)
|
29
|
+
def call(token, only_prompt: false)
|
31
30
|
# if attempt_global_replacement succeeds, then it throws,
|
32
31
|
# it acts like a guard clause all by itself.
|
33
32
|
attempt_global_replacement(token)
|
34
33
|
return if attempt_global_skip(token)
|
35
34
|
|
36
|
-
super
|
35
|
+
super(token) unless only_prompt
|
36
|
+
|
37
|
+
suggestions = ::Spellr::Suggester.fast_suggestions(token)
|
38
|
+
print_suggestions(suggestions) unless only_prompt
|
37
39
|
|
38
|
-
prompt(token)
|
40
|
+
prompt(token, suggestions)
|
39
41
|
end
|
40
42
|
|
41
43
|
def prompt_for_key
|
42
44
|
print "[ ]\e[2D"
|
43
45
|
end
|
44
46
|
|
45
|
-
def loop_within(seconds)
|
47
|
+
def loop_within(seconds)
|
46
48
|
# timeout is just because it gets stuck sometimes
|
47
49
|
Timeout.timeout(seconds * 10) do
|
48
50
|
start_time = monotonic_time
|
@@ -84,11 +86,21 @@ module Spellr
|
|
84
86
|
"^#{char.tr(CTRL_STR, ALPHABET)}"
|
85
87
|
end
|
86
88
|
|
87
|
-
def
|
89
|
+
def print_suggestions(suggestions)
|
90
|
+
return if suggestions.empty?
|
91
|
+
|
92
|
+
puts "Did you mean: #{number_suggestions(suggestions)}"
|
93
|
+
end
|
94
|
+
|
95
|
+
def number_suggestions(suggestions)
|
96
|
+
suggestions.map.with_index(1) { |word, i| "#{key i.to_s} #{word}" }.join(', ')
|
97
|
+
end
|
98
|
+
|
99
|
+
def prompt(token, suggestions)
|
88
100
|
print "#{key 'add'}, #{key 'replace'}, #{key 'skip'}, #{key 'help'}, [^#{bold 'C'}] to exit: "
|
89
101
|
prompt_for_key
|
90
102
|
|
91
|
-
handle_response(token)
|
103
|
+
handle_response(token, suggestions)
|
92
104
|
end
|
93
105
|
|
94
106
|
def clear_line(lines = 1)
|
@@ -121,9 +133,17 @@ module Spellr
|
|
121
133
|
throw :check_file_from, token
|
122
134
|
end
|
123
135
|
|
124
|
-
def
|
136
|
+
def suggestions_options(suggestions)
|
137
|
+
return suggestions if suggestions.empty?
|
138
|
+
|
139
|
+
('1'..(suggestions.length.to_s)).to_a
|
140
|
+
end
|
141
|
+
|
142
|
+
def handle_response(token, suggestions) # rubocop:disable Metrics/CyclomaticComplexity, Metrics/MethodLength, Metrics/AbcSize
|
143
|
+
numbers = suggestions_options(suggestions)
|
125
144
|
# :nocov:
|
126
|
-
|
145
|
+
letter = stdin_getch("qaAsSrR?h\u0003\u0004#{numbers.join}")
|
146
|
+
case letter
|
127
147
|
# :nocov:
|
128
148
|
when 'q', "\u0003" # ctrl c
|
129
149
|
Spellr.exit 1
|
@@ -137,20 +157,37 @@ module Spellr
|
|
137
157
|
Spellr::InteractiveReplacement.new(token, self).global_replace
|
138
158
|
when 'r'
|
139
159
|
Spellr::InteractiveReplacement.new(token, self).replace
|
160
|
+
when *numbers
|
161
|
+
handle_replace_with_suggestion(token, suggestions, letter)
|
140
162
|
when '?', 'h'
|
141
|
-
handle_help(token)
|
163
|
+
handle_help(token, suggestions)
|
142
164
|
end
|
143
165
|
end
|
144
166
|
|
167
|
+
def handle_replace_with_suggestion(token, suggestions, letter)
|
168
|
+
replacement = suggestions[letter.to_i - 1].chomp
|
169
|
+
|
170
|
+
token.replace(replacement)
|
171
|
+
increment(:total_fixed)
|
172
|
+
puts "Replaced #{red(token)} with #{green(replacement)}"
|
173
|
+
throw :check_file_from, token
|
174
|
+
end
|
175
|
+
|
145
176
|
def handle_skip(token)
|
146
177
|
increment(:total_skipped)
|
147
178
|
yield token if block_given?
|
148
179
|
puts "Skipped #{red(token)}"
|
149
180
|
end
|
150
181
|
|
151
|
-
def handle_help(token) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
182
|
+
def handle_help(token, suggestions) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
152
183
|
clear_line(2)
|
153
184
|
puts ''
|
185
|
+
if suggestions.length > 1
|
186
|
+
puts "#{key '1'}...#{key suggestions.length.to_s} "\
|
187
|
+
"Replace #{red token} with the numbered suggestion"
|
188
|
+
elsif suggestions.length == 1
|
189
|
+
puts "#{key '1'} Replace #{red token} with the numbered suggestion"
|
190
|
+
end
|
154
191
|
puts "#{key 'a'} Add #{red token} to a word list"
|
155
192
|
puts "#{key 'r'} Replace #{red token}"
|
156
193
|
puts "#{key 'R'} Replace this and all future instances of #{red token}"
|
@@ -160,7 +197,7 @@ module Spellr
|
|
160
197
|
puts "[ctrl] + #{key 'C'} Exit spellr"
|
161
198
|
puts ''
|
162
199
|
print "What do you want to do? [ ]\e[2D"
|
163
|
-
handle_response(token)
|
200
|
+
handle_response(token, suggestions)
|
164
201
|
end
|
165
202
|
end
|
166
203
|
end
|
@@ -79,7 +79,7 @@ class PossibleKey # rubocop:disable Metrics/ClassLength
|
|
79
79
|
letter_frequency_difference.slice(*FEATURE_LETTERS)
|
80
80
|
end
|
81
81
|
|
82
|
-
def character_set
|
82
|
+
def character_set
|
83
83
|
@character_set ||= case string
|
84
84
|
when /^[a-fA-F0-9\-]+$/ then :hex
|
85
85
|
when /^[a-z0-9]+$/ then :lower36
|
data/lib/spellr/rake_task.rb
CHANGED
@@ -1,7 +1,6 @@
|
|
1
1
|
# frozen_string_literal: true
|
2
2
|
|
3
3
|
require 'rake'
|
4
|
-
require 'spellr/cli'
|
5
4
|
require 'shellwords'
|
6
5
|
|
7
6
|
module Spellr
|
@@ -36,11 +35,13 @@ module Spellr
|
|
36
35
|
desc("Run spellr (default args: #{escaped_argv})")
|
37
36
|
end
|
38
37
|
|
39
|
-
def define_task
|
38
|
+
def define_task # rubocop:disable Metrics/MethodLength
|
40
39
|
task(@name, :'*args') do |_, task_argv|
|
41
|
-
|
42
|
-
|
43
|
-
|
40
|
+
with_utf_8 do
|
41
|
+
argv = argv_or_default(task_argv)
|
42
|
+
write_cli_cmd(argv)
|
43
|
+
run(argv)
|
44
|
+
end
|
44
45
|
end
|
45
46
|
end
|
46
47
|
|
@@ -49,6 +50,7 @@ module Spellr
|
|
49
50
|
end
|
50
51
|
|
51
52
|
def run(argv)
|
53
|
+
require 'spellr/cli'
|
52
54
|
status = Spellr::CLI.new(argv).run
|
53
55
|
exit 1 unless status == 0
|
54
56
|
end
|
@@ -57,5 +59,15 @@ module Spellr
|
|
57
59
|
task_argv = task_argv.to_a.compact
|
58
60
|
task_argv.empty? ? @default_argv : task_argv
|
59
61
|
end
|
62
|
+
|
63
|
+
def with_utf_8 # rubocop:disable Metrics/MethodLength
|
64
|
+
old_default_external = ::Encoding.default_external
|
65
|
+
old_default_internal = ::Encoding.default_internal
|
66
|
+
::Encoding.default_external = ::Encoding::UTF_8
|
67
|
+
::Encoding.default_internal = ::Encoding::UTF_8
|
68
|
+
yield
|
69
|
+
::Encoding.default_external = old_default_external
|
70
|
+
::Encoding.default_internal = old_default_internal
|
71
|
+
end
|
60
72
|
end
|
61
73
|
end
|
data/lib/spellr/reporter.rb
CHANGED
@@ -7,8 +7,8 @@ module Spellr
|
|
7
7
|
class Reporter < Spellr::BaseReporter
|
8
8
|
def finish
|
9
9
|
puts "\n"
|
10
|
-
|
11
|
-
|
10
|
+
print_count(:checked, 'file')
|
11
|
+
print_count(:total, 'error', 'found')
|
12
12
|
|
13
13
|
interactive_command if counts[:total].positive?
|
14
14
|
end
|
@@ -0,0 +1,60 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require 'did_you_mean'
|
4
|
+
require 'jaro_winkler'
|
5
|
+
|
6
|
+
::DidYouMean.send(:remove_const, :JaroWinkler)
|
7
|
+
::DidYouMean::JaroWinkler = ::JaroWinkler
|
8
|
+
|
9
|
+
module Spellr
|
10
|
+
class Suggester
|
11
|
+
class << self
|
12
|
+
def suggestions(token)
|
13
|
+
wordlists = token.location.file.wordlists
|
14
|
+
term = token.spellr_normalize.chomp
|
15
|
+
words = wordlists.flat_map { |wordlist| wordlist.suggestions(token) }.uniq
|
16
|
+
words = ::DidYouMean::SpellChecker.new(dictionary: words).correct(term)
|
17
|
+
words = reduce_suggestions(words, term)
|
18
|
+
|
19
|
+
words.map { |word| word.send(token.case_method) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def slow?
|
23
|
+
return @slow if defined?(@slow)
|
24
|
+
|
25
|
+
@slow = ::JaroWinkler.method(:distance).source_location
|
26
|
+
end
|
27
|
+
|
28
|
+
def fast_suggestions(token)
|
29
|
+
if slow?
|
30
|
+
[]
|
31
|
+
else
|
32
|
+
suggestions(token)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
|
38
|
+
def reduce_suggestions(words, term)
|
39
|
+
return words unless words.length > 1
|
40
|
+
|
41
|
+
threshold = ::JaroWinkler.distance(term, words.first) * 0.98
|
42
|
+
words.select! { |word| ::JaroWinkler.distance(term, word) > threshold }
|
43
|
+
words.sort_by! { |word| [-::JaroWinkler.distance(term, word), word] }
|
44
|
+
words.take(5)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
def initialize(wordlist)
|
49
|
+
@did_you_mean = ::DidYouMean::SpellChecker.new(dictionary: wordlist.to_a)
|
50
|
+
@suggestions = {}
|
51
|
+
end
|
52
|
+
|
53
|
+
def suggestions(term)
|
54
|
+
term = term.spellr_normalize
|
55
|
+
@suggestions.fetch(term) do
|
56
|
+
@suggestions[term] = @did_you_mean.correct(term).map(&:chomp)
|
57
|
+
end
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
data/lib/spellr/token.rb
CHANGED
@@ -66,5 +66,14 @@ module Spellr
|
|
66
66
|
@replacement = replacement
|
67
67
|
location.file.insert(replacement, file_char_range)
|
68
68
|
end
|
69
|
+
|
70
|
+
def case_method
|
71
|
+
@case_method ||= case self
|
72
|
+
when /\A[[:lower:]]+\z/ then :downcase
|
73
|
+
when /\A[[:upper:]]+\z/ then :upcase
|
74
|
+
when /\A[[:upper:]][[:lower:]]*\z/ then :capitalize
|
75
|
+
else :itself
|
76
|
+
end
|
77
|
+
end
|
69
78
|
end
|
70
79
|
end
|
data/lib/spellr/tokenizer.rb
CHANGED
@@ -27,14 +27,14 @@ module Spellr
|
|
27
27
|
end
|
28
28
|
|
29
29
|
def each_term(&block)
|
30
|
-
file.each_line
|
30
|
+
file.each_line do |line|
|
31
31
|
prepare_tokenizer_for_line(line)&.each_term(&block)
|
32
32
|
end
|
33
33
|
ensure
|
34
34
|
file.close
|
35
35
|
end
|
36
36
|
|
37
|
-
def each_token(skip_term_proc: nil)
|
37
|
+
def each_token(skip_term_proc: nil)
|
38
38
|
each_line_with_stats do |line, line_number, char_offset, byte_offset|
|
39
39
|
prepare_tokenizer_for_line(line)&.each_token(skip_term_proc: skip_term_proc) do |token|
|
40
40
|
token.line = prepare_line(line, line_number, char_offset, byte_offset)
|
@@ -56,14 +56,12 @@ module Spellr
|
|
56
56
|
char_offset = @start_at.line_location.char_offset
|
57
57
|
byte_offset = @start_at.line_location.byte_offset
|
58
58
|
|
59
|
-
file
|
60
|
-
|
61
|
-
.with_index(@start_at.line_location.line_number) do |line, line_number|
|
62
|
-
yield line, line_number, char_offset, byte_offset
|
59
|
+
file.each_line.with_index(@start_at.line_location.line_number) do |line, line_number|
|
60
|
+
yield line, line_number, char_offset, byte_offset
|
63
61
|
|
64
|
-
|
65
|
-
|
66
|
-
|
62
|
+
char_offset += line.length
|
63
|
+
byte_offset += line.bytesize
|
64
|
+
end
|
67
65
|
ensure
|
68
66
|
file.close
|
69
67
|
end
|
data/lib/spellr/version.rb
CHANGED
data/lib/spellr/wordlist.rb
CHANGED
@@ -41,7 +41,7 @@ module Spellr
|
|
41
41
|
touch
|
42
42
|
@include[term] = true
|
43
43
|
insert_sorted(term)
|
44
|
-
@path.write(words.join
|
44
|
+
@path.write(words.join) # we don't need to clear the cache
|
45
45
|
end
|
46
46
|
|
47
47
|
def words
|
@@ -55,7 +55,7 @@ module Spellr
|
|
55
55
|
end
|
56
56
|
|
57
57
|
def write(content)
|
58
|
-
@path.write(content
|
58
|
+
@path.write(content)
|
59
59
|
|
60
60
|
clear_cache
|
61
61
|
end
|
@@ -70,7 +70,7 @@ module Spellr
|
|
70
70
|
return if exist?
|
71
71
|
|
72
72
|
@path.dirname.mkpath
|
73
|
-
@path.write(''
|
73
|
+
@path.write('')
|
74
74
|
clear_cache
|
75
75
|
end
|
76
76
|
|
@@ -78,8 +78,20 @@ module Spellr
|
|
78
78
|
to_a.length
|
79
79
|
end
|
80
80
|
|
81
|
+
def suggestions(term)
|
82
|
+
suggester.suggestions(term)
|
83
|
+
end
|
84
|
+
|
81
85
|
private
|
82
86
|
|
87
|
+
def suggester
|
88
|
+
@suggester ||= begin
|
89
|
+
require_relative 'suggester'
|
90
|
+
|
91
|
+
::Spellr::Suggester.new(self)
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
83
95
|
def insert_sorted(term)
|
84
96
|
insert_at = words.bsearch_index { |value| value >= term }
|
85
97
|
insert_at ? words.insert(insert_at, term) : words.push(term)
|
@@ -87,6 +99,7 @@ module Spellr
|
|
87
99
|
|
88
100
|
def clear_cache
|
89
101
|
@words = nil
|
102
|
+
@suggester = nil
|
90
103
|
@include = {}
|
91
104
|
remove_instance_variable(:@exist) if defined?(@exist)
|
92
105
|
end
|
data/spellr.gemspec
CHANGED
@@ -20,7 +20,7 @@ Gem::Specification.new do |spec|
|
|
20
20
|
spec.metadata['changelog_uri'] = "#{spec.homepage}/blob/main/CHANGELOG.md"
|
21
21
|
end
|
22
22
|
|
23
|
-
spec.required_ruby_version = '>= 2.
|
23
|
+
spec.required_ruby_version = '>= 2.5'
|
24
24
|
|
25
25
|
spec.files = Dir.glob('{lib,exe,wordlists}/**/{*,.*}') + %w{
|
26
26
|
CHANGELOG.md
|
@@ -47,6 +47,8 @@ Gem::Specification.new do |spec|
|
|
47
47
|
spec.add_development_dependency 'tty_string', '>= 1.1.0'
|
48
48
|
spec.add_development_dependency 'webmock', '~> 3.8'
|
49
49
|
|
50
|
+
spec.add_dependency 'did_you_mean'
|
50
51
|
spec.add_dependency 'fast_ignore', '>= 0.11.0'
|
52
|
+
spec.add_dependency 'jaro_winkler'
|
51
53
|
spec.add_dependency 'parallel', '~> 1.0'
|
52
54
|
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: spellr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Dana Sherson
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-04-30 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -192,6 +192,20 @@ dependencies:
|
|
192
192
|
- - "~>"
|
193
193
|
- !ruby/object:Gem::Version
|
194
194
|
version: '3.8'
|
195
|
+
- !ruby/object:Gem::Dependency
|
196
|
+
name: did_you_mean
|
197
|
+
requirement: !ruby/object:Gem::Requirement
|
198
|
+
requirements:
|
199
|
+
- - ">="
|
200
|
+
- !ruby/object:Gem::Version
|
201
|
+
version: '0'
|
202
|
+
type: :runtime
|
203
|
+
prerelease: false
|
204
|
+
version_requirements: !ruby/object:Gem::Requirement
|
205
|
+
requirements:
|
206
|
+
- - ">="
|
207
|
+
- !ruby/object:Gem::Version
|
208
|
+
version: '0'
|
195
209
|
- !ruby/object:Gem::Dependency
|
196
210
|
name: fast_ignore
|
197
211
|
requirement: !ruby/object:Gem::Requirement
|
@@ -206,6 +220,20 @@ dependencies:
|
|
206
220
|
- - ">="
|
207
221
|
- !ruby/object:Gem::Version
|
208
222
|
version: 0.11.0
|
223
|
+
- !ruby/object:Gem::Dependency
|
224
|
+
name: jaro_winkler
|
225
|
+
requirement: !ruby/object:Gem::Requirement
|
226
|
+
requirements:
|
227
|
+
- - ">="
|
228
|
+
- !ruby/object:Gem::Version
|
229
|
+
version: '0'
|
230
|
+
type: :runtime
|
231
|
+
prerelease: false
|
232
|
+
version_requirements: !ruby/object:Gem::Requirement
|
233
|
+
requirements:
|
234
|
+
- - ">="
|
235
|
+
- !ruby/object:Gem::Version
|
236
|
+
version: '0'
|
209
237
|
- !ruby/object:Gem::Dependency
|
210
238
|
name: parallel
|
211
239
|
requirement: !ruby/object:Gem::Requirement
|
@@ -235,12 +263,11 @@ files:
|
|
235
263
|
- exe/spellr
|
236
264
|
- lib/.spellr.yml
|
237
265
|
- lib/spellr.rb
|
266
|
+
- lib/spellr/autocorrect_reporter.rb
|
238
267
|
- lib/spellr/backports.rb
|
239
268
|
- lib/spellr/base_reporter.rb
|
240
269
|
- lib/spellr/check.rb
|
241
270
|
- lib/spellr/check_dry_run.rb
|
242
|
-
- lib/spellr/check_interactive.rb
|
243
|
-
- lib/spellr/check_parallel.rb
|
244
271
|
- lib/spellr/cli.rb
|
245
272
|
- lib/spellr/cli_options.rb
|
246
273
|
- lib/spellr/column_location.rb
|
@@ -266,7 +293,7 @@ files:
|
|
266
293
|
- lib/spellr/rake_task.rb
|
267
294
|
- lib/spellr/reporter.rb
|
268
295
|
- lib/spellr/string_format.rb
|
269
|
-
- lib/spellr/
|
296
|
+
- lib/spellr/suggester.rb
|
270
297
|
- lib/spellr/token.rb
|
271
298
|
- lib/spellr/token_regexps.rb
|
272
299
|
- lib/spellr/tokenizer.rb
|
@@ -312,7 +339,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
312
339
|
requirements:
|
313
340
|
- - ">="
|
314
341
|
- !ruby/object:Gem::Version
|
315
|
-
version: '2.
|
342
|
+
version: '2.5'
|
316
343
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
317
344
|
requirements:
|
318
345
|
- - ">="
|
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../spellr'
|
4
|
-
require_relative 'check'
|
5
|
-
|
6
|
-
module Spellr
|
7
|
-
class CheckInteractive < Check
|
8
|
-
private
|
9
|
-
|
10
|
-
def check_file_from_restart(file, restart_token, wordlist_proc)
|
11
|
-
# new wordlist cache when adding a word
|
12
|
-
wordlist_proc = wordlist_proc_for(file) unless restart_token.replacement
|
13
|
-
check_file(file, restart_token.location, wordlist_proc)
|
14
|
-
end
|
15
|
-
|
16
|
-
def check_file(file, start_at = nil, wordlist_proc = wordlist_proc_for(file))
|
17
|
-
restart_token = catch(:check_file_from) do
|
18
|
-
super(file, start_at, wordlist_proc)
|
19
|
-
nil
|
20
|
-
end
|
21
|
-
check_file_from_restart(file, restart_token, wordlist_proc) if restart_token
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
require_relative '../spellr'
|
4
|
-
require_relative 'check'
|
5
|
-
require_relative 'output_stubbed'
|
6
|
-
require 'parallel'
|
7
|
-
|
8
|
-
module Spellr
|
9
|
-
class CheckParallel < Check
|
10
|
-
def check # rubocop:disable Metrics/MethodLength
|
11
|
-
acc_reporter = @reporter
|
12
|
-
|
13
|
-
Parallel.each(files, finish: ->(_, _, result) { acc_reporter.output << result }) do |file|
|
14
|
-
@reporter = acc_reporter.class.new(Spellr::OutputStubbed.new)
|
15
|
-
check_and_count_file(file)
|
16
|
-
reporter.output
|
17
|
-
end
|
18
|
-
@reporter = acc_reporter
|
19
|
-
|
20
|
-
reporter.finish
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,11 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
module Spellr
|
4
|
-
class StringIOWithEncoding < ::StringIO
|
5
|
-
def each_line(*args, encoding: nil, **kwargs, &block)
|
6
|
-
string.force_encoding(encoding) if encoding && !string.frozen?
|
7
|
-
|
8
|
-
super(*args, **kwargs, &block)
|
9
|
-
end
|
10
|
-
end
|
11
|
-
end
|