cane 2.3.0 → 2.4.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.
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