rdoc-spellcheck 1.0

Sign up to get free protection for your applications and to get access to all the features.
Binary file
@@ -0,0 +1,17 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'autotest/restart'
4
+
5
+ Autotest.add_hook :initialize do |at|
6
+ at.testlib = 'minitest/autorun'
7
+ at.add_exception '.git'
8
+
9
+ def at.path_to_classname s
10
+ sep = File::SEPARATOR
11
+ f = s.sub(/^test#{sep}/, '').sub(/\.rb$/, '').split(sep)
12
+ f = f.map { |path| path.split(/_|(\d+)/).map { |seg| seg.capitalize }.join }
13
+ f = f.map { |path| path =~ /^Test/ ? path : "Test#{path}" }
14
+ f.join('::').gsub('Rdoc', 'RDoc')
15
+ end
16
+ end
17
+
File without changes
@@ -0,0 +1,5 @@
1
+ === 1.0 / 2012-04-05
2
+
3
+ * Major enhancements
4
+ * Birthday!
5
+
@@ -0,0 +1,8 @@
1
+ .autotest
2
+ History.rdoc
3
+ Manifest.txt
4
+ README.rdoc
5
+ Rakefile
6
+ lib/rdoc/discover.rb
7
+ lib/rdoc/generator/spellcheck.rb
8
+ test/test_rdoc_generator_spellcheck.rb
@@ -0,0 +1,80 @@
1
+ = rdoc-spellcheck
2
+
3
+ home :: https://github.com/drbrain/rdoc-spellcheck
4
+ rdoc :: http://docs.seattlerb.org/rdoc-spellcheck
5
+ bugs :: https://github.com/drbrain/rdoc-spellcheck/issues
6
+
7
+ == Description
8
+
9
+ rdoc-spellcheck checks your documentation for spelling errors. File, class,
10
+ and method names are automatically excluded from the results and you can add
11
+ your own words to the default word list.
12
+
13
+ == Features
14
+
15
+ * Checks documentation for pages, classes, modules, methods, constants, etc.
16
+ * Prints a report showing each misspelled word and correction suggestions
17
+
18
+ == Problems
19
+
20
+ rdoc-spellcheck depends on aspell for which development has ceased despite
21
+ messages to the contrary. I've submitted two pull requests to the
22
+ hunspell-ffi gem that should allow it to become a usable replacement for the
23
+ raspell gem. (The currently released hunspell-ffi does not appear to support
24
+ private or session dictionaries.)
25
+
26
+ For some projects it seems there are too many false positives for names and
27
+ programming words. I've reduced this somewhat by automatically including many
28
+ programming words in the session dictionary. One solution involves switching
29
+ to hunspell which appears to have better-maintained word dictionaries. The
30
+ other involves exploring an upper threshold for the edit distance between a
31
+ given word and its suggestion.
32
+
33
+ == Synopsis
34
+
35
+ $ rdoc -f spellcheck lib *.rdoc
36
+
37
+ == Requirements
38
+
39
+ * rdoc
40
+ * libaspell -- See https://github.com/evan/raspell/blob/master/README.rdoc for
41
+ installation instructions for aspell
42
+
43
+ == Install
44
+
45
+ sudo gem install rdoc-spellcheck
46
+
47
+ == Developers
48
+
49
+ After checking out the source, run:
50
+
51
+ $ rake newb
52
+
53
+ This task will install any missing dependencies, run the tests/specs,
54
+ and generate the RDoc.
55
+
56
+ == License
57
+
58
+ (The MIT License)
59
+
60
+ Copyright (c) Eric Hodel
61
+
62
+ Permission is hereby granted, free of charge, to any person obtaining
63
+ a copy of this software and associated documentation files (the
64
+ 'Software'), to deal in the Software without restriction, including
65
+ without limitation the rights to use, copy, modify, merge, publish,
66
+ distribute, sublicense, and/or sell copies of the Software, and to
67
+ permit persons to whom the Software is furnished to do so, subject to
68
+ the following conditions:
69
+
70
+ The above copyright notice and this permission notice shall be
71
+ included in all copies or substantial portions of the Software.
72
+
73
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
74
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
75
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
76
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
77
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
78
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
79
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
80
+
@@ -0,0 +1,23 @@
1
+ # -*- ruby -*-
2
+
3
+ require 'rubygems'
4
+ require 'hoe'
5
+
6
+ Hoe.plugin :minitest
7
+ Hoe.plugin :git
8
+ Hoe.plugin :travis
9
+
10
+ Hoe.spec 'rdoc-spellcheck' do
11
+ developer 'Eric Hodel', 'drbrain@segment7.net'
12
+
13
+ rdoc_locations <<
14
+ 'docs.seattlerb.org:/data/www/docs.seattlerb.org/rdoc-spellcheck/'
15
+
16
+ # Too lazy to make Unicode Regexps work on Ruby 1.8 and 1.9
17
+ spec_extras['required_ruby_version'] = '>= 1.9.2'
18
+
19
+ dependency 'raspell', '~> 1.3'
20
+ dependency 'rdoc', '~> 3.12'
21
+ end
22
+
23
+ # vim: syntax=ruby
@@ -0,0 +1,2 @@
1
+ require 'rdoc/generator/spellcheck'
2
+
@@ -0,0 +1,714 @@
1
+ # coding: UTF-8
2
+
3
+ require 'raspell'
4
+
5
+ ##
6
+ # A spell checking generator for RDoc.
7
+ #
8
+ # This generator creates a report of misspelled words. You can use it to find
9
+ # when you acidentally make a typo. For example, this line contains one.
10
+
11
+ class RDoc::Generator::Spellcheck
12
+
13
+ RDoc::RDoc.add_generator self
14
+
15
+ ##
16
+ # This version of rdoc-spellcheck
17
+
18
+ VERSION = '1.0'
19
+
20
+ ##
21
+ # A list of common words that aspell may not include, but are commonly used
22
+ # in ruby programs.
23
+ #--
24
+ # Please keep this list sorted in your pull requests
25
+
26
+ DEFAULT_WORDS = %w[
27
+ API
28
+ ArgumentError
29
+ CGI
30
+ DES
31
+ ECDSA
32
+ EOFError
33
+ ERb
34
+ Encoding::CompatibilityError
35
+ Encoding::ConverterNotFoundError
36
+ Encoding::InvalidByteSequenceError
37
+ Encoding::UndefinedConversionError
38
+ EncodingError
39
+ Errno::E2BIG
40
+ Errno::EACCES
41
+ Errno::EADDRINUSE
42
+ Errno::EADDRNOTAVAIL
43
+ Errno::EAFNOSUPPORT
44
+ Errno::EAGAIN
45
+ Errno::EALREADY
46
+ Errno::EAUTH
47
+ Errno::EBADF
48
+ Errno::EBADMSG
49
+ Errno::EBADRPC
50
+ Errno::EBUSY
51
+ Errno::ECANCELED
52
+ Errno::ECHILD
53
+ Errno::ECONNABORTED
54
+ Errno::ECONNREFUSED
55
+ Errno::ECONNRESET
56
+ Errno::EDEADLK
57
+ Errno::EDESTADDRREQ
58
+ Errno::EDOM
59
+ Errno::EDQUOT
60
+ Errno::EEXIST
61
+ Errno::EFAULT
62
+ Errno::EFBIG
63
+ Errno::EFTYPE
64
+ Errno::EHOSTDOWN
65
+ Errno::EHOSTUNREACH
66
+ Errno::EIDRM
67
+ Errno::EILSEQ
68
+ Errno::EINPROGRESS
69
+ Errno::EINTR
70
+ Errno::EINVAL
71
+ Errno::EIO
72
+ Errno::EISCONN
73
+ Errno::EISDIR
74
+ Errno::ELOOP
75
+ Errno::EMFILE
76
+ Errno::EMLINK
77
+ Errno::EMSGSIZE
78
+ Errno::EMULTIHOP
79
+ Errno::ENAMETOOLONG
80
+ Errno::ENEEDAUTH
81
+ Errno::ENETDOWN
82
+ Errno::ENETRESET
83
+ Errno::ENETUNREACH
84
+ Errno::ENFILE
85
+ Errno::ENOATTR
86
+ Errno::ENOBUFS
87
+ Errno::ENODATA
88
+ Errno::ENODEV
89
+ Errno::ENOENT
90
+ Errno::ENOEXEC
91
+ Errno::ENOLCK
92
+ Errno::ENOLINK
93
+ Errno::ENOMEM
94
+ Errno::ENOMSG
95
+ Errno::ENOPROTOOPT
96
+ Errno::ENOSPC
97
+ Errno::ENOSR
98
+ Errno::ENOSTR
99
+ Errno::ENOSYS
100
+ Errno::ENOTBLK
101
+ Errno::ENOTCONN
102
+ Errno::ENOTDIR
103
+ Errno::ENOTEMPTY
104
+ Errno::ENOTRECOVERABLE
105
+ Errno::ENOTSOCK
106
+ Errno::ENOTSUP
107
+ Errno::ENOTTY
108
+ Errno::ENXIO
109
+ Errno::EOPNOTSUPP
110
+ Errno::EOVERFLOW
111
+ Errno::EOWNERDEAD
112
+ Errno::EPERM
113
+ Errno::EPFNOSUPPORT
114
+ Errno::EPIPE
115
+ Errno::EPROCLIM
116
+ Errno::EPROCUNAVAIL
117
+ Errno::EPROGMISMATCH
118
+ Errno::EPROGUNAVAIL
119
+ Errno::EPROTO
120
+ Errno::EPROTONOSUPPORT
121
+ Errno::EPROTOTYPE
122
+ Errno::ERANGE
123
+ Errno::EREMOTE
124
+ Errno::EROFS
125
+ Errno::ERPCMISMATCH
126
+ Errno::ESHUTDOWN
127
+ Errno::ESOCKTNOSUPPORT
128
+ Errno::ESPIPE
129
+ Errno::ESRCH
130
+ Errno::ESTALE
131
+ Errno::ETIME
132
+ Errno::ETIMEDOUT
133
+ Errno::ETOOMANYREFS
134
+ Errno::ETXTBSY
135
+ Errno::EUSERS
136
+ Errno::EXDEV
137
+ Errno::NOERROR
138
+ Exception
139
+ FIXME
140
+ FQDN
141
+ FiberError
142
+ FileUtils
143
+ FloatDomainError
144
+ GPL
145
+ IETF
146
+ IOError
147
+ IndexError
148
+ Interrupt
149
+ KeyError
150
+ LoadError
151
+ LocalJumpError
152
+ MSDN
153
+ Math::DomainError
154
+ NTFS
155
+ NUL
156
+ NameError
157
+ NoMemoryError
158
+ NoMethodError
159
+ NoMethodError
160
+ NotImplementedError
161
+ O'Reilly
162
+ PHP
163
+ PNG
164
+ POSIX
165
+ PRNG
166
+ README
167
+ RangeError
168
+ RegexpError
169
+ RuntimeError
170
+ SIGABRT
171
+ SIGALRM
172
+ SIGBUS
173
+ SIGCHLD
174
+ SIGCLD
175
+ SIGCONT
176
+ SIGEMT
177
+ SIGEXIT
178
+ SIGFPE
179
+ SIGHUP
180
+ SIGILL
181
+ SIGINFO
182
+ SIGINT
183
+ SIGIO
184
+ SIGIOT
185
+ SIGKILL
186
+ SIGPIPE
187
+ SIGPROF
188
+ SIGQUIT
189
+ SIGSEGV
190
+ SIGSTOP
191
+ SIGSYS
192
+ SIGTERM
193
+ SIGTRAP
194
+ SIGTSTP
195
+ SIGTTIN
196
+ SIGTTOU
197
+ SIGURG
198
+ SIGUSR1
199
+ SIGUSR2
200
+ SIGVTALRM
201
+ SIGWINCH
202
+ SIGXCPU
203
+ SIGXFSZ
204
+ SMTP
205
+ SMTPS
206
+ ScriptError
207
+ SecurityError
208
+ SignalException
209
+ StandardError
210
+ StopIteration
211
+ StringIO
212
+ SyntaxError
213
+ SystemCallError
214
+ SystemExit
215
+ SystemStackError
216
+ ThreadError
217
+ TypeError
218
+ URI
219
+ UUCP
220
+ VCS
221
+ Wikipedia
222
+ XHTML
223
+ ZeroDivisionError
224
+ Zlib
225
+ accessor
226
+ accessors
227
+ argf
228
+ argv
229
+ ary
230
+ authenticators
231
+ baz
232
+ bom
233
+ bzip
234
+ canonicalization
235
+ cfg
236
+ cpp
237
+ crlf
238
+ cryptographic
239
+ csh
240
+ daemonizing
241
+ decrypt
242
+ decrypted
243
+ decrypter
244
+ decrypting
245
+ decrypts
246
+ deprecations
247
+ dereferenced
248
+ deserialization
249
+ deserialize
250
+ deserialized
251
+ deserializes
252
+ deserializing
253
+ dev
254
+ druby
255
+ dRuby
256
+ dup
257
+ duplexed
258
+ elsif
259
+ emacs
260
+ encodings
261
+ encrypter
262
+ endian
263
+ env
264
+ erb
265
+ finalized
266
+ finalizer
267
+ finalizers
268
+ globals
269
+ gsub
270
+ gzip
271
+ gzipped
272
+ http
273
+ https
274
+ img
275
+ incrementing
276
+ initializer
277
+ inlining
278
+ instantiation
279
+ irb
280
+ iso
281
+ ivar
282
+ kbd
283
+ klass
284
+ klasses
285
+ lang
286
+ lexing
287
+ lookup
288
+ lossy
289
+ mailto
290
+ matz
291
+ mktmpdir
292
+ natively
293
+ newb
294
+ nonces
295
+ perl
296
+ popup
297
+ proleptic
298
+ proxied
299
+ pwd
300
+ racc
301
+ radian
302
+ radians
303
+ radix
304
+ rbw
305
+ redistributions
306
+ refactor
307
+ refactored
308
+ reinitializes
309
+ resized
310
+ rhtml
311
+ rsync
312
+ serializable
313
+ startup
314
+ stderr
315
+ stdin
316
+ stdout
317
+ struct
318
+ succ
319
+ sudo
320
+ tmpdir
321
+ tokenizer
322
+ tokenizes
323
+ txt
324
+ unbuffered
325
+ unescape
326
+ unescapes
327
+ uniq
328
+ unmaintained
329
+ unmarshal
330
+ unmarshalled
331
+ unmarshalling
332
+ unordered
333
+ untagged
334
+ untrusted
335
+ utf
336
+ validator
337
+ validators
338
+ versioning
339
+ visibilities
340
+ www
341
+ yacc
342
+ ]
343
+
344
+ ##
345
+ # OptionParser validator for Aspell language dictionaries
346
+
347
+ SpellLanguage = Object.new
348
+
349
+ attr_accessor :minimum_word_length # :nodoc:
350
+
351
+ attr_reader :spell # :nodoc:
352
+
353
+ ##
354
+ # Adds rdoc-spellcheck options to the rdoc command
355
+
356
+ def self.setup_options options
357
+ default_language, = ENV['LANG'].split '.'
358
+
359
+ options.spell_add_words = false
360
+ options.spell_language = default_language
361
+ options.spell_minimum_word_length = 4
362
+ options.spell_source_dir = Dir.pwd
363
+ options.quiet = true # suppress statistics
364
+
365
+ op = options.option_parser
366
+
367
+ op.accept SpellLanguage do |language|
368
+ found = Aspell.list_dicts.find do |dict|
369
+ dict.name == language
370
+ end
371
+
372
+ raise OptionParser::InvalidArgument,
373
+ "dictionary #{language} not installed" unless found
374
+
375
+ language
376
+ end
377
+
378
+ op.separator nil
379
+ op.separator 'Spellcheck options:'
380
+ op.separator nil
381
+
382
+ op.on('--spell-add-words [WORDLIST]',
383
+ 'Adds words to the aspell personal wordlist.',
384
+ 'The word list may be a comma-separated',
385
+ 'list of words which must contain multiple',
386
+ 'words, a file or empty to read words from',
387
+ 'stdin') do |wordlist|
388
+ words = if wordlist.nil? then
389
+ $stdin.read.split
390
+ elsif wordlist =~ /,/ then
391
+ wordlist.split ','
392
+ else
393
+ open wordlist do |io|
394
+ io.read.split
395
+ end
396
+ end
397
+
398
+ options.spell_add_words = words
399
+ end
400
+
401
+ op.separator nil
402
+
403
+ op.on('--[no-]spell-aggregate-all',
404
+ 'Show aggregate counts for all misspellings.') do |aggregate_all|
405
+ options.spell_aggregate_all = aggregate_all
406
+ end
407
+
408
+ op.separator nil
409
+
410
+ op.on('--spell-language=LANGUAGE', SpellLanguage,
411
+ 'Language to use for spell checking.',
412
+ "The default language is #{default_language}") do |language|
413
+ options.spell_language = language
414
+ end
415
+
416
+ op.separator nil
417
+
418
+ op.on('--spell-minimum-word-length=LENGTH', Integer,
419
+ 'Minimum length of a word to spell check.',
420
+ "The default is #{options.spell_minimum_word_length}") do |length|
421
+ options.spell_minimum_word_length = length
422
+ end
423
+ end
424
+
425
+ def initialize options # :not-new:
426
+ @options = options
427
+
428
+ @encoding = @options.encoding
429
+ @aggregate_all = @options.spell_aggregate_all
430
+ @minimum_word_length = @options.spell_minimum_word_length
431
+ @source_dir = @options.spell_source_dir
432
+
433
+ @misspellings = Hash.new 0
434
+
435
+ @spell = Aspell.new @options.spell_language, nil, nil, @encoding.name
436
+ @spell.suggestion_mode = Aspell::NORMAL
437
+ @spell.set_option 'run-together', 'true'
438
+
439
+ if words = @options.spell_add_words then
440
+ words.each do |word|
441
+ @spell.add_to_personal word
442
+ end
443
+
444
+ @spell.save_all_word_lists
445
+ end
446
+ end
447
+
448
+ ##
449
+ # Adds +name+ to the dictionary, splitting the word on '_' (a character
450
+ # Aspell does not allow)
451
+
452
+ def add_name name
453
+ name.scan(/[a-z]+/i) do |part|
454
+ @spell.add_to_session part
455
+ end
456
+ end
457
+
458
+ ##
459
+ # Returns a report of misspelled words in +comment+. The report contains
460
+ # each misspelled word and its offset in the comment's text.
461
+
462
+ def find_misspelled comment
463
+ report = []
464
+
465
+ comment.text.scan(/\p{L}[\p{L}']+\p{L}/i) do |word|
466
+ next if $&.length < @minimum_word_length
467
+ offset = $`.length # store
468
+
469
+ word = $` if word =~ /'s$/i
470
+
471
+ next if @spell.check word
472
+
473
+ offset = offset.zero? ? 0 : offset + 1
474
+
475
+ report << [word, offset]
476
+
477
+ @misspellings[word] += 1
478
+ end
479
+
480
+ report
481
+ end
482
+
483
+ ##
484
+ # Creates the spelling report
485
+
486
+ def generate files
487
+ setup_dictionary
488
+
489
+ report = []
490
+
491
+ RDoc::TopLevel.all_classes_and_modules.each do |mod|
492
+ mod.comment_location.each do |comment, location|
493
+ report.concat misspellings_for(mod.definition, comment, location)
494
+ end
495
+
496
+ mod.each_include do |incl|
497
+ name = "#{incl.parent.full_name}.include #{incl.name}"
498
+
499
+ report.concat misspellings_for(name, incl.comment, incl.file)
500
+ end
501
+
502
+ mod.each_constant do |const|
503
+ # TODO add missing RDoc::Constant#full_name
504
+ name = const.parent ? const.parent.full_name : '(unknown)'
505
+ name = "#{name}::#{const.name}"
506
+
507
+ report.concat misspellings_for(name, const.comment, const.file)
508
+ end
509
+
510
+ mod.each_attribute do |attr|
511
+ name = "#{attr.parent.full_name}.#{attr.definition} :#{attr.name}"
512
+
513
+ report.concat misspellings_for(name, attr.comment, attr.file)
514
+ end
515
+
516
+ mod.each_method do |meth|
517
+ report.concat misspellings_for(meth.full_name, meth.comment, meth.file)
518
+ end
519
+ end
520
+
521
+ RDoc::TopLevel.all_files.each do |file|
522
+ report.concat misspellings_for(nil, file.comment, file)
523
+ end
524
+
525
+ if @misspellings.empty? then
526
+ puts 'No misspellings found'
527
+ else
528
+ puts report.join "\n"
529
+ puts
530
+
531
+ num_width = @misspellings.values.max.to_s.length
532
+ order = @misspellings.sort_by do |word, count|
533
+ [-count, word]
534
+ end
535
+
536
+ order = order.first 10 unless @aggregate_all
537
+
538
+ puts 'Aggregate misspellings:'
539
+ order.each do |word, count|
540
+ puts "%*d %s" % [num_width, count, word]
541
+ end
542
+
543
+ total = @misspellings.values.inject :+
544
+
545
+ puts
546
+ puts "Total misspellings: #{total}"
547
+ end
548
+ end
549
+
550
+ ##
551
+ # Determines the line and column of the misspelling in +comment+ at +offset+
552
+ # in the +file+.
553
+
554
+ def location_of text, offset, file
555
+ last_newline = text[0, offset].rindex "\n"
556
+ start_of_line = last_newline ? last_newline + 1 : 0
557
+
558
+ line_text = text[start_of_line..offset]
559
+
560
+ full_path = File.expand_path file.absolute_name, @source_dir
561
+
562
+ file_content = RDoc::Encoding.read_file full_path, @encoding
563
+
564
+ raise "[bug] Unable to read #{full_path}" unless file_content
565
+
566
+ file_content.each_line.with_index do |line, index|
567
+ if line =~ /#{Regexp.escape line_text}/ then
568
+ column = $`.length + line_text.length
569
+ return index, column
570
+ end
571
+ end
572
+
573
+ # TODO typos in include file
574
+
575
+ nil
576
+ end
577
+
578
+ ##
579
+ # Returns a report of misspellings the +comment+ at +location+ for
580
+ # documentation item +name+
581
+
582
+ def misspellings_for name, comment, location
583
+ out = []
584
+
585
+ return out if comment.empty?
586
+
587
+ misspelled = find_misspelled comment
588
+
589
+ return out if misspelled.empty?
590
+
591
+ if name then
592
+ out << "#{name} in #{location.full_name}:"
593
+ else
594
+ out << "In #{location.full_name}:"
595
+ end
596
+
597
+ out << nil
598
+
599
+ out.concat misspelled.flat_map { |word, offset|
600
+ suggestion = suggestion_text comment.text, word, offset
601
+ line, column = location_of word, offset, location
602
+
603
+ if line then
604
+ ["#{location.absolute_name}:#{line}:#{column}", suggestion]
605
+ else
606
+ ["(via include)", suggestion]
607
+ end
608
+ }
609
+
610
+ out
611
+ end
612
+
613
+ ##
614
+ # Adds file names, class names, module names, method names, etc. from the
615
+ # documentation tree to the session spelling dictionary.
616
+
617
+ def setup_dictionary
618
+ DEFAULT_WORDS.each do |word|
619
+ add_name word
620
+ end
621
+
622
+ RDoc::TopLevel.all_classes_and_modules.each do |mod|
623
+ add_name mod.name
624
+
625
+ mod.each_include do |incl|
626
+ add_name incl.name
627
+ end
628
+
629
+ mod.each_constant do |const|
630
+ add_name const.name
631
+ end
632
+
633
+ mod.each_attribute do |attr|
634
+ add_name attr.name
635
+ end
636
+
637
+ mod.each_method do |meth|
638
+ add_name meth.name
639
+ add_name meth.params if meth.params
640
+ add_name meth.block_params if meth.block_params
641
+ end
642
+ end
643
+
644
+ RDoc::TopLevel.all_files.each do |file|
645
+ file.absolute_name.split(%r%[/\\.]%).each do |part|
646
+ add_name part
647
+ end
648
+ end
649
+ end
650
+
651
+ ##
652
+ # Creates suggestion text for the misspelled +word+ at +offset+ in +text+
653
+
654
+ def suggestion_text text, word, offset
655
+ prefix = offset - 10
656
+ prefix = 0 if prefix < 0
657
+
658
+ text =~ /\A.{#{prefix}}(.{0,10})#{Regexp.escape word}(.{0,10})/m
659
+
660
+ before = "#{prefix.zero? ? nil : '...'}#{$1}"
661
+ after = "#{$2}#{$2.length < 10 ? nil : '...'}"
662
+
663
+ highlight = "\e[1;31m#{word}\e[m"
664
+
665
+ suggestions = @spell.suggest(word).first 5
666
+
667
+ <<-TEXT
668
+ "#{before}#{highlight}#{after}"
669
+
670
+ "#{word}" suggestions:
671
+ \t#{suggestions.join ', '}
672
+
673
+ TEXT
674
+ rescue => e
675
+ $stderr.puts "[bug] #{e.class}: #{e.message}"
676
+ $stderr.puts
677
+ $stderr.puts "word: #{word}"
678
+ $stderr.puts "offset: #{offset}"
679
+ $stderr.puts ">>>> start text <<<<\n#{text}\n>>>>> end text <<<<<"
680
+ raise
681
+ end
682
+
683
+ end
684
+
685
+ class RDoc::Options
686
+
687
+ ##
688
+ # Enables addition of words to the personal wordlist
689
+
690
+ attr_accessor :spell_add_words
691
+
692
+ ##
693
+ # Display all found misspellings instead of the top ten.
694
+
695
+ attr_accessor :spell_aggregate_all
696
+
697
+ ##
698
+ # The Aspell dictionary language to use. Defaults to the language in the
699
+ # LANG environment variable.
700
+
701
+ attr_accessor :spell_language
702
+
703
+ ##
704
+ # The minimum length of a word for spell checking.
705
+
706
+ attr_accessor :spell_minimum_word_length
707
+
708
+ ##
709
+ # The directory spellcheck was run from which contains all the source files.
710
+
711
+ attr_accessor :spell_source_dir
712
+
713
+ end
714
+