Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP

Loading…

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

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?

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

Xavier Shay
Admin

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

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
Admin

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
Admin

No obvious next action, closing.

Xavier Shay xaviershay closed this
Xavier Shay
Admin

.use method is supported in 2.1.0

James Healy
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
View
@@ -1,4 +1,5 @@
require 'cane/abc_check'
+require 'cane/encoding_check'
require 'cane/style_check'
require 'cane/doc_check'
require 'cane/threshold_check'
@@ -16,6 +17,7 @@ def run(opts)
class Runner
CHECKERS = {
abc: AbcCheck,
+ encoding: EncodingCheck,
style: StyleCheck,
doc: DocCheck,
threshold: ThresholdCheck
9 lib/cane/cli/spec.rb
View
@@ -13,6 +13,7 @@ class Spec
style_glob: '{app,lib,spec}/**/*.rb',
style_measure: '80',
doc_glob: '{app,lib}/**/*.rb',
+ encoding_glob: '{app,lib}/**/*.rb',
max_violations: '0',
}
@@ -26,6 +27,7 @@ def initialize
add_abc_options
add_style_options
add_doc_options
+ add_encoding_options
add_threshold_options
add_cane_options
@@ -66,6 +68,13 @@ def add_abc_options
parser.separator ""
end
+ def add_encoding_options
+ add_option %w(--encoding-glob GLOB), "Glob to run encoding metrics over"
+ add_option %w(--no-encoding), "Disable Encoding checking"
+
+ parser.separator ""
+ end
+
def add_style_options
add_option %w(--style-glob GLOB), "Glob to run style metrics over"
add_option %w(--style-measure VALUE), "Max line length"
7 lib/cane/cli/translator.rb
View
@@ -8,6 +8,7 @@ def to_hash
result = {}
translate_abc_options(result)
translate_doc_options(result)
+ translate_encoding_options(result)
translate_style_options(result)
result[:threshold] = options.fetch(:threshold, [])
@@ -36,6 +37,12 @@ def translate_doc_options(result)
} unless check_disabled(:no_doc, [:doc_glob])
end
+ def translate_encoding_options(result)
+ result[:encoding] = {
+ files: option_with_default(:encoding_glob),
+ } unless check_disabled(:no_encoding, [:encoding_glob])
+ end
+
def check_disabled(check, params)
relevant_options = options.keys & params + [check]
39 lib/cane/encoding_check.rb
View
@@ -0,0 +1,39 @@
+module Cane
+
+ # Creates violations for ruby files that have no encoding marker in the
+ # first two lines
+ class EncodingCheck < Struct.new(:opts)
+ def violations
+ file_names.map { |file_name|
+ find_violations(file_name)
+ }.flatten.compact
+ end
+
+ def find_violations(file_name)
+ data = File.open(file_name, 'r:utf-8')
+ line_one, line_two = *data.lines
+
+ if !line_one.to_s.match(/coding:/) && !line_two.to_s.match(/coding:/)
+ NoEncodingViolation.new(file_name)
+ end
+ end
+
+ def file_names
+ Dir[opts.fetch(:files)]
+ end
+
+ end
+
+ # Value object used by EncodingCheck
+ class NoEncodingViolation < Struct.new(:file_name)
+ def description
+ "Source file missing an encoding marker"
+ end
+
+ def columns
+ [file_name]
+ end
+
+ end
+
+end
6 lib/cane/rake_task.rb
View
@@ -30,6 +30,10 @@ class RakeTask < ::Rake::TaskLib
attr_accessor :doc_glob
# TRUE to disable doc checks
attr_accessor :no_doc
+ # Glob to run encoding checks over (default: "lib/**/*.rb")
+ attr_accessor :encoding_glob
+ # TRUE to disable encoding checks
+ attr_accessor :no_encoding
# Max violations to tolerate (default: 0)
attr_accessor :max_violations
@@ -60,6 +64,8 @@ def options
:abc_max,
:doc_glob,
:no_doc,
+ :encoding_glob,
+ :no_encoding,
:max_violations,
:style_glob,
:no_style,
18 spec/cane_spec.rb
View
@@ -33,7 +33,7 @@ def complex_method(a)
end
RUBY
- _, exitstatus = run("--abc-glob #{file_name} --abc-max 1")
+ _, exitstatus = run("--abc-glob #{file_name} --abc-max 1 --no-encoding")
exitstatus.should == 1
end
@@ -41,7 +41,7 @@ def complex_method(a)
it 'fails if style metrics do not meet requirements' do
file_name = make_file("whitespace ")
- output, exitstatus = run("--style-glob #{file_name}")
+ output, exitstatus = run("--style-glob #{file_name} --no-encoding")
exitstatus.should == 1
output.should include("Lines violated style requirements")
end
@@ -57,7 +57,8 @@ def complex_method(a)
it 'does not include trailing new lines in the character count' do
file_name = make_file('#' * 80 + "\n" + '#' * 80)
- output, exitstatus = run("--style-glob #{file_name} --style-measure 80")
+ options = "--style-glob #{file_name} --style-measure 80 --no-encoding"
+ output, exitstatus = run(options)
exitstatus.should == 0
output.should be_empty
end
@@ -65,7 +66,8 @@ def complex_method(a)
it 'allows upper bound of failed checks' do
file_name = make_file("whitespace ")
- output, exitstatus = run("--style-glob #{file_name} --max-violations 1")
+ options = "--style-glob #{file_name} --max-violations 1 --no-encoding"
+ output, exitstatus = run(options)
exitstatus.should == 0
output.should include("Lines violated style requirements")
end
@@ -86,6 +88,14 @@ def complex_method(a)
output.should include("Classes are not documented")
end
+ it 'allows checking of file encoding markers' do
+ file_name = make_file("puts 'foo'")
+
+ output, exitstatus = run("--encoding-glob #{file_name}")
+ exitstatus.should == 1
+ output.should include("Source file missing an encoding marker")
+ end
+
context 'with a .cane file' do
before(:each) do
file_name = make_file("class NoDoc")
51 spec/encoding_check_spec.rb
View
@@ -0,0 +1,51 @@
+require 'spec_helper'
+
+require 'cane/encoding_check'
+
+describe Cane::EncodingCheck do
+ context "with a source file that has no encoding marker" do
+ let!(:file_name) {
+ make_file <<-RUBY
+puts "chunky bacon"
+ RUBY
+ }
+
+ it 'creates an EncodingViolation' do
+ violations = described_class.new(files: file_name).violations
+ violations.length.should == 1
+
+ violations[0].should be_instance_of(Cane::NoEncodingViolation)
+ violations[0].file_name.should == file_name
+ end
+ end
+
+ context "with a source file that has an encoding marker on line 1" do
+ let!(:file_name) {
+ make_file <<-RUBY
+# coding: utf-8
+puts "chunky bacon"
+ RUBY
+ }
+
+ it 'creates no violationsn' do
+ violations = described_class.new(files: file_name).violations
+ violations.length.should == 0
+ end
+ end
+
+ context "with a source file that has an encoding marker on line 2" do
+ let!(:file_name) {
+ make_file <<-RUBY
+#!/bin/env ruby
+# coding: utf-8
+puts "chunky bacon"
+ RUBY
+ }
+
+ it 'creates no violationsn' do
+ violations = described_class.new(files: file_name).violations
+ violations.length.should == 0
+ end
+ end
+
+end
Something went wrong with that request. Please try again.