cane 2.3.0 → 2.4.0

Sign up to get free protection for your applications and to get access to all the features.
data/HISTORY.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # Cane History
2
2
 
3
+ ## 2.4.0 - 21 October 2012 (46949e77)
4
+
5
+ * Feature: Rake task can load configuration from a `.cane` file.
6
+ * Feature: Coverage threshold can be specifed in a file.
7
+ * Feature: Provide `--all` option for working with single files.
8
+ * Bugfix: Allow README file to be lowercase.
9
+
3
10
  ## 2.3.0 - 16 September 2012 (229252ff)
4
11
 
5
12
  * Feature: `--json` option for machine-readable output.
data/README.md CHANGED
@@ -24,7 +24,7 @@ a non-zero exit code if any quality checks fail. Also, a report:
24
24
  lib/cane.rb:20 Line length >80
25
25
  lib/cane.rb:42 Trailing whitespace
26
26
 
27
- Class definitions require explanatory comments on preceeding line (1):
27
+ Class definitions require explanatory comments on preceding line (1):
28
28
  lib/cane:3 SomeClass
29
29
 
30
30
  Customize behaviour with a wealth of options:
@@ -52,6 +52,7 @@ Customize behaviour with a wealth of options:
52
52
 
53
53
  --gte FILE,THRESHOLD If FILE contains a number, verify it is >= to THRESHOLD
54
54
 
55
+ -f, --all FILE Apply all checks to given file
55
56
  --max-violations VALUE Max allowed violations (default: 0)
56
57
  --parallel Use all processors. Slower on small projects, faster on large.
57
58
 
@@ -86,6 +87,9 @@ Command-line arguments will override arguments specified in the `.cane` file.
86
87
  warn "cane not available, quality task not provided."
87
88
  end
88
89
 
90
+ Loading options from a `.cane` file is supported by setting `canefile=` to the
91
+ file name.
92
+
89
93
  Rescuing `LoadError` is a good idea, since `rake -T` failing is totally
90
94
  frustrating.
91
95
 
@@ -28,6 +28,7 @@ module Cane
28
28
  Cane.default_checks.each do |check|
29
29
  add_check_options(check)
30
30
  end
31
+ add_checks_shortcut
31
32
 
32
33
  add_cane_options
33
34
 
@@ -48,8 +49,12 @@ module Cane
48
49
  end
49
50
 
50
51
  def get_default_options
51
- if Cane::File.exists?('./.cane')
52
- Cane::File.contents('./.cane').split(/\s+/m)
52
+ read_options_from_file './.cane'
53
+ end
54
+
55
+ def read_options_from_file(file)
56
+ if Cane::File.exists?(file)
57
+ Cane::File.contents(file).split(/\s+/m)
53
58
  else
54
59
  []
55
60
  end
@@ -116,6 +121,17 @@ BANNER
116
121
  parser.separator ""
117
122
  end
118
123
 
124
+ def add_checks_shortcut
125
+ description = "Apply all checks to given file"
126
+ parser.on("-f", "--all FILE", description) do |f|
127
+ # This is a bit of a hack, but provides a really useful UI for
128
+ # dealing with single files. Let's see how it evolves.
129
+ options[:abc_glob] = f
130
+ options[:style_glob] = f
131
+ options[:doc_glob] = f
132
+ end
133
+ end
134
+
119
135
  def add_version
120
136
  parser.on_tail("-v", "--version", "Show version") do
121
137
  stdout.puts Cane::VERSION
@@ -4,11 +4,11 @@ require 'cane/task_runner'
4
4
  module Cane
5
5
 
6
6
  # Creates violations for class definitions that do not have an explantory
7
- # comment immediately preceeding.
7
+ # comment immediately preceding.
8
8
  class DocCheck < Struct.new(:opts)
9
9
 
10
10
  DESCRIPTION =
11
- "Class definitions require explanatory comments on preceeding line"
11
+ "Class definitions require explanatory comments on preceding line"
12
12
 
13
13
  def self.key; :doc; end
14
14
  def self.name; "documentation checking"; end
@@ -54,13 +54,15 @@ module Cane
54
54
 
55
55
  def missing_file_violations
56
56
  result = []
57
- unless opts[:no_readme]
58
- unless ['', '.txt', '.md'].any? {|x| Cane::File.exists?("README#{x}") }
59
- result << {
60
- description: 'Missing documentation',
61
- label: 'No README found'
62
- }
63
- end
57
+ return result if opts[:no_readme]
58
+
59
+ filenames = ['README', 'readme']
60
+ extensions = ['', '.txt', '.md']
61
+ combinations = filenames.product(extensions)
62
+
63
+ if combinations.none? {|n, x| Cane::File.exists?(n + x) }
64
+ result << { description: 'Missing documentation',
65
+ label: 'No README found' }
64
66
  end
65
67
  result
66
68
  end
@@ -2,6 +2,7 @@ require 'rake'
2
2
  require 'rake/tasklib'
3
3
 
4
4
  require 'cane/cli/options'
5
+ require 'cane/cli/parser'
5
6
 
6
7
  module Cane
7
8
  # Creates a rake task to run cane with given configuration.
@@ -42,6 +43,12 @@ module Cane
42
43
  @options[:checks] = @options[:checks] + [check]
43
44
  end
44
45
 
46
+ def canefile=(file)
47
+ canefile = Cane::CLI::Parser.new
48
+ canefile.parser.parse!(canefile.read_options_from_file(file))
49
+ options.merge! canefile.options
50
+ end
51
+
45
52
  def initialize(task_name = nil)
46
53
  self.name = task_name || :cane
47
54
  @gte = []
@@ -9,17 +9,26 @@ module Cane
9
9
  def self.key; :threshold; end
10
10
  def self.options
11
11
  {
12
- gte: ["If FILE contains a number, verify it is >= to THRESHOLD",
12
+ gte: ["Check the number in FILE is >= to THRESHOLD " +
13
+ "(a number or another file name)",
13
14
  variable: "FILE,THRESHOLD",
14
15
  type: Array]
15
16
  }
16
17
  end
17
18
 
18
19
  def violations
19
- thresholds.map do |operator, file, limit|
20
- value = value_from_file(file)
20
+ thresholds.map do |operator, file, threshold|
21
+ value = normalized_limit(file)
22
+ limit = normalized_limit(threshold)
21
23
 
22
- unless value.send(operator, limit.to_f)
24
+ if !limit.real?
25
+ {
26
+ description: 'Quality threshold could not be read',
27
+ label: "%s is not a number or a file" % [
28
+ threshold
29
+ ]
30
+ }
31
+ elsif !value.send(operator, limit)
23
32
  {
24
33
  description: 'Quality threshold crossed',
25
34
  label: "%s is %s, should be %s %s" % [
@@ -30,6 +39,12 @@ module Cane
30
39
  end.compact
31
40
  end
32
41
 
42
+ def normalized_limit(limit)
43
+ Float(limit)
44
+ rescue ArgumentError
45
+ value_from_file(limit)
46
+ end
47
+
33
48
  def value_from_file(file)
34
49
  begin
35
50
  contents = Cane::File.contents(file).chomp.to_f
@@ -49,6 +64,7 @@ module Cane
49
64
  class UnavailableValue
50
65
  def >=(_); false end
51
66
  def to_s; 'unavailable' end
67
+ def real?; false; end
52
68
  end
53
69
  end
54
70
 
@@ -1,3 +1,3 @@
1
1
  module Cane
2
- VERSION = '2.3.0'
2
+ VERSION = '2.4.0'
3
3
  end
@@ -60,6 +60,9 @@ class Doc; end
60
60
  file.should_receive(:exists?).with("README").and_return(false)
61
61
  file.should_receive(:exists?).with("README.md").and_return(false)
62
62
  file.should_receive(:exists?).with("README.txt").and_return(false)
63
+ file.should_receive(:exists?).with("readme").and_return(false)
64
+ file.should_receive(:exists?).with("readme.md").and_return(false)
65
+ file.should_receive(:exists?).with("readme.txt").and_return(false)
63
66
 
64
67
  violations = check("").violations
65
68
  violations.length.should == 1
@@ -27,6 +27,18 @@ describe Cane::CLI::Parser do
27
27
  result[:max_violations].should == 1
28
28
  end
29
29
 
30
+ it 'uses positional arguments as shortcut for individual files' do
31
+ output, result = run("--all mysinglefile")
32
+ result[:abc_glob].should == 'mysinglefile'
33
+ result[:style_glob].should == 'mysinglefile'
34
+ result[:doc_glob].should == 'mysinglefile'
35
+
36
+ output, result = run("--all mysinglefile --abc-glob myotherfile")
37
+ result[:abc_glob].should == 'myotherfile'
38
+ result[:style_glob].should == 'mysinglefile'
39
+ result[:doc_glob].should == 'mysinglefile'
40
+ end
41
+
30
42
  it 'displays a help message' do
31
43
  output, result = run("--help")
32
44
 
@@ -32,6 +32,21 @@ describe Cane::RakeTask do
32
32
  out.should include("theopt")
33
33
  end
34
34
 
35
+ it 'can be configured using a .cane file' do
36
+ conf = "--gte 90,99"
37
+
38
+ task = Cane::RakeTask.new(:canefile_quality) do |cane|
39
+ cane.canefile = make_file(conf)
40
+ end
41
+
42
+ task.should_receive(:abort)
43
+ out = capture_stdout do
44
+ Rake::Task['canefile_quality'].invoke
45
+ end
46
+
47
+ out.should include("Quality threshold crossed")
48
+ end
49
+
35
50
  after do
36
51
  Rake::Task.clear
37
52
  end
@@ -3,11 +3,48 @@ require 'spec_helper'
3
3
  require 'cane/threshold_check'
4
4
 
5
5
  describe Cane::ThresholdCheck do
6
- it 'returns a value of unavailable when file cannot be read' do
7
- check = Cane::ThresholdCheck.new(gte: [['bogus_file', 20]])
8
- violations = check.violations
9
- violations.length.should == 1
10
- violations[0][:label].should ==
11
- 'bogus_file is unavailable, should be >= 20'
6
+
7
+ context "checking violations" do
8
+
9
+ context "when the current coverage cannot be read" do
10
+ it 'reports a violation' do
11
+ check = Cane::ThresholdCheck.new(gte: [['bogus_file', '20']])
12
+ violations = check.violations
13
+ violations.length.should == 1
14
+ violations[0][:label].should ==
15
+ 'bogus_file is unavailable, should be >= 20.0'
16
+ end
17
+ end
18
+
19
+ context "when the coverage threshold is incorrectly specified" do
20
+ it 'reports a violation' do
21
+ check = Cane::ThresholdCheck.new(gte: [['20', 'bogus_file']])
22
+ violations = check.violations
23
+ violations.length.should == 1
24
+ violations[0][:label].should ==
25
+ 'bogus_file is not a number or a file'
26
+ end
27
+ end
28
+
29
+ end
30
+
31
+ context "normalizing a user supplied value to a threshold" do
32
+ it "normalizes an integer to itself" do
33
+ subject.normalized_limit(99).should == 99
34
+ end
35
+
36
+ it "normalizes a float to itself" do
37
+ subject.normalized_limit(99.6).should == 99.6
38
+ end
39
+
40
+ it "normalizes a valid file to its contents" do
41
+ subject.normalized_limit(make_file('99.5')).should == 99.5
42
+ end
43
+
44
+ it "normalizes an invalid file to an unavailable value" do
45
+ limit = subject.normalized_limit("/File.does.not.exist")
46
+ limit.should be_a Cane::ThresholdCheck::UnavailableValue
47
+ end
12
48
  end
49
+
13
50
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: cane
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.3.0
4
+ version: 2.4.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-09-16 00:00:00.000000000 Z
12
+ date: 2012-10-21 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: parallel
@@ -154,7 +154,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
154
154
  version: '0'
155
155
  requirements: []
156
156
  rubyforge_project:
157
- rubygems_version: 1.8.24
157
+ rubygems_version: 1.8.23
158
158
  signing_key:
159
159
  specification_version: 3
160
160
  summary: Fails your build if code quality thresholds are not met. Provides complexity