spellr 0.4.1 → 0.5.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +5 -0
- data/Gemfile.lock +1 -1
- data/README.md +188 -8
- data/lib/.spellr.yml +1 -2
- data/lib/spellr/cli.rb +3 -107
- data/lib/spellr/interactive.rb +4 -4
- data/lib/spellr/language.rb +20 -26
- data/lib/spellr/version.rb +1 -1
- data/wordlists/english.LICENSE.txt +43 -0
- data/wordlists/english.txt +266850 -0
- data/wordlists/english/AU.LICENSE.txt +43 -0
- data/wordlists/english/AU.txt +8703 -0
- data/wordlists/english/CA.LICENSE.txt +43 -0
- data/wordlists/english/CA.txt +8495 -0
- data/wordlists/english/GB.txt +14244 -0
- data/wordlists/english/GBs.LICENSE.txt +43 -0
- data/wordlists/english/GBs.txt +8584 -0
- data/wordlists/english/GBz.LICENSE.txt +43 -0
- data/wordlists/english/GBz.txt +8495 -0
- data/wordlists/english/US.LICENSE.txt +43 -0
- data/wordlists/english/US.txt +8422 -0
- data/wordlists/javascript.txt +3 -0
- metadata +14 -3
- data/bin/fetch_wordlist/english +0 -67
- data/bin/fetch_wordlist/ruby +0 -150
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b12a7a52fc68f4960a9156f4d500366225de366b3ca20213231a22176c898030
|
4
|
+
data.tar.gz: 816aafdee27ec4c997e96b3726f37f1e08dc22aaee9f29680aee9f86b8481693
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 52e520722759e56c001ee0271408a7bb87e47cfb3ed1cba15ae1c208356a26cae1be01f05e72c316a6141e0e7e71aebe3878862de975cf12eedd77e64c2c1c3f
|
7
|
+
data.tar.gz: 3f11b304e48cc73823dd66b23daec1622ab1ee0e94545929a15d0baf80a4fc616a3dfa8f2ec9dda28e9792701d277fb0dc8e3cbbf673531dc8aca3fe9947ffd0
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,8 @@
|
|
1
|
+
# v0.5.0
|
2
|
+
- Removed the fetch command it was just unnecessarily slow and awkward. instead use `locale: [US,AU]`
|
3
|
+
- Added usage documentation
|
4
|
+
- Fixed an issue where file-specific wordlists couldn't be added to
|
5
|
+
|
1
6
|
# v0.4.1
|
2
7
|
- fix the private method 'touch' issue when generating wordlists
|
3
8
|
- fix the js/javascript defaults being named differently (now consistently is named javascript)
|
data/Gemfile.lock
CHANGED
data/README.md
CHANGED
@@ -4,29 +4,209 @@
|
|
4
4
|
|
5
5
|
Spell check your source code for fun and occasionally finding bugs
|
6
6
|
|
7
|
-
This is inspired by https://github.com/myint/scspell
|
7
|
+
This is inspired by https://github.com/myint/scspell, and uses wordlists from [SCOWL](http://wordlist.aspell.net) - see the license [here](https://github.com/robotdana/spellr/blob/master/wordlists/english.LICENSE.txt).
|
8
|
+
|
9
|
+
## What makes a spell checker a source code spell checker?
|
10
|
+
|
11
|
+
1. It tokenizes CamelCase and snake_case and kebab-case and checks these as independent words including CAMELCase with acronyms.
|
12
|
+
2. It skips urls
|
13
|
+
3. It skips things that heuristically look like base64 or hex strings rather than words. This uses a bayesian classifier and is not magic. Find the balance of false-positive to false-negative that works for you with the `key_heuristic_weight` [configuration](#configuration) option.
|
14
|
+
4. It comes with some wordlists for built in commands in some common programming languages, and recognizes hashbangs.
|
15
|
+
5. Configure whether you want US, AU, CA, or GB english (or all of them).
|
16
|
+
6. It checks directories recursively, obeying .gitignore
|
17
|
+
7. It's easy to add terms to wordlists
|
18
|
+
8. It's easy to integrate with CI pipelines
|
19
|
+
7. It's very configurable
|
20
|
+
|
21
|
+
## A brief aside on "correct" spelling.
|
22
|
+
|
23
|
+
There's no correct way to spell anything. You can't trust dictionaries, they only react to the way everyone else uses words. Any agreement about certain spellings is a collective hallucination, and is a terrible proxy for attention or intelligence or education or value. Those who get to declare what "correct" spelling is, or even what counts as a real word, tend to be those groups that have more social power and it's (sometimes unconsciously) used as a way to maintain that power.
|
24
|
+
|
25
|
+
However, in a programming context spelling things _consistently_ is useful, where method definitions must match method calls, and comments about these are clearer when also matching. It also makes grepping easier, not that you'd find the word 'grepping' in most dictionaries.
|
8
26
|
|
9
27
|
## Installation
|
10
28
|
|
11
|
-
|
29
|
+
### With Bundler
|
30
|
+
|
31
|
+
Add this line to your application's `Gemfile`:
|
12
32
|
|
13
33
|
```ruby
|
14
34
|
gem 'spellr', require: false
|
15
35
|
```
|
16
36
|
|
17
|
-
|
37
|
+
Then execute:
|
38
|
+
|
39
|
+
```bash
|
40
|
+
$ bundle install
|
41
|
+
```
|
42
|
+
|
43
|
+
### With Rubygems
|
18
44
|
|
19
|
-
|
45
|
+
```bash
|
46
|
+
$ gem install spellr
|
47
|
+
```
|
20
48
|
|
21
|
-
|
49
|
+
### With Docker
|
22
50
|
|
23
|
-
|
51
|
+
execute this command instead of `spellr`. This is otherwise identical to using the gem version
|
52
|
+
|
53
|
+
```bash
|
54
|
+
$ docker run -it -v $PWD:/app robotdana/spellr
|
55
|
+
```
|
24
56
|
|
25
57
|
## Usage
|
26
58
|
|
27
|
-
|
59
|
+
The main way to interact with `spellr` is through the executable.
|
60
|
+
|
61
|
+
```bash
|
62
|
+
$ spellr # will run the spell checker
|
63
|
+
$ spellr --interactive # will run the spell checker, interactively
|
64
|
+
$ spellr --wordlist # will output all words that fail the spell checker in spellr wordlist format
|
65
|
+
$ spellr --quiet # will suppress all output
|
66
|
+
```
|
67
|
+
|
68
|
+
To check a single file or subset of files, just add paths or globs:
|
69
|
+
```bash
|
70
|
+
$ spellr --interactive path/to/my/file.txt and/another/file.sh
|
71
|
+
$ spellr --wordlist '*.rb' '*_test.js'
|
72
|
+
```
|
73
|
+
|
74
|
+
There are some support commands available:
|
75
|
+
|
76
|
+
```bash
|
77
|
+
$ spellr --dry-run # list files that will be checked
|
78
|
+
$ spellr --version # for the current version
|
79
|
+
$ spellr --help # for the list of flags available
|
80
|
+
```
|
81
|
+
|
82
|
+
### First run
|
83
|
+
|
84
|
+
Feel free to just `spellr --interactive` and go, but I prefer this process when first adding spellr to a large project.
|
85
|
+
|
86
|
+
```bash
|
87
|
+
$ spellr --dry-run
|
88
|
+
```
|
89
|
+
|
90
|
+
Look at the list of files, are there some that shouldn't be checked (generated files etc)? .gitignored files and some binary file extensions are already skipped by default.
|
91
|
+
|
92
|
+
Add any additional files to ignore to a `.spellr.yml` file in your project root directory.
|
93
|
+
```yml
|
94
|
+
excludes:
|
95
|
+
- ignore
|
96
|
+
- /generated
|
97
|
+
- "!files"
|
98
|
+
- in/*
|
99
|
+
- .gitignore
|
100
|
+
- "*.format"
|
101
|
+
```
|
102
|
+
|
103
|
+
Then output the existing words that fail the default dictionaries.
|
104
|
+
```bash
|
105
|
+
$ spellr --wordlist > .spellr-wordlists/english.txt
|
106
|
+
```
|
107
|
+
|
108
|
+
Open `.spellr-wordlists/english.txt` and remove those lines that look like typos or mistakes, leaving the file in ascii order.
|
109
|
+
|
110
|
+
Now it's time to run the interactive spell checker
|
111
|
+
|
112
|
+
```bash
|
113
|
+
$ spellr --interactive
|
114
|
+
```
|
115
|
+
|
116
|
+
### Interactive spell checking
|
117
|
+
|
118
|
+
To start an interactive spell checking session:
|
119
|
+
```bash
|
120
|
+
$ spellr --interactive
|
121
|
+
```
|
122
|
+
|
123
|
+
You'll be shown each word that's not found in a dictionary, it's location (path:line:column), along with a prompt.
|
124
|
+
```
|
125
|
+
file.rb:1:0 notaword
|
126
|
+
[r,R,s,S,a,e?]
|
127
|
+
```
|
128
|
+
|
129
|
+
Type `?` for this list of what each letter command does
|
130
|
+
```
|
131
|
+
[r] Replace notaword
|
132
|
+
[R] Replace all future instances of notaword
|
133
|
+
[s] Skip notaword
|
134
|
+
[S] Skip all future instances of notaword
|
135
|
+
[a] Add notaword to a word list
|
136
|
+
[e] Edit the whole line
|
137
|
+
[?] Show this help
|
138
|
+
```
|
139
|
+
|
140
|
+
If you type `r`, `R` or `e` you'll be shown a prompt with the original word and it prefilled ready for correcting:
|
141
|
+
```
|
142
|
+
file.txt:1:0 notaword
|
143
|
+
>> notaword
|
144
|
+
=> not_a_word
|
145
|
+
```
|
146
|
+
To submit your choice and continue with the spell checking click enter. Your replacement word will be immediately spellchecked. To instead go back press Ctrl-C once (pressing it twice will exit the spell checking).
|
147
|
+
|
148
|
+
If you instead type `s` or `S` it will skip this word and continue with the spell checking.
|
149
|
+
|
150
|
+
---
|
151
|
+
|
152
|
+
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`.
|
153
|
+
```
|
154
|
+
Add notaword to wordlist:
|
155
|
+
[e] english
|
156
|
+
[r] ruby
|
157
|
+
```
|
158
|
+
Type `e` to add this word to the english wordlist and continue on through the spell checking. To instead go back to the prompt press Ctrl-C once (pressing it twice will exit the spell checking).
|
159
|
+
|
160
|
+
### Disabling the tokenizer
|
161
|
+
|
162
|
+
If the tokenizer finds a word you don't want to add to the wordlist (perhaps it's an intentional example of a typo, or a non-word string not excluded by the heuristic) then place on the lines before and after
|
163
|
+
```ruby
|
164
|
+
# spellr:disable
|
165
|
+
"Test typo of the: teh"
|
166
|
+
# spellr:enable
|
167
|
+
```
|
168
|
+
|
169
|
+
## Configuration
|
170
|
+
|
171
|
+
Spellr's configuration is a `.spellr.yml` file in your project root. This is combined with the gem defaults defined [here](https://github.com/robotdana/spellr/blob/master/lib/.spellr.yml).
|
172
|
+
There are top-level keys and per-language keys.
|
173
|
+
```yml
|
174
|
+
word_minimum_length: 3 # any words shorter than this will be ignored
|
175
|
+
key_minimum_length: 6 # any strings shorter than this won't be considered non-word strings
|
176
|
+
key_heuristic_weight: 5 # higher values mean strings are more likely to be considered words or non-words by the classifier.
|
177
|
+
excludes:
|
178
|
+
- ignore
|
179
|
+
- "!files"
|
180
|
+
- in/*
|
181
|
+
- .gitignore
|
182
|
+
- "*.format"
|
183
|
+
includes:
|
184
|
+
- limit to
|
185
|
+
- "files*"
|
186
|
+
- in/*
|
187
|
+
- .gitignore-esque
|
188
|
+
- "*.format"
|
28
189
|
```
|
29
|
-
|
190
|
+
The includes format is documented [here](https://github.com/robotdana/fast_ignore#using-an-includes-list).
|
191
|
+
|
192
|
+
Also within this file are language definitions:
|
193
|
+
```yml
|
194
|
+
languages:
|
195
|
+
english: # this must match exactly the name of the file in .spellr-wordlists/
|
196
|
+
locale: # US, AU, CA, or GB
|
197
|
+
- US
|
198
|
+
- AU
|
199
|
+
ruby:
|
200
|
+
includes:
|
201
|
+
- patterns*
|
202
|
+
- "*_here.rb"
|
203
|
+
- limit-which-files
|
204
|
+
- the/wordlist/**/*
|
205
|
+
- /applies_to/
|
206
|
+
key: r # this is the letter used to choose this wordlist when using `spellr --interactive`.
|
207
|
+
hashbangs:
|
208
|
+
- ruby # if the hashbang contains ruby, this file will match,
|
209
|
+
# even if it doesn't otherwise match the includes pattern.
|
30
210
|
```
|
31
211
|
|
32
212
|
## Development
|
data/lib/.spellr.yml
CHANGED
@@ -28,8 +28,7 @@ excludes: # this list is parsed with the .gitignore format
|
|
28
28
|
|
29
29
|
languages:
|
30
30
|
english:
|
31
|
-
|
32
|
-
# TODO: don't generate the ruby file until you actually need one
|
31
|
+
locale: US # options US, CA, AU, GBs (GB with -ise endings), GBz (GB with -ize endings)
|
33
32
|
ruby:
|
34
33
|
includes: # Filtered using gitignore format
|
35
34
|
- '*.rb'
|
data/lib/spellr/cli.rb
CHANGED
@@ -7,8 +7,7 @@ require 'open3'
|
|
7
7
|
require_relative '../spellr'
|
8
8
|
|
9
9
|
module Spellr
|
10
|
-
class CLI
|
11
|
-
attr_writer :fetch_output_dir
|
10
|
+
class CLI
|
12
11
|
attr_reader :argv
|
13
12
|
|
14
13
|
def initialize(argv)
|
@@ -67,108 +66,13 @@ module Spellr
|
|
67
66
|
exit
|
68
67
|
end
|
69
68
|
|
70
|
-
def get_wordlist_option(command)
|
71
|
-
get_wordlist_dir.join(command)
|
72
|
-
end
|
73
|
-
|
74
|
-
def fetch_output_dir
|
75
|
-
@fetch_output_dir ||= Pathname.pwd.join('.spellr_wordlists/generated').expand_path
|
76
|
-
end
|
77
|
-
|
78
|
-
def fetch_words_for_wordlist(wordlist)
|
79
|
-
wordlist_command(wordlist, *argv)
|
80
|
-
end
|
81
|
-
|
82
|
-
def wordlist_command(wordlist, *args)
|
83
|
-
require 'shellwords'
|
84
|
-
command = fetch_wordlist_dir.join(wordlist).to_s
|
85
|
-
fetch_output_dir.mkpath
|
86
|
-
|
87
|
-
command_with_args = args.unshift(command).shelljoin
|
88
|
-
|
89
|
-
out, err, status = Open3.capture3(command_with_args)
|
90
|
-
puts err unless err.empty?
|
91
|
-
return out if status.exitstatus == 0
|
92
|
-
|
93
|
-
exit
|
94
|
-
end
|
95
|
-
|
96
|
-
def replace_wordlist(words, wordlist)
|
97
|
-
require_relative '../../lib/spellr/wordlist'
|
98
|
-
|
99
|
-
Spellr::Wordlist.new(fetch_output_dir.join("#{wordlist}.txt")).clean(StringIO.new(words))
|
100
|
-
end
|
101
|
-
|
102
|
-
def extract_and_write_license(words, wordlist)
|
103
|
-
words, license = words.split('---', 2).reverse
|
104
|
-
|
105
|
-
fetch_output_dir.join("#{wordlist}.LICENSE.txt").write(license) if license
|
106
|
-
|
107
|
-
words
|
108
|
-
end
|
109
|
-
|
110
|
-
def fetch
|
111
|
-
wordlist = argv.shift
|
112
|
-
puts "Fetching #{wordlist} wordlist"
|
113
|
-
words = fetch_words_for_wordlist(wordlist)
|
114
|
-
puts "Preparing #{wordlist} wordlist"
|
115
|
-
words = extract_and_write_license(words, wordlist)
|
116
|
-
puts "cleaning #{wordlist} wordlist"
|
117
|
-
replace_wordlist(words, wordlist)
|
118
|
-
end
|
119
|
-
|
120
|
-
def output_option(dir)
|
121
|
-
self.fetch_output_dir = Pathname.pwd.join(dir).expand_path
|
122
|
-
end
|
123
|
-
|
124
|
-
def wordlists
|
125
|
-
fetch_wordlist_dir.children.map { |p| p.basename.to_s }
|
126
|
-
end
|
127
|
-
|
128
|
-
def fetch_wordlist_dir
|
129
|
-
@fetch_wordlist_dir ||= Pathname.new(__dir__).parent.parent.join('bin', 'fetch_wordlist').expand_path
|
130
|
-
end
|
131
|
-
|
132
69
|
def parse_command
|
133
|
-
|
134
|
-
|
135
|
-
parse_fetch_options
|
136
|
-
fetch
|
137
|
-
else
|
138
|
-
parse_options
|
139
|
-
check
|
140
|
-
end
|
141
|
-
end
|
142
|
-
|
143
|
-
def fetch_options
|
144
|
-
@fetch_options ||= begin
|
145
|
-
opts = OptionParser.new
|
146
|
-
opts.banner = "Usage: spellr fetch [options] WORDLIST [wordlist options]\nAvailable wordlists: #{wordlists}"
|
147
|
-
|
148
|
-
opts.separator('')
|
149
|
-
opts.on('-o', '--output=OUTPUT', 'Outputs the fetched wordlist to OUTPUT/WORDLIST.txt', &method(:output_option))
|
150
|
-
opts.on('-h', '--help', 'Shows help for fetch', &method(:fetch_options_help))
|
151
|
-
|
152
|
-
opts
|
153
|
-
end
|
154
|
-
end
|
155
|
-
|
156
|
-
def fetch_options_help(*_)
|
157
|
-
puts fetch_options.help
|
158
|
-
|
159
|
-
wordlist = argv.first
|
160
|
-
if wordlist
|
161
|
-
puts
|
162
|
-
wordlist_command('english', '--help')
|
163
|
-
end
|
164
|
-
|
165
|
-
exit
|
70
|
+
parse_options
|
71
|
+
check
|
166
72
|
end
|
167
73
|
|
168
74
|
def options_help(_)
|
169
75
|
puts options.help
|
170
|
-
puts
|
171
|
-
puts fetch_options.help
|
172
76
|
|
173
77
|
exit
|
174
78
|
end
|
@@ -177,14 +81,6 @@ module Spellr
|
|
177
81
|
options.parse!(argv)
|
178
82
|
end
|
179
83
|
|
180
|
-
def parse_fetch_options
|
181
|
-
argv.shift
|
182
|
-
fetch_options.order!(argv) do |non_arg|
|
183
|
-
argv.unshift(non_arg)
|
184
|
-
break
|
185
|
-
end
|
186
|
-
end
|
187
|
-
|
188
84
|
def options # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
|
189
85
|
@options ||= begin
|
190
86
|
opts = OptionParser.new
|
data/lib/spellr/interactive.rb
CHANGED
@@ -50,7 +50,7 @@ module Spellr
|
|
50
50
|
end
|
51
51
|
|
52
52
|
def prompt(token)
|
53
|
-
print bold('[
|
53
|
+
print bold('[r,R,s,S,a,e,?]')
|
54
54
|
|
55
55
|
handle_response(token)
|
56
56
|
rescue Interrupt
|
@@ -120,10 +120,10 @@ module Spellr
|
|
120
120
|
# TODO: handle more than 16 options
|
121
121
|
def handle_add(token) # rubocop:disable Metrics/AbcSize, Metrics/MethodLength
|
122
122
|
puts "Add #{red(token)} to wordlist:"
|
123
|
-
languages = Spellr.config.languages_for(token.location.file)
|
123
|
+
languages = Spellr.config.languages_for(token.location.file.path)
|
124
124
|
|
125
|
-
languages.each do |
|
126
|
-
puts "[#{
|
125
|
+
languages.each do |language|
|
126
|
+
puts "[#{language.key}] #{language.name}"
|
127
127
|
end
|
128
128
|
choice = STDIN.getch
|
129
129
|
clear_current_line
|
data/lib/spellr/language.rb
CHANGED
@@ -13,7 +13,8 @@ module Spellr
|
|
13
13
|
only: [],
|
14
14
|
includes: [],
|
15
15
|
description: '',
|
16
|
-
hashbangs: []
|
16
|
+
hashbangs: [],
|
17
|
+
locale: [])
|
17
18
|
unless only.empty?
|
18
19
|
warn <<~WARNING
|
19
20
|
\e[33mSpellr: `only:` language yaml key with a list of fnmatch rules is deprecated.
|
@@ -21,12 +22,20 @@ module Spellr
|
|
21
22
|
see github.com/robotdana/fast_ignore#using-an-includes-list for details\e[0m
|
22
23
|
WARNING
|
23
24
|
end
|
25
|
+
|
26
|
+
if generate
|
27
|
+
warn <<~WARNING
|
28
|
+
\e[33mSpellr: `generate:` and generation is now deprecated. Choose the language
|
29
|
+
using the key `locale:` (any of US,AU,CA,GB,GBz,GBs as a string or array).\e[0m
|
30
|
+
WARNING
|
31
|
+
end
|
32
|
+
|
24
33
|
@name = name
|
25
34
|
@key = key
|
26
35
|
@description = description
|
27
|
-
@generate = generate
|
28
36
|
@includes = only + includes
|
29
37
|
@hashbangs = hashbangs
|
38
|
+
@locales = Array(locale)
|
30
39
|
end
|
31
40
|
|
32
41
|
def matches?(file)
|
@@ -43,24 +52,9 @@ module Spellr
|
|
43
52
|
end
|
44
53
|
|
45
54
|
def wordlists
|
46
|
-
generate_wordlist unless generated_project_wordlist.exist?
|
47
55
|
default_wordlists.select(&:exist?)
|
48
56
|
end
|
49
57
|
|
50
|
-
def generate_wordlist
|
51
|
-
return [] unless generate
|
52
|
-
|
53
|
-
require_relative 'cli'
|
54
|
-
require 'shellwords'
|
55
|
-
warn "Generating wordlist for #{name}"
|
56
|
-
|
57
|
-
generated_project_wordlist.touch
|
58
|
-
|
59
|
-
Spellr::CLI.new(generate.shellsplit)
|
60
|
-
|
61
|
-
default_wordlists
|
62
|
-
end
|
63
|
-
|
64
58
|
def gem_wordlist
|
65
59
|
@gem_wordlist ||= Spellr::Wordlist.new(
|
66
60
|
Pathname.new(__dir__).parent.parent.join('wordlists', "#{name}.txt")
|
@@ -74,17 +68,17 @@ module Spellr
|
|
74
68
|
)
|
75
69
|
end
|
76
70
|
|
77
|
-
def
|
78
|
-
@
|
79
|
-
|
80
|
-
|
71
|
+
def locale_wordlists
|
72
|
+
@locale_wordlists ||= @locales.map do |locale|
|
73
|
+
Spellr::Wordlist.new(
|
74
|
+
Pathname.new(__dir__).parent.parent.join('wordlists', name.to_s, "#{locale}.txt")
|
75
|
+
)
|
76
|
+
end
|
81
77
|
end
|
82
78
|
|
83
79
|
private
|
84
80
|
|
85
|
-
|
86
|
-
|
87
|
-
def load_wordlists(name, paths, _generate)
|
81
|
+
def load_wordlists(name, paths)
|
88
82
|
wordlists = paths + default_wordlist_paths(name)
|
89
83
|
|
90
84
|
wordlists.map(&Spellr::Wordlist.method(:new))
|
@@ -93,8 +87,8 @@ module Spellr
|
|
93
87
|
def default_wordlists
|
94
88
|
[
|
95
89
|
gem_wordlist,
|
96
|
-
|
97
|
-
|
90
|
+
project_wordlist,
|
91
|
+
*locale_wordlists
|
98
92
|
]
|
99
93
|
end
|
100
94
|
end
|