sugarcane 0.0.1
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.
- checksums.yaml +7 -0
- data/HISTORY.md +126 -0
- data/LICENSE +14 -0
- data/README.md +235 -0
- data/bin/sugarcane +7 -0
- data/lib/cane.rb +4 -0
- data/lib/sugarcane/abc_check.rb +216 -0
- data/lib/sugarcane/cli/options.rb +30 -0
- data/lib/sugarcane/cli/parser.rb +191 -0
- data/lib/sugarcane/cli.rb +21 -0
- data/lib/sugarcane/default_checks.rb +17 -0
- data/lib/sugarcane/doc_check.rb +156 -0
- data/lib/sugarcane/encoding_aware_iterator.rb +30 -0
- data/lib/sugarcane/ext/array.rb +24 -0
- data/lib/sugarcane/file.rb +30 -0
- data/lib/sugarcane/json_formatter.rb +17 -0
- data/lib/sugarcane/menu.rb +228 -0
- data/lib/sugarcane/rake_task.rb +78 -0
- data/lib/sugarcane/runner.rb +59 -0
- data/lib/sugarcane/style_check.rb +91 -0
- data/lib/sugarcane/task_runner.rb +20 -0
- data/lib/sugarcane/threshold_check.rb +83 -0
- data/lib/sugarcane/version.rb +3 -0
- data/lib/sugarcane/violation_formatter.rb +75 -0
- data/spec/abc_check_spec.rb +164 -0
- data/spec/cane_spec.rb +136 -0
- data/spec/cli_spec.rb +23 -0
- data/spec/doc_check_spec.rb +163 -0
- data/spec/encoding_aware_iterator_spec.rb +32 -0
- data/spec/file_spec.rb +25 -0
- data/spec/json_formatter_spec.rb +10 -0
- data/spec/parser_spec.rb +161 -0
- data/spec/rake_task_spec.rb +68 -0
- data/spec/runner_spec.rb +23 -0
- data/spec/spec_helper.rb +71 -0
- data/spec/style_check_spec.rb +57 -0
- data/spec/threshold_check_spec.rb +101 -0
- data/spec/violation_formatter_spec.rb +38 -0
- data/sugarcane.gemspec +41 -0
- metadata +196 -0
data/spec/parser_spec.rb
ADDED
@@ -0,0 +1,161 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require "stringio"
|
3
|
+
require 'sugarcane/cli/parser'
|
4
|
+
|
5
|
+
describe SugarCane::CLI::Parser do
|
6
|
+
def run(cli_args)
|
7
|
+
result = nil
|
8
|
+
output = StringIO.new("")
|
9
|
+
result = SugarCane::CLI::Parser.new(output).parse(cli_args.split(/\s+/m))
|
10
|
+
|
11
|
+
[output.string, result]
|
12
|
+
end
|
13
|
+
|
14
|
+
it 'allows style options to be configured' do
|
15
|
+
output, result = run("--style-glob myfile --style-measure 3")
|
16
|
+
result[:style_glob].should == 'myfile'
|
17
|
+
result[:style_measure].should == 3
|
18
|
+
end
|
19
|
+
|
20
|
+
it 'allows checking gte of a value in a file' do
|
21
|
+
output, result = run("--gte myfile,90")
|
22
|
+
result[:gte].should == [['myfile', '90']]
|
23
|
+
end
|
24
|
+
|
25
|
+
it 'allows checking eq of a value in a file' do
|
26
|
+
output, result = run("--eq myfile,90")
|
27
|
+
result[:eq].should == [['myfile', '90']]
|
28
|
+
end
|
29
|
+
|
30
|
+
it 'allows checking lte of a value in a file' do
|
31
|
+
output, result = run("--lte myfile,90")
|
32
|
+
result[:lte].should == [['myfile', '90']]
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'allows checking lt of a value in a file' do
|
36
|
+
output, result = run("--lt myfile,90")
|
37
|
+
result[:lt].should == [['myfile', '90']]
|
38
|
+
end
|
39
|
+
|
40
|
+
it 'allows checking gt of a value in a file' do
|
41
|
+
output, resugt = run("--gt myfile,90")
|
42
|
+
resugt[:gt].should == [['myfile', '90']]
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'allows upper bound of failed checks' do
|
46
|
+
output, result = run("--max-violations 1")
|
47
|
+
result[:max_violations].should == 1
|
48
|
+
end
|
49
|
+
|
50
|
+
it 'uses positional arguments as shortcut for individual files' do
|
51
|
+
output, result = run("--all mysinglefile")
|
52
|
+
result[:abc_glob].should == 'mysinglefile'
|
53
|
+
result[:style_glob].should == 'mysinglefile'
|
54
|
+
result[:doc_glob].should == 'mysinglefile'
|
55
|
+
|
56
|
+
output, result = run("--all mysinglefile --abc-glob myotherfile")
|
57
|
+
result[:abc_glob].should == 'myotherfile'
|
58
|
+
result[:style_glob].should == 'mysinglefile'
|
59
|
+
result[:doc_glob].should == 'mysinglefile'
|
60
|
+
end
|
61
|
+
|
62
|
+
it 'displays a help message' do
|
63
|
+
output, result = run("--help")
|
64
|
+
|
65
|
+
result.should be
|
66
|
+
output.should include("Usage:")
|
67
|
+
end
|
68
|
+
|
69
|
+
it 'handles invalid options by showing help' do
|
70
|
+
output, result = run("--bogus")
|
71
|
+
|
72
|
+
output.should include("Usage:")
|
73
|
+
result.should_not be
|
74
|
+
end
|
75
|
+
|
76
|
+
it 'displays version' do
|
77
|
+
output, result = run("--version")
|
78
|
+
|
79
|
+
result.should be
|
80
|
+
output.should include(SugarCane::VERSION)
|
81
|
+
end
|
82
|
+
|
83
|
+
it 'supports exclusions' do
|
84
|
+
options = [
|
85
|
+
"--abc-exclude", "Harness#complex_method",
|
86
|
+
"--doc-exclude", 'myfile',
|
87
|
+
"--style-exclude", 'myfile'
|
88
|
+
].join(' ')
|
89
|
+
|
90
|
+
_, result = run(options)
|
91
|
+
result[:abc_exclude].should == [['Harness#complex_method']]
|
92
|
+
result[:doc_exclude].should == [['myfile']]
|
93
|
+
result[:style_exclude].should == [['myfile']]
|
94
|
+
end
|
95
|
+
|
96
|
+
describe 'argument ordering' do
|
97
|
+
it 'gives precedence to the last argument #1' do
|
98
|
+
_, result = run("--doc-glob myfile --no-doc")
|
99
|
+
result[:no_doc].should be
|
100
|
+
|
101
|
+
_, result = run("--no-doc --doc-glob myfile")
|
102
|
+
result[:no_doc].should_not be
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
it 'loads default options from .sugarcane' do
|
107
|
+
defaults = <<-EOS
|
108
|
+
--no-doc
|
109
|
+
--abc-glob myfile
|
110
|
+
--style-glob myfile
|
111
|
+
EOS
|
112
|
+
|
113
|
+
SugarCane::File.stub(:exists?).with("./.sugarcane").and_return(true)
|
114
|
+
SugarCane::File.stub(:contents).with("./.sugarcane").and_return(defaults)
|
115
|
+
|
116
|
+
_, result = run("--style-glob myotherfile")
|
117
|
+
|
118
|
+
result[:no_doc].should be
|
119
|
+
result[:abc_glob].should == 'myfile'
|
120
|
+
result[:style_glob].should == 'myotherfile'
|
121
|
+
end
|
122
|
+
|
123
|
+
it 'loads default options from .cane if .sugarcane is not present' do
|
124
|
+
defaults = <<-EOS
|
125
|
+
--no-doc
|
126
|
+
--abc-glob myfile
|
127
|
+
--style-glob myfile
|
128
|
+
EOS
|
129
|
+
|
130
|
+
SugarCane::File.stub(:exists?).with("./.sugarcane").and_return(false)
|
131
|
+
SugarCane::File.stub(:exists?).with("./.cane").and_return(true)
|
132
|
+
SugarCane::File.stub(:contents).with("./.cane").and_return(defaults)
|
133
|
+
|
134
|
+
_, result = run("--style-glob myotherfile")
|
135
|
+
|
136
|
+
result[:no_doc].should be
|
137
|
+
result[:abc_glob].should == 'myfile'
|
138
|
+
result[:style_glob].should == 'myotherfile'
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'allows parallel option' do
|
142
|
+
_, result = run("--parallel")
|
143
|
+
result[:parallel].should be
|
144
|
+
end
|
145
|
+
|
146
|
+
it 'handles ambiguous options' do
|
147
|
+
output, result = run("-abc-max")
|
148
|
+
output.should include("Usage:")
|
149
|
+
result.should_not be
|
150
|
+
end
|
151
|
+
|
152
|
+
it 'handles no_readme option' do
|
153
|
+
_, result = run("--no-readme")
|
154
|
+
result[:no_readme].should be
|
155
|
+
end
|
156
|
+
|
157
|
+
it 'handles json option' do
|
158
|
+
_, result = run("--json")
|
159
|
+
result[:json].should be
|
160
|
+
end
|
161
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'sugarcane/rake_task'
|
3
|
+
|
4
|
+
describe SugarCane::RakeTask do
|
5
|
+
it 'enables cane to be configured an run via rake' do
|
6
|
+
fn = make_file("90")
|
7
|
+
my_check = Class.new(Struct.new(:opts)) do
|
8
|
+
def violations
|
9
|
+
[description: 'test', label: opts.fetch(:some_opt)]
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
task = SugarCane::RakeTask.new(:quality) do |cane|
|
14
|
+
cane.no_abc = true
|
15
|
+
cane.no_doc = true
|
16
|
+
cane.no_style = true
|
17
|
+
cane.add_threshold fn, :>=, 99
|
18
|
+
cane.use my_check, some_opt: "theopt"
|
19
|
+
cane.max_violations = 0
|
20
|
+
cane.parallel = false
|
21
|
+
end
|
22
|
+
|
23
|
+
task.no_abc.should == true
|
24
|
+
|
25
|
+
task.should_receive(:abort)
|
26
|
+
out = capture_stdout do
|
27
|
+
Rake::Task['quality'].invoke
|
28
|
+
end
|
29
|
+
|
30
|
+
out.should include("Quality threshold crossed")
|
31
|
+
out.should include("theopt")
|
32
|
+
end
|
33
|
+
|
34
|
+
it 'can be configured using a .cane file' do
|
35
|
+
conf = "--gte 90,99"
|
36
|
+
|
37
|
+
task = SugarCane::RakeTask.new(:canefile_quality) do |cane|
|
38
|
+
cane.canefile = make_file(conf)
|
39
|
+
end
|
40
|
+
|
41
|
+
task.should_receive(:abort)
|
42
|
+
out = capture_stdout do
|
43
|
+
Rake::Task['canefile_quality'].invoke
|
44
|
+
end
|
45
|
+
|
46
|
+
out.should include("Quality threshold crossed")
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'defaults to using a canefile without a block' do
|
50
|
+
in_tmp_dir do
|
51
|
+
conf = "--gte 90,99"
|
52
|
+
File.open('.cane', 'w') {|f| f.write conf }
|
53
|
+
|
54
|
+
task = SugarCane::RakeTask.new(:canefile_quality)
|
55
|
+
|
56
|
+
task.should_receive(:abort)
|
57
|
+
out = capture_stdout do
|
58
|
+
Rake::Task['canefile_quality'].invoke
|
59
|
+
end
|
60
|
+
|
61
|
+
out.should include("Quality threshold crossed")
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
after do
|
66
|
+
Rake::Task.clear
|
67
|
+
end
|
68
|
+
end
|
data/spec/runner_spec.rb
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'sugarcane/runner'
|
3
|
+
|
4
|
+
describe SugarCane::Runner do
|
5
|
+
describe '#run' do
|
6
|
+
it 'returns true iff fewer violations than max allowed' do
|
7
|
+
described_class.new(checks: [], max_violations: 0).run.should be
|
8
|
+
described_class.new(checks: [], max_violations: -1).run.should_not be
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'returns JSON output' do
|
12
|
+
formatter = class_double("SugarCane::JsonFormatter").as_stubbed_const
|
13
|
+
formatter.should_receive(:new).and_return("JSON")
|
14
|
+
buffer = StringIO.new("")
|
15
|
+
|
16
|
+
described_class.new(
|
17
|
+
out: buffer, checks: [], max_violations: 0, json: true
|
18
|
+
).run
|
19
|
+
|
20
|
+
buffer.string.should == "JSON"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,71 @@
|
|
1
|
+
require 'simplecov'
|
2
|
+
require 'coveralls'
|
3
|
+
Coveralls.wear!
|
4
|
+
|
5
|
+
class SimpleCov::Formatter::QualityFormatter
|
6
|
+
def format(result)
|
7
|
+
SimpleCov::Formatter::HTMLFormatter.new.format(result)
|
8
|
+
File.open("tmp/coverage/covered_percent", "w") do |f|
|
9
|
+
f.puts result.source_files.covered_percent.to_i
|
10
|
+
end
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
SimpleCov.formatter = SimpleCov::Formatter::QualityFormatter
|
15
|
+
SimpleCov.start do
|
16
|
+
coverage_dir('tmp/coverage')
|
17
|
+
add_filter "vendor/bundle/"
|
18
|
+
add_filter "spec/"
|
19
|
+
end
|
20
|
+
|
21
|
+
require 'rspec/fire'
|
22
|
+
require 'tempfile'
|
23
|
+
require 'stringio'
|
24
|
+
require 'rake'
|
25
|
+
require 'rake/tasklib'
|
26
|
+
|
27
|
+
RSpec.configure do |config|
|
28
|
+
config.include(RSpec::Fire)
|
29
|
+
|
30
|
+
def capture_stdout &block
|
31
|
+
real_stdout, $stdout = $stdout, StringIO.new
|
32
|
+
yield
|
33
|
+
$stdout.string
|
34
|
+
ensure
|
35
|
+
$stdout = real_stdout
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Keep a reference to all tempfiles so they are not garbage collected until the
|
40
|
+
# process exits.
|
41
|
+
$tempfiles = []
|
42
|
+
|
43
|
+
def make_file(content)
|
44
|
+
tempfile = Tempfile.new('cane')
|
45
|
+
$tempfiles << tempfile
|
46
|
+
tempfile.print(content)
|
47
|
+
tempfile.flush
|
48
|
+
tempfile.path
|
49
|
+
end
|
50
|
+
|
51
|
+
def in_tmp_dir(&block)
|
52
|
+
Dir.mktmpdir do |dir|
|
53
|
+
Dir.chdir(dir, &block)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
RSpec::Matchers.define :have_violation do |label|
|
58
|
+
match do |check|
|
59
|
+
violations = check.violations
|
60
|
+
violations.length.should == 1
|
61
|
+
violations[0][:label].should == label
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
RSpec::Matchers.define :have_no_violations do |label|
|
66
|
+
match do |check|
|
67
|
+
violations = check.violations
|
68
|
+
violations.length.should == 0
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
@@ -0,0 +1,57 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'sugarcane/style_check'
|
3
|
+
|
4
|
+
describe SugarCane::StyleCheck do
|
5
|
+
def check(file_name, opts = {})
|
6
|
+
described_class.new(opts.merge(style_glob: file_name))
|
7
|
+
end
|
8
|
+
|
9
|
+
let(:ruby_with_style_issue) do
|
10
|
+
[
|
11
|
+
"def test ",
|
12
|
+
"\t1",
|
13
|
+
"end"
|
14
|
+
].join("\n")
|
15
|
+
end
|
16
|
+
|
17
|
+
it 'creates a StyleViolation for each method above the threshold' do
|
18
|
+
file_name = make_file(ruby_with_style_issue)
|
19
|
+
|
20
|
+
violations = check(file_name, style_measure: 8).violations
|
21
|
+
violations.length.should == 3
|
22
|
+
end
|
23
|
+
|
24
|
+
it 'skips declared exclusions' do
|
25
|
+
file_name = make_file(ruby_with_style_issue)
|
26
|
+
|
27
|
+
violations = check(file_name,
|
28
|
+
style_measure: 80,
|
29
|
+
style_exclude: [file_name]
|
30
|
+
).violations
|
31
|
+
|
32
|
+
violations.length.should == 0
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'skips declared glob-based exclusions' do
|
36
|
+
file_name = make_file(ruby_with_style_issue)
|
37
|
+
|
38
|
+
violations = check(file_name,
|
39
|
+
style_measure: 80,
|
40
|
+
style_exclude: ["#{File.dirname(file_name)}/*"]
|
41
|
+
).violations
|
42
|
+
|
43
|
+
violations.length.should == 0
|
44
|
+
end
|
45
|
+
|
46
|
+
it 'does not include trailing new lines in the character count' do
|
47
|
+
file_name = make_file('#' * 80 + "\n" + '#' * 80)
|
48
|
+
|
49
|
+
violations = check(file_name,
|
50
|
+
style_measure: 80,
|
51
|
+
style_exclude: [file_name]
|
52
|
+
).violations
|
53
|
+
|
54
|
+
violations.length.should == 0
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'sugarcane/threshold_check'
|
3
|
+
|
4
|
+
describe SugarCane::ThresholdCheck do
|
5
|
+
|
6
|
+
let(:simplecov_last_run) do
|
7
|
+
<<-ENDL
|
8
|
+
{
|
9
|
+
"result": {
|
10
|
+
"covered_percent": 93.88
|
11
|
+
}
|
12
|
+
}
|
13
|
+
ENDL
|
14
|
+
end
|
15
|
+
|
16
|
+
context "checking violations" do
|
17
|
+
|
18
|
+
def run(threshold, value)
|
19
|
+
described_class.new(threshold => [['x', value]])
|
20
|
+
end
|
21
|
+
|
22
|
+
context "when the current coverage cannot be read" do
|
23
|
+
it do
|
24
|
+
run(:gte, 20).should \
|
25
|
+
have_violation('x is unavailable, should be >= 20.0')
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
context "when the coverage threshold is incorrectly specified" do
|
30
|
+
it do
|
31
|
+
described_class.new(gte: [['20', 'bogus_file']]).should \
|
32
|
+
have_violation('bogus_file is not a number or a file')
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
context 'when coverage threshold is valid' do
|
37
|
+
before do
|
38
|
+
file = class_double("SugarCane::File").as_stubbed_const
|
39
|
+
stub_const("SugarCane::File", file)
|
40
|
+
file.should_receive(:contents).with('x').and_return("8\n")
|
41
|
+
end
|
42
|
+
|
43
|
+
context '>' do
|
44
|
+
it { run(:gt, 7).should have_no_violations }
|
45
|
+
it { run(:gt, 8).should have_violation('x is 8.0, should be > 8.0') }
|
46
|
+
it { run(:gt, 9).should have_violation('x is 8.0, should be > 9.0') }
|
47
|
+
end
|
48
|
+
|
49
|
+
context '>=' do
|
50
|
+
it { run(:gte, 7).should have_no_violations }
|
51
|
+
it { run(:gte, 8).should have_no_violations }
|
52
|
+
it { run(:gte, 9).should have_violation('x is 8.0, should be >= 9.0') }
|
53
|
+
end
|
54
|
+
|
55
|
+
context '==' do
|
56
|
+
it { run(:eq, 7).should have_violation('x is 8.0, should be == 7.0') }
|
57
|
+
it { run(:eq, 8).should have_no_violations }
|
58
|
+
it { run(:eq, 9).should have_violation('x is 8.0, should be == 9.0') }
|
59
|
+
end
|
60
|
+
|
61
|
+
context '<=' do
|
62
|
+
it { run(:lte, 7).should have_violation('x is 8.0, should be <= 7.0') }
|
63
|
+
it { run(:lte, 8).should have_no_violations }
|
64
|
+
it { run(:lte, 9).should have_no_violations }
|
65
|
+
end
|
66
|
+
|
67
|
+
context '<' do
|
68
|
+
it { run(:lt, 7).should have_violation('x is 8.0, should be < 7.0') }
|
69
|
+
it { run(:lt, 8).should have_violation('x is 8.0, should be < 8.0') }
|
70
|
+
it { run(:lt, 9).should have_no_violations }
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
end
|
75
|
+
|
76
|
+
context "normalizing a user supplied value to a threshold" do
|
77
|
+
it "normalizes an integer to itself" do
|
78
|
+
subject.normalized_limit(99).should == 99
|
79
|
+
end
|
80
|
+
|
81
|
+
it "normalizes a float to itself" do
|
82
|
+
subject.normalized_limit(99.6).should == 99.6
|
83
|
+
end
|
84
|
+
|
85
|
+
it "normalizes a valid file to its contents" do
|
86
|
+
subject.normalized_limit(make_file('99.5')).should == 99.5
|
87
|
+
end
|
88
|
+
|
89
|
+
it "normalizes an invalid file to an unavailable value" do
|
90
|
+
limit = subject.normalized_limit("/File.does.not.exist")
|
91
|
+
limit.should be_a SugarCane::ThresholdCheck::UnavailableValue
|
92
|
+
end
|
93
|
+
|
94
|
+
|
95
|
+
it 'normalizes a json file to a float' do
|
96
|
+
subject.normalized_limit(make_file(simplecov_last_run)).should == 93.88
|
97
|
+
end
|
98
|
+
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'sugarcane/violation_formatter'
|
3
|
+
|
4
|
+
describe SugarCane::ViolationFormatter do
|
5
|
+
def violation(description)
|
6
|
+
{
|
7
|
+
description: description
|
8
|
+
}
|
9
|
+
end
|
10
|
+
|
11
|
+
it 'includes number of violations in the group header' do
|
12
|
+
described_class.new([violation("FAIL")]).to_s.should include("(1)")
|
13
|
+
end
|
14
|
+
|
15
|
+
it 'includes total number of violations' do
|
16
|
+
violations = [violation("FAIL1"), violation("FAIL2")]
|
17
|
+
result = described_class.new(violations).to_s
|
18
|
+
result.should include("Total Violations: 2")
|
19
|
+
end
|
20
|
+
|
21
|
+
it 'does not colorize output by default' do
|
22
|
+
result = described_class.new([violation("FAIL")]).to_s
|
23
|
+
result.should_not include("\e[31m")
|
24
|
+
end
|
25
|
+
|
26
|
+
it 'colorizes output when passed color: true' do
|
27
|
+
result = described_class.new([violation("FAIL")], color: true).to_s
|
28
|
+
result.should include("\e[31m")
|
29
|
+
result.should include("\e[0m")
|
30
|
+
end
|
31
|
+
|
32
|
+
it 'does not colorize output if max_violations is not crossed' do
|
33
|
+
options = { color: true, max_violations: 1 }
|
34
|
+
result = described_class.new([violation("FAIL")], options).to_s
|
35
|
+
|
36
|
+
result.should_not include("\e[31m")
|
37
|
+
end
|
38
|
+
end
|
data/sugarcane.gemspec
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$LOAD_PATH.unshift File.expand_path('../lib', __FILE__)
|
3
|
+
require 'sugarcane/version'
|
4
|
+
|
5
|
+
Gem::Specification.new do |gem|
|
6
|
+
gem.authors = ["Robert Qualls"]
|
7
|
+
gem.email = ["robert@robertqualls.com"]
|
8
|
+
gem.description = "Cane with a menu that opens a text editor for each issue"
|
9
|
+
gem.summary = %q{
|
10
|
+
Fails your build if code quality thresholds are not met. Provides
|
11
|
+
complexity and style checkers built-in, and allows integration with with
|
12
|
+
custom quality metrics.
|
13
|
+
}
|
14
|
+
gem.homepage = "http://github.com/rlqualls/sugarcane"
|
15
|
+
|
16
|
+
gem.executables = []
|
17
|
+
gem.required_ruby_version = '>= 1.9.0'
|
18
|
+
gem.files = Dir.glob("{spec,lib}/**/*.rb") + %w(
|
19
|
+
README.md
|
20
|
+
HISTORY.md
|
21
|
+
LICENSE
|
22
|
+
sugarcane.gemspec
|
23
|
+
)
|
24
|
+
gem.test_files = Dir.glob("spec/**/*.rb")
|
25
|
+
gem.name = "sugarcane"
|
26
|
+
gem.require_paths = ["lib"]
|
27
|
+
gem.bindir = "bin"
|
28
|
+
gem.executables << "sugarcane"
|
29
|
+
gem.license = "Apache 2.0"
|
30
|
+
gem.version = SugarCane::VERSION
|
31
|
+
gem.has_rdoc = false
|
32
|
+
|
33
|
+
gem.add_dependency 'parallel'
|
34
|
+
gem.add_dependency 'ncursesw'
|
35
|
+
|
36
|
+
gem.add_development_dependency 'rspec', '~> 2.0'
|
37
|
+
gem.add_development_dependency 'rake'
|
38
|
+
gem.add_development_dependency 'simplecov'
|
39
|
+
gem.add_development_dependency 'coveralls'
|
40
|
+
gem.add_development_dependency 'rspec-fire', '~> 1.2.0'
|
41
|
+
end
|