rubocop 0.1.0 → 0.2.0
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.
Potentially problematic release.
This version of rubocop might be problematic. Click here for more details.
- data/.rbenv-version +1 -0
- data/.travis.yml +4 -0
- data/Gemfile +8 -8
- data/README.md +17 -1
- data/VERSION +1 -1
- data/bin/rubocop +1 -1
- data/features/step_definitions/rubocop_steps.rb +1 -0
- data/features/support/env.rb +2 -0
- data/lib/rubocop.rb +6 -0
- data/lib/rubocop/cli.rb +37 -17
- data/lib/rubocop/cop/align_parameters.rb +112 -0
- data/lib/rubocop/cop/cop.rb +43 -21
- data/lib/rubocop/cop/def_parentheses.rb +38 -0
- data/lib/rubocop/cop/empty_lines.rb +7 -6
- data/lib/rubocop/cop/encoding.rb +1 -1
- data/lib/rubocop/cop/end_of_line.rb +17 -0
- data/lib/rubocop/cop/grammar.rb +69 -9
- data/lib/rubocop/cop/hash_syntax.rb +26 -0
- data/lib/rubocop/cop/if_then_else.rb +49 -0
- data/lib/rubocop/cop/indentation.rb +16 -27
- data/lib/rubocop/cop/line_length.rb +2 -2
- data/lib/rubocop/cop/numeric_literals.rb +19 -0
- data/lib/rubocop/cop/offence.rb +2 -3
- data/lib/rubocop/cop/space_after_comma_etc.rb +10 -9
- data/lib/rubocop/cop/surrounding_space.rb +66 -17
- data/lib/rubocop/cop/tab.rb +2 -2
- data/lib/rubocop/cop/trailing_whitespace.rb +2 -2
- data/lib/rubocop/report/emacs_style.rb +4 -3
- data/rubocop.gemspec +16 -2
- data/spec/rubocop/cli_spec.rb +20 -5
- data/spec/rubocop/cops/align_parameters_spec.rb +201 -0
- data/spec/rubocop/cops/cop_spec.rb +4 -2
- data/spec/rubocop/cops/def_parentheses_spec.rb +48 -0
- data/spec/rubocop/cops/empty_lines_spec.rb +9 -8
- data/spec/rubocop/cops/end_of_line_spec.rb +17 -0
- data/spec/rubocop/cops/grammar_spec.rb +51 -11
- data/spec/rubocop/cops/hash_syntax_spec.rb +44 -0
- data/spec/rubocop/cops/if_then_else_spec.rb +74 -0
- data/spec/rubocop/cops/indentation_spec.rb +29 -4
- data/spec/rubocop/cops/line_length_spec.rb +4 -2
- data/spec/rubocop/cops/numeric_literals_spec.rb +49 -0
- data/spec/rubocop/cops/offence_spec.rb +4 -3
- data/spec/rubocop/cops/space_after_comma_etc_spec.rb +7 -5
- data/spec/rubocop/cops/surrounding_space_spec.rb +89 -26
- data/spec/rubocop/cops/tab_spec.rb +4 -2
- data/spec/rubocop/cops/trailing_whitespace_spec.rb +5 -3
- data/spec/rubocop/reports/emacs_style_spec.rb +4 -2
- data/spec/rubocop/reports/report_spec.rb +3 -1
- data/spec/spec_helper.rb +9 -1
- metadata +17 -3
    
        data/.rbenv-version
    ADDED
    
    | @@ -0,0 +1 @@ | |
| 1 | 
            +
            1.9.3-p327
         | 
    
        data/.travis.yml
    ADDED
    
    
    
        data/Gemfile
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 | 
            -
            source  | 
| 1 | 
            +
            source 'http://rubygems.org'
         | 
| 2 2 | 
             
            # Add dependencies required to use your gem here.
         | 
| 3 3 | 
             
            # Example:
         | 
| 4 4 | 
             
            #   gem "activesupport", ">= 2.3.5"
         | 
| @@ -6,11 +6,11 @@ source "http://rubygems.org" | |
| 6 6 | 
             
            # Add dependencies to develop your gem here.
         | 
| 7 7 | 
             
            # Include everything needed to run rake, tests, features, etc.
         | 
| 8 8 | 
             
            group :development do
         | 
| 9 | 
            -
              gem  | 
| 10 | 
            -
              gem  | 
| 11 | 
            -
              gem  | 
| 12 | 
            -
              gem  | 
| 13 | 
            -
              gem  | 
| 14 | 
            -
              gem  | 
| 15 | 
            -
              gem  | 
| 9 | 
            +
              gem 'rspec', '~> 2.8.0'
         | 
| 10 | 
            +
              gem 'yard', '~> 0.7'
         | 
| 11 | 
            +
              gem 'redcarpet'
         | 
| 12 | 
            +
              gem 'cucumber', '>= 0'
         | 
| 13 | 
            +
              gem 'bundler', '~> 1.1.0'
         | 
| 14 | 
            +
              gem 'jeweler', '~> 1.8.3'
         | 
| 15 | 
            +
              gem 'simplecov'
         | 
| 16 16 | 
             
            end
         | 
    
        data/README.md
    CHANGED
    
    | @@ -1,6 +1,22 @@ | |
| 1 | 
            +
            [](https://travis-ci.org/bbatsov/rubocop)
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            # rubocop
         | 
| 2 4 |  | 
| 3 | 
            -
            Ruby code style checker.
         | 
| 5 | 
            +
            Ruby code style checker based on the [Ruby Style Guide](https://github.com/bbatsov/ruby-style-guide).
         | 
| 6 | 
            +
             | 
| 7 | 
            +
            ## Basic Usage
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            Running `rubocop` with no arguments will check all Ruby source files in the current folder:
         | 
| 10 | 
            +
             | 
| 11 | 
            +
            ```bash
         | 
| 12 | 
            +
            $ rubocop
         | 
| 13 | 
            +
            ```
         | 
| 14 | 
            +
             | 
| 15 | 
            +
            Alternatively you can `rubocop` a list of files and folders to check:
         | 
| 16 | 
            +
             | 
| 17 | 
            +
            ```bash
         | 
| 18 | 
            +
            $ rubocop app spec lib/something.rb
         | 
| 19 | 
            +
            ```
         | 
| 4 20 |  | 
| 5 21 | 
             
            ## Contributing to Rubocop
         | 
| 6 22 |  | 
    
        data/VERSION
    CHANGED
    
    | @@ -1 +1 @@ | |
| 1 | 
            -
            0. | 
| 1 | 
            +
            0.2.0
         | 
    
        data/bin/rubocop
    CHANGED
    
    
| @@ -0,0 +1 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
    
        data/features/support/env.rb
    CHANGED
    
    
    
        data/lib/rubocop.rb
    CHANGED
    
    | @@ -12,6 +12,12 @@ require 'rubocop/cop/indentation' | |
| 12 12 | 
             
            require 'rubocop/cop/empty_lines'
         | 
| 13 13 | 
             
            require 'rubocop/cop/surrounding_space'
         | 
| 14 14 | 
             
            require 'rubocop/cop/space_after_comma_etc'
         | 
| 15 | 
            +
            require 'rubocop/cop/hash_syntax'
         | 
| 16 | 
            +
            require 'rubocop/cop/end_of_line'
         | 
| 17 | 
            +
            require 'rubocop/cop/numeric_literals'
         | 
| 18 | 
            +
            require 'rubocop/cop/align_parameters'
         | 
| 19 | 
            +
            require 'rubocop/cop/def_parentheses'
         | 
| 20 | 
            +
            require 'rubocop/cop/if_then_else'
         | 
| 15 21 |  | 
| 16 22 | 
             
            require 'rubocop/report/report'
         | 
| 17 23 | 
             
            require 'rubocop/report/plain_text'
         | 
    
        data/lib/rubocop/cli.rb
    CHANGED
    
    | @@ -11,36 +11,39 @@ module Rubocop | |
| 11 11 | 
             
                # the target files
         | 
| 12 12 | 
             
                # @return [Fixnum] UNIX exit code
         | 
| 13 13 | 
             
                def run(args = ARGV)
         | 
| 14 | 
            -
                  options = { : | 
| 14 | 
            +
                  $options = { mode: :default }
         | 
| 15 15 |  | 
| 16 16 | 
             
                  OptionParser.new do |opts|
         | 
| 17 17 | 
             
                    opts.banner = "Usage: rubocop [options] [file1, file2, ...]"
         | 
| 18 18 |  | 
| 19 19 | 
             
                    opts.on("-v", "--[no-]verbose", "Run verbosely") do |v|
         | 
| 20 | 
            -
                      options[:verbose] = v
         | 
| 20 | 
            +
                      $options[:verbose] = v
         | 
| 21 21 | 
             
                    end
         | 
| 22 22 | 
             
                    opts.on("-e", "--emacs", "Emacs style output") do
         | 
| 23 | 
            -
                      options[:mode] = :emacs_style
         | 
| 23 | 
            +
                      $options[:mode] = :emacs_style
         | 
| 24 24 | 
             
                    end
         | 
| 25 25 | 
             
                  end.parse!(args)
         | 
| 26 26 |  | 
| 27 27 | 
             
                  cops = Cop::Cop.all
         | 
| 28 | 
            +
                  show_cops_on_duty(cops) if $options[:verbose]
         | 
| 28 29 | 
             
                  total_offences = 0
         | 
| 29 30 |  | 
| 30 | 
            -
                  target_files(args). | 
| 31 | 
            -
                    report = Report.create(file, options[:mode])
         | 
| 32 | 
            -
                    source = File.readlines(file).map  | 
| 31 | 
            +
                  target_files(args).each do |file|
         | 
| 32 | 
            +
                    report = Report.create(file, $options[:mode])
         | 
| 33 | 
            +
                    source = File.readlines(file).map do |line|
         | 
| 33 34 | 
             
                      enc = line.encoding.name
         | 
| 34 35 | 
             
                      # Get rid of invalid byte sequences
         | 
| 35 | 
            -
                      line.encode!('UTF-16', enc, : | 
| 36 | 
            +
                      line.encode!('UTF-16', enc, invalid: :replace, replace: '')
         | 
| 36 37 | 
             
                      line.encode!(enc, 'UTF-16')
         | 
| 37 38 |  | 
| 38 39 | 
             
                      line.chomp
         | 
| 39 | 
            -
                     | 
| 40 | 
            +
                    end
         | 
| 41 | 
            +
             | 
| 42 | 
            +
                    tokens, sexp = CLI.rip_source(source)
         | 
| 40 43 |  | 
| 41 44 | 
             
                    cops.each do |cop_klass|
         | 
| 42 45 | 
             
                      cop = cop_klass.new
         | 
| 43 | 
            -
                      cop. | 
| 46 | 
            +
                      cop.inspect(file, source, tokens, sexp)
         | 
| 44 47 | 
             
                      total_offences += cop.offences.count
         | 
| 45 48 | 
             
                      report << cop if cop.has_report?
         | 
| 46 49 | 
             
                    end
         | 
| @@ -54,22 +57,39 @@ module Rubocop | |
| 54 57 | 
             
                  return total_offences == 0 ? 0 : 1
         | 
| 55 58 | 
             
                end
         | 
| 56 59 |  | 
| 60 | 
            +
                def self.rip_source(source)
         | 
| 61 | 
            +
                  tokens = Ripper.lex(source.join("\n")).map { |t| Cop::Token.new(*t) }
         | 
| 62 | 
            +
                  sexp = Ripper.sexp(source.join("\n"))
         | 
| 63 | 
            +
                  Cop::Position.make_position_objects(sexp)
         | 
| 64 | 
            +
                  [tokens, sexp]
         | 
| 65 | 
            +
                end
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                def show_cops_on_duty(cops)
         | 
| 68 | 
            +
                  puts "Reporting for duty:"
         | 
| 69 | 
            +
                  cops.each { |c| puts c }
         | 
| 70 | 
            +
                  puts "*******************"
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
             | 
| 57 73 | 
             
                # Generate a list of target files by expanding globing patterns
         | 
| 58 74 | 
             
                # (if any). If args is empty recursively finds all Ruby source
         | 
| 59 75 | 
             
                # files in the current directory
         | 
| 60 76 | 
             
                # @return [Array] array of filenames
         | 
| 61 77 | 
             
                def target_files(args)
         | 
| 62 | 
            -
                  raw_target_files(args).reject { |name| name =~ /_flymake/ }
         | 
| 63 | 
            -
                end
         | 
| 64 | 
            -
             | 
| 65 | 
            -
                def raw_target_files(args)
         | 
| 66 78 | 
             
                  return Dir['**/*.rb'] if args.empty?
         | 
| 67 79 |  | 
| 68 | 
            -
                   | 
| 69 | 
            -
             | 
| 70 | 
            -
                   | 
| 71 | 
            -
                     | 
| 80 | 
            +
                  files = []
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                  args.each do |target|
         | 
| 83 | 
            +
                    if File.directory?(target)
         | 
| 84 | 
            +
                      files << Dir["#{target}/**/*.rb"]
         | 
| 85 | 
            +
                    elsif target =~ /\*/
         | 
| 86 | 
            +
                      files << Dir[target]
         | 
| 87 | 
            +
                    else
         | 
| 88 | 
            +
                      files << target
         | 
| 89 | 
            +
                    end
         | 
| 72 90 | 
             
                  end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
                  files.flatten
         | 
| 73 93 | 
             
                end
         | 
| 74 94 | 
             
              end
         | 
| 75 95 | 
             
            end
         | 
| @@ -0,0 +1,112 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Rubocop
         | 
| 4 | 
            +
              module Cop
         | 
| 5 | 
            +
                class AlignParameters < Cop
         | 
| 6 | 
            +
                  ERROR_MESSAGE = 'Align the parameters of a method call if they span ' +
         | 
| 7 | 
            +
                    'more than one line.'
         | 
| 8 | 
            +
             | 
| 9 | 
            +
                  def inspect(file, source, tokens, sexp)
         | 
| 10 | 
            +
                    @file = file
         | 
| 11 | 
            +
                    @tokens = tokens
         | 
| 12 | 
            +
                    @token_indexes = {}
         | 
| 13 | 
            +
                    @tokens.each_with_index { |t, ix| @token_indexes[t.pos] = ix }
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                    each(:method_add_arg, sexp) do |method_add_arg|
         | 
| 16 | 
            +
                      args = get_args(method_add_arg) or next
         | 
| 17 | 
            +
                      first_arg, rest_of_args = divide_args(args)
         | 
| 18 | 
            +
                      @first_lparen_ix = get_lparen_ix(method_add_arg)
         | 
| 19 | 
            +
                      pos_of_1st_arg = position_of(first_arg) or next # Give up.
         | 
| 20 | 
            +
                      rest_of_args.each do |arg|
         | 
| 21 | 
            +
                        pos = position_of(arg) or next # Give up if no position found.
         | 
| 22 | 
            +
                        if pos.lineno != pos_of_1st_arg.lineno
         | 
| 23 | 
            +
                          if pos.column != pos_of_1st_arg.column
         | 
| 24 | 
            +
                            add_offence(:convention, pos.lineno, ERROR_MESSAGE)
         | 
| 25 | 
            +
                          end
         | 
| 26 | 
            +
                        end
         | 
| 27 | 
            +
                      end
         | 
| 28 | 
            +
                    end
         | 
| 29 | 
            +
                  end
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  private
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                  def get_args(method_add_arg)
         | 
| 34 | 
            +
                    fcall = method_add_arg[1]
         | 
| 35 | 
            +
                    return nil if fcall[0] != :fcall
         | 
| 36 | 
            +
                    return nil if fcall[1][0..1] == [:@ident, "lambda"]
         | 
| 37 | 
            +
                    arg_paren = method_add_arg[2..-1][0]
         | 
| 38 | 
            +
                    return nil if arg_paren[0] != :arg_paren || arg_paren[1].nil?
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                    # A command (call wihtout parentheses) as first parameter
         | 
| 41 | 
            +
                    # means there's only one parameter.
         | 
| 42 | 
            +
                    return nil if [:command, :command_call].include?(arg_paren[1][0][0])
         | 
| 43 | 
            +
             | 
| 44 | 
            +
                    args_add_block = arg_paren[1]
         | 
| 45 | 
            +
                    unless args_add_block[0] == :args_add_block
         | 
| 46 | 
            +
                      fail "\n#{@file}: #{method_add_arg}"
         | 
| 47 | 
            +
                    end
         | 
| 48 | 
            +
                    args_add_block[1].empty? ? [args_add_block[2]] : args_add_block[1]
         | 
| 49 | 
            +
                  end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
                  def divide_args(args)
         | 
| 52 | 
            +
                    if args[0] == :args_add_star
         | 
| 53 | 
            +
                      first_arg = args[1]
         | 
| 54 | 
            +
                      rest_of_args = args[2..-1]
         | 
| 55 | 
            +
                    else
         | 
| 56 | 
            +
                      first_arg = args[0]
         | 
| 57 | 
            +
                      rest_of_args = args[1..-1]
         | 
| 58 | 
            +
                    end
         | 
| 59 | 
            +
                    [first_arg, rest_of_args]
         | 
| 60 | 
            +
                  end
         | 
| 61 | 
            +
             | 
| 62 | 
            +
                  def get_lparen_ix(method_add_arg)
         | 
| 63 | 
            +
                    method_name_pos = method_add_arg[1][1][-1]
         | 
| 64 | 
            +
                    method_name_ix = @token_indexes[method_name_pos]
         | 
| 65 | 
            +
                    method_name_ix +
         | 
| 66 | 
            +
                      @tokens[method_name_ix..-1].map(&:type).index(:on_lparen)
         | 
| 67 | 
            +
                  end
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                  def position_of(sexp)
         | 
| 70 | 
            +
                    # Indentation inside a string literal is irrelevant.
         | 
| 71 | 
            +
                    return nil if sexp[0] == :string_literal
         | 
| 72 | 
            +
             | 
| 73 | 
            +
                    pos = find_pos_in_sexp(sexp) or return nil # Nil means not found.
         | 
| 74 | 
            +
                    ix = find_first_non_whitespace_token(pos) or return nil
         | 
| 75 | 
            +
                    @tokens[ix].pos
         | 
| 76 | 
            +
                  end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  def find_pos_in_sexp(sexp)
         | 
| 79 | 
            +
                    return sexp[2] if Position === sexp[2]
         | 
| 80 | 
            +
                    sexp.grep(Array).each do |s|
         | 
| 81 | 
            +
                      pos = find_pos_in_sexp(s) and return pos
         | 
| 82 | 
            +
                    end
         | 
| 83 | 
            +
                    nil
         | 
| 84 | 
            +
                  end
         | 
| 85 | 
            +
             | 
| 86 | 
            +
                  def find_first_non_whitespace_token(pos)
         | 
| 87 | 
            +
                    ix = @token_indexes[pos]
         | 
| 88 | 
            +
                    newline_found = false
         | 
| 89 | 
            +
                    start_ix = ix.downto(0) do |i|
         | 
| 90 | 
            +
                      case @tokens[i].text
         | 
| 91 | 
            +
                      when '('
         | 
| 92 | 
            +
                        break i + 1 if i == @first_lparen_ix
         | 
| 93 | 
            +
                      when "\n"
         | 
| 94 | 
            +
                        newline_found = true
         | 
| 95 | 
            +
                      when /\t/
         | 
| 96 | 
            +
                        # Bail out if tabs are used. Too difficult to calculate column.
         | 
| 97 | 
            +
                        return nil
         | 
| 98 | 
            +
                      when ','
         | 
| 99 | 
            +
                        if newline_found
         | 
| 100 | 
            +
                          break i + 1
         | 
| 101 | 
            +
                        else
         | 
| 102 | 
            +
                          # Bail out if there's a preceding comma on the same line.
         | 
| 103 | 
            +
                          return nil
         | 
| 104 | 
            +
                        end
         | 
| 105 | 
            +
                      end
         | 
| 106 | 
            +
                    end
         | 
| 107 | 
            +
                    offset = @tokens[start_ix..-1].index { |t| not whitespace?(t) }
         | 
| 108 | 
            +
                    start_ix + offset
         | 
| 109 | 
            +
                  end
         | 
| 110 | 
            +
                end
         | 
| 111 | 
            +
              end
         | 
| 112 | 
            +
            end
         | 
    
        data/lib/rubocop/cop/cop.rb
    CHANGED
    
    | @@ -2,6 +2,34 @@ | |
| 2 2 |  | 
| 3 3 | 
             
            module Rubocop
         | 
| 4 4 | 
             
              module Cop
         | 
| 5 | 
            +
                class Position < Struct.new :lineno, :column
         | 
| 6 | 
            +
                  # Does a recursive search and replaces each [lineno, column] array
         | 
| 7 | 
            +
                  # in the sexp with a Position object.
         | 
| 8 | 
            +
                  def self.make_position_objects(sexp)
         | 
| 9 | 
            +
                    if sexp[0] =~ /^@/
         | 
| 10 | 
            +
                      sexp[2] = Position.new(*sexp[2])
         | 
| 11 | 
            +
                    else
         | 
| 12 | 
            +
                      sexp.grep(Array).each { |s| make_position_objects(s) }
         | 
| 13 | 
            +
                    end
         | 
| 14 | 
            +
                  end
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                  # The point of this class is to provide named attribute access.
         | 
| 17 | 
            +
                  # So we don't want backwards compatibility with array indexing.
         | 
| 18 | 
            +
                  undef_method :[]
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                class Token
         | 
| 22 | 
            +
                  attr_reader :pos, :type, :text
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  def initialize(pos, type, text)
         | 
| 25 | 
            +
                    @pos, @type, @text = Position.new(*pos), type, text
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  def to_s
         | 
| 29 | 
            +
                    "[[#{@pos.lineno}, #{@pos.column}], #@type, #{@text.inspect}]"
         | 
| 30 | 
            +
                  end
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 5 33 | 
             
                class Cop
         | 
| 6 34 | 
             
                  attr_accessor :offences
         | 
| 7 35 |  | 
| @@ -16,7 +44,6 @@ module Rubocop | |
| 16 44 | 
             
                  end
         | 
| 17 45 |  | 
| 18 46 | 
             
                  def self.inherited(subclass)
         | 
| 19 | 
            -
                    puts "Registering cop #{subclass}"
         | 
| 20 47 | 
             
                    all << subclass
         | 
| 21 48 | 
             
                  end
         | 
| 22 49 |  | 
| @@ -36,42 +63,37 @@ module Rubocop | |
| 36 63 | 
             
                    !@offences.empty?
         | 
| 37 64 | 
             
                  end
         | 
| 38 65 |  | 
| 39 | 
            -
                  def  | 
| 40 | 
            -
                     | 
| 41 | 
            -
                    when 2
         | 
| 42 | 
            -
                      inspect(file, source)
         | 
| 43 | 
            -
                    else
         | 
| 44 | 
            -
                      tokens = Ripper.lex(source.join("\n"))
         | 
| 45 | 
            -
                      sexp = Ripper.sexp(source.join("\n"))
         | 
| 46 | 
            -
                      inspect(file, source, tokens, sexp)
         | 
| 47 | 
            -
                    end
         | 
| 48 | 
            -
                  end
         | 
| 49 | 
            -
             | 
| 50 | 
            -
                  def add_offence(file, line_number, line, message)
         | 
| 51 | 
            -
                    @offences << Offence.new(file, line_number, line, message)
         | 
| 66 | 
            +
                  def add_offence(file, line_number, message)
         | 
| 67 | 
            +
                    @offences << Offence.new(file, line_number, message)
         | 
| 52 68 | 
             
                  end
         | 
| 53 69 |  | 
| 54 70 | 
             
                  private
         | 
| 55 71 |  | 
| 56 72 | 
             
                  def each_parent_of(sym, sexp)
         | 
| 57 73 | 
             
                    parents = []
         | 
| 58 | 
            -
                    sexp.each  | 
| 74 | 
            +
                    sexp.each do |elem|
         | 
| 59 75 | 
             
                      if Array === elem
         | 
| 60 76 | 
             
                        if elem[0] == sym
         | 
| 61 | 
            -
                          parents << sexp
         | 
| 77 | 
            +
                          parents << sexp unless parents.include?(sexp)
         | 
| 62 78 | 
             
                          elem = elem[1..-1]
         | 
| 63 79 | 
             
                        end
         | 
| 64 | 
            -
                        each_parent_of(sym, elem)  | 
| 80 | 
            +
                        each_parent_of(sym, elem) do |parent|
         | 
| 81 | 
            +
                          parents << parent unless parents.include?(parent)
         | 
| 82 | 
            +
                        end
         | 
| 65 83 | 
             
                      end
         | 
| 66 | 
            -
                     | 
| 67 | 
            -
                    parents. | 
| 84 | 
            +
                    end
         | 
| 85 | 
            +
                    parents.each { |parent| yield parent }
         | 
| 68 86 | 
             
                  end
         | 
| 69 87 |  | 
| 70 88 | 
             
                  def each(sym, sexp)
         | 
| 71 89 | 
             
                    yield sexp if sexp[0] == sym
         | 
| 72 | 
            -
                    sexp.each  | 
| 90 | 
            +
                    sexp.each do |elem|
         | 
| 73 91 | 
             
                      each(sym, elem) { |s| yield s } if Array === elem
         | 
| 74 | 
            -
                     | 
| 92 | 
            +
                    end
         | 
| 93 | 
            +
                  end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                  def whitespace?(token)
         | 
| 96 | 
            +
                    [:on_sp, :on_ignored_nl, :on_nl].include?(token.type)
         | 
| 75 97 | 
             
                  end
         | 
| 76 98 | 
             
                end
         | 
| 77 99 | 
             
              end
         | 
| @@ -0,0 +1,38 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Rubocop
         | 
| 4 | 
            +
              module Cop
         | 
| 5 | 
            +
                class DefParentheses < Cop
         | 
| 6 | 
            +
                  ERROR_MESSAGE = ['Use def with parentheses when there are arguments.',
         | 
| 7 | 
            +
                                   "Omit the parentheses in defs when the method " +
         | 
| 8 | 
            +
                                   "doesn't accept any arguments."]
         | 
| 9 | 
            +
                  EMPTY_PARAMS = [:params, nil, nil, nil, nil, nil]
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  def inspect(file, source, tokens, sexp)
         | 
| 12 | 
            +
                    each(:def, sexp) do |def_sexp|
         | 
| 13 | 
            +
                      pos = def_sexp[1][-1]
         | 
| 14 | 
            +
                      case def_sexp[2][0]
         | 
| 15 | 
            +
                      when :params
         | 
| 16 | 
            +
                        if def_sexp[2] != EMPTY_PARAMS
         | 
| 17 | 
            +
                          add_offence(:convention, pos.lineno, ERROR_MESSAGE[0])
         | 
| 18 | 
            +
                        end
         | 
| 19 | 
            +
                      when :paren
         | 
| 20 | 
            +
                        if def_sexp[2][1] == EMPTY_PARAMS
         | 
| 21 | 
            +
                          method_name_ix = tokens.index { |t| t.pos == pos }
         | 
| 22 | 
            +
                          start = method_name_ix + 1
         | 
| 23 | 
            +
                          rparen_ix = start + tokens[start..-1].index { |t| t.text == ')' }
         | 
| 24 | 
            +
                          first_body_token = tokens[(rparen_ix + 1)..-1].find do |t|
         | 
| 25 | 
            +
                            not whitespace?(t)
         | 
| 26 | 
            +
                          end
         | 
| 27 | 
            +
                          if first_body_token.pos.lineno > pos.lineno
         | 
| 28 | 
            +
                            # Only report offence if there's a line break after
         | 
| 29 | 
            +
                            # the empty parens.
         | 
| 30 | 
            +
                            add_offence(:convention, pos.lineno, ERROR_MESSAGE[1])
         | 
| 31 | 
            +
                          end
         | 
| 32 | 
            +
                        end
         | 
| 33 | 
            +
                      end
         | 
| 34 | 
            +
                    end
         | 
| 35 | 
            +
                  end
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
              end
         | 
| 38 | 
            +
            end
         | 
| @@ -1,3 +1,5 @@ | |
| 1 | 
            +
            # encoding: utf-8
         | 
| 2 | 
            +
             | 
| 1 3 | 
             
            module Rubocop
         | 
| 2 4 | 
             
              module Cop
         | 
| 3 5 | 
             
                class EmptyLines < Cop
         | 
| @@ -7,17 +9,16 @@ module Rubocop | |
| 7 9 | 
             
                    each_parent_of(:def, sexp) do |parent|
         | 
| 8 10 | 
             
                      defs = parent.select { |child| child[0] == :def }
         | 
| 9 11 | 
             
                      identifier_of_first_def = defs[0][1]
         | 
| 10 | 
            -
                      current_row_ix = identifier_of_first_def[-1] | 
| 12 | 
            +
                      current_row_ix = identifier_of_first_def[-1].lineno - 1
         | 
| 11 13 | 
             
                      # The first def doesn't need to have an empty line above it,
         | 
| 12 14 | 
             
                      # so we iterate starting at index 1.
         | 
| 13 | 
            -
                      defs[1..-1].each  | 
| 14 | 
            -
                        next_row_ix = child[1][-1] | 
| 15 | 
            +
                      defs[1..-1].each do |child|
         | 
| 16 | 
            +
                        next_row_ix = child[1][-1].lineno - 1
         | 
| 15 17 | 
             
                        if source[current_row_ix..next_row_ix].grep(/^[ \t]*$/).empty?
         | 
| 16 | 
            -
                          add_offence(:convention, next_row_ix,  | 
| 17 | 
            -
                                      ERROR_MESSAGE)
         | 
| 18 | 
            +
                          add_offence(:convention, next_row_ix + 1, ERROR_MESSAGE)
         | 
| 18 19 | 
             
                        end
         | 
| 19 20 | 
             
                        current_row_ix = next_row_ix
         | 
| 20 | 
            -
                       | 
| 21 | 
            +
                      end
         | 
| 21 22 | 
             
                    end
         | 
| 22 23 | 
             
                  end
         | 
| 23 24 | 
             
                end
         |