class SugarCane::AbcCheck::RubyAst
Wrapper object around sexps returned from ripper.
Constants
- METH_CHARS
Attributes
anon_method_add[RW]
Stateful flag used to determine whether we are currently parsing an anonymous class. See container_label
.
Public Class Methods
new(*args)
click to toggle source
Calls superclass method
# File lib/sugarcane/abc_check.rb, line 70 def initialize(*args) super self.anon_method_add = true end
Public Instance Methods
violations()
click to toggle source
# File lib/sugarcane/abc_check.rb, line 75 def violations process_ast(sexps). select do |nesting, complexity| complexity[:value] > max_allowed_complexity end. map do |violation| { # Here, a violation is an array, like: # ["Class#method", {:value => xx, :line => xx}] file: file_name, line: violation.last[:line], label: violation.first, value: violation.last[:value], description: "Methods exceeded maximum allowed ABC complexity", menu_description: "#{violation.first} exceeded maximum "\ "ABC complexity" } end end
Protected Instance Methods
assignment_nodes()
click to toggle source
# File lib/sugarcane/abc_check.rb, line 164 def assignment_nodes [:assign, :opassign] end
branch_nodes()
click to toggle source
# File lib/sugarcane/abc_check.rb, line 176 def branch_nodes [:call, :fcall, :brace_block, :do_block] end
calculate_abc(method_node)
click to toggle source
# File lib/sugarcane/abc_check.rb, line 123 def calculate_abc(method_node) a = count_nodes(method_node, assignment_nodes) b = count_nodes(method_node, branch_nodes) + 1 c = count_nodes(method_node, condition_nodes) abc = Math.sqrt(a**2 + b**2 + c**2).round abc end
condition_nodes()
click to toggle source
# File lib/sugarcane/abc_check.rb, line 180 def condition_nodes [:==, :===, :"<>", :"<=", :">=", :"=~", :>, :<, :else, :"<=>"] end
container_label(node)
click to toggle source
# File lib/sugarcane/abc_check.rb, line 131 def container_label(node) if container_nodes.include?(node[0]) # def foo, def self.foo node[1][-1][1] elsif node[0] == :method_add_block if anon_method_add # Class.new do ... "(anon)" else # MyClass = Class.new do ... # parent already added when processing a parent node anon_method_add = true nil end elsif node[0] == :assign && node[2][0] == :method_add_block # MyClass = Class.new do ... self.anon_method_add = false node[1][-1][1] end end
container_nodes()
click to toggle source
# File lib/sugarcane/abc_check.rb, line 172 def container_nodes [:class, :module] end
count_nodes(node, types)
click to toggle source
# File lib/sugarcane/abc_check.rb, line 160 def count_nodes(node, types) node.flatten.select {|n| types.include?(n) }.length end
excluded?(method_description)
click to toggle source
# File lib/sugarcane/abc_check.rb, line 186 def excluded?(method_description) exclusions.include?(method_description) end
label_for(node)
click to toggle source
# File lib/sugarcane/abc_check.rb, line 152 def label_for(node) # A default case is deliberately omitted since I know of no way this # could fail and want it to fail fast. node.detect {|x| [:@ident, :@op, :@kw, :@const, :@backtick].include?(x[0]) }[1] end
method_description(node, *modules, meth_name)
click to toggle source
# File lib/sugarcane/abc_check.rb, line 190 def method_description(node, *modules, meth_name) separator = METH_CHARS.fetch(node.first) description = [modules.join('::'), meth_name].join(separator) end
method_nodes()
click to toggle source
# File lib/sugarcane/abc_check.rb, line 168 def method_nodes [:def, :defs] end
process_ast(node, complexity = {}, nesting = [])
click to toggle source
Recursive function to process an AST. The `complexity` variable mutates, which is a bit confusing. `nesting` does not.
# File lib/sugarcane/abc_check.rb, line 103 def process_ast(node, complexity = {}, nesting = []) if method_nodes.include?(node[0]) nesting = nesting + [label_for(node)] desc = method_description(node, *nesting) unless excluded?(desc) complexity[desc] = { :value => calculate_abc(node), :line => node.line_number } end elsif parent = container_label(node) nesting = nesting + [parent] end if node.is_a? Array node[1..-1].each {|n| process_ast(n, complexity, nesting) if n } end complexity end