metric_abc 0.0.2

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.
@@ -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