forspell 0.0.6 → 0.0.7

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 4dd2b546e45d6a2fab1fb824f628cc2f17d802ce
4
- data.tar.gz: e575a2f71a0968b33e715a153d535400dec007e6
3
+ metadata.gz: 67422b4f2942f8a061b0551a4fa837c0c0c93140
4
+ data.tar.gz: b56c34d10ecd2bee9dbfa14757ec7853d8a6fe17
5
5
  SHA512:
6
- metadata.gz: f8f3d245078e74f33da758e09f724d2c911655ee7e4d792e599bd11d7a073fa8ae2acf8972868552939b91a6567d703d3c8972a11adce97bd573fb3c2496a641
7
- data.tar.gz: 62826962163488488a5ce89fb72a608fd02a858fbec5e428ec96f8be4980208bc1349eca19d0800967241208b2b2cf833da6536591551f196c62f2df0d6b2885
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
  ""
@@ -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: '../test/popular_gems/json/')
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
- # binding.pry
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 |data_entry|
26
- data_entry[:errors].each do |error|
27
- if @result[error]
28
- @result[error] = @result[error].merge(count: @result.dig(error, :count) + 1, gems: (@result.dig(error, :gems) + [gem_name]).uniq)
29
- else
30
- @result[error] = { count: 1, gems: [gem_name] }
31
- end
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
- # DictionaryCreator.new.process.result
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.each_pair do |word, data|
45
- csv << [word, data[:count], data[:gems].join(', '), nil]
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/json/*.log
3
+ rm ./test/popular_gems/*.dict
4
4
 
5
5
  for var in $(ls ../gem_src/)
6
6
  do
7
- ./bin/forspell ../gem_src/$var test/popular_gems/json/$var.log
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.boolean '--gen-dictionary', 'Generate custom dictionary'
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
@@ -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
- (to_process - to_exclude).map{ |path| path.gsub('//', '/')}
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] }.join.split(/\s|,|;|—/)
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{ |token| token.first == :comment }
14
- # example: [:comment, "# def loader_class path\n", [85, 2356]]
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)
@@ -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
- ERROR_FORMAT = '%<file>s:%<line>i: %<text>s (suggestions: %<suggestions>s)'
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
- puts readable(word, suggestions) if @format == 'readable'
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
- suggestions: suggestions.join(', '))
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| puts 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
- puts format(SUMMARY, files: @files.size, errors: total_errors_colorized)
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
@@ -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
- args
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
- config
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
- dir
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
- proc
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
- repo
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
- subtype: example
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
@@ -10,8 +10,13 @@ module Forspell
10
10
  end
11
11
 
12
12
  def call
13
- @files.each do |path|
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
@@ -5,18 +5,12 @@ require 'cgi'
5
5
 
6
6
  module Forspell
7
7
  module Sanitizer
8
- REMOVE_PUNCT = /[[:punct:]&&[^\-\'\_\.]]$/.freeze
8
+ REMOVE_PUNCT = %r{[!|?|,|(|)|"|;]+}.freeze
9
9
 
10
10
  def self.sanitize(input)
11
11
 
12
- result = CGI.unescapeHTML(Sanitize.fragment(input,
13
- elements: [], remove_contents: true))
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
@@ -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
- dictionary.check?(word)
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(SUGGESTIONS_SIZE)
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
- \'? # could start with apostrophe
7
- ([a-z]|[A-Z])? # at least one letter,
8
- ([[:lower:]])+ # then any number of letters,
9
- ([\'\-])? # optional dash/apostrophe,
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.6
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-26 00:00:00.000000000 Z
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