sugarcane 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- 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
|