lib/rubocop/cop/surrounding_space.rb in rubocop-0.1.0 vs lib/rubocop/cop/surrounding_space.rb in rubocop-0.2.0

- old
+ new

@@ -1,44 +1,93 @@ +# encoding: utf-8 + require_relative 'grammar' module Rubocop module Cop class SurroundingSpace < Cop - ERROR_MESSAGE = 'Surrounding space missing for operator' + ERROR_MESSAGE = 'Surrounding space missing for ' def inspect(file, source, tokens, sexp) - Grammar.new(tokens).correlate(sexp).sort.each { |ix, grammar_path| - pos, name, text = tokens[ix] - if name == :on_op + Grammar.new(tokens).correlate(sexp).sort.each do |ix, grammar_path| + t = tokens[ix] + case t.type + when :on_op unless surrounded_by_whitespace?(tokens[ix - 1, 3]) unless ok_without_spaces?(grammar_path) - index = pos[0] - 1 - add_offence(:convention, index, source[index], - ERROR_MESSAGE + " '#{text}'.") + add_offence(:convention, t.pos.lineno, + ERROR_MESSAGE + "operator '#{t.text}'.") end end + when :on_lbrace + unless surrounded_by_whitespace?(tokens[ix - 1, 3]) + add_offence(:convention, t.pos.lineno, ERROR_MESSAGE + "'{'.") + end + when :on_rbrace + unless whitespace?(tokens[ix - 1]) + add_offence(:convention, t.pos.lineno, + "Space missing to the left of '}'.") + end end - } + end + tokens.each_index do |ix| + t = tokens[ix] + prev, nxt = tokens.values_at(ix - 1, ix + 1) + offence_detected = case t.type + when :on_lbracket, :on_lparen + nxt.type == :on_sp + when :on_rbracket, :on_rparen + if prev.type == :on_sp + prev_ns = previous_non_space(tokens, ix) + prev_ns && tokens_on_same_row?(prev_ns, + tokens[ix]) && + # Avoid double repoting of [ ] and ( ) + prev_ns.type != :on_lbracket && + prev_ns.type != :on_lparen + end + when :on_op + t.text == '**' && + (whitespace?(prev) || whitespace?(nxt)) + end + if offence_detected + kind = case t.type + when :on_lparen, :on_rparen + 'inside parentheses' + when :on_lbracket, :on_rbracket + 'inside square brackets' + when :on_op + "around operator #{t.text}" + end + add_offence(:convention, t.pos.lineno, "Space #{kind} detected.") + end + end end + private + + def tokens_on_same_row?(t1, t2) + t1.pos.lineno == t2.pos.lineno + end + + def previous_non_space(tokens, ix) + (ix - 1).downto(0) do |i| + t = tokens[i] + return t unless whitespace?(t) + end + nil + end + def ok_without_spaces?(grammar_path) - grandparent, parent, child = grammar_path.values_at(-3, -2, -1) + parent, child = grammar_path.values_at(-2, -1) return true if [:unary, :symbol, :defs, :def, :call].include?(parent) - return true if [:rest_param, :blockarg, :block_var, :args_add_star, - :args_add_block, :const_path_ref, :dot2, - :dot3].include?(child) - return true if grandparent == :unary && parent == :vcall + return true if [:**, :block_var].include?(child) return true if parent == :command_call && child == :'::' false end def surrounded_by_whitespace?(nearby_tokens) left, _, right = nearby_tokens whitespace?(left) && whitespace?(right) - end - - def whitespace?(token) - [:on_sp, :on_ignored_nl, :on_nl].include?(token[1]) end end end end