spellr 0.1.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.
Files changed (48) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +2 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +186 -0
  5. data/.ruby-version +1 -0
  6. data/.spellr.yml +23 -0
  7. data/.spellr_wordlists/dictionary.txt +120 -0
  8. data/.spellr_wordlists/english.txt +3 -0
  9. data/.spellr_wordlists/lorem.txt +4 -0
  10. data/.spellr_wordlists/ruby.txt +2 -0
  11. data/.travis.yml +7 -0
  12. data/Gemfile +8 -0
  13. data/Gemfile.lock +67 -0
  14. data/LICENSE.txt +21 -0
  15. data/README.md +64 -0
  16. data/Rakefile +8 -0
  17. data/bin/console +8 -0
  18. data/bin/fetch_wordlist/english +65 -0
  19. data/bin/fetch_wordlist/ruby +150 -0
  20. data/bin/setup +3 -0
  21. data/exe/spellr +5 -0
  22. data/lib/.spellr.yml +93 -0
  23. data/lib/spellr.rb +26 -0
  24. data/lib/spellr/check.rb +56 -0
  25. data/lib/spellr/cli.rb +205 -0
  26. data/lib/spellr/column_location.rb +49 -0
  27. data/lib/spellr/config.rb +105 -0
  28. data/lib/spellr/file.rb +27 -0
  29. data/lib/spellr/file_list.rb +45 -0
  30. data/lib/spellr/interactive.rb +191 -0
  31. data/lib/spellr/language.rb +104 -0
  32. data/lib/spellr/line_location.rb +29 -0
  33. data/lib/spellr/line_tokenizer.rb +181 -0
  34. data/lib/spellr/reporter.rb +27 -0
  35. data/lib/spellr/string_format.rb +43 -0
  36. data/lib/spellr/token.rb +83 -0
  37. data/lib/spellr/tokenizer.rb +72 -0
  38. data/lib/spellr/version.rb +5 -0
  39. data/lib/spellr/wordlist.rb +100 -0
  40. data/lib/spellr/wordlist_reporter.rb +21 -0
  41. data/spellr.gemspec +35 -0
  42. data/wordlist +2 -0
  43. data/wordlists/dockerfile.txt +21 -0
  44. data/wordlists/html.txt +340 -0
  45. data/wordlists/javascript.txt +64 -0
  46. data/wordlists/ruby.txt +2344 -0
  47. data/wordlists/shell.txt +2 -0
  48. metadata +217 -0
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'string_format'
4
+
5
+ module Spellr
6
+ class Reporter
7
+ include Spellr::StringFormat
8
+
9
+ attr_accessor :total
10
+
11
+ def initialize
12
+ @total = 0
13
+ end
14
+
15
+ def finish(checked)
16
+ puts "\n"
17
+ puts "#{pluralize 'file', checked} checked"
18
+ puts "#{pluralize 'error', total} found"
19
+ end
20
+
21
+ def call(token)
22
+ puts "#{aqua token.location} #{token.line.highlight(token.char_range).strip}"
23
+
24
+ self.total += 1
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,43 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'config'
4
+
5
+ module Spellr
6
+ module StringFormat
7
+ module_function
8
+
9
+ def pluralize(word, count)
10
+ "#{count} #{word}#{'s' if count != 1}"
11
+ end
12
+
13
+ def color_enabled?
14
+ return $stdout.tty? if Spellr.config.color.nil?
15
+
16
+ Spellr.config.color
17
+ end
18
+
19
+ def aqua(text)
20
+ return text unless Spellr::StringFormat.color_enabled?
21
+
22
+ "\e[36m#{text}#{normal}"
23
+ end
24
+
25
+ def normal(text = '')
26
+ return text unless Spellr::StringFormat.color_enabled?
27
+
28
+ "\e[0m#{text}"
29
+ end
30
+
31
+ def bold(text)
32
+ return text unless Spellr::StringFormat.color_enabled?
33
+
34
+ "\e[1;39m#{text}#{normal}"
35
+ end
36
+
37
+ def red(text)
38
+ return text unless Spellr::StringFormat.color_enabled?
39
+
40
+ "\e[1;31m#{text}#{normal}"
41
+ end
42
+ end
43
+ end
@@ -0,0 +1,83 @@
1
+ # frozen_string_literal: true
2
+
3
+ # frozen string_literal: true
4
+
5
+ require_relative 'column_location'
6
+ require_relative 'string_format'
7
+
8
+ module Spellr
9
+ class Token < String
10
+ attr_reader :location, :line
11
+ def self.normalize(value)
12
+ return value.normalize if value.is_a?(Spellr::Token)
13
+
14
+ value.strip.downcase.unicode_normalize.tr('’', "'") + "\n"
15
+ end
16
+
17
+ def self.wrap(value)
18
+ return value if value.is_a?(Spellr::Token)
19
+
20
+ Spellr::Token.new(value || '')
21
+ end
22
+
23
+ def initialize(string, line: string, location: ColumnLocation.new)
24
+ @location = location
25
+ @line = line
26
+ super(string)
27
+ end
28
+
29
+ def strip
30
+ @strip ||= begin
31
+ lstripped = lstrip
32
+ new_column_location = lstripped_column_location(lstripped)
33
+ Token.new(lstripped.rstrip, line: line, location: new_column_location)
34
+ end
35
+ end
36
+
37
+ def lstripped_column_location(lstripped)
38
+ ColumnLocation.new(
39
+ byte_offset: bytesize - lstripped.bytesize,
40
+ char_offset: length - lstripped.length,
41
+ line_location: location.line_location
42
+ )
43
+ end
44
+
45
+ def normalize
46
+ @normalize ||= self.class.normalize(to_s)
47
+ end
48
+
49
+ def inspect
50
+ "#<#{self.class.name} #{to_s.inspect} @#{location}>"
51
+ end
52
+
53
+ def char_range
54
+ @char_range ||= location.char_offset...(location.char_offset + length)
55
+ end
56
+
57
+ def byte_range
58
+ @byte_range ||= location.byte_offset...(location.byte_offset + bytesize)
59
+ end
60
+
61
+ def coordinates
62
+ location.coordinates
63
+ end
64
+
65
+ def highlight(range = char_range)
66
+ "#{slice(0...(range.first))}#{Spellr::StringFormat.red slice(range)}#{slice(range.last..-1)}"
67
+ end
68
+
69
+ def replace(replacement)
70
+ ::File.open(file_name, 'r+') do |f|
71
+ body = f.read
72
+ body[location.absolute_char_offset...(location.absolute_char_offset + length)] = replacement
73
+ f.rewind
74
+ f.truncate(0)
75
+ f.write(body)
76
+ end
77
+ end
78
+
79
+ def file_name
80
+ location.file_name
81
+ end
82
+ end
83
+ end
@@ -0,0 +1,72 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative '../spellr'
4
+ require_relative 'token'
5
+ require_relative 'column_location'
6
+ require_relative 'line_location'
7
+ require_relative 'line_tokenizer'
8
+
9
+ module Spellr
10
+ class Tokenizer
11
+ attr_reader :file
12
+ attr_reader :start_at
13
+
14
+ attr_accessor :disabled
15
+ alias_method :disabled?, :disabled
16
+
17
+ def initialize(file, start_at: nil, skip_uri: true, skip_key: true)
18
+ # $stderr.puts start_at if start_at
19
+ @start_at = start_at || ColumnLocation.new(line_location: LineLocation.new(file))
20
+ @file = file.is_a?(StringIO) || file.is_a?(IO) ? file : ::File.new(file)
21
+ @file.pos = @start_at.line_location.byte_offset
22
+
23
+ @line_tokenizer = LineTokenizer.new(skip_uri: skip_uri, skip_key: skip_key)
24
+ end
25
+
26
+ def terms
27
+ enum_for(:each_term).to_a
28
+ end
29
+
30
+ def map(&block)
31
+ enum_for(:each_token).map(&block)
32
+ end
33
+
34
+ def each_term(&block)
35
+ each_line_with_offset do |line, line_number|
36
+ prepare_tokenizer_for_line(line, line_number).each_term(&block)
37
+ end
38
+ end
39
+
40
+ def each_token(&block) # rubocop:disable Metrics/AbcSize
41
+ char_offset = @start_at.line_location.char_offset
42
+ byte_offset = @start_at.line_location.byte_offset
43
+
44
+ each_line_with_offset do |line, line_number|
45
+ line_location = LineLocation.new(file, line_number, byte_offset: byte_offset, char_offset: char_offset)
46
+ char_offset += line.length
47
+ byte_offset += line.bytesize
48
+ line = Token.new(line, location: ColumnLocation.new(line_location: line_location))
49
+ prepare_tokenizer_for_line(line, line_number).each_token(&block)
50
+ end
51
+ end
52
+
53
+ def normalized_terms
54
+ enum_for(:each_term).lazy.map { |t| Token.normalize(t) }.uniq.sort
55
+ end
56
+
57
+ private
58
+
59
+ attr_reader :line_tokenizer
60
+
61
+ def each_line_with_offset(&block)
62
+ file.each_line.with_index(@start_at.line_number, &block)
63
+ end
64
+
65
+ def prepare_tokenizer_for_line(line, _line_number)
66
+ line_tokenizer.string = line
67
+ line_tokenizer.pos = 0
68
+ # line_tokenizer.pos = @start_at.byte_offset if line_number == @start_at.line_number
69
+ line_tokenizer
70
+ end
71
+ end
72
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spellr
4
+ VERSION = '0.1.0'
5
+ end
@@ -0,0 +1,100 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+ require_relative '../spellr'
5
+ require_relative 'token'
6
+
7
+ module Spellr
8
+ class Wordlist
9
+ class NotFound < Spellr::Error; end
10
+
11
+ include Enumerable
12
+
13
+ attr_reader :path, :name
14
+
15
+ def initialize(file, name: file)
16
+ path = @file = file
17
+ @path = Pathname.pwd.join('.spellr_wordlists').join(path).expand_path
18
+ @name = name
19
+ end
20
+
21
+ def each(&block)
22
+ raise_unless_exists?
23
+
24
+ @path.each_line(&block)
25
+ end
26
+
27
+ def inspect
28
+ "#<#{self.class.name}:#{@path}>"
29
+ end
30
+
31
+ # significantly faster than default Enumerable#include?
32
+ # requires terms to be sorted
33
+ def include?(term)
34
+ include_cache[Spellr::Token.normalize(term)]
35
+ end
36
+
37
+ def include_cache
38
+ @include_cache ||= Hash.new do |cache, term|
39
+ cache[term] = to_a.bsearch do |value|
40
+ term <=> value
41
+ end
42
+ end
43
+ end
44
+
45
+ def to_a
46
+ @to_a ||= super
47
+ end
48
+
49
+ def clean(file = @path)
50
+ require_relative 'tokenizer'
51
+ write(Spellr::Tokenizer.new(file, skip_uri: false, skip_key: false).normalized_terms.join)
52
+ end
53
+
54
+ def write(content)
55
+ @path.write(content)
56
+
57
+ clear_cache
58
+ end
59
+
60
+ def read
61
+ raise_unless_exists?
62
+
63
+ @path.read
64
+ end
65
+
66
+ def clear_cache
67
+ @to_a = nil
68
+ @include = nil
69
+ end
70
+
71
+ def exist?
72
+ @path.exist?
73
+ end
74
+
75
+ def add(term)
76
+ touch
77
+ term = Spellr::Token.normalize(term)
78
+ include_cache[term] = true
79
+ to_a << term
80
+ to_a.sort!
81
+ write(@to_a.join)
82
+ Spellr.config.clear_cache if to_a.length == 1
83
+ end
84
+
85
+ private
86
+
87
+ def touch
88
+ return if exist?
89
+
90
+ @path.dirname.mkpath
91
+ @path.write('')
92
+ end
93
+
94
+ def raise_unless_exists?
95
+ return if exist?
96
+
97
+ raise Spellr::Wordlist::NotFound, "Wordlist file #{@file} doesn't exist at #{@path}"
98
+ end
99
+ end
100
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module Spellr
6
+ class WordlistReporter
7
+ attr_reader :words
8
+
9
+ def initialize
10
+ @words = Set.new
11
+ end
12
+
13
+ def finish(_checked)
14
+ puts words.sort.join
15
+ end
16
+
17
+ def call(token)
18
+ words << token.normalize
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ lib = ::File.expand_path('lib', __dir__)
4
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
5
+ require 'spellr/version'
6
+
7
+ Gem::Specification.new do |spec|
8
+ spec.name = 'spellr'
9
+ spec.version = Spellr::VERSION
10
+ spec.authors = ['Dana Sherson']
11
+ spec.email = ['robot@dana.sh']
12
+
13
+ spec.summary = 'Spell check your source code'
14
+ spec.homepage = 'http://github.com/robotdana/spellr'
15
+ spec.license = 'MIT'
16
+
17
+ # Specify which files should be added to the gem when it is released.
18
+ # The `git ls-files -z` loads the files in the RubyGem that have been added into git.
19
+ spec.files = Dir.chdir(::File.expand_path(__dir__)) do
20
+ `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
21
+ end
22
+ spec.bindir = 'exe'
23
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
24
+ spec.require_paths = ['lib']
25
+
26
+ spec.add_development_dependency 'bundler', '~> 1.17'
27
+ spec.add_development_dependency 'pry'
28
+ spec.add_development_dependency 'rake', '~> 10.0'
29
+ spec.add_development_dependency 'rspec', '~> 3.0'
30
+ spec.add_development_dependency 'rspec-eventually'
31
+ spec.add_development_dependency 'rubocop'
32
+ spec.add_development_dependency 'rubocop-rspec'
33
+ spec.add_dependency 'fast_ignore'
34
+ spec.add_dependency 'parallel'
35
+ end
@@ -0,0 +1,2 @@
1
+ bar
2
+ foo
@@ -0,0 +1,21 @@
1
+ add
2
+ arg
3
+ as
4
+ cmd
5
+ copy
6
+ docker
7
+ dockerfile
8
+ entrypoint
9
+ env
10
+ expose
11
+ from
12
+ healthcheck
13
+ label
14
+ maintainer
15
+ onbuild
16
+ run
17
+ shell
18
+ stopsignal
19
+ user
20
+ volume
21
+ workdir
@@ -0,0 +1,340 @@
1
+ a
2
+ abbr
3
+ accept
4
+ accesskey
5
+ acronym
6
+ action
7
+ activedescendant
8
+ address
9
+ alert
10
+ alertdialog
11
+ align
12
+ allow
13
+ alt
14
+ applet
15
+ application
16
+ area
17
+ aria
18
+ article
19
+ aside
20
+ async
21
+ atomic
22
+ audio
23
+ autocapitalize
24
+ autocomplete
25
+ autofocus
26
+ autoplay
27
+ b
28
+ banner
29
+ base
30
+ basefont
31
+ bdi
32
+ bdo
33
+ bgcolor
34
+ bgsound
35
+ big
36
+ blink
37
+ blockquote
38
+ body
39
+ br
40
+ buffered
41
+ busy
42
+ button
43
+ canvas
44
+ caption
45
+ cell
46
+ center
47
+ challenge
48
+ charset
49
+ checkbox
50
+ checked
51
+ cite
52
+ class
53
+ code
54
+ codebase
55
+ col
56
+ colcount
57
+ colgroup
58
+ colindex
59
+ color
60
+ cols
61
+ colspan
62
+ columnheader
63
+ combobox
64
+ command
65
+ complementary
66
+ content
67
+ contenteditable
68
+ contentinfo
69
+ contextmenu
70
+ controls
71
+ coords
72
+ crossorigin
73
+ csp
74
+ current
75
+ data
76
+ datalist
77
+ datetime
78
+ dd
79
+ decoding
80
+ default
81
+ defer
82
+ definition
83
+ del
84
+ describedby
85
+ details
86
+ dfn
87
+ dialog
88
+ dir
89
+ directory
90
+ dirname
91
+ disabled
92
+ div
93
+ dl
94
+ document
95
+ download
96
+ draggable
97
+ dropeffect
98
+ dropzone
99
+ dt
100
+ element
101
+ em
102
+ embed
103
+ enctype
104
+ equiv
105
+ errormessage
106
+ expanded
107
+ feed
108
+ fieldset
109
+ figcaption
110
+ figure
111
+ flowto
112
+ font
113
+ footer
114
+ for
115
+ form
116
+ formaction
117
+ frame
118
+ frameset
119
+ grabbed
120
+ grid
121
+ gridcell
122
+ group
123
+ h
124
+ haspopup
125
+ head
126
+ header
127
+ headers
128
+ heading
129
+ height
130
+ hgroup
131
+ hidden
132
+ high
133
+ hr
134
+ href
135
+ hreflang
136
+ html
137
+ http
138
+ i
139
+ icon
140
+ id
141
+ iframe
142
+ image
143
+ img
144
+ importance
145
+ input
146
+ ins
147
+ integrity
148
+ invalid
149
+ isindex
150
+ ismap
151
+ itemprop
152
+ kbd
153
+ keygen
154
+ keyshortcuts
155
+ keytype
156
+ kind
157
+ label
158
+ labelledby
159
+ lang
160
+ language
161
+ lazyload
162
+ legend
163
+ level
164
+ li
165
+ link
166
+ list
167
+ listbox
168
+ listing
169
+ listitem
170
+ live
171
+ log
172
+ loop
173
+ low
174
+ main
175
+ manifest
176
+ map
177
+ mark
178
+ marquee
179
+ math
180
+ max
181
+ maxlength
182
+ media
183
+ menu
184
+ menubar
185
+ menuitem
186
+ menuitemcheckbox
187
+ menuitemradio
188
+ meta
189
+ meter
190
+ method
191
+ min
192
+ minlength
193
+ modal
194
+ multicol
195
+ multiline
196
+ multiple
197
+ multiselectable
198
+ muted
199
+ name
200
+ nav
201
+ navigation
202
+ nextid
203
+ nobr
204
+ noembed
205
+ noframes
206
+ none
207
+ noscript
208
+ note
209
+ novalidate
210
+ object
211
+ ol
212
+ open
213
+ optgroup
214
+ optimum
215
+ option
216
+ orientation
217
+ output
218
+ owns
219
+ p
220
+ param
221
+ pattern
222
+ picture
223
+ ping
224
+ placeholder
225
+ plaintext
226
+ posinset
227
+ poster
228
+ pre
229
+ preload
230
+ presentation
231
+ pressed
232
+ progress
233
+ progressbar
234
+ q
235
+ radio
236
+ radiogroup
237
+ rb
238
+ readonly
239
+ referrerpolicy
240
+ region
241
+ rel
242
+ relevant
243
+ required
244
+ reversed
245
+ role
246
+ roledescription
247
+ row
248
+ rowcount
249
+ rowgroup
250
+ rowheader
251
+ rowindex
252
+ rows
253
+ rowspan
254
+ rp
255
+ rt
256
+ rtc
257
+ ruby
258
+ s
259
+ samp
260
+ sandbox
261
+ scope
262
+ scoped
263
+ script
264
+ scrollbar
265
+ search
266
+ searchbox
267
+ section
268
+ select
269
+ selected
270
+ separator
271
+ setsize
272
+ shadow
273
+ shape
274
+ size
275
+ sizes
276
+ slider
277
+ slot
278
+ small
279
+ sort
280
+ source
281
+ spacer
282
+ span
283
+ spellcheck
284
+ spinbutton
285
+ src
286
+ srcdoc
287
+ srclang
288
+ srcset
289
+ start
290
+ status
291
+ step
292
+ strike
293
+ strong
294
+ style
295
+ sub
296
+ summary
297
+ sup
298
+ switch
299
+ tab
300
+ tabindex
301
+ table
302
+ tablist
303
+ tabpanel
304
+ target
305
+ tbody
306
+ td
307
+ template
308
+ term
309
+ textarea
310
+ textbox
311
+ tfoot
312
+ th
313
+ thead
314
+ time
315
+ timer
316
+ title
317
+ toolbar
318
+ tooltip
319
+ tr
320
+ track
321
+ translate
322
+ tree
323
+ treegrid
324
+ treeitem
325
+ tt
326
+ type
327
+ u
328
+ ul
329
+ usemap
330
+ value
331
+ valuemax
332
+ valuemin
333
+ valuenow
334
+ valuetext
335
+ var
336
+ video
337
+ wbr
338
+ width
339
+ wrap
340
+ xmp