Checking ends of lines
authorGreg Wilson <gvwilson@third-bit.com>
Thu, 30 Jun 2016 03:16:39 +0000 (23:16 -0400)
committerGreg Wilson <gvwilson@third-bit.com>
Thu, 30 Jun 2016 03:16:39 +0000 (23:16 -0400)
Makefile
bin/lesson_check.py
bin/util.py

index 7b1b1b9710278773c04ac93197913fa6c22698c7..71166297823615ef511eda638c301c55cc02036a 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -11,23 +11,23 @@ DST=_site
 .PHONY : commands clean files
 all : commands
 
-## commands       : show all commands.
+## commands         : show all commands.
 commands :
        @grep -h -E '^##' ${MAKEFILES} | sed -e 's/## //g'
 
-## serve          : run a local server.
+## serve            : run a local server.
 serve : lesson-rmd
        ${JEKYLL} serve --config _config.yml,_config_dev.yml
 
-## site           : build files but do not run a server.
+## site             : build files but do not run a server.
 site : lesson-rmd
        ${JEKYLL} build --config _config.yml,_config_dev.yml
 
-## figures        : re-generate inclusion displaying all figures.
+## figures          : re-generate inclusion displaying all figures.
 figures :
        @bin/extract_figures.py -s _episodes -p ${PARSER} > _includes/all_figures.html
 
-## clean          : clean up junk files.
+## clean            : clean up junk files.
 clean :
        @rm -rf ${DST}
        @rm -rf .sass-cache
@@ -36,7 +36,7 @@ clean :
        @find . -name '*~' -exec rm {} \;
        @find . -name '*.pyc' -exec rm {} \;
 
-## clean-rmd      : clean intermediate R files (that need to be committed to the repo).
+## clean-rmd        : clean intermediate R files (that need to be committed to the repo).
 clear-rmd :
        @rm -rf ${RMD_DST}
        @rm -rf fig/rmd-*
@@ -46,7 +46,7 @@ clear-rmd :
 
 .PHONY : workshop-check
 
-## workshop-check : check workshop homepage.
+## workshop-check   : check workshop homepage.
 workshop-check :
        @bin/workshop_check.py .
 
@@ -79,25 +79,30 @@ HTML_DST = \
   $(patsubst _extras/%.md,${DST}/%/index.html,$(wildcard _extras/*.md)) \
   ${DST}/license/index.html
 
-## lesson-rmd:    : convert Rmarkdown files to markdown
+## lesson-rmd       : convert Rmarkdown files to markdown
 lesson-rmd: $(RMD_SRC)
        @bin/knit_lessons.sh $(RMD_SRC)
 
-## lesson-check   : validate lesson Markdown.
+## lesson-check     : validate lesson Markdown.
 lesson-check :
        @bin/lesson_check.py -s . -p ${PARSER}
 
+## lesson-check-all : validate lesson Markdown, checking line lengths and trailing whitespace.
+lesson-check-all :
+       @bin/lesson_check.py -s . -p ${PARSER} -l -w
+
+## unittest         : run unit tests on checking tools.
 unittest :
        python bin/test_lesson_check.py
 
-## lesson-files   : show expected names of generated files for debugging.
+## lesson-files     : show expected names of generated files for debugging.
 lesson-files :
        @echo 'RMD_SRC:' ${RMD_SRC}
        @echo 'RMD_DST:' ${RMD_DST}
        @echo 'MARKDOWN_SRC:' ${MARKDOWN_SRC}
        @echo 'HTML_DST:' ${HTML_DST}
 
-## lesson-fixme   : show FIXME markers embedded in source files.
+## lesson-fixme     : show FIXME markers embedded in source files.
 lesson-fixme :
        @fgrep -i -n FIXME ${MARKDOWN_SRC} || true
 
index c123984aad2e325770098e9eb7721ed91129f5ae..c85661e649271864c57b6adea0a13baf5b24926d 100755 (executable)
@@ -11,7 +11,7 @@ import json
 import re
 from optparse import OptionParser
 
-from util import Reporter, read_markdown
+from util import Reporter, read_markdown, load_yaml
 
 __version__ = '0.2'
 
@@ -106,7 +106,7 @@ def parse_args():
     parser = OptionParser()
     parser.add_option('-l', '--linelen',
                       default=False,
-                      dest='line_len',
+                      dest='line_lengths',
                       help='Check line lengths')
     parser.add_option('-p', '--parser',
                       default=None,
@@ -116,6 +116,10 @@ def parse_args():
                       default=os.curdir,
                       dest='source_dir',
                       help='source directory')
+    parser.add_option('-w', '--whitespace',
+                      default=False,
+                      dest='trailing_whitespace',
+                      help='Check for trailing whitespace')
 
     args, extras = parser.parse_args()
     require(args.parser is not None,
@@ -227,7 +231,8 @@ class CheckBase(object):
         """Run tests on metadata."""
 
         self.check_metadata()
-        self.check_text()
+        self.check_line_lengths()
+        self.check_trailing_whitespace()
         self.check_blockquote_classes()
         self.check_codeblock_classes()
 
@@ -243,10 +248,10 @@ class CheckBase(object):
             self.reporter.check_field(self.filename, 'metadata', self.metadata, 'layout', self.layout)
 
 
-    def check_text(self):
+    def check_line_lengths(self):
         """Check the raw text of the lesson body."""
 
-        if self.args.line_len:
+        if self.args.line_lengths:
             over = [i for (i, l, n) in self.lines if (n > MAX_LINE_LEN) and (not l.startswith('!'))]
             self.reporter.check(not over,
                                 self.filename,
@@ -254,6 +259,17 @@ class CheckBase(object):
                                 ', '.join([str(i) for i in over]))
 
 
+    def check_trailing_whitespace(self):
+        """Check for whitespace at the ends of lines."""
+
+        if self.args.trailing_whitespace:
+            trailing = [i for (i, l, n) in self.lines if l.endswidth(' ')]
+            self.reporter.check(not trailing,
+                                self.filename,
+                                'Line(s) end with whitespace: {0}',
+                                ', '.join([str[i] for i in over]))
+
+
     def check_blockquote_classes(self):
         """Check that all blockquotes have known classes."""
 
index 6af0a3317061d8663dafad9de41aec2156b7e597..f7aaf2e3fa47606f7ae71f2b75f359aaac952e7e 100644 (file)
@@ -114,9 +114,13 @@ def split_metadata(path, text):
 
 def load_yaml(filename):
     """
-    Wrapper around YAML loading so that 'import yaml' and error
-    handling is only needed in one place.
+    Wrapper around YAML loading so that 'import yaml' is only needed
+    in one file.
     """
 
-    with open(filename, 'r') as reader:
-        return yaml.load(reader)
+    try:
+        with open(filename, 'r') as reader:
+            return yaml.load(reader)
+    except (yaml.YAMLError, FileNotFoundError) as e:
+        print('Unable to load YAML file {0}:\n{1}'.format(filename, e), file=sys.stderr)
+        sys.exit(1)