pelusa 0.0.2 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.pelusa.yml +1 -0
- data/.rvmrc +2 -1
- data/Readme.md +4 -3
- data/lib/pelusa.rb +10 -1
- data/lib/pelusa/cli.rb +3 -1
- data/lib/pelusa/configuration.rb +84 -0
- data/lib/pelusa/lint.rb +3 -0
- data/lib/pelusa/lint/case_statements.rb +35 -0
- data/lib/pelusa/lint/indentation_level.rb +5 -1
- data/lib/pelusa/lint/instance_variables.rb +1 -1
- data/lib/pelusa/lint/line_restriction.rb +1 -1
- data/lib/pelusa/lint/many_arguments.rb +42 -0
- data/lib/pelusa/version.rb +1 -1
- data/test/fixtures/sample_config_one.yml +7 -0
- data/test/pelusa/configuration_test.rb +56 -0
- data/test/pelusa/lint/case_statements_test.rb +43 -0
- data/test/pelusa/lint/indentation_level_test.rb +20 -0
- data/test/pelusa/lint/many_arguments_test.rb +47 -0
- data/test/test_helper.rb +2 -0
- metadata +15 -4
data/.pelusa.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
sources: lib/**/*.rb
|
data/.rvmrc
CHANGED
@@ -1 +1,2 @@
|
|
1
|
-
rvm use rbx
|
1
|
+
rvm use --create rbx@pelusa
|
2
|
+
RBXOPT="$RBXOPT -X19"
|
data/Readme.md
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
# pelusa -
|
1
|
+
# pelusa - /pe 'lu sa/ [![Build Status](https://secure.travis-ci.org/codegram/pelusa.png)](http://travis-ci.org/codegram/pelusa) [![Dependency Status](https://gemnasium.com/codegram/pelusa.png)](https://gemnasium.com/codegram/pelusa)
|
2
|
+
## A Ruby Lint to improve your OO skills
|
2
3
|
|
3
4
|
Pelusa is a static analysis tool and framework to inspect your code style and
|
4
5
|
notify you about possible red flags or missing best practices.
|
@@ -20,9 +21,9 @@ Here's a sample of pelusa linting on its own code base:
|
|
20
21
|
Pelusa happens to be Spanish for the word "Lint". Yeah, I couldn't believe it
|
21
22
|
either.
|
22
23
|
|
23
|
-
##
|
24
|
+
## Installation and usage
|
24
25
|
|
25
|
-
rvm use rbx
|
26
|
+
rvm use rbx
|
26
27
|
gem install pelusa
|
27
28
|
|
28
29
|
To run pelusa, you must run Rubinius in 1.9 mode. To do this, export this
|
data/lib/pelusa.rb
CHANGED
@@ -2,12 +2,21 @@ module Pelusa
|
|
2
2
|
# Public: Runs the runner on a set of files.
|
3
3
|
#
|
4
4
|
# Returns an Array of results of a given Reporter
|
5
|
-
def self.run(files=[], reporter=StdoutReporter
|
5
|
+
def self.run(files=[], reporter=StdoutReporter)
|
6
|
+
lints = configuration.enabled_lints
|
6
7
|
runner = Runner.new(lints, reporter)
|
7
8
|
runner.run(files)
|
8
9
|
end
|
10
|
+
|
11
|
+
# Return configuration
|
12
|
+
def self.configuration
|
13
|
+
@configuration ||= Configuration.new
|
14
|
+
end
|
9
15
|
end
|
10
16
|
|
17
|
+
require 'yaml'
|
18
|
+
|
19
|
+
require 'pelusa/configuration'
|
11
20
|
require 'pelusa/cli'
|
12
21
|
require 'pelusa/runner'
|
13
22
|
require 'pelusa/analyzer'
|
data/lib/pelusa/cli.rb
CHANGED
@@ -21,7 +21,9 @@ module Pelusa
|
|
21
21
|
if glob = @args.detect { |arg| arg =~ /\*/ }
|
22
22
|
return Dir[glob]
|
23
23
|
end
|
24
|
-
@args.select { |arg| arg =~ /\.rb/ }
|
24
|
+
_files = @args.select { |arg| arg =~ /\.rb/ }
|
25
|
+
_files = Dir[Pelusa.configuration.sources] if _files.empty?
|
26
|
+
_files
|
25
27
|
end
|
26
28
|
end
|
27
29
|
end
|
@@ -0,0 +1,84 @@
|
|
1
|
+
module Pelusa
|
2
|
+
# Public: Class providing configuration for the runner and lints
|
3
|
+
#
|
4
|
+
# Examples
|
5
|
+
#
|
6
|
+
# configuration = Pelusa::Configuration.new('my_pelusa_config.yml')
|
7
|
+
# configuration.present? # => true
|
8
|
+
#
|
9
|
+
class Configuration
|
10
|
+
YAML_PATH = './.pelusa.yml'
|
11
|
+
|
12
|
+
# Public: Initializes a configuration instance
|
13
|
+
#
|
14
|
+
# yaml_path - optional path to the configuration file
|
15
|
+
def initialize(yaml_path = YAML_PATH)
|
16
|
+
if File.exist?(yaml_path)
|
17
|
+
@_configuration = YAML.load_file(yaml_path).freeze
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
# Public: Returns if a custom configuration is present
|
22
|
+
#
|
23
|
+
# Examples
|
24
|
+
#
|
25
|
+
# Pelusa.configuration.present? # => true
|
26
|
+
#
|
27
|
+
def present?
|
28
|
+
not @_configuration.nil?
|
29
|
+
end
|
30
|
+
|
31
|
+
# Public: Returns custom configuration for the given lint
|
32
|
+
#
|
33
|
+
# Examples
|
34
|
+
#
|
35
|
+
# Pelusa.configuration['LineRestriction'] # => {'limit' => 50}
|
36
|
+
#
|
37
|
+
# name - the name of the lint
|
38
|
+
def [](name)
|
39
|
+
for_lint(name)
|
40
|
+
end
|
41
|
+
|
42
|
+
# Public: Returns path to sources that should be analyzed
|
43
|
+
#
|
44
|
+
# Examples
|
45
|
+
#
|
46
|
+
# Pelusa.configuration.sources # => lib/**/*.rb
|
47
|
+
#
|
48
|
+
def sources
|
49
|
+
@_configuration['sources']
|
50
|
+
end
|
51
|
+
|
52
|
+
# Public: Returns an Array of enabled lints
|
53
|
+
#
|
54
|
+
# Examples
|
55
|
+
#
|
56
|
+
# Pelusa.configuration.enabled_lints # => [ Pelusa::Lint::DemeterLaw ]
|
57
|
+
#
|
58
|
+
def enabled_lints
|
59
|
+
(Lint.all - disabled_lints).uniq
|
60
|
+
end
|
61
|
+
|
62
|
+
#######
|
63
|
+
private
|
64
|
+
#######
|
65
|
+
|
66
|
+
# Private: Returns a Hash of configuration for lints
|
67
|
+
def lints
|
68
|
+
@_configuration.fetch('lints', {})
|
69
|
+
end
|
70
|
+
|
71
|
+
# Private: Returns an Array of lints disabled in the configuration
|
72
|
+
def disabled_lints
|
73
|
+
lints.select { |lint, conf| conf['enabled'] === false }.map do |lint,|
|
74
|
+
Lint.const_get(lint)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
# Private: Public: Returns custom configuration for the given lint
|
79
|
+
def for_lint(name)
|
80
|
+
lints.fetch(name, {})
|
81
|
+
end
|
82
|
+
|
83
|
+
end # class Configuration
|
84
|
+
end # module Pelusa
|
data/lib/pelusa/lint.rb
CHANGED
@@ -7,6 +7,8 @@ require 'pelusa/lint/else_clauses'
|
|
7
7
|
require 'pelusa/lint/properties'
|
8
8
|
require 'pelusa/lint/collection_wrappers'
|
9
9
|
require 'pelusa/lint/short_identifiers'
|
10
|
+
require 'pelusa/lint/case_statements'
|
11
|
+
require 'pelusa/lint/many_arguments'
|
10
12
|
|
11
13
|
module Pelusa
|
12
14
|
# Public: A Lint is a quality standard, applicable on a given piece of code to
|
@@ -23,6 +25,7 @@ module Pelusa
|
|
23
25
|
Properties,
|
24
26
|
CollectionWrappers,
|
25
27
|
ShortIdentifiers,
|
28
|
+
ManyArguments
|
26
29
|
]
|
27
30
|
end
|
28
31
|
end
|
@@ -0,0 +1,35 @@
|
|
1
|
+
module Pelusa
|
2
|
+
module Lint
|
3
|
+
class CaseStatements
|
4
|
+
def initialize
|
5
|
+
@violations = Set.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def check(klass)
|
9
|
+
initialize
|
10
|
+
iterate_lines!(klass)
|
11
|
+
|
12
|
+
return SuccessfulAnalysis.new(name) if @violations.empty?
|
13
|
+
|
14
|
+
FailedAnalysis.new(name, @violations) do |violations|
|
15
|
+
"There are #{violations.length} case statements in lines #{violations.to_a.join(', ')}"
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
private
|
20
|
+
|
21
|
+
def name
|
22
|
+
"Doesn't use case statements"
|
23
|
+
end
|
24
|
+
|
25
|
+
def iterate_lines!(klass)
|
26
|
+
iterator = Iterator.new do |node|
|
27
|
+
if node.is_a?(Rubinius::AST::Case)
|
28
|
+
@violations << node.line
|
29
|
+
end
|
30
|
+
end
|
31
|
+
Array(klass).each(&iterator)
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
@@ -29,7 +29,11 @@ module Pelusa
|
|
29
29
|
__iterate = Iterator.new do |node|
|
30
30
|
if body = get_body_from_node[node]
|
31
31
|
if node.line != [body].flatten.first.line
|
32
|
-
|
32
|
+
if body.is_a?(Array)
|
33
|
+
@violations.merge body.map(&:line)
|
34
|
+
else
|
35
|
+
@violations << body.line
|
36
|
+
end
|
33
37
|
end
|
34
38
|
end
|
35
39
|
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Pelusa
|
2
|
+
module Lint
|
3
|
+
class ManyArguments
|
4
|
+
def initialize
|
5
|
+
@violations = Set.new
|
6
|
+
end
|
7
|
+
|
8
|
+
def check(klass)
|
9
|
+
initialize
|
10
|
+
iterate_lines!(klass)
|
11
|
+
return SuccessfulAnalysis.new(name) if @violations.empty?
|
12
|
+
|
13
|
+
FailedAnalysis.new(name, formatted_violations) do |violations|
|
14
|
+
"Methods with more than #{limit} arguments: #{violations.join(', ')}"
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
private
|
19
|
+
|
20
|
+
def name
|
21
|
+
"Methods have short argument lists"
|
22
|
+
end
|
23
|
+
|
24
|
+
def limit
|
25
|
+
Pelusa.configuration['ManyArguments'].fetch('limit', 3)
|
26
|
+
end
|
27
|
+
|
28
|
+
def iterate_lines!(klass)
|
29
|
+
iterator = Iterator.new do |node|
|
30
|
+
if node.is_a?(Rubinius::AST::Define) && node.arguments.total_args > limit
|
31
|
+
@violations << node.name
|
32
|
+
end
|
33
|
+
end
|
34
|
+
Array(klass).each(&iterator)
|
35
|
+
end
|
36
|
+
|
37
|
+
def formatted_violations
|
38
|
+
@violations.to_a
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/lib/pelusa/version.rb
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Pelusa
|
4
|
+
describe Configuration do
|
5
|
+
let(:configuration) do
|
6
|
+
Pelusa::Configuration.new("#{FIXTURES_PATH}/sample_config_one.yml")
|
7
|
+
end
|
8
|
+
|
9
|
+
describe "#present?" do
|
10
|
+
it "returns false when configuration doesn't file exists" do
|
11
|
+
configuration = Pelusa::Configuration.new("#{FIXTURES_PATH}/not_here.yml")
|
12
|
+
configuration.present?.must_equal(false)
|
13
|
+
end
|
14
|
+
|
15
|
+
it "returns false when configuration file exists" do
|
16
|
+
configuration.present?.must_equal(true)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
describe '#sources' do
|
21
|
+
it 'returns path to sources' do
|
22
|
+
configuration.sources.must_equal 'lib/**/*.rb'
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '#enabled_lints' do
|
27
|
+
let(:enabled_lints) { Lint.all - [ Pelusa::Lint::ElseClauses ] }
|
28
|
+
|
29
|
+
it 'returns all enabled lints' do
|
30
|
+
configuration.enabled_lints.must_equal(enabled_lints)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe '#[]' do
|
35
|
+
describe 'when lint configuration exists' do
|
36
|
+
let(:lint_configuration) { configuration['LineRestriction'] }
|
37
|
+
|
38
|
+
it 'returns a configuration hash for the given lint' do
|
39
|
+
lint_configuration.must_be_instance_of(Hash)
|
40
|
+
end
|
41
|
+
|
42
|
+
it 'must return valid configuration' do
|
43
|
+
lint_configuration['limit'].must_equal(80)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
describe "when lint configuration doesn't exist" do
|
48
|
+
let(:lint_configuration) { configuration['DemeterLaw'] }
|
49
|
+
|
50
|
+
it 'returns an empty configuration hash' do
|
51
|
+
lint_configuration.must_equal({})
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Pelusa
|
4
|
+
module Lint
|
5
|
+
describe CaseStatements do
|
6
|
+
before do
|
7
|
+
@lint = CaseStatements.new
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#check' do
|
11
|
+
describe 'when the class does not use switch statements' do
|
12
|
+
it 'returns a SuccessAnalysis' do
|
13
|
+
klass = """
|
14
|
+
class Foo
|
15
|
+
def initialize
|
16
|
+
return nil
|
17
|
+
end
|
18
|
+
end""".to_ast
|
19
|
+
|
20
|
+
analysis = @lint.check(klass)
|
21
|
+
analysis.successful?.must_equal true
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'when the class uses case statements' do
|
26
|
+
it 'returns a FailureAnalysis' do
|
27
|
+
klass = """
|
28
|
+
class Foo
|
29
|
+
def initialize
|
30
|
+
case foo
|
31
|
+
when bar
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end""".to_ast
|
35
|
+
|
36
|
+
analysis = @lint.check(klass)
|
37
|
+
analysis.failed?.must_equal true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -41,6 +41,26 @@ module Pelusa
|
|
41
41
|
analysis.failed?.must_equal true
|
42
42
|
end
|
43
43
|
end
|
44
|
+
|
45
|
+
describe "when there is method which produces nested list" do
|
46
|
+
it 'returns a FailureAnalysis' do
|
47
|
+
klass = """
|
48
|
+
class Foo
|
49
|
+
def initialize
|
50
|
+
if test
|
51
|
+
a = [
|
52
|
+
(1..3).map do |num|
|
53
|
+
num
|
54
|
+
end
|
55
|
+
]
|
56
|
+
end
|
57
|
+
end
|
58
|
+
end""".to_ast
|
59
|
+
|
60
|
+
analysis = @lint.check klass
|
61
|
+
analysis.failed?.must_equal true
|
62
|
+
end
|
63
|
+
end
|
44
64
|
end
|
45
65
|
end
|
46
66
|
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
module Pelusa
|
4
|
+
module Lint
|
5
|
+
describe ManyArguments do
|
6
|
+
before do
|
7
|
+
@lint = ManyArguments.new
|
8
|
+
end
|
9
|
+
|
10
|
+
describe '#check' do
|
11
|
+
describe 'when the class contains only method definitions with a small number of arguments' do
|
12
|
+
it 'returns a SuccessAnalysis' do
|
13
|
+
klass = """
|
14
|
+
class Foo
|
15
|
+
def bar(dog)
|
16
|
+
return dog
|
17
|
+
end
|
18
|
+
def baz(dog, cat)
|
19
|
+
return dog + cat
|
20
|
+
end
|
21
|
+
def bam(dog, cat, fish)
|
22
|
+
return dog + cat + fish
|
23
|
+
end
|
24
|
+
end""".to_ast
|
25
|
+
|
26
|
+
analysis = @lint.check(klass)
|
27
|
+
analysis.successful?.must_equal true
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'when the class contains a method definition with many arguments' do
|
32
|
+
it 'returns a FailureAnalysis' do
|
33
|
+
klass = """
|
34
|
+
class Foo
|
35
|
+
def bar(dog, cat, fish, lobster)
|
36
|
+
x = 2
|
37
|
+
end
|
38
|
+
end""".to_ast
|
39
|
+
|
40
|
+
analysis = @lint.check(klass)
|
41
|
+
analysis.failed?.must_equal true
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
data/test/test_helper.rb
CHANGED
metadata
CHANGED
@@ -2,24 +2,24 @@
|
|
2
2
|
name: pelusa
|
3
3
|
version: !ruby/object:Gem::Version
|
4
4
|
prerelease:
|
5
|
-
version: 0.0
|
5
|
+
version: 0.1.0
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
8
8
|
- Josep M. Bach
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-02-
|
12
|
+
date: 2012-02-24 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
|
-
version_requirements: &
|
15
|
+
version_requirements: &4832 !ruby/object:Gem::Requirement
|
16
16
|
none: false
|
17
17
|
requirements:
|
18
18
|
- - ! '>='
|
19
19
|
- !ruby/object:Gem::Version
|
20
20
|
version: '0'
|
21
21
|
prerelease: false
|
22
|
-
requirement: *
|
22
|
+
requirement: *4832
|
23
23
|
name: mocha
|
24
24
|
type: :development
|
25
25
|
description: Static analysis Lint-type tool to improve your OO Ruby code
|
@@ -31,6 +31,7 @@ extensions: []
|
|
31
31
|
extra_rdoc_files: []
|
32
32
|
files:
|
33
33
|
- .gitignore
|
34
|
+
- .pelusa.yml
|
34
35
|
- .rvmrc
|
35
36
|
- .travis.yml
|
36
37
|
- Gemfile
|
@@ -42,14 +43,17 @@ files:
|
|
42
43
|
- lib/pelusa/analyzer.rb
|
43
44
|
- lib/pelusa/class_analyzer.rb
|
44
45
|
- lib/pelusa/cli.rb
|
46
|
+
- lib/pelusa/configuration.rb
|
45
47
|
- lib/pelusa/iterator.rb
|
46
48
|
- lib/pelusa/lint.rb
|
49
|
+
- lib/pelusa/lint/case_statements.rb
|
47
50
|
- lib/pelusa/lint/collection_wrappers.rb
|
48
51
|
- lib/pelusa/lint/demeter_law.rb
|
49
52
|
- lib/pelusa/lint/else_clauses.rb
|
50
53
|
- lib/pelusa/lint/indentation_level.rb
|
51
54
|
- lib/pelusa/lint/instance_variables.rb
|
52
55
|
- lib/pelusa/lint/line_restriction.rb
|
56
|
+
- lib/pelusa/lint/many_arguments.rb
|
53
57
|
- lib/pelusa/lint/properties.rb
|
54
58
|
- lib/pelusa/lint/short_identifiers.rb
|
55
59
|
- lib/pelusa/report.rb
|
@@ -59,16 +63,20 @@ files:
|
|
59
63
|
- lib/pelusa/runner.rb
|
60
64
|
- lib/pelusa/version.rb
|
61
65
|
- pelusa.gemspec
|
66
|
+
- test/fixtures/sample_config_one.yml
|
62
67
|
- test/pelusa/analysis_test.rb
|
63
68
|
- test/pelusa/analyzer_test.rb
|
64
69
|
- test/pelusa/class_analyzer_test.rb
|
70
|
+
- test/pelusa/configuration_test.rb
|
65
71
|
- test/pelusa/iterator_test.rb
|
72
|
+
- test/pelusa/lint/case_statements_test.rb
|
66
73
|
- test/pelusa/lint/collection_wrappers_test.rb
|
67
74
|
- test/pelusa/lint/demeter_law_test.rb
|
68
75
|
- test/pelusa/lint/else_clauses_test.rb
|
69
76
|
- test/pelusa/lint/indentation_level_test.rb
|
70
77
|
- test/pelusa/lint/instance_variables_test.rb
|
71
78
|
- test/pelusa/lint/line_restriction_test.rb
|
79
|
+
- test/pelusa/lint/many_arguments_test.rb
|
72
80
|
- test/pelusa/lint/properties_test.rb
|
73
81
|
- test/pelusa/lint/short_identifiers_test.rb
|
74
82
|
- test/pelusa/reporters/ruby_reporter_test.rb
|
@@ -105,14 +113,17 @@ test_files:
|
|
105
113
|
- test/pelusa/analysis_test.rb
|
106
114
|
- test/pelusa/analyzer_test.rb
|
107
115
|
- test/pelusa/class_analyzer_test.rb
|
116
|
+
- test/pelusa/configuration_test.rb
|
108
117
|
- test/pelusa/iterator_test.rb
|
109
118
|
- test/pelusa/runner_test.rb
|
119
|
+
- test/pelusa/lint/case_statements_test.rb
|
110
120
|
- test/pelusa/lint/collection_wrappers_test.rb
|
111
121
|
- test/pelusa/lint/demeter_law_test.rb
|
112
122
|
- test/pelusa/lint/else_clauses_test.rb
|
113
123
|
- test/pelusa/lint/indentation_level_test.rb
|
114
124
|
- test/pelusa/lint/instance_variables_test.rb
|
115
125
|
- test/pelusa/lint/line_restriction_test.rb
|
126
|
+
- test/pelusa/lint/many_arguments_test.rb
|
116
127
|
- test/pelusa/lint/properties_test.rb
|
117
128
|
- test/pelusa/lint/short_identifiers_test.rb
|
118
129
|
- test/pelusa/reporters/ruby_reporter_test.rb
|