pelusa 0.0.2 → 0.1.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/.pelusa.yml ADDED
@@ -0,0 +1 @@
1
+ sources: lib/**/*.rb
data/.rvmrc CHANGED
@@ -1 +1,2 @@
1
- rvm use rbx-head@pelusa
1
+ rvm use --create rbx@pelusa
2
+ RBXOPT="$RBXOPT -X19"
data/Readme.md CHANGED
@@ -1,4 +1,5 @@
1
- # pelusa - a Ruby Lint to improve your OO skills [![Build Status](https://secure.travis-ci.org/codegram/pelusa.png)](http://travis-ci.org/codegram/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
- ## Install and usage
24
+ ## Installation and usage
24
25
 
25
- rvm use rbx-head
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, lints=Lint.all)
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
- @violations << body.line
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
@@ -23,7 +23,7 @@ module Pelusa
23
23
  end
24
24
 
25
25
  def limit
26
- 3
26
+ Pelusa.configuration['InstanceVariables'].fetch('limit', 3)
27
27
  end
28
28
 
29
29
  def iterate_lines!(klass)
@@ -23,7 +23,7 @@ module Pelusa
23
23
  end
24
24
 
25
25
  def limit
26
- 50
26
+ Pelusa.configuration['LineRestriction'].fetch('limit', 50)
27
27
  end
28
28
 
29
29
  def lines
@@ -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
@@ -1,3 +1,3 @@
1
1
  module Pelusa
2
- VERSION = "0.0.2"
2
+ VERSION = "0.1.0"
3
3
  end
@@ -0,0 +1,7 @@
1
+ sources: lib/**/*.rb
2
+ lints:
3
+ ElseClauses:
4
+ enabled: false
5
+ LineRestriction:
6
+ enabled: true
7
+ limit: 80
@@ -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
@@ -3,3 +3,5 @@ require 'minitest/spec'
3
3
  require 'mocha'
4
4
 
5
5
  require 'pelusa'
6
+
7
+ FIXTURES_PATH = File.dirname(__FILE__) + '/fixtures'
metadata CHANGED
@@ -2,24 +2,24 @@
2
2
  name: pelusa
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 0.0.2
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-15 00:00:00.000000000 Z
12
+ date: 2012-02-24 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
- version_requirements: &6324 !ruby/object:Gem::Requirement
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: *6324
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