Last active
August 29, 2015 13:57
-
-
Save deepak/9703757 to your computer and use it in GitHub Desktop.
A dumb metric which considers single variable names and floats as sins. Uses parser and AST::Processor
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'parser/current' | |
require 'pp' | |
require 'rake' | |
require 'pry' | |
module SexpLisper | |
def self.parse(path) | |
code = File.read(path) | |
source_buffer = Parser::Source::Buffer.new(path, 1) | |
source_buffer.source = code | |
builder = SexpLisper::Builder.new | |
parser = Parser::CurrentRuby.new(builder) | |
parser.diagnostics.all_errors_are_fatal = true | |
parser.diagnostics.ignore_warnings = true | |
ast, comments = parser.parse_with_comments(source_buffer) | |
[ast, comments] | |
rescue Parser::SyntaxError | |
[nil, nil] | |
end | |
class Builder < ::Parser::Builders::Default | |
def n(type, children, location) | |
return Node.new(type, children, :location => location) | |
end | |
end # Builder | |
class Node < ::Parser::AST::Node | |
def line | |
return location.expression.line if location | |
end | |
def column | |
return location.expression.column + 1 if location | |
end | |
def file | |
return location.expression.source_buffer.name if location | |
end | |
end # Node | |
end | |
class Analysis < Parser::AST::Processor | |
attr_accessor :report | |
def initialize report | |
@report = report | |
end | |
private | |
def log(node, type) | |
@report[node.file] ||= [] | |
@report[node.file] << { | |
line: node.line, | |
value: node.children[0], | |
type: type | |
} | |
end | |
end | |
module DumbMetric | |
class FloatCheck < Analysis | |
def on_float(node) | |
log(node, :float) | |
end | |
end | |
class SingleVariableCheck < Analysis | |
def on_ivasgn(node) # eg: @i | |
variable_name = node.children[0] | |
log(node, :single_var) if variable_name.length == 2 | |
end | |
def on_lvasgn(node) | |
variable_name = node.children[0] | |
log(node, :single_var) if variable_name.length == 1 | |
end | |
def on_lvar(node) | |
variable_name = node.children[0] | |
log(node, :single_var) if variable_name.length == 1 | |
end | |
end | |
class Metric | |
attr_accessor :report | |
COST = { float: 2, single_var: 5 } | |
def initialize | |
@report = {} | |
end | |
def process(ast) | |
float_check = FloatCheck.new(report) | |
float_check.process(ast) | |
var_check = SingleVariableCheck.new(report) | |
var_check.process(ast) | |
aggregate_score[ast.file] || 0 | |
end | |
private | |
def aggregate_score | |
report.each_pair.each_with_object({}) do |(file, metrics), hash| | |
total_cost = metrics.map { |line| COST[line[:type]] }.inject(:+) | |
hash[file] = total_cost | |
end | |
end | |
end | |
end | |
class FileProcessor | |
def self.process path | |
metric = DumbMetric::Metric.new | |
ast, comments = SexpLisper.parse(path) | |
return 'NA' unless ast | |
metric.process ast | |
end | |
end | |
if $0 == __FILE__ | |
# ARGV.each do |path| | |
# pp FileProcessor.process path | |
# end | |
project = ARGV[0] | |
Dir.chdir(project) do | |
Rake::FileList.new("**/*.rb").map do |path| | |
score = FileProcessor.process path | |
if score != 'NA' and score > 0 | |
puts "#{path} has #{score}" | |
end | |
end | |
end | |
end | |
# /usr/local/opt/rbenv/versions/2.0.0-p247/lib/ruby/gems/2.0.0/gems/activerecord-4.0.2/lib/active_record/association_relation.rb |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Foo | |
attr_accessor :i | |
def initialize | |
@i = 1 | |
end | |
def process | |
test = 2.5 + 2.5 | |
b = 1 | |
@a = test + b | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(class | |
(const nil :Foo) nil | |
(begin | |
(def :initialize | |
(args) | |
(ivasgn :@i | |
(int 1))) | |
(def :process | |
(args) | |
(begin | |
(lvasgn :test | |
(send | |
(float 2.5) :+ | |
(float 2.5))) | |
(lvasgn :b | |
(int 1)) | |
(ivasgn :@a | |
(send | |
(lvar :test) :+ | |
(lvar :b))))))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment