mdspell 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.
@@ -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.
@@ -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.
@@ -0,0 +1,10 @@
1
+ #!/usr/bin/env ruby
2
+ begin
3
+ require 'mdspell'
4
+ rescue LoadError
5
+ # For running in development without bundler
6
+ $LOAD_PATH << File.expand_path('../lib', File.dirname(__FILE__))
7
+ require 'mdspell'
8
+ end
9
+
10
+ MdSpell.run
@@ -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
@@ -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,8 @@
1
+ require 'mixlib/config'
2
+
3
+ module MdSpell
4
+ # Stores configuration from both command line and config file.
5
+ class Configuration
6
+ extend Mixlib::Config
7
+ end
8
+ 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
@@ -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
@@ -0,0 +1,3 @@
1
+ module MdSpell
2
+ VERSION = '0.1.0'
3
+ end
@@ -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,5 @@
1
+ # Simple
2
+
3
+ markdown
4
+
5
+ *file*
@@ -0,0 +1,5 @@
1
+ # This file has mispelled words
2
+
3
+ And qiute few of them actualy.
4
+
5
+ Four tobe precise.
@@ -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
@@ -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: