spellr 0.3.2 → 0.4.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 +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'
|