class SandiMeter::Analyzer
Attributes
classes[R]
method_calls[R]
methods[R]
parent_token[RW]
private_or_protected[RW]
Public Class Methods
new()
click to toggle source
# File lib/sandi_meter/analyzer.rb, line 14 def initialize @classes = [] @methods = {} @method_calls = [] end
Public Instance Methods
analyze(file_path)
click to toggle source
# File lib/sandi_meter/analyzer.rb, line 20 def analyze(file_path) @file_path = file_path @file_body = File.read(file_path) @file_lines = @file_body.split(/$/).map { |l| l.gsub("\n", '') } @indentation_warnings = indentation_warnings # TODO # add better determination wheter file is controller @controller = !!(file_path =~ /\w+_controller.rb$/) sexp = Ripper.sexp(@file_body) scan_sexp(sexp) output end
Private Instance Methods
find_args_add_block(method_call_sexp)
click to toggle source
# File lib/sandi_meter/analyzer.rb, line 115 def find_args_add_block(method_call_sexp) return unless method_call_sexp.kind_of?(Array) method_call_sexp.each do |sexp| next unless sexp.kind_of?(Array) if sexp.first == :args_add_block counter = SandiMeter::MethodArgumentsCounter.new arguments_count, line = counter.count(sexp) @method_calls << SandiMeter::MethodCall.new( path: @file_path, first_line: line, number_of_arguments: arguments_count ) find_args_add_block(sexp) else find_args_add_block(sexp) end end end
find_class_params(sexp, current_namespace)
click to toggle source
# File lib/sandi_meter/analyzer.rb, line 49 def find_class_params(sexp, current_namespace) flat_sexp = sexp[1].flatten const_indexes = flat_sexp.each_index.select{ |i| flat_sexp[i] == :@const } line_number = flat_sexp[const_indexes.first + 2] class_tokens = const_indexes.map { |i| flat_sexp[i + 1] } class_tokens.insert(0, current_namespace) unless current_namespace.empty? class_name = class_tokens.join('::') { name: class_name, first_line: line_number, path: @file_path } end
find_last_line(line, token = 'class')
click to toggle source
# File lib/sandi_meter/analyzer.rb, line 83 def find_last_line(line, token = 'class') token_indentation = @file_lines[line - 1].index(token) # TODO # add check for trailing spaces last_line = @file_lines[line..-1].index { |l| l =~ %r(\A\s{#{token_indentation}}end\s*\z) } last_line ? last_line + line + 1 : nil end
find_method_params(sexp)
click to toggle source
# File lib/sandi_meter/analyzer.rb, line 74 def find_method_params(sexp) name, first_line = sexp[1].flatten[1, 2] { name: name, first_line: first_line, path: @file_path } end
indentation_warnings()
click to toggle source
# File lib/sandi_meter/analyzer.rb, line 195 def indentation_warnings warning_scanner = SandiMeter::WarningScanner.new warning_scanner.scan(@file_body) end
number_of_arguments(method_sexp)
click to toggle source
MOVE to method scanner class
# File lib/sandi_meter/analyzer.rb, line 67 def number_of_arguments(method_sexp) arguments = method_sexp[2] arguments = arguments[1] if arguments.first == :paren arguments[1] == nil ? 0 : arguments[1].size end
output()
click to toggle source
# File lib/sandi_meter/analyzer.rb, line 36 def output loc_checker = SandiMeter::LOCChecker.new(@file_lines) { classes: @classes, misindented_classes: @misindented_classes, methods: @methods, misindented_methods: @misindented_methods, method_calls: @method_calls, instance_variables: @instance_variables } end
scan_class_sexp(element, current_namespace = '')
click to toggle source
# File lib/sandi_meter/analyzer.rb, line 92 def scan_class_sexp(element, current_namespace = '') case element.first when :module module_params = find_class_params(element, current_namespace) module_params[:last_line] = find_last_line(module_params[:first_line], 'module') current_namespace = module_params[:name] scan_sexp(element, current_namespace) when :class class_params = find_class_params(element, current_namespace) unless @indentation_warnings['class'] && @indentation_warnings['class'].any? { |first_line, last_line| first_line == class_params[:first_line] } class_params[:last_line] = find_last_line(class_params[:first_line]) end @classes << SandiMeter::Class.new(class_params) current_namespace = class_params[:name] scan_sexp(element, current_namespace) end end
scan_def_for_ivars(current_namespace, method_name, method_sexp)
click to toggle source
# File lib/sandi_meter/analyzer.rb, line 138 def scan_def_for_ivars(current_namespace, method_name, method_sexp) return unless method_sexp.kind_of?(Array) method_sexp.each do |sexp| next unless sexp.kind_of?(Array) if sexp.first == :assign method = @methods[current_namespace].find { |m| m.name == method_name } method.ivars << sexp[1][1][1] if sexp[1][1][0] == :@ivar else scan_def_for_ivars(current_namespace, method_name, sexp) end end end
scan_sexp(sexp, current_namespace = '')
click to toggle source
# File lib/sandi_meter/analyzer.rb, line 153 def scan_sexp(sexp, current_namespace = '') sexp.each do |element| next unless element.kind_of?(Array) @parent_token = element.first case element.first when :def method_params = find_method_params(element) method_params[:number_of_arguments] = number_of_arguments(element) unless @indentation_warnings['def'] && @indentation_warnings['def'].any? { |first_line, last_line| first_line == method_params[:first_line] } method_params[:last_line] = find_last_line(method_params[:first_line], 'def') end @methods[current_namespace] ||= [] @methods[current_namespace] << SandiMeter::Method.new(method_params) unless @private_or_protected if @controller && !@private_or_protected scan_def_for_ivars(current_namespace, method_params[:name], element) end find_args_add_block(element) when :module, :class scan_class_sexp(element, current_namespace) when :vcall if element[1].first == :@ident case element[1][1] when "private" @private_or_protected = true when "public" @private_or_protected = false else scan_sexp(element, current_namespace) end else scan_sexp(element, current_namespace) end else scan_sexp(element, current_namespace) end end end