spellr 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2019 Dana Sherson
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,64 @@
1
+ # Spellr
2
+
3
+ Spell check your source code for fun and occasionally finding bugs
4
+
5
+ This is inspired by https://github.com/myint/scspell but i wanted a ruby gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'spellr', require: false
13
+ ```
14
+
15
+ And then execute:
16
+
17
+ $ bundle
18
+
19
+ Or install it yourself as:
20
+
21
+ $ gem install spellr
22
+
23
+ ## Usage
24
+
25
+ To start an interactive spell checking session
26
+ ```
27
+ spellr --interactive
28
+ ```
29
+
30
+ ## Development
31
+
32
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
33
+
34
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
35
+
36
+ ## Contributing
37
+
38
+ Bug reports and pull requests are welcome on GitHub at https://github.com/robotdana/spellr.
39
+
40
+ ## License
41
+
42
+ The gem is available as open source under the terms of the [MIT License](https://opensource.org/licenses/MIT).
43
+
44
+ ## TODO Before release
45
+
46
+ - [x] handle interactive add
47
+ - [x] handling wordlists per language better
48
+ - [x] global wordlists
49
+ - [x] dynamic wordlist (e.g. built from ruby and YOUR Gemfile and stdlib packages)
50
+ - [x] gem committed semi-dynamic wordlist
51
+ - [x] gem committed static wordlist
52
+ - [x] enable/disable
53
+ - [x] get marketplacer codebase green
54
+ - [x] escape
55
+ - [ ] remove default dynamic wordlist nonsense
56
+ - [x] fix bugs, have specs
57
+ - [x] attempt key recognition
58
+ ## TODO after release
59
+ - [ ] throw instead of raise for flow control
60
+ - [ ] attempt subwords again
61
+ - [ ] (semi)dynamic js wordlist
62
+ - [ ] (semi)dynamic html wordlist
63
+ - [ ] (semi)dynamic bash wordlist
64
+ - [ ] editor plugins
@@ -0,0 +1,8 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'bundler/gem_tasks'
4
+ require 'rspec/core/rake_task'
5
+
6
+ RSpec::Core::RakeTask.new(:spec)
7
+
8
+ task default: :spec
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'bundler/setup'
5
+ require 'spellr'
6
+ require 'pry'
7
+
8
+ Pry.start
@@ -0,0 +1,65 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'net/http'
5
+ require 'optparse'
6
+
7
+ class SCOWLDownloader
8
+ SIZE_OPTIONS = %w{10 20 35 40 50 55 60 70 80 95}.freeze
9
+ VARIANT_OPTIONS = %w{none common acceptable seldom-used}.freeze
10
+ DIACRITIC_OPTIONS = %w{strip keep both}.freeze
11
+ SPELLING_LANGUAGE_OPTIONS = %w{US GBs GBz CA AU}.freeze
12
+
13
+ def initialize
14
+ set_default_options
15
+ parse_options
16
+ puts Net::HTTP.get_response(uri).body
17
+ end
18
+
19
+ private
20
+
21
+ def set_default_options
22
+ @options = {
23
+ max_size: 50,
24
+ spelling: :US,
25
+ max_variant: 0,
26
+ diacritic: :both,
27
+ hacker: true
28
+ }
29
+ end
30
+
31
+ def parse_options # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
32
+ # rubocop:disable Metrics/LineLength
33
+ OptionParser.new do |opts|
34
+ opts.banner = 'Usage: spellr [options] fetch english [wordlist options]'
35
+ opts.on('-s', '--max-size', '=SIZE', String, SIZE_OPTIONS, 'Wordlist size. Options: 10 (~5,000 words), 20, 35, 40, 50 (default), 60, 70 (~170,000 words)') { |i| @options[:max_size] = i }
36
+ opts.on('-v', '--max-variants', '=VARIANTS', String, VARIANT_OPTIONS, 'Spelling variants. Options: none (default), common, acceptable, seldom-used') { |i| @options[:max_variant] = VARIANT_OPTIONS.index(i) }
37
+ opts.on('-d', '--diacritic', '=DIACRITIC', String, DIACRITIC_OPTIONS, 'Include diacritics in words. Options: strip (café becomes cafe), keep, both (default. cafe & café)') { |s| @options[:diacritic] = s }
38
+ opts.on('-l', '--language=x,y,z', Array, 'Comma separated list of English variations. Options: US (default), GBs (GB with -ise), GBz (GB with -ize), CA, AU') do |a|
39
+ raise ArgumentError unless (a - SPELLING_LANGUAGE_OPTIONS).empty?
40
+
41
+ @options[:spelling] = a
42
+ end
43
+ opts.on('-p', '--[no-]programming', 'include common programming terms like grep (default true)') { |h| @options[:special] = :hacker if h }
44
+ opts.on_tail('-h', '--help') do
45
+ warn opts.to_s
46
+ exit 1
47
+ end
48
+ end.parse!
49
+ # rubocop:enable Metrics/LineLength
50
+ end
51
+
52
+ attr_reader :options
53
+
54
+ def uri
55
+ query = URI.encode_www_form(
56
+ **options,
57
+ download: :wordlist,
58
+ encoding: :'utf-8',
59
+ format: :inline
60
+ )
61
+ URI.parse("http://app.aspell.net/create?#{query}")
62
+ end
63
+ end
64
+
65
+ SCOWLDownloader.new
@@ -0,0 +1,150 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require 'optparse'
5
+ class RubyWords # rubocop:disable Metrics/ClassLength
6
+ def initialize
7
+ @strings = []
8
+ prepare_excluded_classes
9
+
10
+ parse_options
11
+
12
+ prepare_post_excluded_classes
13
+
14
+ puts generate_words
15
+ end
16
+
17
+ private
18
+
19
+ def prepare_excluded_classes
20
+ @looked_at = []
21
+ @looked_at << RubyWords.__id__
22
+ @looked_at << OptionParser.__id__ # because we're including it here
23
+ end
24
+
25
+ def generate_words
26
+ $VERBOSE = nil
27
+ @strings = []
28
+ generate_words_for(Module)
29
+ generate_keywords
30
+ generate_convention_words
31
+ end
32
+
33
+ def generate_words_for(constant)
34
+ return if @looked_at.include?(constant.__id__) # to prevent endless loops
35
+
36
+ @looked_at << constant.__id__
37
+
38
+ generate_methods_for(constant)
39
+ generate_child_constants_for(constant)
40
+ end
41
+
42
+ def generate_methods_for(constant)
43
+ @strings |= constant.public_instance_methods(false) if constant.respond_to?(:public_instance_methods)
44
+ @strings |= constant.public_methods(false) if constant.respond_to?(:public_methods)
45
+ end
46
+
47
+ def generate_child_constants_for(constant) # rubocop:disable Metrics/MethodLength
48
+ return unless constant.respond_to?(:constants)
49
+
50
+ constant.constants.each do |child|
51
+ if autoload?(child)
52
+ warn "Skipping autoload constant #{constant}::#{child}"
53
+ next
54
+ end
55
+
56
+ @strings |= [child]
57
+ child = constant.const_get(child)
58
+ generate_words_for(child)
59
+ rescue StandardError, LoadError => e
60
+ warn "Error loading #{constant}::#{child} => #{e.message}"
61
+ end
62
+ end
63
+
64
+ def generate_keywords
65
+ @strings |= %w{
66
+ __ENCODING__ __LINE__ __FILE__ BEGIN END alias and begin break case class def
67
+ defined? do else elsif end ensure false for if in module next nil not or redo
68
+ rescue retry return self super then true undef unless until when while yield
69
+ }
70
+ end
71
+
72
+ def generate_convention_words
73
+ @strings |= %w{
74
+ klass
75
+ }
76
+ end
77
+
78
+ # badly behaved classes that I'll always have to exclude
79
+ # TODO: use the full class name rather than __id__ so i don't have to load anything
80
+ def prepare_post_excluded_classes
81
+ %w{RSpec::Core::Runner I18n::Tests}.each do |exclude|
82
+ @looked_at << Module.const_get(exclude).__id__
83
+ rescue StandardError, LoadError # rubocop:disable Lint/HandleExceptions
84
+ end
85
+ end
86
+
87
+ def exclude_option(excludes, quiet: false)
88
+ excludes.each do |exclude|
89
+ @looked_at << Module.const_get(exclude).__id__
90
+ rescue StandardError, LoadError => e
91
+ warn "Error excluding #{exclude} => #{e.message}" unless quiet
92
+ end
93
+ end
94
+
95
+ def bundler_option(_)
96
+ require 'bundler/setup'
97
+ require_each Bundler.setup.requires.values.flatten(1)
98
+ end
99
+
100
+ def require_each(requirables)
101
+ requirables.each(&method(:soft_require))
102
+ end
103
+
104
+ def soft_require(requireable)
105
+ require requireable
106
+ rescue LoadError => e
107
+ warn "Error requiring #{requireable} => #{e.message}"
108
+ end
109
+
110
+ def require_option(gems)
111
+ soft_require 'bundler/setup'
112
+ require_each(gems)
113
+ end
114
+
115
+ def available_stdlibs
116
+ %w{
117
+ abbrev base64 benchmark bigdecimal cgi cmath coverage csv date delegate digest
118
+ drb/drb e2mmap English erb etc expect fcntl fiddle fileutils find forwardable
119
+ getoptlong io/console io/nonblock io/wait ipaddr irb json logger matrix mkmf
120
+ monitor mutex_m net/ftp net/http net/imap net/pop net/smtp net/telnet nkf
121
+ objspace observer open-uri open3 openssl optionparser optparse ostruct pathname
122
+ pp prettyprint prime pstore psych pty racc/parser readline resolv ripper rss scanf
123
+ sdbm securerandom set shell shellwords singleton socket stringio strscan sync syslog
124
+ tempfile thwait time timeout tmpdir tracer tsort uri weakref webrick yaml zlib
125
+ }
126
+ end
127
+
128
+ def stdlib_option(stdlibs)
129
+ stdlibs &= available_stdlibs
130
+ stdlibs.each { |p| require p }
131
+ @strings += stdlibs
132
+ @looked_at -= [OptionParser.__id__] if stdlibs.include?('optparse') # because they might want it too
133
+ end
134
+
135
+ def parse_options # rubocop:disable Metrics/MethodLength
136
+ OptionParser.new do |opts|
137
+ opts.set_program_name 'spellr --fetch ruby'
138
+ opts.on('-r', '--require=x,y,z', Array, 'requires the specified gems', &method(:require_option))
139
+ opts.on('-s', '--stdlib=x,y,z', Array, 'requires the specified stdlib packages', &method(:stdlib_option))
140
+ opts.on('-b', '--bundler', 'includes methods and constants required by emfile', &method(:bundler_option))
141
+ opts.on('-x', '--exclude=x,y,z', Array, 'exclude listing these constants and their methods', &method(:exclude_option)) # rubocop:disable Metrics/LineLength
142
+ opts.on_tail('-h', '--help', 'Shows this message') do
143
+ warn opts
144
+ exit 1
145
+ end
146
+ end.parse!
147
+ end
148
+ end
149
+
150
+ RubyWords.new
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env bash
2
+
3
+ bundle install
@@ -0,0 +1,5 @@
1
+ #!/usr/bin/env ruby
2
+ # frozen_string_literal: true
3
+
4
+ require_relative '../lib/spellr/cli'
5
+ Spellr::CLI.new(ARGV)
@@ -0,0 +1,93 @@
1
+ ---
2
+ word_minimum_length: 3
3
+
4
+ ignore: # this list is parsed with the .gitignore format
5
+ - /.git/
6
+ - .DS_Store
7
+ - Gemfile.lock
8
+ - .rspec_status
9
+ - '*.png'
10
+ - '*.jpg'
11
+ - '*.gif'
12
+ - '*.ico'
13
+ - .gitkeep
14
+ - .keep
15
+ - '*.svg'
16
+ - '*.eot'
17
+ - '*.ttf'
18
+ - '*.woff'
19
+ - '*.woff2'
20
+ - '*.zip'
21
+ - '*.pdf'
22
+ - '*.xlsx'
23
+ - '*.gz'
24
+
25
+ languages:
26
+ english:
27
+ generate: "fetch english"
28
+ # TODO: don't generate the ruby file until you actually need one
29
+ ruby:
30
+ only: # Filtered using File.fn_match
31
+ - '*.rb'
32
+ - '*.rake'
33
+ - '*.gemspec'
34
+ - '*.erb'
35
+ - '*.haml'
36
+ - '*.jbuilder'
37
+ - '*.builder'
38
+ - Gemfile
39
+ - Rakefile
40
+ - config.ru
41
+ hashbangs:
42
+ - ruby
43
+ html:
44
+ only:
45
+ - '*.html'
46
+ - '*.hml'
47
+ - '*.jsx'
48
+ - '*.tsx'
49
+ - '*.js'
50
+ - '*.ts'
51
+ - '*.coffee'
52
+ - '*.haml'
53
+ - '*.erb'
54
+ - '*.rb'
55
+ - '*.builder'
56
+ - '*.css'
57
+ - '*.scss'
58
+ - '*.sass'
59
+ - '*.less'
60
+ js:
61
+ only:
62
+ - '*.html'
63
+ - '*.hml'
64
+ - '*.jsx'
65
+ - '*.tsx'
66
+ - '*.js'
67
+ - '*.ts'
68
+ - '*.coffee'
69
+ - '*.haml'
70
+ - '*.erb'
71
+ - '*.json'
72
+ shell:
73
+ only:
74
+ - '*.sh'
75
+ - Dockerfile
76
+ hashbangs:
77
+ - bash
78
+ - sh
79
+ dockerfile:
80
+ only:
81
+ - Dockerfile
82
+ css:
83
+ only:
84
+ - '*.css'
85
+ - '*.sass'
86
+ - '*.scss'
87
+ xml:
88
+ only:
89
+ - '*.xml'
90
+ - '*.html'
91
+ - '*.haml'
92
+ - '*.hml'
93
+ - '*.svg'
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Spellr
4
+ class Error < StandardError; end
5
+ class DidReplacement < Spellr::Error
6
+ attr_reader :token
7
+
8
+ def initialize(token = nil)
9
+ @token = token
10
+ end
11
+ end
12
+ class DidAdd < Spellr::Error
13
+ attr_reader :token
14
+
15
+ def initialize(token = nil)
16
+ @token = token
17
+ end
18
+ end
19
+
20
+ module_function
21
+
22
+ def config
23
+ require_relative 'spellr/config'
24
+ @config ||= Spellr::Config.new
25
+ end
26
+ end