metric_abc 0.0.2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1 @@
1
+ pkg/*
data/README ADDED
@@ -0,0 +1,29 @@
1
+ Metric ABC
2
+ ==========
3
+
4
+ This little tool calculates ABC metric for your Ruby code. Requires Ruby 1.9 but should work more or less with sources compatible with 1.9 and 1.8.
5
+
6
+ Installation
7
+ ============
8
+
9
+ $ gem install metric_abc
10
+
11
+ Usage
12
+ =====
13
+
14
+ $ metric_abc filename1 [filename2] ...
15
+
16
+ Understanding output
17
+ ====================
18
+
19
+ Output from metric_abc is in form of:
20
+
21
+ /path/to/file.rb#Module1#Module2#ClassName#method_name: SCORE
22
+
23
+ where SCORE is a number. The higher SCORE is, the more crazy code is. If a method scores above 20, it very likely needs some refactoring because it's complete shit.
24
+
25
+ TODO:
26
+ =====
27
+
28
+ - method is not always properly recognized, sometimes it's full of shit like #@const#1#5#@const etc. Need to look at AST to figure out what's wrong
29
+
@@ -0,0 +1,13 @@
1
+ begin
2
+ require 'jeweler'
3
+ Jeweler::Tasks.new do |gemspec|
4
+ gemspec.name = "metric_abc"
5
+ gemspec.summary = "Quick and *DIRTY* ABC metric for Ruby 1.9 code"
6
+ gemspec.description = "Calculates ABC metric for Ruby 1.9. Just like Flog but much more dull."
7
+ gemspec.email = "hubert.lepick@amberbit.com"
8
+ gemspec.homepage = "http://github.com/hubertlepicki/metric_abc"
9
+ gemspec.authors = ["Hubert Lepicki"]
10
+ end
11
+ rescue LoadError
12
+ puts "Jeweler not available. Install it with: gem install jeweler"
13
+ end
data/VERSION ADDED
@@ -0,0 +1 @@
1
+ 0.0.2
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require File.join(File.dirname(__FILE__), "..", "lib", 'metric_abc')
4
+
5
+ if ARGV.empty?
6
+ puts "USAGE:\nmetric_abc filename [filename] ..."
7
+ end
8
+
9
+ ARGV.collect do |filename|
10
+ MetricABC.new(filename).complexity
11
+ end.inject({}) do |merged, current|
12
+ merged.merge(current)
13
+ end.sort{|a,b| b[1]<=>a[1]}.each do |function, score|
14
+ puts "#{function}: #{score}"
15
+ end
@@ -0,0 +1,51 @@
1
+ require 'ripper'
2
+ require 'pp' if ENV["DEBUG"]
3
+
4
+ class MetricABC
5
+ attr_accessor :ast, :complexity
6
+
7
+ def initialize(file_name)
8
+ File.open(file_name, "r") do |f|
9
+ @ast = Ripper::SexpBuilder.new(f.read).parse
10
+ end
11
+ return if @ast.empty?
12
+ @complexity = {}
13
+ @nesting = [file_name]
14
+ process_ast(@ast)
15
+ pp @ast if ENV["DEBUG"]
16
+ end
17
+
18
+ def process_ast(node)
19
+ backup_nesting = @nesting.clone
20
+
21
+ if node[0] == :def
22
+ @nesting << node[1][1]
23
+ @complexity[@nesting.join("#")] = calculate_abc(node)
24
+ elsif node[0] == :class || node[0] == :const
25
+ @nesting << node[1][1][1]
26
+ end
27
+
28
+ node[1..-1].each { |n| process_ast(n) if n } if node.is_a? Array
29
+ @nesting = backup_nesting
30
+ end
31
+
32
+ def calculate_abc(method_node)
33
+ a = calculate_assignments(method_node)
34
+ b = calculate_branches(method_node)
35
+ c = calculate_conditions(method_node)
36
+ abc = Math.sqrt(a**2 + b**2 + c**2).round
37
+ abc
38
+ end
39
+
40
+ def calculate_assignments(node)
41
+ node.flatten.select{|n| [:assign, :opassign].include?(n)}.size.to_f
42
+ end
43
+
44
+ def calculate_branches(node)
45
+ node.flatten.select{|n| [:call, :fcall, :brace_block, :do_block].include?(n)}.size.to_f + 1.0
46
+ end
47
+
48
+ def calculate_conditions(node, sum=0)
49
+ node.flatten.select{|n| [:==, :===, :"<>", :"<=", :">=", :"=~", :>, :<, :else, :"<=>"].include?(n)}.size.to_f
50
+ end
51
+ end
@@ -0,0 +1,55 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{metric_abc}
8
+ s.version = "0.0.2"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Hubert Lepicki"]
12
+ s.date = %q{2010-08-24}
13
+ s.default_executable = %q{metric_abc}
14
+ s.description = %q{Calculates ABC metric for Ruby 1.9. Just like Flog but much more dull.}
15
+ s.email = %q{hubert.lepick@amberbit.com}
16
+ s.executables = ["metric_abc"]
17
+ s.extra_rdoc_files = [
18
+ "README"
19
+ ]
20
+ s.files = [
21
+ ".gitignore",
22
+ "README",
23
+ "Rakefile",
24
+ "VERSION",
25
+ "bin/metric_abc",
26
+ "lib/metric_abc.rb",
27
+ "metric_abc.gemspec",
28
+ "spec/fixtures/example.rb",
29
+ "spec/fixtures/not_valid.rb",
30
+ "spec/functional/metric_abc_spec.rb",
31
+ "spec/spec_helper.rb"
32
+ ]
33
+ s.homepage = %q{http://github.com/hubertlepicki/metric_abc}
34
+ s.rdoc_options = ["--charset=UTF-8"]
35
+ s.require_paths = ["lib"]
36
+ s.rubygems_version = %q{1.3.7}
37
+ s.summary = %q{Quick and *DIRTY* ABC metric for Ruby 1.9 code}
38
+ s.test_files = [
39
+ "spec/fixtures/example.rb",
40
+ "spec/fixtures/not_valid.rb",
41
+ "spec/spec_helper.rb",
42
+ "spec/functional/metric_abc_spec.rb"
43
+ ]
44
+
45
+ if s.respond_to? :specification_version then
46
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
47
+ s.specification_version = 3
48
+
49
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
50
+ else
51
+ end
52
+ else
53
+ end
54
+ end
55
+
@@ -0,0 +1,49 @@
1
+ def outside_function
2
+ a = 5
3
+ end
4
+
5
+ module Test
6
+ class Test2
7
+ def class_in_module_function
8
+ a=1
9
+ b=2
10
+ a += 1
11
+ b *= 2
12
+ 5
13
+ [1,2,3].each do |element|
14
+ puts element
15
+ end
16
+ end
17
+ end
18
+ end
19
+ class Example
20
+ attr_accessor :something
21
+ def simple_function
22
+ return 0
23
+ end
24
+ def medium_function(param1, param2=whatever)
25
+ a = simple_function()
26
+ if param1 == nil
27
+ a = asdfaf()
28
+ elsif param1 < 4
29
+ elsif param1 > 3
30
+ elsif param2 <=2
31
+ elsif param3() >=3
32
+ else
33
+ puts 'test'
34
+ end
35
+ a
36
+ end
37
+ def complex_function(param1, param2=whatever)
38
+ while param1 > 0
39
+ for i=0; i<=7; i++
40
+ param2.collect{|c| c+2}.inject("+")
41
+ end
42
+ end
43
+ if something == param1 && tewww != asdf || a === Object
44
+ Array.new(a + b)
45
+ end
46
+ end
47
+ end
48
+
49
+
@@ -0,0 +1,3 @@
1
+ class module def Ziom;
2
+ def hello
3
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe MetricABC, "initialization" do
4
+
5
+ it "should read passed file and generate AST for it on initialization" do
6
+ metric = MetricABC.new(File.join(File.dirname(__FILE__), "..", "fixtures", "example.rb"))
7
+ metric.ast.should be_instance_of(Array)
8
+ metric.ast.should_not be_empty
9
+ end
10
+
11
+ it "should throw exception when file is not found" do
12
+ lambda{ MetricABC.new(File.join(File.dirname(__FILE__), "..", "fixtures", "not_found.rb"))}.should raise_exception
13
+ end
14
+
15
+ end
16
+
17
+ describe MetricABC, "calculating" do
18
+ before :each do
19
+ @metric = MetricABC.new(File.join(File.dirname(__FILE__), "..", "fixtures", "example.rb"))
20
+ end
21
+
22
+ it "should have 1 complexity for simple function" do
23
+ @metric.complexity["Example#simple_function"].should eql(1)
24
+ end
25
+
26
+ it "should recognize top level functions" do
27
+ @metric.complexity["outside_function"].should_not be_nil
28
+ end
29
+
30
+ it "should recognize modules functions" do
31
+ @metric.complexity["Test#Test2#class_in_module_function"].should_not be_nil
32
+ end
33
+
34
+ it "should have complexity of 7 for medium method" do
35
+ @metric.complexity["Example#medium_function"].should eql(7)
36
+ end
37
+ end
@@ -0,0 +1,12 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "..", "lib", "metric_abc"))
2
+
3
+ RSpec.configure do |config|
4
+ config.mock_with :rspec
5
+
6
+ #config.before(:each) do
7
+ #end
8
+
9
+ #config.after(:each) do
10
+ #end
11
+ end
12
+
metadata ADDED
@@ -0,0 +1,77 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: metric_abc
3
+ version: !ruby/object:Gem::Version
4
+ prerelease: false
5
+ segments:
6
+ - 0
7
+ - 0
8
+ - 2
9
+ version: 0.0.2
10
+ platform: ruby
11
+ authors:
12
+ - Hubert Lepicki
13
+ autorequire:
14
+ bindir: bin
15
+ cert_chain: []
16
+
17
+ date: 2010-08-24 00:00:00 +02:00
18
+ default_executable: metric_abc
19
+ dependencies: []
20
+
21
+ description: Calculates ABC metric for Ruby 1.9. Just like Flog but much more dull.
22
+ email: hubert.lepick@amberbit.com
23
+ executables:
24
+ - metric_abc
25
+ extensions: []
26
+
27
+ extra_rdoc_files:
28
+ - README
29
+ files:
30
+ - .gitignore
31
+ - README
32
+ - Rakefile
33
+ - VERSION
34
+ - bin/metric_abc
35
+ - lib/metric_abc.rb
36
+ - metric_abc.gemspec
37
+ - spec/fixtures/example.rb
38
+ - spec/fixtures/not_valid.rb
39
+ - spec/functional/metric_abc_spec.rb
40
+ - spec/spec_helper.rb
41
+ has_rdoc: true
42
+ homepage: http://github.com/hubertlepicki/metric_abc
43
+ licenses: []
44
+
45
+ post_install_message:
46
+ rdoc_options:
47
+ - --charset=UTF-8
48
+ require_paths:
49
+ - lib
50
+ required_ruby_version: !ruby/object:Gem::Requirement
51
+ none: false
52
+ requirements:
53
+ - - ">="
54
+ - !ruby/object:Gem::Version
55
+ segments:
56
+ - 0
57
+ version: "0"
58
+ required_rubygems_version: !ruby/object:Gem::Requirement
59
+ none: false
60
+ requirements:
61
+ - - ">="
62
+ - !ruby/object:Gem::Version
63
+ segments:
64
+ - 0
65
+ version: "0"
66
+ requirements: []
67
+
68
+ rubyforge_project:
69
+ rubygems_version: 1.3.7
70
+ signing_key:
71
+ specification_version: 3
72
+ summary: Quick and *DIRTY* ABC metric for Ruby 1.9 code
73
+ test_files:
74
+ - spec/fixtures/example.rb
75
+ - spec/fixtures/not_valid.rb
76
+ - spec/spec_helper.rb
77
+ - spec/functional/metric_abc_spec.rb