forspell 0.0.6 → 0.0.7
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/exe/clone_repos.sh +1 -1
- data/exe/create_dictionary +14 -16
- data/exe/generate_logs +5 -2
- data/lib/forspell/cli.rb +9 -4
- data/lib/forspell/file_list.rb +8 -4
- data/lib/forspell/loaders/markdown.rb +3 -1
- data/lib/forspell/loaders/ruby.rb +13 -3
- data/lib/forspell/reporter.rb +33 -8
- data/lib/forspell/ruby.dict +384 -7
- data/lib/forspell/runner.rb +6 -1
- data/lib/forspell/sanitizer.rb +3 -9
- data/lib/forspell/speller.rb +14 -4
- data/lib/forspell/word_matcher.rb +4 -6
- metadata +30 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 67422b4f2942f8a061b0551a4fa837c0c0c93140
|
|
4
|
+
data.tar.gz: b56c34d10ecd2bee9dbfa14757ec7853d8a6fe17
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 1e2512ac8231b29ac095fdf2d71b426a82ba9365c6ae4d9cbf52f349f76b12bf7cdfe170b2001b4f0fe7b3fc4239175f59d8cec7f9742880c30d7a0bc8c88cff
|
|
7
|
+
data.tar.gz: 432eb94fcf818aba269b8292988956ba905964426e239ae35a9c3972813d6d1b7c19d9a1da2e4146d3f649bfbe13902359ba49fe532458e330e04c6cc4ad89b7
|
data/exe/clone_repos.sh
CHANGED
|
@@ -43,7 +43,7 @@ array=( "https://github.com/rspec/rspec-core.git"
|
|
|
43
43
|
"https://github.com/paper-trail-gem/paper_trail.git"
|
|
44
44
|
"https://github.com/aasm/aasm.git"
|
|
45
45
|
"https://github.com/rubysherpas/paranoia.git"
|
|
46
|
-
""
|
|
46
|
+
"https://github.com/rubocop-hq/rubocop.git"
|
|
47
47
|
""
|
|
48
48
|
""
|
|
49
49
|
""
|
data/exe/create_dictionary
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
#!/usr/bin/env ruby
|
|
2
2
|
require 'yaml'
|
|
3
|
-
require 'pry'
|
|
4
3
|
require 'csv'
|
|
4
|
+
require 'pry'
|
|
5
5
|
|
|
6
6
|
class DictionaryCreator
|
|
7
7
|
attr_reader :result
|
|
8
8
|
|
|
9
|
-
def initialize(path: '
|
|
9
|
+
def initialize(path: 'test/popular_gems/')
|
|
10
10
|
@path = path
|
|
11
11
|
@data = {}
|
|
12
12
|
@result = {}
|
|
@@ -14,21 +14,20 @@ class DictionaryCreator
|
|
|
14
14
|
|
|
15
15
|
def process
|
|
16
16
|
(Dir.entries(@path) - ['.', '..']).each do |filename|
|
|
17
|
-
|
|
18
|
-
@data[filename] = YAML.load_file("#{@path}#{filename}")
|
|
17
|
+
@data[filename] = File.read("#{@path}#{filename}")
|
|
19
18
|
end
|
|
20
19
|
|
|
21
20
|
@data.each_pair do |log_filename, data|
|
|
22
21
|
next if data == false
|
|
23
22
|
|
|
24
23
|
gem_name = log_filename.split('.').first
|
|
25
|
-
data.each do |
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
24
|
+
data.split(/\n/).each do |error_with_count|
|
|
25
|
+
error, count = error_with_count.split(' # ')
|
|
26
|
+
count = count.to_i
|
|
27
|
+
if @result[error]
|
|
28
|
+
@result[error] = @result[error].merge(count: @result.dig(error, :count) + count, gems: (@result.dig(error, :gems) + [gem_name]).uniq)
|
|
29
|
+
else
|
|
30
|
+
@result[error] = { count: count, gems: [gem_name] }
|
|
32
31
|
end
|
|
33
32
|
end
|
|
34
33
|
end
|
|
@@ -37,11 +36,10 @@ class DictionaryCreator
|
|
|
37
36
|
end
|
|
38
37
|
end
|
|
39
38
|
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
CSV.open('../ruby_dict.csv', 'wb') do |csv|
|
|
39
|
+
CSV.open('ruby_dict_sort.csv', 'wb') do |csv|
|
|
43
40
|
csv << ['word', 'count', 'gems', 'should_include?']
|
|
44
|
-
DictionaryCreator.new.process.result
|
|
45
|
-
|
|
41
|
+
res = DictionaryCreator.new.process.result
|
|
42
|
+
res.keys.sort.each do |word|
|
|
43
|
+
csv << [word, res[word][:count], res[word][:gems].join(', '), nil]
|
|
46
44
|
end
|
|
47
45
|
end
|
data/exe/generate_logs
CHANGED
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
#!/bin/bash
|
|
2
2
|
cd ~/forspell
|
|
3
|
-
rm ./test/popular_gems
|
|
3
|
+
rm ./test/popular_gems/*.dict
|
|
4
4
|
|
|
5
5
|
for var in $(ls ../gem_src/)
|
|
6
6
|
do
|
|
7
|
-
|
|
7
|
+
cd ~/gem_src/$var
|
|
8
|
+
rm forspell.dict
|
|
9
|
+
~/forspell/exe/forspell --gen-dictionary .
|
|
10
|
+
cp forspell.dict ~/forspell/test/popular_gems/$var.forspell.dict
|
|
8
11
|
done
|
data/lib/forspell/cli.rb
CHANGED
|
@@ -20,9 +20,12 @@ module Forspell
|
|
|
20
20
|
o.string '-d', '--dictionary-path', 'Path to main hunspell dictionary to use (by default, forspell\'s en_US)', default: 'en_US'
|
|
21
21
|
o.array '-c', '--custom-paths', 'Paths to custom dictionaries', default: []
|
|
22
22
|
o.string '-f', '--format', 'Output formats: readable(default), JSON, YAML', default: 'readable'
|
|
23
|
-
o.
|
|
23
|
+
o.bool '--gen-dictionary', 'Generate custom dictionary', default: false
|
|
24
|
+
o.bool '--print-filepaths', 'Enable file paths in dictionary mode', default: false
|
|
24
25
|
o.string '-l', '--logfile', 'Log to specified path'
|
|
25
|
-
o.bool '-v', '--verbose', 'Verbose mode'
|
|
26
|
+
o.bool '-v', '--verbose', 'Verbose mode', default: false
|
|
27
|
+
o.bool '--no-suggest', 'Output without suggestions', default: false
|
|
28
|
+
o.integer '--suggestions-size', 'How many suggestions for each error should be returned', default: 3
|
|
26
29
|
o.on '--help' do
|
|
27
30
|
puts o
|
|
28
31
|
exit
|
|
@@ -71,12 +74,14 @@ module Forspell
|
|
|
71
74
|
end
|
|
72
75
|
|
|
73
76
|
@opts[:custom_paths] << DEFAULT_CUSTOM_DICT if File.exist?(DEFAULT_CUSTOM_DICT)
|
|
77
|
+
suggestions_size = (@opts[:gen_dictionary] || @opts[:no_suggest]) ? 0 : @opts[:suggestions_size]
|
|
78
|
+
suggestions_size ||= 0
|
|
74
79
|
|
|
75
|
-
@speller = Speller.new(@opts[:dictionary_path], *@opts[:custom_paths])
|
|
80
|
+
@speller = Speller.new(@opts[:dictionary_path], *@opts[:custom_paths], suggestions_size: suggestions_size)
|
|
76
81
|
end
|
|
77
82
|
|
|
78
83
|
def init_reporter
|
|
79
|
-
@reporter = Reporter.new(**@opts.to_hash.slice(:logfile, :format, :verbose))
|
|
84
|
+
@reporter = Reporter.new(**@opts.to_hash.slice(:logfile, :format, :verbose, :print_filepaths))
|
|
80
85
|
end
|
|
81
86
|
|
|
82
87
|
def run
|
data/lib/forspell/file_list.rb
CHANGED
|
@@ -16,17 +16,21 @@ module Forspell
|
|
|
16
16
|
def initialize(paths:, exclude_paths:)
|
|
17
17
|
@paths = paths
|
|
18
18
|
@exclude_paths = exclude_paths
|
|
19
|
-
end
|
|
20
19
|
|
|
21
|
-
def each(&block)
|
|
22
20
|
to_process = @paths.flat_map(&method(:expand_paths))
|
|
23
|
-
|
|
24
21
|
to_exclude = @exclude_paths.flat_map(&method(:expand_paths))
|
|
22
|
+
@files = to_process - to_exclude
|
|
23
|
+
end
|
|
25
24
|
|
|
26
|
-
|
|
25
|
+
def each(&block)
|
|
26
|
+
@files.map{ |path| path.gsub('//', '/')}
|
|
27
27
|
.each(&block)
|
|
28
28
|
end
|
|
29
29
|
|
|
30
|
+
def size
|
|
31
|
+
@size ||= @files.size
|
|
32
|
+
end
|
|
33
|
+
|
|
30
34
|
private
|
|
31
35
|
|
|
32
36
|
def expand_paths(path)
|
|
@@ -45,8 +45,10 @@ module Forspell::Loaders
|
|
|
45
45
|
|
|
46
46
|
group_by_location = chunks.group_by { |res| res[:location] }
|
|
47
47
|
.transform_values do |lines|
|
|
48
|
-
lines.map { |v| SPECIAL_CHARS_MAP[v[:value]] || v[:value] }
|
|
48
|
+
lines.map { |v| SPECIAL_CHARS_MAP[v[:value]] || v[:value] }
|
|
49
|
+
.join.split(%r{[[:punct:]]&&[^-'_./\\:]|\s})
|
|
49
50
|
end
|
|
51
|
+
|
|
50
52
|
group_by_location.each_pair do |location, words|
|
|
51
53
|
words.reject(&:empty?)
|
|
52
54
|
.each { |word| result << Word.new(@file, location || 0, word) }
|
|
@@ -2,20 +2,30 @@
|
|
|
2
2
|
|
|
3
3
|
require 'yard'
|
|
4
4
|
require 'yard/parser/ruby/ruby_parser'
|
|
5
|
+
require 'rdoc'
|
|
5
6
|
require_relative 'source'
|
|
6
7
|
|
|
7
8
|
module Forspell::Loaders
|
|
8
9
|
class Ruby < Source
|
|
10
|
+
MAX_COMMENT_LENGTH = 777
|
|
11
|
+
|
|
12
|
+
def initialize(file: nil, text: nil)
|
|
13
|
+
super
|
|
14
|
+
@markup = RDoc::Markup.new
|
|
15
|
+
@formatter = RDoc::Markup::ToMarkdown.new
|
|
16
|
+
@formatter.width = MAX_COMMENT_LENGTH
|
|
17
|
+
end
|
|
18
|
+
|
|
9
19
|
private
|
|
10
20
|
|
|
11
21
|
def comments
|
|
12
22
|
YARD::Parser::Ruby::RubyParser.new(@input, @file).parse
|
|
13
|
-
.tokens.select{ |
|
|
14
|
-
|
|
23
|
+
.tokens.select{ |type,| type == :comment }
|
|
24
|
+
.reject{ |_, text,| text.start_with?('# ') }
|
|
15
25
|
end
|
|
16
26
|
|
|
17
27
|
def text(comment)
|
|
18
|
-
comment[1]
|
|
28
|
+
@markup.convert(comment[1], @formatter)
|
|
19
29
|
end
|
|
20
30
|
|
|
21
31
|
def line(comment)
|
data/lib/forspell/reporter.rb
CHANGED
|
@@ -4,18 +4,26 @@ require 'fileutils'
|
|
|
4
4
|
require 'pastel'
|
|
5
5
|
require 'logger'
|
|
6
6
|
require 'json'
|
|
7
|
+
require 'highline'
|
|
8
|
+
require 'ruby-progressbar'
|
|
7
9
|
|
|
8
10
|
module Forspell
|
|
9
11
|
class Reporter
|
|
10
12
|
SUCCESS_CODE = 0
|
|
11
13
|
ERROR_CODE = 1
|
|
12
|
-
|
|
14
|
+
DICT_PATH = File.join(Dir.pwd, 'forspell.dict')
|
|
15
|
+
DICT_OVERWRITE = 'Do you want to overwrite forspell.dict? (yN)'
|
|
16
|
+
SUGGEST_FORMAT = '(suggestions: %<suggestions>s)'
|
|
17
|
+
ERROR_FORMAT = '%<file>s:%<line>i: %<text>s %<suggest>s'
|
|
13
18
|
SUMMARY = "Forspell inspects *.rb, *.c, *.cpp, *.md files\n"\
|
|
14
19
|
'%<files>i inspected, %<errors>s detected'
|
|
15
20
|
|
|
21
|
+
attr_accessor :progress_bar
|
|
22
|
+
|
|
16
23
|
def initialize(logfile:,
|
|
17
24
|
verbose:,
|
|
18
|
-
format
|
|
25
|
+
format:,
|
|
26
|
+
print_filepaths: false)
|
|
19
27
|
|
|
20
28
|
FileUtils.touch(logfile) if logfile.is_a?(String)
|
|
21
29
|
@logger = Logger.new(logfile || STDERR)
|
|
@@ -26,6 +34,7 @@ module Forspell
|
|
|
26
34
|
@pastel = Pastel.new(enabled: $stdout.tty?)
|
|
27
35
|
@errors = []
|
|
28
36
|
@files = []
|
|
37
|
+
@print_filepaths = print_filepaths
|
|
29
38
|
end
|
|
30
39
|
|
|
31
40
|
def file(path)
|
|
@@ -35,7 +44,7 @@ module Forspell
|
|
|
35
44
|
|
|
36
45
|
def error(word, suggestions)
|
|
37
46
|
@errors << [word, suggestions]
|
|
38
|
-
|
|
47
|
+
print(readable(word, suggestions)) if @format == 'readable'
|
|
39
48
|
end
|
|
40
49
|
|
|
41
50
|
def parsing_error(error)
|
|
@@ -64,17 +73,19 @@ module Forspell
|
|
|
64
73
|
private
|
|
65
74
|
|
|
66
75
|
def readable(word, suggestions)
|
|
76
|
+
suggest = format(SUGGEST_FORMAT, suggestions: suggestions.join(', ')) unless suggestions.empty?
|
|
77
|
+
|
|
67
78
|
format(ERROR_FORMAT,
|
|
68
79
|
file: word[:file],
|
|
69
80
|
line: word[:line],
|
|
70
81
|
text: @pastel.red(word[:text]),
|
|
71
|
-
|
|
82
|
+
suggest: suggest)
|
|
72
83
|
end
|
|
73
84
|
|
|
74
85
|
def print_formatted
|
|
75
86
|
@errors.map { |word, suggestions| word.to_h.merge(suggestions: suggestions) }
|
|
76
87
|
.public_send("to_#{@format}")
|
|
77
|
-
.tap { |res|
|
|
88
|
+
.tap { |res| print res }
|
|
78
89
|
end
|
|
79
90
|
|
|
80
91
|
def print_summary
|
|
@@ -82,18 +93,32 @@ module Forspell
|
|
|
82
93
|
color = err_count.positive? ? :red : :green
|
|
83
94
|
total_errors_colorized = @pastel.decorate(err_count.to_s, color)
|
|
84
95
|
|
|
85
|
-
|
|
96
|
+
print format(SUMMARY, files: @files.size, errors: total_errors_colorized)
|
|
86
97
|
end
|
|
87
98
|
|
|
88
99
|
def print_dictionary
|
|
100
|
+
puts DICT_PATH
|
|
101
|
+
if File.exist?(DICT_PATH)
|
|
102
|
+
cli = HighLine.new
|
|
103
|
+
answer = cli.ask(DICT_OVERWRITE)
|
|
104
|
+
out = answer.downcase == 'y' ? File.new(DICT_PATH, 'w') : exit(1)
|
|
105
|
+
else
|
|
106
|
+
out = File.new(DICT_PATH, 'w')
|
|
107
|
+
end
|
|
89
108
|
@errors.map(&:first)
|
|
90
109
|
.group_by(&:text)
|
|
91
110
|
.transform_values { |v| v.map(&:file).uniq }
|
|
92
111
|
.sort_by { |word, *| word.downcase }
|
|
93
112
|
.each do |text, files|
|
|
94
|
-
files.each { |file| puts "\# #{file}" }
|
|
95
|
-
puts @pastel.decorate(text, :red)
|
|
113
|
+
files.each { |file| out.puts "\# #{file}" } if @print_filepaths
|
|
114
|
+
out.puts out.tty? ? @pastel.decorate(text, :red) : text
|
|
96
115
|
end
|
|
97
116
|
end
|
|
117
|
+
|
|
118
|
+
private
|
|
119
|
+
|
|
120
|
+
def print something
|
|
121
|
+
$stdout.tty? ? @progress_bar&.log(something) : puts(something)
|
|
122
|
+
end
|
|
98
123
|
end
|
|
99
124
|
end
|
data/lib/forspell/ruby.dict
CHANGED
|
@@ -1,77 +1,454 @@
|
|
|
1
|
+
Cianfrocca
|
|
1
2
|
Gemfile: example
|
|
3
|
+
Hansson
|
|
4
|
+
Heinemeier
|
|
2
5
|
Rakefile
|
|
6
|
+
aasm
|
|
3
7
|
accessor: example
|
|
8
|
+
activerecord
|
|
9
|
+
activesupport
|
|
10
|
+
addon
|
|
4
11
|
admin: example
|
|
5
|
-
|
|
12
|
+
amongst
|
|
13
|
+
arel
|
|
14
|
+
arg: argument
|
|
15
|
+
arity
|
|
16
|
+
asciidoc
|
|
17
|
+
asciidoctor
|
|
6
18
|
async
|
|
7
19
|
attr: example
|
|
20
|
+
auth
|
|
21
|
+
authenticatable
|
|
22
|
+
autocorrect
|
|
23
|
+
autocorrected
|
|
24
|
+
autogenerated
|
|
25
|
+
autoload: load
|
|
26
|
+
autoloadable
|
|
27
|
+
autoloaded
|
|
28
|
+
autoloading
|
|
29
|
+
autosave
|
|
8
30
|
backend: example
|
|
9
31
|
backport: port
|
|
32
|
+
backtick
|
|
10
33
|
backtrace: example
|
|
34
|
+
basecamp
|
|
35
|
+
basename: name
|
|
36
|
+
baseurl
|
|
37
|
+
bcrypt
|
|
38
|
+
behaviour: behavior
|
|
39
|
+
benchmarking
|
|
40
|
+
bigint
|
|
41
|
+
bignum
|
|
42
|
+
bing
|
|
43
|
+
binstubs
|
|
11
44
|
bitwise
|
|
12
45
|
boolean: example
|
|
46
|
+
broadcastings
|
|
47
|
+
bugfix: fix
|
|
48
|
+
bugfixes
|
|
13
49
|
builtin
|
|
14
|
-
bundler
|
|
50
|
+
bundler: example
|
|
51
|
+
byebug
|
|
52
|
+
bytesize: size
|
|
53
|
+
capybara: example
|
|
54
|
+
chainable
|
|
55
|
+
changelog: log
|
|
56
|
+
changeset: set
|
|
15
57
|
charset: example
|
|
58
|
+
checkbox: box
|
|
59
|
+
checksum: gum
|
|
60
|
+
chmod
|
|
61
|
+
cli
|
|
62
|
+
cmd
|
|
63
|
+
codebase: base
|
|
16
64
|
codepoint: example
|
|
65
|
+
coderay
|
|
66
|
+
colour: color
|
|
67
|
+
commandline: line
|
|
68
|
+
compat
|
|
69
|
+
compatability
|
|
17
70
|
composable
|
|
18
|
-
|
|
71
|
+
concat
|
|
72
|
+
config: example
|
|
73
|
+
confirmable
|
|
74
|
+
const
|
|
75
|
+
constantize
|
|
76
|
+
crossref
|
|
77
|
+
cryptographically
|
|
78
|
+
ctx
|
|
79
|
+
cukes
|
|
80
|
+
customizable
|
|
81
|
+
customizations
|
|
82
|
+
datagram
|
|
19
83
|
dataset: set
|
|
84
|
+
datetime
|
|
85
|
+
declaratively
|
|
86
|
+
decrypt
|
|
87
|
+
dedupe
|
|
88
|
+
deferrable
|
|
89
|
+
defs
|
|
90
|
+
delegator
|
|
91
|
+
deprecations
|
|
92
|
+
deprecator
|
|
93
|
+
desc
|
|
94
|
+
deserialised
|
|
20
95
|
deserialization
|
|
21
96
|
deserialize: rise
|
|
22
|
-
|
|
97
|
+
deserialized
|
|
98
|
+
dest
|
|
99
|
+
destructor
|
|
100
|
+
destructuring
|
|
101
|
+
deterministically
|
|
102
|
+
dev
|
|
103
|
+
diff
|
|
104
|
+
diffable
|
|
105
|
+
dir: beer
|
|
106
|
+
docstring
|
|
107
|
+
docstrings
|
|
108
|
+
dogfoods
|
|
109
|
+
downcase
|
|
110
|
+
downcased
|
|
111
|
+
dup
|
|
112
|
+
dynamoid
|
|
113
|
+
eg
|
|
114
|
+
el
|
|
115
|
+
elsif
|
|
23
116
|
encoding: example
|
|
117
|
+
endian
|
|
118
|
+
enqueue
|
|
119
|
+
enqueued
|
|
120
|
+
enqueues
|
|
121
|
+
enqueuing
|
|
24
122
|
enum
|
|
123
|
+
enumerables
|
|
124
|
+
enums
|
|
125
|
+
env
|
|
126
|
+
epoll
|
|
127
|
+
erb
|
|
128
|
+
errback
|
|
129
|
+
erubi
|
|
130
|
+
erubis
|
|
131
|
+
erubis
|
|
132
|
+
etag
|
|
133
|
+
etag
|
|
134
|
+
eval
|
|
135
|
+
eval'd
|
|
136
|
+
evented
|
|
137
|
+
extensibility
|
|
138
|
+
extname
|
|
25
139
|
fallback: example
|
|
140
|
+
falsey
|
|
141
|
+
falsy
|
|
142
|
+
favour
|
|
143
|
+
fieldset
|
|
26
144
|
filesystem: system
|
|
145
|
+
fixnum
|
|
27
146
|
formatter: example
|
|
147
|
+
freenode
|
|
148
|
+
frontend
|
|
149
|
+
gemspec: specification
|
|
150
|
+
geocode: code
|
|
151
|
+
geocoded
|
|
152
|
+
geocoder
|
|
153
|
+
geocoding
|
|
28
154
|
geospatial
|
|
155
|
+
getter
|
|
156
|
+
gettext
|
|
157
|
+
gitter
|
|
158
|
+
globbing
|
|
159
|
+
gmail
|
|
160
|
+
grapheme
|
|
161
|
+
graphviz
|
|
162
|
+
gsub
|
|
163
|
+
gzip
|
|
164
|
+
gzipped
|
|
165
|
+
habtm
|
|
166
|
+
haml
|
|
167
|
+
hardcode
|
|
168
|
+
hardcoded
|
|
169
|
+
heredoc: document
|
|
170
|
+
highline
|
|
171
|
+
hiredis
|
|
172
|
+
hostname: name
|
|
173
|
+
href
|
|
174
|
+
hstore
|
|
175
|
+
https
|
|
29
176
|
i18n
|
|
177
|
+
iconv
|
|
178
|
+
iframe
|
|
179
|
+
impl
|
|
180
|
+
incrementing
|
|
181
|
+
inflector
|
|
182
|
+
initialised
|
|
30
183
|
initializer: example
|
|
31
184
|
inline
|
|
185
|
+
instantiation
|
|
186
|
+
interdependencies
|
|
187
|
+
invoker
|
|
32
188
|
io
|
|
189
|
+
irb
|
|
190
|
+
iteratively
|
|
191
|
+
ivar: variable
|
|
192
|
+
javascripts
|
|
193
|
+
jbuilder
|
|
194
|
+
jruby
|
|
195
|
+
jruby
|
|
196
|
+
js
|
|
197
|
+
json
|
|
198
|
+
klass
|
|
199
|
+
kqueue
|
|
200
|
+
kramdown
|
|
201
|
+
lcs
|
|
33
202
|
lexer: example
|
|
34
203
|
lib: rib
|
|
204
|
+
libxml
|
|
205
|
+
libxml-ruby
|
|
206
|
+
libxslt
|
|
35
207
|
lifecycle: example
|
|
208
|
+
localhost
|
|
209
|
+
lookups
|
|
210
|
+
loopback
|
|
211
|
+
lua
|
|
212
|
+
markaby
|
|
213
|
+
maruku
|
|
214
|
+
matcher: catcher
|
|
215
|
+
mediawiki
|
|
216
|
+
memcache
|
|
36
217
|
memoization
|
|
218
|
+
memoize
|
|
37
219
|
memoized
|
|
220
|
+
merb
|
|
38
221
|
metadata
|
|
222
|
+
metaprogramming
|
|
39
223
|
middleware: example
|
|
224
|
+
minitest: example
|
|
225
|
+
mins
|
|
40
226
|
mixin: toxin
|
|
227
|
+
modularity
|
|
228
|
+
mongo
|
|
229
|
+
mongoid
|
|
41
230
|
monkeypatch: patch
|
|
42
231
|
monkeypatching
|
|
232
|
+
mtime
|
|
233
|
+
multibyte
|
|
234
|
+
multiline
|
|
43
235
|
multithreaded
|
|
44
236
|
multithreading
|
|
237
|
+
mustermann
|
|
238
|
+
mutator
|
|
45
239
|
mutex: class
|
|
240
|
+
namer
|
|
46
241
|
namespace: example
|
|
242
|
+
natively
|
|
243
|
+
nginx
|
|
244
|
+
nginx
|
|
245
|
+
nils
|
|
246
|
+
nodoc
|
|
247
|
+
nokogiri: example
|
|
248
|
+
nonces
|
|
249
|
+
noop
|
|
250
|
+
npm
|
|
251
|
+
numericality
|
|
252
|
+
offence
|
|
253
|
+
openssl
|
|
254
|
+
overridable
|
|
47
255
|
override: ride
|
|
256
|
+
overriden
|
|
257
|
+
pandoc
|
|
258
|
+
parallelize
|
|
48
259
|
param: example
|
|
49
260
|
parens
|
|
261
|
+
parseable
|
|
50
262
|
parser: example
|
|
263
|
+
pathname
|
|
264
|
+
pathname
|
|
265
|
+
perf
|
|
266
|
+
performant
|
|
267
|
+
permalink: link
|
|
268
|
+
pid
|
|
269
|
+
pipelined
|
|
270
|
+
pipelining
|
|
271
|
+
plaintext
|
|
272
|
+
pluggable
|
|
51
273
|
plugin: penguin
|
|
274
|
+
populator
|
|
275
|
+
postfix
|
|
276
|
+
postgres
|
|
52
277
|
pre
|
|
278
|
+
precompile
|
|
279
|
+
precompiled
|
|
280
|
+
preload
|
|
281
|
+
preloaded
|
|
282
|
+
preloader
|
|
283
|
+
preloading
|
|
284
|
+
preloads
|
|
53
285
|
prepend: append
|
|
54
|
-
|
|
286
|
+
preprocessing
|
|
287
|
+
prerelease
|
|
288
|
+
proc: example
|
|
289
|
+
profiler
|
|
290
|
+
programmatically
|
|
291
|
+
proxied
|
|
292
|
+
proxying
|
|
293
|
+
pubsub
|
|
294
|
+
pygments
|
|
295
|
+
rack-contrib
|
|
296
|
+
rackup
|
|
297
|
+
ragel
|
|
298
|
+
rails's
|
|
299
|
+
railtie
|
|
300
|
+
railties
|
|
301
|
+
rbenv
|
|
302
|
+
rbx
|
|
303
|
+
rdoc
|
|
304
|
+
readline
|
|
305
|
+
readme
|
|
306
|
+
readonly
|
|
307
|
+
rebase
|
|
308
|
+
reconfirmable
|
|
309
|
+
redcarpet
|
|
310
|
+
redistribution: distribution
|
|
55
311
|
refactor
|
|
56
312
|
refactoring
|
|
313
|
+
refactorings
|
|
57
314
|
regex
|
|
58
315
|
regexp
|
|
59
|
-
|
|
316
|
+
reloader: loader
|
|
317
|
+
rememberable
|
|
318
|
+
renderer: example
|
|
319
|
+
repl
|
|
320
|
+
repo: example
|
|
321
|
+
representable
|
|
322
|
+
representer
|
|
323
|
+
repro
|
|
324
|
+
reraise
|
|
325
|
+
resque
|
|
326
|
+
rhs
|
|
327
|
+
roadmap
|
|
328
|
+
rspec
|
|
329
|
+
rspec-dev
|
|
330
|
+
rspec-support
|
|
331
|
+
rubinius
|
|
332
|
+
rubocop
|
|
60
333
|
rubygems
|
|
61
334
|
runtime: example
|
|
335
|
+
sanitization
|
|
336
|
+
savepoint: point
|
|
337
|
+
scalability
|
|
338
|
+
schemas
|
|
339
|
+
scss
|
|
340
|
+
segv
|
|
341
|
+
sendmail
|
|
342
|
+
serializable
|
|
343
|
+
serializer: example
|
|
344
|
+
serializers
|
|
345
|
+
servlet
|
|
346
|
+
sexualized
|
|
347
|
+
sharding
|
|
348
|
+
sidekiq
|
|
349
|
+
signalling
|
|
350
|
+
simples
|
|
351
|
+
singularized
|
|
352
|
+
solaris
|
|
353
|
+
src
|
|
354
|
+
ssl
|
|
355
|
+
stabby
|
|
356
|
+
stateful
|
|
357
|
+
stdcall
|
|
62
358
|
stderr
|
|
63
359
|
stdin
|
|
64
360
|
stdlib
|
|
361
|
+
stdlibs
|
|
65
362
|
stdout
|
|
363
|
+
str
|
|
364
|
+
strftime
|
|
365
|
+
stringified
|
|
366
|
+
stringify
|
|
367
|
+
stringify
|
|
368
|
+
struct: structure
|
|
66
369
|
stylesheet: sheet
|
|
67
370
|
subclass: class
|
|
68
371
|
subclassing
|
|
69
|
-
|
|
372
|
+
subcommand: commnad
|
|
373
|
+
subdirectory: directory
|
|
374
|
+
subfolder: folder
|
|
375
|
+
sublicense: license
|
|
376
|
+
subpath: path
|
|
377
|
+
subprocess
|
|
378
|
+
substring: string
|
|
379
|
+
subtype: type
|
|
380
|
+
sudo
|
|
70
381
|
superclass: class
|
|
382
|
+
symlink: link
|
|
383
|
+
symlinked
|
|
384
|
+
syntaxes
|
|
385
|
+
sysrandom
|
|
386
|
+
teardown
|
|
387
|
+
tempfile: file
|
|
388
|
+
templating
|
|
389
|
+
textarea: area
|
|
390
|
+
thoughtbot
|
|
391
|
+
threadsafe
|
|
71
392
|
timestamp: stamp
|
|
393
|
+
timezone: zone
|
|
394
|
+
tmp
|
|
395
|
+
todo
|
|
396
|
+
tokenize
|
|
397
|
+
tokenized
|
|
72
398
|
tokenizer: example
|
|
399
|
+
toplevel
|
|
400
|
+
trackable
|
|
401
|
+
tradeoff
|
|
402
|
+
transactional
|
|
403
|
+
transcoding
|
|
404
|
+
triaging
|
|
73
405
|
truthy
|
|
406
|
+
tt
|
|
407
|
+
tty
|
|
408
|
+
turbolinks
|
|
409
|
+
typedef
|
|
410
|
+
tz
|
|
411
|
+
uglifier
|
|
412
|
+
unary
|
|
413
|
+
uncomment
|
|
74
414
|
unescape
|
|
415
|
+
unescaped
|
|
416
|
+
unescapes
|
|
417
|
+
unescaping
|
|
418
|
+
unformatted
|
|
419
|
+
unhandled
|
|
75
420
|
unicode
|
|
421
|
+
unindent
|
|
422
|
+
uniq
|
|
423
|
+
unlink: link
|
|
424
|
+
unlinked
|
|
425
|
+
unparenthesized
|
|
426
|
+
unreferenced
|
|
427
|
+
unregister
|
|
428
|
+
unscoped
|
|
429
|
+
untrusted
|
|
430
|
+
uri
|
|
431
|
+
usec
|
|
76
432
|
username: example
|
|
433
|
+
uuid
|
|
434
|
+
valgrind
|
|
435
|
+
validator: predator
|
|
436
|
+
validators
|
|
437
|
+
vendored
|
|
438
|
+
vendoring
|
|
439
|
+
verifier
|
|
440
|
+
verifiers
|
|
441
|
+
viewport
|
|
442
|
+
webrick
|
|
443
|
+
webserver
|
|
77
444
|
whitespace: example
|
|
445
|
+
wkhtmltopdf
|
|
446
|
+
writeable
|
|
447
|
+
wtf
|
|
448
|
+
xmlns
|
|
449
|
+
xpath
|
|
450
|
+
yajl
|
|
451
|
+
yaml
|
|
452
|
+
yardoc
|
|
453
|
+
yay
|
|
454
|
+
zoneinfo
|
data/lib/forspell/runner.rb
CHANGED
|
@@ -10,8 +10,13 @@ module Forspell
|
|
|
10
10
|
end
|
|
11
11
|
|
|
12
12
|
def call
|
|
13
|
-
@files.
|
|
13
|
+
increment = (@files.size / 100.0).ceil
|
|
14
|
+
total = @files.size <= 100 ? @files.size : 100
|
|
15
|
+
@reporter.progress_bar = ProgressBar.create(total: total, output: $stderr)
|
|
16
|
+
|
|
17
|
+
@files.each_with_index do |path, index|
|
|
14
18
|
process_file path
|
|
19
|
+
@reporter.progress_bar.increment if (index + 1) % increment == 0
|
|
15
20
|
end
|
|
16
21
|
|
|
17
22
|
@reporter.report
|
data/lib/forspell/sanitizer.rb
CHANGED
|
@@ -5,18 +5,12 @@ require 'cgi'
|
|
|
5
5
|
|
|
6
6
|
module Forspell
|
|
7
7
|
module Sanitizer
|
|
8
|
-
REMOVE_PUNCT =
|
|
8
|
+
REMOVE_PUNCT = %r{[!|?|,|(|)|"|;]+}.freeze
|
|
9
9
|
|
|
10
10
|
def self.sanitize(input)
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
.gsub(REMOVE_PUNCT, '').gsub(/[\!\.\?]{1}$/, '')
|
|
15
|
-
if result.start_with?("'") && result.end_with?("'")
|
|
16
|
-
result[1..-2]
|
|
17
|
-
else
|
|
18
|
-
result
|
|
12
|
+
CGI.unescapeHTML(Sanitize.fragment(input, elements: [], remove_contents: true))
|
|
13
|
+
.gsub(REMOVE_PUNCT, '').gsub(%r{[.:]+$}, '')
|
|
19
14
|
end
|
|
20
|
-
end
|
|
21
15
|
end
|
|
22
16
|
end
|
data/lib/forspell/speller.rb
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
require 'ffi/hunspell'
|
|
4
|
+
require 'backports/2.5.0/enumerable/all'
|
|
4
5
|
|
|
5
6
|
module Forspell
|
|
6
7
|
class Speller
|
|
7
8
|
attr_reader :dictionary
|
|
8
9
|
|
|
9
|
-
SUGGESTIONS_SIZE = 3
|
|
10
10
|
HUNSPELL_DIRS = [File.join(__dir__, 'dictionaries')]
|
|
11
11
|
RUBY_DICT = File.join(__dir__, 'ruby.dict')
|
|
12
12
|
|
|
13
|
-
def initialize(main_dictionary, *custom_dictionaries)
|
|
13
|
+
def initialize(main_dictionary, *custom_dictionaries, suggestions_size: 0)
|
|
14
|
+
@suggestions_size = suggestions_size
|
|
14
15
|
FFI::Hunspell.directories = HUNSPELL_DIRS << File.dirname(main_dictionary)
|
|
15
16
|
@dictionary = FFI::Hunspell.dict(File.basename(main_dictionary))
|
|
16
17
|
|
|
@@ -28,11 +29,20 @@ module Forspell
|
|
|
28
29
|
end
|
|
29
30
|
|
|
30
31
|
def correct?(word)
|
|
31
|
-
|
|
32
|
+
parts = word.split('-')
|
|
33
|
+
if parts.size == 1
|
|
34
|
+
alterations = [word]
|
|
35
|
+
alterations << word.capitalize unless word.capitalize == word
|
|
36
|
+
alterations << word.upcase unless word.upcase == word
|
|
37
|
+
|
|
38
|
+
alterations.any?{ |w| dictionary.check?(w) }
|
|
39
|
+
else
|
|
40
|
+
parts.all? { |part| correct?(part) }
|
|
41
|
+
end
|
|
32
42
|
end
|
|
33
43
|
|
|
34
44
|
def suggest(word)
|
|
35
|
-
dictionary.suggest(word).first(
|
|
45
|
+
@suggestions_size.positive? ? dictionary.suggest(word).first(@suggestions_size) : []
|
|
36
46
|
end
|
|
37
47
|
end
|
|
38
48
|
end
|
|
@@ -3,12 +3,10 @@ require 'backports/2.4.0/regexp/match'
|
|
|
3
3
|
module Forspell
|
|
4
4
|
module WordMatcher
|
|
5
5
|
WORD = %r{^
|
|
6
|
-
|
|
7
|
-
([
|
|
8
|
-
([[:lower:]])
|
|
9
|
-
([
|
|
10
|
-
([[:lower:]])* # another bunch of letters
|
|
11
|
-
\'? # could end with apostrophe
|
|
6
|
+
([a-z]|[A-Z]) # at least one letter,
|
|
7
|
+
([[:lower:]])* # then any number of letters,
|
|
8
|
+
([\'\-][[:lower:]])? # optional dash/apostrophe, followed by letter
|
|
9
|
+
([[:lower:]])* # another bunch of letters
|
|
12
10
|
$}x
|
|
13
11
|
|
|
14
12
|
def self.word? text
|
metadata
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: forspell
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.0.
|
|
4
|
+
version: 0.0.7
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Kirill Kuprikov
|
|
@@ -9,7 +9,7 @@ authors:
|
|
|
9
9
|
autorequire:
|
|
10
10
|
bindir: exe
|
|
11
11
|
cert_chain: []
|
|
12
|
-
date: 2019-05-
|
|
12
|
+
date: 2019-05-27 00:00:00.000000000 Z
|
|
13
13
|
dependencies:
|
|
14
14
|
- !ruby/object:Gem::Dependency
|
|
15
15
|
name: slop
|
|
@@ -137,6 +137,34 @@ dependencies:
|
|
|
137
137
|
- - ">="
|
|
138
138
|
- !ruby/object:Gem::Version
|
|
139
139
|
version: '0'
|
|
140
|
+
- !ruby/object:Gem::Dependency
|
|
141
|
+
name: highline
|
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
|
143
|
+
requirements:
|
|
144
|
+
- - ">="
|
|
145
|
+
- !ruby/object:Gem::Version
|
|
146
|
+
version: '0'
|
|
147
|
+
type: :runtime
|
|
148
|
+
prerelease: false
|
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
150
|
+
requirements:
|
|
151
|
+
- - ">="
|
|
152
|
+
- !ruby/object:Gem::Version
|
|
153
|
+
version: '0'
|
|
154
|
+
- !ruby/object:Gem::Dependency
|
|
155
|
+
name: ruby-progressbar
|
|
156
|
+
requirement: !ruby/object:Gem::Requirement
|
|
157
|
+
requirements:
|
|
158
|
+
- - ">="
|
|
159
|
+
- !ruby/object:Gem::Version
|
|
160
|
+
version: '0'
|
|
161
|
+
type: :runtime
|
|
162
|
+
prerelease: false
|
|
163
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
164
|
+
requirements:
|
|
165
|
+
- - ">="
|
|
166
|
+
- !ruby/object:Gem::Version
|
|
167
|
+
version: '0'
|
|
140
168
|
- !ruby/object:Gem::Dependency
|
|
141
169
|
name: rspec
|
|
142
170
|
requirement: !ruby/object:Gem::Requirement
|