spellr 0.3.2 → 0.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/Gemfile.lock +13 -10
- data/bin/fetch_wordlist/english +3 -1
- data/lib/.spellr.yml +12 -9
- data/lib/spellr/backports.rb +19 -0
- data/lib/spellr/check.rb +15 -12
- data/lib/spellr/config.rb +46 -11
- data/lib/spellr/file.rb +7 -8
- data/lib/spellr/file_list.rb +15 -10
- data/lib/spellr/interactive.rb +8 -3
- data/lib/spellr/key_tuner/data.yml +1242 -0
- data/lib/spellr/key_tuner/naive_bayes.rb +162 -0
- data/lib/spellr/key_tuner/possible_key.rb +170 -0
- data/lib/spellr/key_tuner/stats.rb +33 -0
- data/lib/spellr/language.rb +20 -5
- data/lib/spellr/line_tokenizer.rb +115 -84
- data/lib/spellr/string_format.rb +8 -3
- data/lib/spellr/token.rb +14 -10
- data/lib/spellr/tokenizer.rb +1 -2
- data/lib/spellr/version.rb +1 -1
- data/lib/spellr/wordlist.rb +6 -5
- data/lib/spellr.rb +5 -14
- data/spellr.gemspec +3 -2
- metadata +24 -5
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 3725eb0cbde87e7f9ba2e6c8cfbd3c64143e3518e9d835ae284cd44214063f61
|
4
|
+
data.tar.gz: c7949e1f234014929bc8d57455127ca0c00e907a152cd346778621991c15f390
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: b076fef5196b5d997ef375de33f575aa83a351d6529755fa26c4de9aeab6b43162ca7b76668ec171405b57e7dec733228d10aaa860f1ebc975aa84e859ace642
|
7
|
+
data.tar.gz: 248adcf239ec2cc0c8d271d45f295a1aeeb2661ae3ba1c5852e671d98726f776ba1691bda4dec39647f9b03596c8282bf0cfac0a9ec50e6428e2f2de24837778
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,14 @@
|
|
1
|
+
# v0.4.0 (unreleased)
|
2
|
+
- LOTS of performance improvements. it's about 4 times faster
|
3
|
+
- significantly better key heuristic matching, with configurable weight (`key_heuristic_weight`).
|
4
|
+
- Update FastIgnore dependency.
|
5
|
+
- Change the yml format slightly. `ignore` is now `excludes`. `only` is now `includes`
|
6
|
+
I feel like this makes more sense for the way the config is merged. and the right time to do it is when you'll probably have to tweak it anyway because:
|
7
|
+
- the `only`/`includes` items are now parsed using FastIgnore's gitignore inspired allow list format
|
8
|
+
(see https://github.com/robotdana/fast_ignore#using-an-includes-list)
|
9
|
+
Mostly it's the same just more flexible, though there may need to be some small adjustments.
|
10
|
+
- the cli arguments are now also managed using FastIgnore's rules, fixing issues with absolute paths and paths beginning with `./` also it's a LOT faster when just checking a single file, basically instant. so that's nice.
|
11
|
+
|
1
12
|
# v0.3.2
|
2
13
|
- add automatic rubygems and dockerhub deploy
|
3
14
|
|
data/Gemfile.lock
CHANGED
@@ -1,8 +1,8 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
spellr (0.
|
5
|
-
fast_ignore
|
4
|
+
spellr (0.4.0)
|
5
|
+
fast_ignore (~> 0.4.0)
|
6
6
|
|
7
7
|
GEM
|
8
8
|
remote: https://rubygems.org/
|
@@ -10,11 +10,11 @@ GEM
|
|
10
10
|
ast (2.4.0)
|
11
11
|
coderay (1.1.2)
|
12
12
|
diff-lcs (1.3)
|
13
|
-
fast_ignore (0.
|
13
|
+
fast_ignore (0.4.0)
|
14
14
|
jaro_winkler (1.5.3)
|
15
15
|
method_source (0.9.2)
|
16
16
|
parallel (1.17.0)
|
17
|
-
parser (2.6.
|
17
|
+
parser (2.6.5.0)
|
18
18
|
ast (~> 2.4.0)
|
19
19
|
pry (0.12.2)
|
20
20
|
coderay (~> 1.1.0)
|
@@ -28,23 +28,25 @@ GEM
|
|
28
28
|
rspec-core (3.8.2)
|
29
29
|
rspec-support (~> 3.8.0)
|
30
30
|
rspec-eventually (0.2.2)
|
31
|
-
rspec-expectations (3.8.
|
31
|
+
rspec-expectations (3.8.5)
|
32
32
|
diff-lcs (>= 1.2.0, < 2.0)
|
33
33
|
rspec-support (~> 3.8.0)
|
34
|
-
rspec-mocks (3.8.
|
34
|
+
rspec-mocks (3.8.2)
|
35
35
|
diff-lcs (>= 1.2.0, < 2.0)
|
36
36
|
rspec-support (~> 3.8.0)
|
37
|
-
rspec-support (3.8.
|
38
|
-
rubocop (0.
|
37
|
+
rspec-support (3.8.3)
|
38
|
+
rubocop (0.75.0)
|
39
39
|
jaro_winkler (~> 1.5.1)
|
40
40
|
parallel (~> 1.10)
|
41
41
|
parser (>= 2.6)
|
42
42
|
rainbow (>= 2.2.2, < 4.0)
|
43
43
|
ruby-progressbar (~> 1.7)
|
44
44
|
unicode-display_width (>= 1.4.0, < 1.7)
|
45
|
-
rubocop-rspec (1.
|
46
|
-
rubocop (>= 0.
|
45
|
+
rubocop-rspec (1.36.0)
|
46
|
+
rubocop (>= 0.68.1)
|
47
47
|
ruby-progressbar (1.10.1)
|
48
|
+
terminal-table (1.8.0)
|
49
|
+
unicode-display_width (~> 1.1, >= 1.1.1)
|
48
50
|
tty_string (0.1.0)
|
49
51
|
unicode-display_width (1.6.0)
|
50
52
|
|
@@ -60,6 +62,7 @@ DEPENDENCIES
|
|
60
62
|
rubocop
|
61
63
|
rubocop-rspec
|
62
64
|
spellr!
|
65
|
+
terminal-table
|
63
66
|
tty_string
|
64
67
|
|
65
68
|
BUNDLED WITH
|
data/bin/fetch_wordlist/english
CHANGED
@@ -40,7 +40,9 @@ class SCOWLDownloader
|
|
40
40
|
|
41
41
|
@options[:spelling] = a
|
42
42
|
end
|
43
|
-
opts.on('-p', '--[no-]programming', 'include common programming terms like grep (default true)')
|
43
|
+
opts.on('-p', '--[no-]programming', 'include common programming terms like grep (default true)') do |h|
|
44
|
+
@options[:special] = :hacker if h
|
45
|
+
end
|
44
46
|
opts.on_tail('-h', '--help') do
|
45
47
|
warn opts.to_s
|
46
48
|
exit 1
|
data/lib/.spellr.yml
CHANGED
@@ -1,14 +1,17 @@
|
|
1
1
|
---
|
2
2
|
word_minimum_length: 3
|
3
|
+
key_heuristic_weight: 5
|
4
|
+
key_minimum_length: 6
|
3
5
|
|
4
|
-
|
5
|
-
-
|
6
|
+
excludes: # this list is parsed with the .gitignore format
|
7
|
+
- .git/
|
6
8
|
- .spellr_wordlists/
|
7
9
|
- .DS_Store
|
8
10
|
- Gemfile.lock
|
9
11
|
- .rspec_status
|
10
12
|
- '*.png'
|
11
13
|
- '*.jpg'
|
14
|
+
- '*.jpeg'
|
12
15
|
- '*.gif'
|
13
16
|
- '*.ico'
|
14
17
|
- .gitkeep
|
@@ -28,7 +31,7 @@ languages:
|
|
28
31
|
generate: "fetch english"
|
29
32
|
# TODO: don't generate the ruby file until you actually need one
|
30
33
|
ruby:
|
31
|
-
|
34
|
+
includes: # Filtered using gitignore format
|
32
35
|
- '*.rb'
|
33
36
|
- '*.rake'
|
34
37
|
- '*.gemspec'
|
@@ -42,7 +45,7 @@ languages:
|
|
42
45
|
hashbangs:
|
43
46
|
- ruby
|
44
47
|
html:
|
45
|
-
|
48
|
+
includes:
|
46
49
|
- '*.html'
|
47
50
|
- '*.hml'
|
48
51
|
- '*.jsx'
|
@@ -59,7 +62,7 @@ languages:
|
|
59
62
|
- '*.sass'
|
60
63
|
- '*.less'
|
61
64
|
js:
|
62
|
-
|
65
|
+
includes:
|
63
66
|
- '*.html'
|
64
67
|
- '*.hml'
|
65
68
|
- '*.jsx'
|
@@ -71,22 +74,22 @@ languages:
|
|
71
74
|
- '*.erb'
|
72
75
|
- '*.json'
|
73
76
|
shell:
|
74
|
-
|
77
|
+
includes:
|
75
78
|
- '*.sh'
|
76
79
|
- Dockerfile
|
77
80
|
hashbangs:
|
78
81
|
- bash
|
79
82
|
- sh
|
80
83
|
dockerfile:
|
81
|
-
|
84
|
+
includes:
|
82
85
|
- Dockerfile
|
83
86
|
css:
|
84
|
-
|
87
|
+
includes:
|
85
88
|
- '*.css'
|
86
89
|
- '*.sass'
|
87
90
|
- '*.scss'
|
88
91
|
xml:
|
89
|
-
|
92
|
+
includes:
|
90
93
|
- '*.xml'
|
91
94
|
- '*.html'
|
92
95
|
- '*.haml'
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
class Array
|
4
|
+
unless RUBY_VERSION >= '2.4'
|
5
|
+
def sum
|
6
|
+
reduce(0) do |total, value|
|
7
|
+
total + if block_given?
|
8
|
+
yield value
|
9
|
+
else
|
10
|
+
value
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
class String
|
18
|
+
alias_method :match?, :match unless RUBY_VERSION >= '2.4'
|
19
|
+
end
|
data/lib/spellr/check.rb
CHANGED
@@ -36,21 +36,24 @@ module Spellr
|
|
36
36
|
|
37
37
|
private
|
38
38
|
|
39
|
-
def check_file(file, start_at: nil, wordlists: Spellr.config.wordlists_for(file)) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
39
|
+
def check_file(file, start_at: nil, wordlists: Spellr.config.wordlists_for(file)) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
40
|
+
restart_token = catch(:check_file_from) do
|
41
|
+
Spellr::Tokenizer.new(file, start_at: start_at).each_token do |token|
|
42
|
+
next if wordlists.any? { |d| d.include?(token) }
|
43
|
+
|
44
|
+
start_at = token.location
|
45
|
+
reporter.call(token)
|
46
|
+
@exit_code = 1
|
47
|
+
end
|
48
|
+
nil
|
49
|
+
end
|
50
|
+
if restart_token
|
51
|
+
wordlist_arg = restart_token.replacement ? { wordlists: wordlists } : {} # new wordlist cache when adding a word
|
52
|
+
check_file(file, start_at: restart_token.location, **wordlist_arg)
|
46
53
|
end
|
47
|
-
rescue Spellr::DidReplacement => e # Yeah this is exceptions for control flow, but it makes sense to me
|
48
|
-
check_file(file, start_at: e.token.location, wordlists: wordlists)
|
49
|
-
rescue Spellr::DidAdd => e
|
50
|
-
check_file(file, start_at: e.token.location) # don't cache the wordlists
|
51
54
|
rescue InvalidByteSequence
|
52
55
|
# sometimes files are binary
|
53
|
-
|
56
|
+
warn "Skipped unreadable file: #{file}" unless Spellr.config.quiet?
|
54
57
|
end
|
55
58
|
end
|
56
59
|
end
|
data/lib/spellr/config.rb
CHANGED
@@ -2,9 +2,12 @@
|
|
2
2
|
|
3
3
|
require_relative '../spellr'
|
4
4
|
require_relative 'config_loader'
|
5
|
+
require_relative 'language'
|
6
|
+
require_relative 'reporter'
|
7
|
+
require 'pathname'
|
5
8
|
|
6
9
|
module Spellr
|
7
|
-
class Config
|
10
|
+
class Config # rubocop:disable Metrics/ClassLength
|
8
11
|
attr_writer :reporter
|
9
12
|
attr_reader :config_file
|
10
13
|
attr_accessor :quiet
|
@@ -33,35 +36,69 @@ module Spellr
|
|
33
36
|
end
|
34
37
|
|
35
38
|
def word_minimum_length
|
36
|
-
@config[:word_minimum_length]
|
39
|
+
@word_minimum_length ||= @config[:word_minimum_length]
|
37
40
|
end
|
38
41
|
|
39
|
-
def
|
40
|
-
@config[:
|
42
|
+
def key_heuristic_weight
|
43
|
+
@key_heuristic_weight ||= @config[:key_heuristic_weight]
|
41
44
|
end
|
42
45
|
|
43
|
-
def
|
44
|
-
@config[:
|
46
|
+
def key_minimum_length
|
47
|
+
@key_minimum_length ||= @config[:key_minimum_length]
|
48
|
+
end
|
49
|
+
|
50
|
+
def includes
|
51
|
+
return @includes if defined?(@includes)
|
52
|
+
|
53
|
+
if @config[:only]
|
54
|
+
warn <<~WARNING
|
55
|
+
\e[33mSpellr: `only:` yaml key with a list of fnmatch rules is deprecated.
|
56
|
+
Please use `includes:` instead, which uses gitignore-inspired rules.
|
57
|
+
see github.com/robotdana/fast_ignore#using-an-includes-list for details\e[0m
|
58
|
+
WARNING
|
59
|
+
end
|
60
|
+
|
61
|
+
@includes = (@config[:includes] || []) + (@config[:only] || [])
|
62
|
+
end
|
63
|
+
|
64
|
+
def excludes
|
65
|
+
return @excludes if defined?(@excludes)
|
66
|
+
|
67
|
+
if @config[:ignore]
|
68
|
+
warn <<~WARNING
|
69
|
+
\e[33mSpellr: `ignore:` yaml key is deprecated.
|
70
|
+
Please use `excludes:` instead.\e[0m
|
71
|
+
WARNING
|
72
|
+
end
|
73
|
+
|
74
|
+
@excludes = (@config[:excludes] || []) + (@config[:ignore] || [])
|
45
75
|
end
|
46
76
|
|
47
77
|
def color
|
48
78
|
@config[:color]
|
49
79
|
end
|
50
80
|
|
51
|
-
def clear_cache
|
81
|
+
def clear_cache # rubocop:disable Metrics/CyclomaticComplexity, Metrics/PerceivedComplexity
|
52
82
|
remove_instance_variable(:@wordlists) if defined?(@wordlists)
|
53
83
|
remove_instance_variable(:@languages) if defined?(@languages)
|
54
84
|
remove_instance_variable(:@errors) if defined?(@errors)
|
85
|
+
remove_instance_variable(:@word_minimum_length) if defined?(@word_minimum_length)
|
86
|
+
remove_instance_variable(:@key_heuristic_weight) if defined?(@key_heuristic_weight)
|
87
|
+
remove_instance_variable(:@key_minimum_length) if defined?(@key_minimum_length)
|
88
|
+
remove_instance_variable(:@excludes) if defined?(@excludes)
|
89
|
+
remove_instance_variable(:@includes) if defined?(@includes)
|
55
90
|
end
|
56
91
|
|
57
92
|
def languages
|
58
|
-
require_relative 'language'
|
59
|
-
|
60
93
|
@languages ||= @config[:languages].map do |key, args|
|
61
94
|
Spellr::Language.new(key, args)
|
62
95
|
end
|
63
96
|
end
|
64
97
|
|
98
|
+
def pwd
|
99
|
+
@pwd ||= Pathname.pwd
|
100
|
+
end
|
101
|
+
|
65
102
|
def languages_for(file)
|
66
103
|
languages.select { |l| l.matches?(file) }
|
67
104
|
end
|
@@ -109,8 +146,6 @@ module Spellr
|
|
109
146
|
end
|
110
147
|
|
111
148
|
def default_reporter
|
112
|
-
require_relative 'reporter'
|
113
|
-
|
114
149
|
Spellr::Reporter.new
|
115
150
|
end
|
116
151
|
end
|
data/lib/spellr/file.rb
CHANGED
@@ -2,6 +2,8 @@
|
|
2
2
|
|
3
3
|
require 'pathname'
|
4
4
|
|
5
|
+
# TODO: maybe just extend pathname if you have to
|
6
|
+
|
5
7
|
module Spellr
|
6
8
|
class File < Pathname
|
7
9
|
def self.wrap(file)
|
@@ -9,19 +11,16 @@ module Spellr
|
|
9
11
|
end
|
10
12
|
|
11
13
|
def hashbang
|
12
|
-
|
13
|
-
|
14
|
+
@hashbang ||= begin
|
15
|
+
return if extname != ''
|
16
|
+
return unless first_line&.start_with?('#!')
|
14
17
|
|
15
|
-
|
18
|
+
first_line
|
19
|
+
end
|
16
20
|
end
|
17
21
|
|
18
22
|
def first_line
|
19
23
|
@first_line ||= each_line.first
|
20
24
|
end
|
21
|
-
|
22
|
-
def fnmatch?(pattern)
|
23
|
-
relative_path_from(Pathname.pwd).fnmatch?(pattern, ::File::FNM_DOTMATCH) ||
|
24
|
-
Pathname.new(basename).fnmatch?(pattern, ::File::FNM_DOTMATCH)
|
25
|
-
end
|
26
25
|
end
|
27
26
|
end
|
data/lib/spellr/file_list.rb
CHANGED
@@ -12,22 +12,27 @@ module Spellr
|
|
12
12
|
@patterns = patterns
|
13
13
|
end
|
14
14
|
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
15
|
+
# anchored patterns are significantly faster on large codebases
|
16
|
+
def cli_patterns
|
17
|
+
@patterns.map do |pattern|
|
18
|
+
if pattern.match?(%r{^([/~*]|\.{1,2}/)})
|
19
|
+
pattern
|
20
|
+
else
|
21
|
+
"/#{pattern}"
|
22
|
+
end
|
23
|
+
end
|
21
24
|
end
|
22
25
|
|
23
26
|
def each
|
24
|
-
# TODO: handle no gitignore
|
25
27
|
gitignore = ::File.join(Dir.pwd, '.gitignore')
|
26
28
|
gitignore = nil unless ::File.exist?(gitignore)
|
27
|
-
|
29
|
+
|
30
|
+
FastIgnore.new(
|
31
|
+
ignore_rules: Spellr.config.excludes,
|
32
|
+
include_rules: Spellr.config.includes + cli_patterns,
|
33
|
+
gitignore: gitignore
|
34
|
+
).each do |file|
|
28
35
|
file = Spellr::File.new(file)
|
29
|
-
next unless cli_only?(file)
|
30
|
-
next unless config_only?(file)
|
31
36
|
|
32
37
|
yield(file)
|
33
38
|
end
|
data/lib/spellr/interactive.rb
CHANGED
@@ -61,6 +61,7 @@ module Spellr
|
|
61
61
|
return unless global_skips.include?(token.to_s) ||
|
62
62
|
global_insensitive_skips.include?(token.normalize)
|
63
63
|
|
64
|
+
puts "Automatically skipped #{red(token)}"
|
64
65
|
self.total_skipped += 1
|
65
66
|
end
|
66
67
|
|
@@ -71,7 +72,8 @@ module Spellr
|
|
71
72
|
|
72
73
|
token.replace(global_replacement)
|
73
74
|
self.total_fixed += 1
|
74
|
-
|
75
|
+
puts "Automatically replaced #{red(token)} with #{green(global_replacement)}"
|
76
|
+
throw :check_file_from, token
|
75
77
|
end
|
76
78
|
|
77
79
|
def clear_current_line
|
@@ -112,6 +114,7 @@ module Spellr
|
|
112
114
|
def handle_skip(token)
|
113
115
|
self.total_skipped += 1
|
114
116
|
yield token if block_given?
|
117
|
+
puts "Skipped #{red(token)}"
|
115
118
|
end
|
116
119
|
|
117
120
|
# TODO: handle more than 16 options
|
@@ -133,7 +136,8 @@ module Spellr
|
|
133
136
|
|
134
137
|
wl.add(token)
|
135
138
|
self.total_added += 1
|
136
|
-
|
139
|
+
puts "Added #{red(token)} to #{wl.name} wordlist"
|
140
|
+
throw :check_file_from, token
|
137
141
|
else
|
138
142
|
handle_add(token)
|
139
143
|
end
|
@@ -152,7 +156,8 @@ module Spellr
|
|
152
156
|
token.replace(full_replacement)
|
153
157
|
yield replacement if block_given?
|
154
158
|
self.total_fixed += 1
|
155
|
-
|
159
|
+
puts "Replaced #{red(token.chomp)} with #{green(replacement.chomp)}"
|
160
|
+
throw :check_file_from, token
|
156
161
|
end
|
157
162
|
rescue Interrupt
|
158
163
|
puts '^C again to exit'
|