mdspell 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/LICENSE +19 -0
- data/README.md +44 -0
- data/bin/mdspell +10 -0
- data/lib/mdspell.rb +37 -0
- data/lib/mdspell/cli.rb +58 -0
- data/lib/mdspell/configuration.rb +8 -0
- data/lib/mdspell/spell_checker.rb +39 -0
- data/lib/mdspell/text_line.rb +113 -0
- data/lib/mdspell/typo.rb +44 -0
- data/lib/mdspell/version.rb +3 -0
- data/spec/examples.cache +39 -0
- data/spec/examples/simple.md +5 -0
- data/spec/examples/with_errors.md +5 -0
- data/spec/mdspell/spell_checker_spec.rb +70 -0
- data/spec/mdspell/text_line_spec.rb +111 -0
- data/spec/mdspell/typo_spec.rb +83 -0
- data/spec/spec_helper.rb +68 -0
- metadata +100 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 557ab534f964bbd18e0453ddcbe9561698441d5b
|
4
|
+
data.tar.gz: bb03a5b7f5a40b1e1fe689d383abd1a35a4ccaa8
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 21066ee2957e17175a5c353dacd2d9aea1a0a7067ef83813fad211c4548705027867509cfed1a4195893840013e2e92986b9ab8a34ffe6f22c66c81bc3562299
|
7
|
+
data.tar.gz: c96d072fc81fb88d458807e34953dcae4c01f96d3ec997f8269e527025ee5f1b6b4f4216ce1a9ffc50875b25efdf26b97478e5510833b888cde9ddf0777ecb1f
|
data/LICENSE
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
Copyright (c) 2015 Marek Tuchowski
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
4
|
+
of this software and associated documentation files (the "Software"), to deal
|
5
|
+
in the Software without restriction, including without limitation the rights
|
6
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
7
|
+
copies of the Software, and to permit persons to whom the Software is
|
8
|
+
furnished to do so, subject to the following conditions:
|
9
|
+
|
10
|
+
The above copyright notice and this permission notice shall be included in
|
11
|
+
all copies or substantial portions of the Software.
|
12
|
+
|
13
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
14
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
15
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
16
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
17
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
18
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
19
|
+
THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# MdSpell
|
2
|
+
|
3
|
+
[![Build Status](https://travis-ci.org/mtuchowski/mdspell.svg)](
|
4
|
+
https://travis-ci.org/mtuchowski/mdspell)
|
5
|
+
[![Code Climate](https://codeclimate.com/github/mtuchowski/mdspell/badges/gpa.svg)](
|
6
|
+
https://codeclimate.com/github/mtuchowski/mdspell)
|
7
|
+
[![Test Coverage](https://codeclimate.com/github/mtuchowski/mdspell/badges/coverage.svg)](
|
8
|
+
https://codeclimate.com/github/mtuchowski/mdspell/coverage)
|
9
|
+
|
10
|
+
A Ruby markdown spell checking tool.
|
11
|
+
|
12
|
+
## Installation
|
13
|
+
|
14
|
+
To install from [rubygems.org](http://rubygems.org/), run:
|
15
|
+
|
16
|
+
```console
|
17
|
+
gem install mdspell
|
18
|
+
```
|
19
|
+
|
20
|
+
## Usage
|
21
|
+
|
22
|
+
To spell-check markdown files, simply run `mdspell` with the filenames as a parameter:
|
23
|
+
|
24
|
+
```console
|
25
|
+
mdspell README.md
|
26
|
+
```
|
27
|
+
|
28
|
+
To check all markdown files within the directory:
|
29
|
+
|
30
|
+
```console
|
31
|
+
mdspell docs/
|
32
|
+
```
|
33
|
+
|
34
|
+
For each spelling error found, MdSpell will display the misspelled word, filename and line number:
|
35
|
+
|
36
|
+
```console
|
37
|
+
Spell-checking ./README.md...
|
38
|
+
./README.md:10: actualy
|
39
|
+
```
|
40
|
+
|
41
|
+
## MIT Licensed
|
42
|
+
|
43
|
+
See [LICENSE](https://github.com/mtuchowski/mdspell/blob/master/LICENSE) file for full license
|
44
|
+
text.
|
data/bin/mdspell
ADDED
data/lib/mdspell.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require_relative 'mdspell/cli'
|
2
|
+
require_relative 'mdspell/configuration'
|
3
|
+
require_relative 'mdspell/spell_checker'
|
4
|
+
require_relative 'mdspell/text_line'
|
5
|
+
require_relative 'mdspell/typo'
|
6
|
+
require_relative 'mdspell/version'
|
7
|
+
|
8
|
+
require 'rainbow'
|
9
|
+
|
10
|
+
# This module holds all the MdSpell code (except mdspell shell command).
|
11
|
+
module MdSpell
|
12
|
+
def self.run
|
13
|
+
cli = MdSpell::CLI.new
|
14
|
+
cli.run
|
15
|
+
|
16
|
+
# Spell-check each file.
|
17
|
+
cli.files.each do |filename|
|
18
|
+
verbose "Spell-checking #{filename}..."
|
19
|
+
|
20
|
+
SpellChecker.new(filename).typos.each do |typo|
|
21
|
+
error "#{filename}:#{typo.line.location}: #{typo.word}"
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
# Private class methods
|
27
|
+
|
28
|
+
def self.verbose(str)
|
29
|
+
puts str if Configuration[:verbose]
|
30
|
+
end
|
31
|
+
private_class_method :verbose
|
32
|
+
|
33
|
+
def self.error(str)
|
34
|
+
puts Rainbow(str).red
|
35
|
+
end
|
36
|
+
private_class_method :error
|
37
|
+
end
|
data/lib/mdspell/cli.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'mixlib/cli'
|
2
|
+
|
3
|
+
module MdSpell
|
4
|
+
# Class responsible for parsing all of command line arguments.
|
5
|
+
class CLI
|
6
|
+
include Mixlib::CLI
|
7
|
+
|
8
|
+
banner "Usage: #{File.basename($PROGRAM_NAME)} [options] [FILE.md|DIR ...]"
|
9
|
+
|
10
|
+
option :config_file,
|
11
|
+
short: '-c',
|
12
|
+
long: '--config FILE',
|
13
|
+
description: 'The configuration file to use',
|
14
|
+
default: '~/.mdspell'
|
15
|
+
|
16
|
+
option :language,
|
17
|
+
short: '-l',
|
18
|
+
long: '--language LANG',
|
19
|
+
description: 'Set documents language',
|
20
|
+
default: 'en_US'
|
21
|
+
|
22
|
+
option :verbose,
|
23
|
+
short: '-v',
|
24
|
+
long: '--[no-]verbose',
|
25
|
+
description: 'Be more/less verbose',
|
26
|
+
boolean: true
|
27
|
+
|
28
|
+
option :version,
|
29
|
+
on: :tail,
|
30
|
+
short: '-V',
|
31
|
+
long: '--version',
|
32
|
+
description: 'Show version',
|
33
|
+
boolean: true,
|
34
|
+
proc: proc { puts MdSpell::VERSION },
|
35
|
+
exit: 0
|
36
|
+
|
37
|
+
def run(argv = ARGV)
|
38
|
+
parse_options(argv)
|
39
|
+
|
40
|
+
# Load optional config file if it's present.
|
41
|
+
config_filename = File.expand_path(config[:config_file])
|
42
|
+
MdSpell::Configuration.from_file(config_filename) if File.exist?(config_filename)
|
43
|
+
|
44
|
+
# Store command line configuration options.
|
45
|
+
MdSpell::Configuration.merge!(config)
|
46
|
+
end
|
47
|
+
|
48
|
+
# List of markdown files from argument list.
|
49
|
+
def files
|
50
|
+
cli_arguments.each_with_index do |filename, index|
|
51
|
+
if Dir.exist?(filename)
|
52
|
+
cli_arguments[index] = Dir["#{filename}/**/*.md"]
|
53
|
+
end
|
54
|
+
end
|
55
|
+
cli_arguments.flatten!
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end
|
@@ -0,0 +1,39 @@
|
|
1
|
+
require_relative 'configuration'
|
2
|
+
|
3
|
+
require 'kramdown'
|
4
|
+
require 'ffi/aspell'
|
5
|
+
|
6
|
+
module MdSpell
|
7
|
+
# A class for finding spelling errors in document.
|
8
|
+
class SpellChecker
|
9
|
+
# Name of the file this object was created from.
|
10
|
+
attr_reader :filename
|
11
|
+
|
12
|
+
# A Kramdown::Document object containing the parsed markdown document.
|
13
|
+
attr_reader :document
|
14
|
+
|
15
|
+
# Create a new instance from specified file.
|
16
|
+
# @param filename [String] a name of file to load.
|
17
|
+
def initialize(filename)
|
18
|
+
@filename = filename
|
19
|
+
@document = Kramdown::Document.new(File.read(filename), input: 'GFM')
|
20
|
+
end
|
21
|
+
|
22
|
+
# Returns found spelling errors.
|
23
|
+
def typos
|
24
|
+
results = []
|
25
|
+
|
26
|
+
FFI::Aspell::Speller.open(Configuration[:language]) do |speller|
|
27
|
+
TextLine.scan(document).each do |line|
|
28
|
+
line.words.each do |word|
|
29
|
+
unless speller.correct? word
|
30
|
+
results << Typo.new(line, word, speller.suggestions(word))
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
results
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
@@ -0,0 +1,113 @@
|
|
1
|
+
require 'kramdown'
|
2
|
+
|
3
|
+
module MdSpell
|
4
|
+
# Containing concatenated text from single document line.
|
5
|
+
class TextLine
|
6
|
+
# Accepted types of elements.
|
7
|
+
ELEMENT_TYPES = [:text, :smart_quote]
|
8
|
+
|
9
|
+
# Line number of the element in document.
|
10
|
+
attr_reader :location
|
11
|
+
|
12
|
+
# Textual content of the element.
|
13
|
+
attr_reader :content
|
14
|
+
|
15
|
+
# Create a new TextLine from Kramdown::Element object.
|
16
|
+
# @param element [Kramdown::Element]
|
17
|
+
def initialize(element)
|
18
|
+
TextLine.assert_element_type element
|
19
|
+
|
20
|
+
@content = ''
|
21
|
+
@location = element.options[:location]
|
22
|
+
self << element
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return all words in this element.
|
26
|
+
def words
|
27
|
+
@content.scan(/[\w\']+/)
|
28
|
+
end
|
29
|
+
|
30
|
+
# Append Kramdown::Element's content to this element.
|
31
|
+
# @param element [Kramdown::Element]
|
32
|
+
# @raise ArgumentError if element is in different location.
|
33
|
+
def <<(element)
|
34
|
+
TextLine.assert_element_type element
|
35
|
+
|
36
|
+
return self unless ELEMENT_TYPES.include? element.type
|
37
|
+
return self unless element.options[:location] == @location
|
38
|
+
|
39
|
+
value = element.value
|
40
|
+
|
41
|
+
if element.type == :smart_quote
|
42
|
+
appent_quote(value)
|
43
|
+
else
|
44
|
+
append_text(value)
|
45
|
+
end
|
46
|
+
|
47
|
+
self
|
48
|
+
end
|
49
|
+
|
50
|
+
# Scan Kramdown::Document for TextLines.
|
51
|
+
# @param document [Kramdown::Document]
|
52
|
+
def self.scan(document)
|
53
|
+
results = []
|
54
|
+
|
55
|
+
get_all_textual_elements(document.root.children).each do |element|
|
56
|
+
matching_element_found = results.any? do |text_element|
|
57
|
+
if text_element.location == element.options[:location]
|
58
|
+
text_element << element
|
59
|
+
true
|
60
|
+
else
|
61
|
+
false
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
results << TextLine.new(element) unless matching_element_found
|
66
|
+
end
|
67
|
+
|
68
|
+
results
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def append_text(value)
|
74
|
+
return if value.nil? || value.empty?
|
75
|
+
|
76
|
+
value = value.strip
|
77
|
+
if @content.empty? || @content[-1] == "'"
|
78
|
+
@content += value
|
79
|
+
else
|
80
|
+
@content += ' ' + value
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def appent_quote(type)
|
85
|
+
case type
|
86
|
+
when :lsquo, :rsquo
|
87
|
+
@content += "'"
|
88
|
+
when :ldquo, :rdquo
|
89
|
+
@content += '"'
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
# Private class methods
|
94
|
+
|
95
|
+
def self.assert_element_type(elem)
|
96
|
+
fail ArgumentError, 'expected Kramdown::Element' unless elem.instance_of? Kramdown::Element
|
97
|
+
end
|
98
|
+
|
99
|
+
def self.get_all_textual_elements(elements)
|
100
|
+
result = []
|
101
|
+
|
102
|
+
elements.each do |element|
|
103
|
+
if ELEMENT_TYPES.include? element.type
|
104
|
+
result << element
|
105
|
+
else
|
106
|
+
result |= get_all_textual_elements(element.children)
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
result
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
data/lib/mdspell/typo.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
module MdSpell
|
2
|
+
# A wrapper class for single, misspelled word.
|
3
|
+
class Typo
|
4
|
+
# A TextLine that contains this error.
|
5
|
+
attr_reader :line
|
6
|
+
|
7
|
+
# A misspelled word.
|
8
|
+
attr_reader :word
|
9
|
+
|
10
|
+
# A list of suggestions for this error.
|
11
|
+
attr_reader :suggestions
|
12
|
+
|
13
|
+
# Create a new SpellingError.
|
14
|
+
# @param line [TextLine] the TextLine that contains the error.
|
15
|
+
# @param word [String] the misspelled word.
|
16
|
+
# @param suggestions [Array] an array of suggestions for the word.
|
17
|
+
def initialize(line, word, suggestions)
|
18
|
+
assert_proper_line_type(line)
|
19
|
+
assert_proper_word_type(word)
|
20
|
+
assert_proper_suggestions_type(suggestions)
|
21
|
+
|
22
|
+
@line = line
|
23
|
+
@word = word
|
24
|
+
@suggestions = suggestions
|
25
|
+
end
|
26
|
+
|
27
|
+
private
|
28
|
+
|
29
|
+
def assert_proper_line_type(line)
|
30
|
+
fail ArgumentError, "expected TextLine, got #{line.class.inspect}" unless
|
31
|
+
line.class == TextLine
|
32
|
+
end
|
33
|
+
|
34
|
+
def assert_proper_word_type(word)
|
35
|
+
fail ArgumentError, "expected String, got #{word.class.inspect}" unless
|
36
|
+
word.class == String
|
37
|
+
end
|
38
|
+
|
39
|
+
def assert_proper_suggestions_type(suggestions)
|
40
|
+
fail ArgumentError, "expected Array, got #{suggestions.class.inspect}" unless
|
41
|
+
suggestions.class == Array
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/spec/examples.cache
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
example_id | status | run_time |
|
2
|
+
--------------------------------------------- | ------- | --------------- |
|
3
|
+
./spec/mdspell/spell_checker_spec.rb[1:1:1] | passed | 0.00141 seconds |
|
4
|
+
./spec/mdspell/spell_checker_spec.rb[1:1:2] | passed | 0.00088 seconds |
|
5
|
+
./spec/mdspell/spell_checker_spec.rb[1:1:3] | passed | 0.00055 seconds |
|
6
|
+
./spec/mdspell/spell_checker_spec.rb[1:2:1] | passed | 0.00014 seconds |
|
7
|
+
./spec/mdspell/spell_checker_spec.rb[1:2:2] | passed | 0.00048 seconds |
|
8
|
+
./spec/mdspell/spell_checker_spec.rb[1:2:3] | failed | 0.01636 seconds |
|
9
|
+
./spec/mdspell/spell_checker_spec.rb[1:3:1] | passed | 0.03322 seconds |
|
10
|
+
./spec/mdspell/spell_checker_spec.rb[1:3:2:1] | failed | 0.00015 seconds |
|
11
|
+
./spec/mdspell/spell_checker_spec.rb[1:4:1] | passed | 0.00181 seconds |
|
12
|
+
./spec/mdspell/spell_checker_spec.rb[1:5:1] | failed | 0.00789 seconds |
|
13
|
+
./spec/mdspell/spell_checker_spec.rb[1:5:2] | passed | 0.00703 seconds |
|
14
|
+
./spec/mdspell/spell_checker_spec.rb[1:5:3] | pending | 0.00001 seconds |
|
15
|
+
./spec/mdspell/text_line_spec.rb[1:1:1] | passed | 0.00007 seconds |
|
16
|
+
./spec/mdspell/text_line_spec.rb[1:1:2] | passed | 0.00008 seconds |
|
17
|
+
./spec/mdspell/text_line_spec.rb[1:1:3] | passed | 0.00008 seconds |
|
18
|
+
./spec/mdspell/text_line_spec.rb[1:1:4] | passed | 0.00009 seconds |
|
19
|
+
./spec/mdspell/text_line_spec.rb[1:2:1] | passed | 0.0004 seconds |
|
20
|
+
./spec/mdspell/text_line_spec.rb[1:3:1] | passed | 0.00008 seconds |
|
21
|
+
./spec/mdspell/text_line_spec.rb[1:4:1] | passed | 0.00009 seconds |
|
22
|
+
./spec/mdspell/text_line_spec.rb[1:5:1] | passed | 0.0001 seconds |
|
23
|
+
./spec/mdspell/text_line_spec.rb[1:6:1] | passed | 0.00014 seconds |
|
24
|
+
./spec/mdspell/text_line_spec.rb[1:6:2:1] | passed | 0.00008 seconds |
|
25
|
+
./spec/mdspell/text_line_spec.rb[1:6:3:1] | passed | 0.00011 seconds |
|
26
|
+
./spec/mdspell/text_line_spec.rb[1:6:3:2] | passed | 0.0001 seconds |
|
27
|
+
./spec/mdspell/text_line_spec.rb[1:6:4:1] | passed | 0.00009 seconds |
|
28
|
+
./spec/mdspell/text_line_spec.rb[1:7:1] | passed | 0.00012 seconds |
|
29
|
+
./spec/mdspell/text_line_spec.rb[1:7:2] | passed | 0.00086 seconds |
|
30
|
+
./spec/mdspell/typo_spec.rb[1:1:1] | passed | 0.00011 seconds |
|
31
|
+
./spec/mdspell/typo_spec.rb[1:1:2] | passed | 0.0001 seconds |
|
32
|
+
./spec/mdspell/typo_spec.rb[1:1:3] | passed | 0.00008 seconds |
|
33
|
+
./spec/mdspell/typo_spec.rb[1:2:1] | passed | 0.00012 seconds |
|
34
|
+
./spec/mdspell/typo_spec.rb[1:2:2] | passed | 0.00016 seconds |
|
35
|
+
./spec/mdspell/typo_spec.rb[1:2:3] | passed | 0.00014 seconds |
|
36
|
+
./spec/mdspell/typo_spec.rb[1:3:1] | passed | 0.00044 seconds |
|
37
|
+
./spec/mdspell/typo_spec.rb[1:4:1] | passed | 0.00007 seconds |
|
38
|
+
./spec/mdspell/typo_spec.rb[1:5:1] | passed | 0.00008 seconds |
|
39
|
+
./spec/mdspell/typo_spec.rb[1:5:2] | passed | 0.0001 seconds |
|
@@ -0,0 +1,70 @@
|
|
1
|
+
describe MdSpell::SpellChecker do
|
2
|
+
let(:simple) { MdSpell::SpellChecker.new('spec/examples/simple.md') }
|
3
|
+
let(:with_errors) { MdSpell::SpellChecker.new('spec/examples/with_errors.md') }
|
4
|
+
let(:from_stdin) do
|
5
|
+
allow(STDIN).to receive(:read) { '# Header' }
|
6
|
+
MdSpell::SpellChecker.new('-')
|
7
|
+
end
|
8
|
+
|
9
|
+
context 'attributes' do
|
10
|
+
subject { simple }
|
11
|
+
|
12
|
+
it { is_expected.to respond_to :filename }
|
13
|
+
it { is_expected.to respond_to :document }
|
14
|
+
it { is_expected.to respond_to :typos }
|
15
|
+
end
|
16
|
+
|
17
|
+
context '#initialize' do
|
18
|
+
it 'should expect filename' do
|
19
|
+
expect { MdSpell::SpellChecker.new }.to raise_error ArgumentError
|
20
|
+
end
|
21
|
+
|
22
|
+
it 'should fail if given wrong filename' do
|
23
|
+
expect { MdSpell::SpellChecker.new('not_existing.md') }.to raise_error Errno::ENOENT
|
24
|
+
end
|
25
|
+
|
26
|
+
it "should read from stdin if given '-' as filename" do
|
27
|
+
allow(STDIN).to receive(:read) { '# Header' }
|
28
|
+
expect { MdSpell::SpellChecker.new('-') }.not_to raise_error
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context '#filename' do
|
33
|
+
it 'should return proper path' do
|
34
|
+
expect(simple.filename).to eq 'spec/examples/simple.md'
|
35
|
+
expect(with_errors.filename).to eq 'spec/examples/with_errors.md'
|
36
|
+
end
|
37
|
+
|
38
|
+
context 'if initialized from stdin' do
|
39
|
+
it "should return 'stdin'" do
|
40
|
+
expect(stdin_md.filename).to eq 'stdin'
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context '#document' do
|
46
|
+
it 'should be of proper type' do
|
47
|
+
expect(simple.document).to be_instance_of Kramdown::Document
|
48
|
+
expect(with_errors.document).to be_instance_of Kramdown::Document
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context '#typos' do
|
53
|
+
it 'should return empty array if there are no errors' do
|
54
|
+
expect(simple.typos).to have(0).items
|
55
|
+
expect(from_stdin.typos).to have(0).items
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should return proper results' do
|
59
|
+
typos = with_errors.typos
|
60
|
+
|
61
|
+
expect(typos).to have(4).items
|
62
|
+
expect(typos[0].word).to eq 'mispelled'
|
63
|
+
expect(typos[1].word).to eq 'qiute'
|
64
|
+
expect(typos[2].word).to eq 'actualy'
|
65
|
+
expect(typos[3].word).to eq 'tobe'
|
66
|
+
end
|
67
|
+
|
68
|
+
it 'should use configured language'
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
describe MdSpell::TextLine do
|
2
|
+
let(:md_p_element) { Kramdown::Element.new(:p) }
|
3
|
+
let(:md_header_element) { Kramdown::Element.new(:header) }
|
4
|
+
let(:md_text_element) { Kramdown::Element.new(:text, "Joe's shop", nil, location: 42) }
|
5
|
+
let(:md_other_text_element) { Kramdown::Element.new(:text, 'text', nil, location: 42) }
|
6
|
+
let(:md_quote_element) { Kramdown::Element.new(:smart_quote, :lsquo, nil, location: 42) }
|
7
|
+
let(:md_empty_text_element) { Kramdown::Element.new(:text, nil, nil, location: 42) }
|
8
|
+
let(:md_empty_quote_element) { Kramdown::Element.new(:smart_quote, nil, nil, location: 42) }
|
9
|
+
let(:md_text_element_diff_location) { Kramdown::Element.new(:text, 'test', nil, location: 41) }
|
10
|
+
|
11
|
+
subject { MdSpell::TextLine.new(md_text_element) }
|
12
|
+
|
13
|
+
context 'attributes' do
|
14
|
+
it { is_expected.to respond_to :location }
|
15
|
+
it { is_expected.to respond_to :content }
|
16
|
+
it { is_expected.to respond_to :words }
|
17
|
+
it { is_expected.to respond_to :<< }
|
18
|
+
end
|
19
|
+
|
20
|
+
context '#initialize' do
|
21
|
+
it 'should expect Kramdown::Element as argument' do
|
22
|
+
expect { MdSpell::TextLine.new }.to raise_error ArgumentError
|
23
|
+
expect { MdSpell::TextLine.new('test') }.to raise_error ArgumentError
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
context '#location' do
|
28
|
+
it 'should return proper value' do
|
29
|
+
expect(subject.location).to eq 42
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
context '#content' do
|
34
|
+
it 'should contain proper text' do
|
35
|
+
expect(subject.content).to eq "Joe's shop"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context '#words' do
|
40
|
+
it 'should return proper content' do
|
41
|
+
expect(subject.words).to eq ["Joe's", 'shop']
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
context '#<<' do
|
46
|
+
it 'should accept only Kramdown::Element' do
|
47
|
+
expect { subject << 'p_element' }.to raise_error ArgumentError
|
48
|
+
expect { subject << nil }.to raise_error ArgumentError
|
49
|
+
expect { subject << md_empty_text_element }.not_to raise_error
|
50
|
+
expect { subject << md_empty_quote_element }.not_to raise_error
|
51
|
+
end
|
52
|
+
|
53
|
+
context 'when given text element' do
|
54
|
+
it 'should update content' do
|
55
|
+
subject << md_other_text_element
|
56
|
+
expect(subject.content).to eq "Joe's shop text"
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'when given smart quote element' do
|
61
|
+
let(:lsquo_element) { Kramdown::Element.new(:smart_quote, :lsquo, nil, location: 42) }
|
62
|
+
let(:rsquo_element) { Kramdown::Element.new(:smart_quote, :rsquo, nil, location: 42) }
|
63
|
+
let(:ldquo_element) { Kramdown::Element.new(:smart_quote, :ldquo, nil, location: 42) }
|
64
|
+
let(:rdquo_element) { Kramdown::Element.new(:smart_quote, :rdquo, nil, location: 42) }
|
65
|
+
|
66
|
+
it 'should translate to content properly' do
|
67
|
+
subject << lsquo_element
|
68
|
+
expect(subject.content).to eq "Joe's shop'"
|
69
|
+
subject << ldquo_element
|
70
|
+
expect(subject.content).to eq "Joe's shop'\""
|
71
|
+
subject << rsquo_element
|
72
|
+
expect(subject.content).to eq "Joe's shop'\"'"
|
73
|
+
subject << rdquo_element
|
74
|
+
expect(subject.content).to eq "Joe's shop'\"'\""
|
75
|
+
end
|
76
|
+
|
77
|
+
it 'should properly concatenate words' do
|
78
|
+
subject << md_quote_element
|
79
|
+
subject << md_other_text_element
|
80
|
+
expect(subject.content).to eq "Joe's shop'text"
|
81
|
+
subject << md_other_text_element
|
82
|
+
expect(subject.content).to eq "Joe's shop'text text"
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
context 'when given element from different location' do
|
87
|
+
it 'should not update content' do
|
88
|
+
subject << md_text_element_diff_location
|
89
|
+
expect(subject.content).to eq "Joe's shop"
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
context '::scan' do
|
95
|
+
let(:simple_md) { Kramdown::Document.new(File.read('spec/examples/simple.md'), input: 'GFM') }
|
96
|
+
|
97
|
+
it 'should expect Kramdown::Document as argument' do
|
98
|
+
expect { MdSpell::TextLine.scan }. to raise_error ArgumentError
|
99
|
+
end
|
100
|
+
|
101
|
+
it 'should find proper lines' do
|
102
|
+
lines = MdSpell::TextLine.scan(simple_md)
|
103
|
+
|
104
|
+
expect(lines).to have(3).items
|
105
|
+
|
106
|
+
expect(lines[0].content).to eq 'Simple'
|
107
|
+
expect(lines[1].content).to eq 'markdown'
|
108
|
+
expect(lines[2].content).to eq 'file'
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
describe MdSpell::Typo do
|
2
|
+
let(:text_line) do
|
3
|
+
MdSpell::TextLine.new(Kramdown::Element.new(:text, 'black rabit', nil, location: 42))
|
4
|
+
end
|
5
|
+
let(:misspelled_word) { 'rabit' }
|
6
|
+
let(:suggested_word) { 'rabbit' }
|
7
|
+
|
8
|
+
subject { MdSpell::Typo.new(text_line, misspelled_word, [suggested_word]) }
|
9
|
+
|
10
|
+
context 'attributes' do
|
11
|
+
it { is_expected.to respond_to :line }
|
12
|
+
it { is_expected.to respond_to :word }
|
13
|
+
it { is_expected.to respond_to :suggestions }
|
14
|
+
end
|
15
|
+
|
16
|
+
context '#initialize' do
|
17
|
+
it 'should expect TextLine as first argument' do
|
18
|
+
expect do
|
19
|
+
MdSpell::Typo.new(nil, misspelled_word, [suggested_word])
|
20
|
+
end.to raise_error ArgumentError, 'expected TextLine, got NilClass'
|
21
|
+
|
22
|
+
expect do
|
23
|
+
MdSpell::Typo.new('black rabit', misspelled_word, [suggested_word])
|
24
|
+
end.to raise_error ArgumentError, 'expected TextLine, got String'
|
25
|
+
|
26
|
+
expect do
|
27
|
+
MdSpell::Typo.new(text_line, misspelled_word, [suggested_word])
|
28
|
+
end.not_to raise_error
|
29
|
+
end
|
30
|
+
|
31
|
+
it 'should expect word as second argument' do
|
32
|
+
expect do
|
33
|
+
MdSpell::Typo.new(text_line, nil, [suggested_word])
|
34
|
+
end.to raise_error ArgumentError, 'expected String, got NilClass'
|
35
|
+
|
36
|
+
expect do
|
37
|
+
MdSpell::Typo.new(text_line, :c, [suggested_word])
|
38
|
+
end.to raise_error ArgumentError, 'expected String, got Symbol'
|
39
|
+
|
40
|
+
expect do
|
41
|
+
MdSpell::Typo.new(text_line, misspelled_word, [suggested_word])
|
42
|
+
end.not_to raise_error
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'should expect array as third argument' do
|
46
|
+
expect do
|
47
|
+
MdSpell::Typo.new(text_line, misspelled_word, nil)
|
48
|
+
end.to raise_error ArgumentError, 'expected Array, got NilClass'
|
49
|
+
|
50
|
+
expect do
|
51
|
+
MdSpell::Typo.new(text_line, misspelled_word, 'a')
|
52
|
+
end.to raise_error ArgumentError, 'expected Array, got String'
|
53
|
+
|
54
|
+
expect { MdSpell::Typo.new(text_line, misspelled_word, []) }.not_to raise_error
|
55
|
+
expect do
|
56
|
+
MdSpell::Typo.new(text_line, misspelled_word, [suggested_word])
|
57
|
+
end.not_to raise_error
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
context '#line' do
|
62
|
+
it 'should return proper object' do
|
63
|
+
expect(subject.line).to be text_line
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
context '#word' do
|
68
|
+
it 'should return proper word' do
|
69
|
+
expect(subject.word).to eq misspelled_word
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
context '#suggestions' do
|
74
|
+
it 'should be an array' do
|
75
|
+
expect(subject.suggestions).to be_instance_of Array
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'should return proper items' do
|
79
|
+
expect(subject.suggestions).to have(1).item
|
80
|
+
expect(subject.suggestions).to eq [suggested_word]
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,68 @@
|
|
1
|
+
# Conventionally, all specs live under a `spec` directory, which RSpec adds to the `$LOAD_PATH`.
|
2
|
+
# The generated `.rspec` file contains `--require spec_helper` which will cause this file to always
|
3
|
+
# be loaded, without a need to explicitly require it in any files.
|
4
|
+
#
|
5
|
+
# Given that it is always loaded, keep this file as light-weight as possible. Requiring heavyweight
|
6
|
+
# dependencies from this file will add to the boot time of test suite on EVERY test run, even for
|
7
|
+
# an individual file that may not need all of that loaded. Instead, consider making a separate
|
8
|
+
# helper file that requires the additional dependencies and performs the additional setup,
|
9
|
+
# and require it from the spec files that actually need it.
|
10
|
+
#
|
11
|
+
# The `.rspec` file also contains a few flags that are not defaults but that are commonly wanted.
|
12
|
+
#
|
13
|
+
# See http://rubydoc.info/gems/rspec-core/RSpec/Core/Configuration
|
14
|
+
|
15
|
+
# Setup Code Climate test reporter.
|
16
|
+
require 'codeclimate-test-reporter'
|
17
|
+
|
18
|
+
CodeClimate::TestReporter.start
|
19
|
+
|
20
|
+
# For checking arrays.
|
21
|
+
require 'rspec/collection_matchers'
|
22
|
+
|
23
|
+
# The whole lib is not that big, requiring it here cleans up the specs a little bit.
|
24
|
+
require 'mdspell'
|
25
|
+
|
26
|
+
RSpec.configure do |config|
|
27
|
+
# rspec-expectations config goes here.
|
28
|
+
config.expect_with :rspec do |expectations|
|
29
|
+
# This option will default to `true` in RSpec 4. It makes the `description` and
|
30
|
+
# `failure_message` of custom matchers include text for helper methods defined using
|
31
|
+
# `chain`, e.g.:
|
32
|
+
# be_bigger_than(2).and_smaller_than(4).description
|
33
|
+
# # => "be bigger than 2 and smaller than 4"
|
34
|
+
# ...rather than:
|
35
|
+
# # => "be bigger than 2"
|
36
|
+
expectations.include_chain_clauses_in_custom_matcher_descriptions = true
|
37
|
+
|
38
|
+
# Only allow expect syntax.
|
39
|
+
expectations.syntax = :expect
|
40
|
+
end
|
41
|
+
|
42
|
+
# rspec-mocks config goes here.
|
43
|
+
config.mock_with :rspec do |mocks|
|
44
|
+
# Prevents from mocking or stubbing a method that does not exist on a real object.
|
45
|
+
# This is generally recommended, and will default to `true` in RSpec 4.
|
46
|
+
mocks.verify_partial_doubles = true
|
47
|
+
end
|
48
|
+
|
49
|
+
# Allows RSpec to persist some state between runs in order to support the `--only-failures` and
|
50
|
+
# `--next-failure` CLI options. Source control system should be configured to ignore this file.
|
51
|
+
config.example_status_persistence_file_path = 'spec/examples.cache'
|
52
|
+
|
53
|
+
# Run specs in random order to surface order dependencies. To debug an order dependency after
|
54
|
+
# finding one, fix the order by providing the seed, which is printed after each run.
|
55
|
+
# --seed 1234
|
56
|
+
config.order = :random
|
57
|
+
|
58
|
+
# Seed global randomization in this process using the `--seed` CLI option. Setting this allows
|
59
|
+
# to use `--seed` to deterministically reproduce test failures related to randomization
|
60
|
+
# by passing the same `--seed` value as the one that triggered the failure.
|
61
|
+
Kernel.srand config.seed
|
62
|
+
|
63
|
+
# Allow filtering specs with `focus: true`.
|
64
|
+
config.filter_run focus: true
|
65
|
+
|
66
|
+
# Run all specs if none are filtered.
|
67
|
+
config.run_all_when_everything_filtered = true
|
68
|
+
end
|
metadata
ADDED
@@ -0,0 +1,100 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: mdspell
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Marek Tuchowski
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2015-08-30 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: kramdown
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.8'
|
20
|
+
type: :runtime
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.8'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: ffi-aspell
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '1.1'
|
34
|
+
type: :runtime
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '1.1'
|
41
|
+
description: Check markdown files for spelling errors.
|
42
|
+
email: marek@tuchowski.com.pl
|
43
|
+
executables: []
|
44
|
+
extensions: []
|
45
|
+
extra_rdoc_files:
|
46
|
+
- README.md
|
47
|
+
- LICENSE
|
48
|
+
files:
|
49
|
+
- LICENSE
|
50
|
+
- README.md
|
51
|
+
- bin/mdspell
|
52
|
+
- lib/mdspell.rb
|
53
|
+
- lib/mdspell/cli.rb
|
54
|
+
- lib/mdspell/configuration.rb
|
55
|
+
- lib/mdspell/spell_checker.rb
|
56
|
+
- lib/mdspell/text_line.rb
|
57
|
+
- lib/mdspell/typo.rb
|
58
|
+
- lib/mdspell/version.rb
|
59
|
+
- spec/examples.cache
|
60
|
+
- spec/examples/simple.md
|
61
|
+
- spec/examples/with_errors.md
|
62
|
+
- spec/mdspell/spell_checker_spec.rb
|
63
|
+
- spec/mdspell/text_line_spec.rb
|
64
|
+
- spec/mdspell/typo_spec.rb
|
65
|
+
- spec/spec_helper.rb
|
66
|
+
homepage: https://github.com/mtuchowski/mdspell
|
67
|
+
licenses:
|
68
|
+
- MIT
|
69
|
+
metadata: {}
|
70
|
+
post_install_message:
|
71
|
+
rdoc_options:
|
72
|
+
- "--charset"
|
73
|
+
- UTF-8
|
74
|
+
require_paths:
|
75
|
+
- lib
|
76
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
77
|
+
requirements:
|
78
|
+
- - ">="
|
79
|
+
- !ruby/object:Gem::Version
|
80
|
+
version: 2.0.0
|
81
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
82
|
+
requirements:
|
83
|
+
- - ">="
|
84
|
+
- !ruby/object:Gem::Version
|
85
|
+
version: '0'
|
86
|
+
requirements: []
|
87
|
+
rubyforge_project:
|
88
|
+
rubygems_version: 2.4.8
|
89
|
+
signing_key:
|
90
|
+
specification_version: 4
|
91
|
+
summary: A Ruby markdown spell checking tool.
|
92
|
+
test_files:
|
93
|
+
- spec/spec_helper.rb
|
94
|
+
- spec/examples/with_errors.md
|
95
|
+
- spec/examples/simple.md
|
96
|
+
- spec/mdspell/text_line_spec.rb
|
97
|
+
- spec/mdspell/typo_spec.rb
|
98
|
+
- spec/mdspell/spell_checker_spec.rb
|
99
|
+
- spec/examples.cache
|
100
|
+
has_rdoc:
|