Skip to content
This repository

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

New Check: all ruby files should have an encoding marker #15

Closed
wants to merge 2 commits into from

2 participants

James Healy Xavier Shay
James Healy
yob commented June 17, 2012

I have a project where team style dictates that every ruby file should have an encoding marker.

This is admittedly not something every team wants and wouldn't be a good default check.

Implementing the check was straight forward ( cf7e549 ), however I was surprised at the size of the subsequent commit that wired it into cane ( ba85d41 ).

What do you think about an addition to the rake task that allows teams to load custom checks? Something like:

 Cane::RakeTask.new(:cane) do |cane|
   cane.use EncodingCheck.new
   cane.use MethodLengthCheck.new(15)
   cane.use ObscureTeamCheck.new
   cane.use FilteredParamsCheck.new
 end

end

Xavier Shay

sorry I try to keep my code bases vegan :P

Xavier Shay

The idea of the run method was to provide a place to default everything to off. Could --no-coding be moved there?

Owner

Actually I think I'd want --no-encoding to be the default behaviour, since AFAIK not many teams enforce this style.

Xavier Shay
Owner

Yeah you're right, wiring in new things is kind of insane. Maybe there is a way to combine your use suggestion (which I like) with a way to also set up the right command line params, documentation, etc...

James Healy
yob commented June 17, 2012

I'm not seriously proposing EncodingCheck for merging upstream, it was mostly to provide code and context for my 'use' suggestion.

The one problem with it is how to support the command line. Is that what you're referring to with "a way to also set up the right command line params, documentation"?

Xavier Shay
Owner

Yeah, I was thinking something like:

class EncodingCheck
  def self.command_line_options
    # Returns some meta data sufficient to specify command line options and rake task
    {}
  end
end

Then the CLI class can just iterate through all known checks and pull the meta data off them. That way, implementing a new check is all confined to the one class, rather than having to sprinkle things throughout the code base. Maybe it's simpler not even to go the meta data route, instead just call EncodingCheck.translate_cli_options(options). I'd have to play with it.

Xavier Shay
Owner

No obvious next action, closing.

Xavier Shay xaviershay closed this August 01, 2012
Xavier Shay
Owner

.use method is supported in 2.1.0

James Healy
yob commented August 26, 2012
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
This page is out of date. Refresh to see the latest.
2  lib/cane.rb
... ...
@@ -1,4 +1,5 @@
1 1
 require 'cane/abc_check'
  2
+require 'cane/encoding_check'
2 3
 require 'cane/style_check'
3 4
 require 'cane/doc_check'
4 5
 require 'cane/threshold_check'
@@ -16,6 +17,7 @@ def run(opts)
16 17
   class Runner
17 18
     CHECKERS = {
18 19
       abc:       AbcCheck,
  20
+      encoding:  EncodingCheck,
19 21
       style:     StyleCheck,
20 22
       doc:       DocCheck,
21 23
       threshold: ThresholdCheck
9  lib/cane/cli/spec.rb
@@ -13,6 +13,7 @@ class Spec
13 13
         style_glob:     '{app,lib,spec}/**/*.rb',
14 14
         style_measure:  '80',
15 15
         doc_glob:       '{app,lib}/**/*.rb',
  16
+        encoding_glob:  '{app,lib}/**/*.rb',
16 17
         max_violations: '0',
17 18
       }
18 19
 
@@ -26,6 +27,7 @@ def initialize
26 27
         add_abc_options
27 28
         add_style_options
28 29
         add_doc_options
  30
+        add_encoding_options
29 31
         add_threshold_options
30 32
         add_cane_options
31 33
 
@@ -66,6 +68,13 @@ def add_abc_options
66 68
         parser.separator ""
67 69
       end
68 70
 
  71
+      def add_encoding_options
  72
+        add_option %w(--encoding-glob GLOB), "Glob to run encoding metrics over"
  73
+        add_option %w(--no-encoding), "Disable Encoding checking"
  74
+
  75
+        parser.separator ""
  76
+      end
  77
+
69 78
       def add_style_options
70 79
         add_option %w(--style-glob GLOB), "Glob to run style metrics over"
71 80
         add_option %w(--style-measure VALUE), "Max line length"
7  lib/cane/cli/translator.rb
@@ -8,6 +8,7 @@ def to_hash
8 8
         result = {}
9 9
         translate_abc_options(result)
10 10
         translate_doc_options(result)
  11
+        translate_encoding_options(result)
11 12
         translate_style_options(result)
12 13
 
13 14
         result[:threshold] = options.fetch(:threshold, [])
@@ -36,6 +37,12 @@ def translate_doc_options(result)
36 37
         } unless check_disabled(:no_doc, [:doc_glob])
37 38
       end
38 39
 
  40
+      def translate_encoding_options(result)
  41
+        result[:encoding] = {
  42
+          files: option_with_default(:encoding_glob),
  43
+        } unless check_disabled(:no_encoding, [:encoding_glob])
  44
+      end
  45
+
39 46
       def check_disabled(check, params)
40 47
         relevant_options = options.keys & params + [check]
41 48
 
39  lib/cane/encoding_check.rb
... ...
@@ -0,0 +1,39 @@
  1
+module Cane
  2
+
  3
+  # Creates violations for ruby files that have no encoding marker in the
  4
+  # first two lines
  5
+  class EncodingCheck < Struct.new(:opts)
  6
+    def violations
  7
+      file_names.map { |file_name|
  8
+        find_violations(file_name)
  9
+      }.flatten.compact
  10
+    end
  11
+
  12
+    def find_violations(file_name)
  13
+      data = File.open(file_name, 'r:utf-8')
  14
+      line_one, line_two = *data.lines
  15
+
  16
+      if !line_one.to_s.match(/coding:/) && !line_two.to_s.match(/coding:/)
  17
+        NoEncodingViolation.new(file_name)
  18
+      end
  19
+    end
  20
+
  21
+    def file_names
  22
+      Dir[opts.fetch(:files)]
  23
+    end
  24
+
  25
+  end
  26
+
  27
+  # Value object used by EncodingCheck
  28
+  class NoEncodingViolation < Struct.new(:file_name)
  29
+    def description
  30
+      "Source file missing an encoding marker"
  31
+    end
  32
+
  33
+    def columns
  34
+      [file_name]
  35
+    end
  36
+
  37
+  end
  38
+
  39
+end
6  lib/cane/rake_task.rb
@@ -30,6 +30,10 @@ class RakeTask < ::Rake::TaskLib
30 30
     attr_accessor :doc_glob
31 31
     # TRUE to disable doc checks
32 32
     attr_accessor :no_doc
  33
+    # Glob to run encoding checks over (default: "lib/**/*.rb")
  34
+    attr_accessor :encoding_glob
  35
+    # TRUE to disable encoding checks
  36
+    attr_accessor :no_encoding
33 37
     # Max violations to tolerate (default: 0)
34 38
     attr_accessor :max_violations
35 39
 
@@ -60,6 +64,8 @@ def options
60 64
         :abc_max,
61 65
         :doc_glob,
62 66
         :no_doc,
  67
+        :encoding_glob,
  68
+        :no_encoding,
63 69
         :max_violations,
64 70
         :style_glob,
65 71
         :no_style,
18  spec/cane_spec.rb
@@ -33,7 +33,7 @@ def complex_method(a)
33 33
       end
34 34
     RUBY
35 35
 
36  
-    _, exitstatus = run("--abc-glob #{file_name} --abc-max 1")
  36
+    _, exitstatus = run("--abc-glob #{file_name} --abc-max 1 --no-encoding")
37 37
 
38 38
     exitstatus.should == 1
39 39
   end
@@ -41,7 +41,7 @@ def complex_method(a)
41 41
   it 'fails if style metrics do not meet requirements' do
42 42
     file_name = make_file("whitespace ")
43 43
 
44  
-    output, exitstatus = run("--style-glob #{file_name}")
  44
+    output, exitstatus = run("--style-glob #{file_name} --no-encoding")
45 45
     exitstatus.should == 1
46 46
     output.should include("Lines violated style requirements")
47 47
   end
@@ -57,7 +57,8 @@ def complex_method(a)
57 57
   it 'does not include trailing new lines in the character count' do
58 58
     file_name = make_file('#' * 80 + "\n" + '#' * 80)
59 59
 
60  
-    output, exitstatus = run("--style-glob #{file_name} --style-measure 80")
  60
+    options = "--style-glob #{file_name} --style-measure 80 --no-encoding"
  61
+    output, exitstatus = run(options)
61 62
     exitstatus.should == 0
62 63
     output.should be_empty
63 64
   end
@@ -65,7 +66,8 @@ def complex_method(a)
65 66
   it 'allows upper bound of failed checks' do
66 67
     file_name = make_file("whitespace ")
67 68
 
68  
-    output, exitstatus = run("--style-glob #{file_name} --max-violations 1")
  69
+    options = "--style-glob #{file_name} --max-violations 1 --no-encoding"
  70
+    output, exitstatus = run(options)
69 71
     exitstatus.should == 0
70 72
     output.should include("Lines violated style requirements")
71 73
   end
@@ -86,6 +88,14 @@ def complex_method(a)
86 88
     output.should include("Classes are not documented")
87 89
   end
88 90
 
  91
+  it 'allows checking of file encoding markers' do
  92
+    file_name = make_file("puts 'foo'")
  93
+
  94
+    output, exitstatus = run("--encoding-glob #{file_name}")
  95
+    exitstatus.should == 1
  96
+    output.should include("Source file missing an encoding marker")
  97
+  end
  98
+
89 99
   context 'with a .cane file' do
90 100
     before(:each) do
91 101
       file_name = make_file("class NoDoc")
51  spec/encoding_check_spec.rb
... ...
@@ -0,0 +1,51 @@
  1
+require 'spec_helper'
  2
+
  3
+require 'cane/encoding_check'
  4
+
  5
+describe Cane::EncodingCheck do
  6
+  context "with a source file that has no encoding marker" do
  7
+    let!(:file_name) {
  8
+      make_file <<-RUBY
  9
+puts "chunky bacon"
  10
+      RUBY
  11
+    }
  12
+
  13
+    it 'creates an EncodingViolation' do
  14
+      violations = described_class.new(files: file_name).violations
  15
+      violations.length.should == 1
  16
+
  17
+      violations[0].should be_instance_of(Cane::NoEncodingViolation)
  18
+      violations[0].file_name.should == file_name
  19
+    end
  20
+  end
  21
+
  22
+  context "with a source file that has an encoding marker on line 1" do
  23
+    let!(:file_name) {
  24
+      make_file <<-RUBY
  25
+# coding: utf-8
  26
+puts "chunky bacon"
  27
+      RUBY
  28
+    }
  29
+
  30
+    it 'creates no violationsn' do
  31
+      violations = described_class.new(files: file_name).violations
  32
+      violations.length.should == 0
  33
+    end
  34
+  end
  35
+
  36
+  context "with a source file that has an encoding marker on line 2" do
  37
+    let!(:file_name) {
  38
+      make_file <<-RUBY
  39
+#!/bin/env ruby
  40
+# coding: utf-8
  41
+puts "chunky bacon"
  42
+      RUBY
  43
+    }
  44
+
  45
+    it 'creates no violationsn' do
  46
+      violations = described_class.new(files: file_name).violations
  47
+      violations.length.should == 0
  48
+    end
  49
+  end
  50
+
  51
+end
Commit_comment_tip

Tip: You can add notes to lines in a file. Hover to the left of a line to make a note

Something went wrong with that request. Please try again.