rubocop 0.4.0 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of rubocop might be problematic. Click here for more details.

Files changed (190) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +50 -0
  3. data/.rubocop.yml +5 -127
  4. data/.travis.yml +7 -1
  5. data/CHANGELOG.md +157 -0
  6. data/CONTRIBUTING.md +13 -6
  7. data/Gemfile +3 -8
  8. data/README.md +160 -9
  9. data/Rakefile +3 -17
  10. data/bin/rubocop +16 -10
  11. data/config/default.yml +46 -0
  12. data/config/disabled.yml +5 -0
  13. data/config/enabled.yml +322 -0
  14. data/lib/rubocop/cli.rb +248 -93
  15. data/lib/rubocop/config.rb +205 -0
  16. data/lib/rubocop/config_store.rb +37 -0
  17. data/lib/rubocop/cop/access_control.rb +41 -0
  18. data/lib/rubocop/cop/alias.rb +17 -0
  19. data/lib/rubocop/cop/align_parameters.rb +20 -95
  20. data/lib/rubocop/cop/and_or.rb +26 -0
  21. data/lib/rubocop/cop/ascii_comments.rb +13 -0
  22. data/lib/rubocop/cop/ascii_identifiers.rb +19 -0
  23. data/lib/rubocop/cop/avoid_class_vars.rb +15 -0
  24. data/lib/rubocop/cop/avoid_for.rb +17 -0
  25. data/lib/rubocop/cop/avoid_global_vars.rb +61 -0
  26. data/lib/rubocop/cop/avoid_perl_backrefs.rb +17 -0
  27. data/lib/rubocop/cop/avoid_perlisms.rb +47 -0
  28. data/lib/rubocop/cop/block_comments.rb +15 -0
  29. data/lib/rubocop/cop/blocks.rb +11 -47
  30. data/lib/rubocop/cop/case_indentation.rb +22 -0
  31. data/lib/rubocop/cop/class_and_module_camel_case.rb +20 -11
  32. data/lib/rubocop/cop/class_methods.rb +15 -0
  33. data/lib/rubocop/cop/collection_methods.rb +16 -16
  34. data/lib/rubocop/cop/colon_method_call.rb +20 -0
  35. data/lib/rubocop/cop/constant_name.rb +24 -0
  36. data/lib/rubocop/cop/cop.rb +34 -47
  37. data/lib/rubocop/cop/def_parentheses.rb +43 -35
  38. data/lib/rubocop/cop/empty_line_between_defs.rb +22 -0
  39. data/lib/rubocop/cop/empty_lines.rb +21 -13
  40. data/lib/rubocop/cop/empty_literal.rb +47 -0
  41. data/lib/rubocop/cop/encoding.rb +3 -3
  42. data/lib/rubocop/cop/end_of_line.rb +3 -3
  43. data/lib/rubocop/cop/ensure_return.rb +19 -0
  44. data/lib/rubocop/cop/eval.rb +19 -0
  45. data/lib/rubocop/cop/favor_join.rb +22 -0
  46. data/lib/rubocop/cop/favor_modifier.rb +38 -48
  47. data/lib/rubocop/cop/favor_percent_r.rb +19 -0
  48. data/lib/rubocop/cop/favor_sprintf.rb +21 -0
  49. data/lib/rubocop/cop/favor_unless_over_negated_if.rb +19 -17
  50. data/lib/rubocop/cop/handle_exceptions.rb +17 -0
  51. data/lib/rubocop/cop/hash_syntax.rb +29 -14
  52. data/lib/rubocop/cop/if_then_else.rb +32 -29
  53. data/lib/rubocop/cop/leading_comment_space.rb +17 -0
  54. data/lib/rubocop/cop/line_continuation.rb +15 -0
  55. data/lib/rubocop/cop/line_length.rb +4 -4
  56. data/lib/rubocop/cop/loop.rb +33 -0
  57. data/lib/rubocop/cop/method_and_variable_snake_case.rb +41 -17
  58. data/lib/rubocop/cop/method_length.rb +52 -0
  59. data/lib/rubocop/cop/new_lambda_literal.rb +8 -6
  60. data/lib/rubocop/cop/not.rb +21 -0
  61. data/lib/rubocop/cop/numeric_literals.rb +9 -7
  62. data/lib/rubocop/cop/offence.rb +12 -1
  63. data/lib/rubocop/cop/op_method.rb +26 -0
  64. data/lib/rubocop/cop/parameter_lists.rb +12 -6
  65. data/lib/rubocop/cop/parentheses_around_condition.rb +11 -11
  66. data/lib/rubocop/cop/percent_r.rb +19 -0
  67. data/lib/rubocop/cop/reduce_arguments.rb +29 -0
  68. data/lib/rubocop/cop/rescue_exception.rb +26 -0
  69. data/lib/rubocop/cop/rescue_modifier.rb +17 -0
  70. data/lib/rubocop/cop/semicolon.rb +31 -0
  71. data/lib/rubocop/cop/single_line_methods.rb +44 -0
  72. data/lib/rubocop/cop/space_after_comma_etc.rb +30 -10
  73. data/lib/rubocop/cop/space_after_control_keyword.rb +29 -0
  74. data/lib/rubocop/cop/string_literals.rb +9 -23
  75. data/lib/rubocop/cop/surrounding_space.rb +223 -83
  76. data/lib/rubocop/cop/symbol_array.rb +31 -0
  77. data/lib/rubocop/cop/symbol_name.rb +23 -0
  78. data/lib/rubocop/cop/syntax.rb +35 -5
  79. data/lib/rubocop/cop/tab.rb +3 -3
  80. data/lib/rubocop/cop/ternary_operator.rb +26 -24
  81. data/lib/rubocop/cop/trailing_whitespace.rb +3 -5
  82. data/lib/rubocop/cop/trivial_accessors.rb +26 -0
  83. data/lib/rubocop/cop/unless_else.rb +11 -7
  84. data/lib/rubocop/cop/util.rb +26 -0
  85. data/lib/rubocop/cop/variable_interpolation.rb +29 -0
  86. data/lib/rubocop/cop/when_then.rb +6 -14
  87. data/lib/rubocop/cop/word_array.rb +37 -0
  88. data/lib/rubocop/report/emacs_style.rb +2 -2
  89. data/lib/rubocop/report/plain_text.rb +1 -1
  90. data/lib/rubocop/version.rb +3 -1
  91. data/lib/rubocop.rb +48 -8
  92. data/rubocop.gemspec +32 -151
  93. data/spec/project_spec.rb +27 -0
  94. data/spec/rubocop/cli_spec.rb +573 -200
  95. data/spec/rubocop/config_spec.rb +409 -0
  96. data/spec/rubocop/config_store_spec.rb +66 -0
  97. data/spec/rubocop/cops/access_control_spec.rb +129 -0
  98. data/spec/rubocop/cops/alias_spec.rb +39 -0
  99. data/spec/rubocop/cops/align_parameters_spec.rb +66 -70
  100. data/spec/rubocop/cops/and_or_spec.rb +37 -0
  101. data/spec/rubocop/cops/ascii_comments_spec.rb +26 -0
  102. data/spec/rubocop/cops/ascii_identifiers_spec.rb +26 -0
  103. data/spec/rubocop/cops/avoid_class_vars_spec.rb +25 -0
  104. data/spec/rubocop/cops/avoid_for_spec.rb +35 -0
  105. data/spec/rubocop/cops/avoid_global_vars_spec.rb +32 -0
  106. data/spec/rubocop/cops/avoid_perl_backrefs_spec.rb +18 -0
  107. data/spec/rubocop/cops/avoid_perlisms_spec.rb +44 -0
  108. data/spec/rubocop/cops/block_comments_spec.rb +25 -0
  109. data/spec/rubocop/cops/blocks_spec.rb +33 -0
  110. data/spec/rubocop/cops/{indentation_spec.rb → case_indentation_spec.rb} +7 -7
  111. data/spec/rubocop/cops/class_and_module_camel_case_spec.rb +15 -5
  112. data/spec/rubocop/cops/class_methods_spec.rb +49 -0
  113. data/spec/rubocop/cops/collection_methods_spec.rb +9 -4
  114. data/spec/rubocop/cops/colon_method_call_spec.rb +53 -0
  115. data/spec/rubocop/cops/constant_name_spec.rb +42 -0
  116. data/spec/rubocop/cops/def_with_parentheses_spec.rb +13 -8
  117. data/spec/rubocop/cops/def_without_parentheses_spec.rb +11 -5
  118. data/spec/rubocop/cops/empty_line_between_defs_spec.rb +83 -0
  119. data/spec/rubocop/cops/empty_lines_spec.rb +14 -59
  120. data/spec/rubocop/cops/empty_literal_spec.rb +90 -0
  121. data/spec/rubocop/cops/encoding_spec.rb +11 -11
  122. data/spec/rubocop/cops/end_of_line_spec.rb +2 -2
  123. data/spec/rubocop/cops/ensure_return_spec.rb +35 -0
  124. data/spec/rubocop/cops/eval_spec.rb +39 -0
  125. data/spec/rubocop/cops/favor_join_spec.rb +35 -0
  126. data/spec/rubocop/cops/favor_modifier_spec.rb +16 -14
  127. data/spec/rubocop/cops/favor_percent_r_spec.rb +29 -0
  128. data/spec/rubocop/cops/favor_sprintf_spec.rb +51 -0
  129. data/spec/rubocop/cops/favor_unless_over_negated_if_spec.rb +4 -4
  130. data/spec/rubocop/cops/favor_until_over_negated_while_spec.rb +3 -3
  131. data/spec/rubocop/cops/handle_exceptions_spec.rb +34 -0
  132. data/spec/rubocop/cops/hash_syntax_spec.rb +11 -6
  133. data/spec/rubocop/cops/if_with_semicolon_spec.rb +7 -1
  134. data/spec/rubocop/cops/leading_comment_space_spec.rb +54 -0
  135. data/spec/rubocop/cops/line_continuation_spec.rb +24 -0
  136. data/spec/rubocop/cops/line_length_spec.rb +3 -2
  137. data/spec/rubocop/cops/loop_spec.rb +31 -0
  138. data/spec/rubocop/cops/method_and_variable_snake_case_spec.rb +55 -9
  139. data/spec/rubocop/cops/method_length_spec.rb +147 -0
  140. data/spec/rubocop/cops/multiline_if_then_spec.rb +15 -15
  141. data/spec/rubocop/cops/new_lambda_literal_spec.rb +5 -6
  142. data/spec/rubocop/cops/not_spec.rb +31 -0
  143. data/spec/rubocop/cops/numeric_literals_spec.rb +13 -13
  144. data/spec/rubocop/cops/offence_spec.rb +13 -0
  145. data/spec/rubocop/cops/one_line_conditional_spec.rb +1 -1
  146. data/spec/rubocop/cops/op_method_spec.rb +78 -0
  147. data/spec/rubocop/cops/parameter_lists_spec.rb +7 -7
  148. data/spec/rubocop/cops/parentheses_around_condition_spec.rb +41 -44
  149. data/spec/rubocop/cops/percent_r_spec.rb +29 -0
  150. data/spec/rubocop/cops/reduce_arguments_spec.rb +57 -0
  151. data/spec/rubocop/cops/rescue_exception_spec.rb +125 -0
  152. data/spec/rubocop/cops/rescue_modifier_spec.rb +37 -0
  153. data/spec/rubocop/cops/semicolon_spec.rb +88 -0
  154. data/spec/rubocop/cops/single_line_methods_spec.rb +50 -0
  155. data/spec/rubocop/cops/space_after_colon_spec.rb +3 -3
  156. data/spec/rubocop/cops/space_after_comma_spec.rb +14 -2
  157. data/spec/rubocop/cops/space_after_control_keyword_spec.rb +67 -0
  158. data/spec/rubocop/cops/space_after_semicolon_spec.rb +6 -1
  159. data/spec/rubocop/cops/space_around_braces_spec.rb +18 -3
  160. data/spec/rubocop/cops/space_around_equals_in_default_parameter_spec.rb +12 -2
  161. data/spec/rubocop/cops/space_around_operators_spec.rb +88 -26
  162. data/spec/rubocop/cops/space_inside_brackets_spec.rb +13 -7
  163. data/spec/rubocop/cops/space_inside_hash_literal_braces_spec.rb +79 -0
  164. data/spec/rubocop/cops/space_inside_parens_spec.rb +7 -3
  165. data/spec/rubocop/cops/string_literals_spec.rb +21 -6
  166. data/spec/rubocop/cops/symbol_array_spec.rb +41 -0
  167. data/spec/rubocop/cops/symbol_name_spec.rb +119 -0
  168. data/spec/rubocop/cops/syntax_spec.rb +28 -5
  169. data/spec/rubocop/cops/tab_spec.rb +2 -2
  170. data/spec/rubocop/cops/ternary_operator_spec.rb +13 -17
  171. data/spec/rubocop/cops/trailing_whitespace_spec.rb +3 -3
  172. data/spec/rubocop/cops/trivial_accessors_spec.rb +329 -0
  173. data/spec/rubocop/cops/unless_else_spec.rb +8 -8
  174. data/spec/rubocop/cops/variable_interpolation_spec.rb +49 -0
  175. data/spec/rubocop/cops/when_then_spec.rb +14 -14
  176. data/spec/rubocop/cops/word_array_spec.rb +47 -0
  177. data/spec/spec_helper.rb +30 -9
  178. data/spec/support/file_helper.rb +21 -0
  179. data/spec/support/isolated_environment.rb +27 -0
  180. metadata +235 -76
  181. data/.document +0 -5
  182. data/Gemfile.lock +0 -41
  183. data/VERSION +0 -1
  184. data/lib/rubocop/cop/ampersands_pipes_vs_and_or.rb +0 -25
  185. data/lib/rubocop/cop/grammar.rb +0 -135
  186. data/lib/rubocop/cop/indentation.rb +0 -44
  187. data/spec/rubocop/cops/ampersands_pipes_vs_and_or_spec.rb +0 -57
  188. data/spec/rubocop/cops/grammar_spec.rb +0 -71
  189. data/spec/rubocop/cops/multiline_blocks_spec.rb +0 -24
  190. data/spec/rubocop/cops/single_line_blocks_spec.rb +0 -22
@@ -2,37 +2,24 @@
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
5
  class Token
22
6
  attr_reader :pos, :type, :text
23
7
 
24
8
  def initialize(pos, type, text)
25
- @pos, @type, @text = Position.new(*pos), type, text
9
+ @pos, @type, @text = pos, type, text
26
10
  end
27
11
 
28
12
  def to_s
29
- "[[#{@pos.lineno}, #{@pos.column}], #@type, #{@text.inspect}]"
13
+ "[[#{@pos.line}, #{@pos.column}], #{@type}, #{@text.inspect}]"
30
14
  end
31
15
  end
32
16
 
33
- class Cop
17
+ class Cop < Parser::AST::Processor
18
+ extend AST::Sexp
19
+
34
20
  attr_accessor :offences
35
- attr_writer :correlations
21
+ attr_accessor :debug
22
+ attr_writer :disabled_lines
36
23
 
37
24
  @all = []
38
25
  @config = {}
@@ -46,50 +33,50 @@ module Rubocop
46
33
  all << subclass
47
34
  end
48
35
 
36
+ def self.cop_name
37
+ name.to_s.split('::').last
38
+ end
39
+
49
40
  def initialize
50
41
  @offences = []
42
+ @debug = false
51
43
  end
52
44
 
53
45
  def has_report?
54
46
  !@offences.empty?
55
47
  end
56
48
 
57
- def add_offence(severity, line_number, message)
58
- @offences << Offence.new(severity, line_number, message)
49
+ def inspect(source, tokens, ast, comments)
50
+ process(ast)
51
+ comments.each { |c| on_comment(c) }
59
52
  end
60
53
 
61
- private
62
-
63
- def each_parent_of(sym, sexp)
64
- parents = []
65
- sexp.each do |elem|
66
- if Array === elem
67
- if elem[0] == sym
68
- parents << sexp unless parents.include?(sexp)
69
- elem = elem[1..-1]
70
- end
71
- each_parent_of(sym, elem) do |parent|
72
- parents << parent unless parents.include?(parent)
73
- end
74
- end
75
- end
76
- parents.each { |parent| yield parent }
54
+ def on_comment(comment)
77
55
  end
78
56
 
79
- def each(sym, sexp)
80
- yield sexp if sexp[0] == sym
81
- sexp.each do |elem|
82
- each(sym, elem) { |s| yield s } if Array === elem
57
+ def add_offence(severity, line_number, message)
58
+ unless @disabled_lines && @disabled_lines.include?(line_number)
59
+ message = debug ? "#{name}: #{message}" : message
60
+ @offences << Offence.new(severity, line_number, message)
83
61
  end
84
62
  end
85
63
 
86
- def whitespace?(token)
87
- [:on_sp, :on_ignored_nl, :on_nl].include?(token.type)
64
+ def name
65
+ self.class.cop_name
88
66
  end
89
67
 
90
- def all_positions(sexp)
91
- return [sexp[2]] if sexp[0] =~ /^@/
92
- sexp.grep(Array).reduce([]) { |memo, s| memo + all_positions(s) }
68
+ private
69
+
70
+ def on_node(syms, sexp, excludes = [])
71
+ yield sexp if Array(syms).include?(sexp.type)
72
+
73
+ return if Array(excludes).include?(sexp.type)
74
+
75
+ sexp.children.each do |elem|
76
+ if Parser::AST::Node === elem
77
+ on_node(syms, elem, excludes) { |s| yield s }
78
+ end
79
+ end
93
80
  end
94
81
  end
95
82
  end
@@ -2,52 +2,60 @@
2
2
 
3
3
  module Rubocop
4
4
  module Cop
5
- module DefParentheses
6
- EMPTY_PARAMS = [:params, nil, nil, nil,
7
- nil, nil, nil, nil] if RUBY_VERSION >= '2.0.0'
8
- EMPTY_PARAMS = [:params, nil, nil, nil,
9
- nil, nil] if RUBY_VERSION < '2.0.0'
10
-
11
- def inspect(file, source, tokens, sexp)
12
- each(:def, sexp) { |def_sexp| check(tokens, def_sexp) }
13
- end
14
- end
15
-
16
5
  class DefWithParentheses < Cop
17
- include DefParentheses
18
- def error_message
19
- "Omit the parentheses in defs when the method doesn't accept any " +
20
- 'arguments.'
6
+ MSG = "Omit the parentheses in defs when the method doesn't accept " +
7
+ 'any arguments.'
8
+
9
+ def on_def(node)
10
+ start_line = node.loc.keyword.line
11
+ end_line = node.loc.end.line
12
+
13
+ return if start_line == end_line
14
+
15
+ _, args = *node
16
+ if args.children == [] && args.loc.begin
17
+ add_offence(:convention, node.loc.line, MSG)
18
+ end
19
+
20
+ super
21
21
  end
22
22
 
23
- def check(tokens, def_sexp)
24
- if def_sexp[2][0] == :paren && def_sexp[2][1] == EMPTY_PARAMS
25
- pos = def_sexp[1][-1]
26
- method_name_ix = tokens.index { |t| t.pos == pos }
27
- start = method_name_ix + 1
28
- rparen_ix = start + tokens[start..-1].index { |t| t.text == ')' }
29
- first_body_token = tokens[(rparen_ix + 1)..-1].find do |t|
30
- not whitespace?(t)
31
- end
32
- if first_body_token.pos.lineno > pos.lineno
33
- # Only report offence if there's a line break after
34
- # the empty parens.
35
- add_offence(:convention, pos.lineno, error_message)
36
- end
23
+ def on_defs(node)
24
+ start_line = node.loc.keyword.line
25
+ end_line = node.loc.end.line
26
+
27
+ return if start_line == end_line
28
+
29
+ _, _, args = *node
30
+ if args.children == [] && args.loc.begin
31
+ add_offence(:convention, node.loc.line, MSG)
37
32
  end
33
+
34
+ super
38
35
  end
39
36
  end
40
37
 
41
38
  class DefWithoutParentheses < Cop
42
- include DefParentheses
43
- def error_message
44
- 'Use def with parentheses when there are arguments.'
39
+ MSG = 'Use def with parentheses when there are arguments.'
40
+
41
+ def on_def(node)
42
+ _, args = *node
43
+
44
+ if args.children.size > 0 && args.loc.begin.nil?
45
+ add_offence(:convention, node.loc.line, MSG)
46
+ end
47
+
48
+ super
45
49
  end
46
50
 
47
- def check(tokens, def_sexp)
48
- if def_sexp[2][0] == :params && def_sexp[2] != EMPTY_PARAMS
49
- add_offence(:convention, def_sexp[1][-1].lineno, error_message)
51
+ def on_defs(node)
52
+ _, _, args = *node
53
+
54
+ if args.children.size > 0 && args.loc.begin.nil?
55
+ add_offence(:convention, node.loc.line, MSG)
50
56
  end
57
+
58
+ super
51
59
  end
52
60
  end
53
61
  end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class EmptyLineBetweenDefs < Cop
6
+ MSG = 'Use empty lines between defs.'
7
+
8
+ def on_def(s)
9
+ def_start = s.loc.keyword.line
10
+ def_end = s.loc.end.line
11
+
12
+ if @prev_def_end && (def_start - @prev_def_end) < 2
13
+ add_offence(:convention, def_start, MSG)
14
+ end
15
+
16
+ @prev_def_end = def_end
17
+
18
+ super
19
+ end
20
+ end
21
+ end
22
+ end
@@ -3,22 +3,30 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class EmptyLines < Cop
6
- ERROR_MESSAGE = 'Use empty lines between defs.'
6
+ MSG = 'Extra blank line detected.'
7
+ LINE_OFFSET = 2
7
8
 
8
- def inspect(file, source, tokens, sexp)
9
- each_parent_of(:def, sexp) do |parent|
10
- defs = parent.select { |child| child[0] == :def }
11
- identifier_of_first_def = defs[0][1]
12
- current_row_ix = identifier_of_first_def[-1].lineno - 1
13
- # The first def doesn't need to have an empty line above it,
14
- # so we iterate starting at index 1.
15
- defs[1..-1].each do |child|
16
- next_row_ix = child[1][-1].lineno - 1
17
- if source[current_row_ix..next_row_ix].grep(/^[ \t]*$/).empty?
18
- add_offence(:convention, next_row_ix + 1, ERROR_MESSAGE)
9
+ def inspect(source, tokens, ast, comments)
10
+ return if tokens.empty?
11
+
12
+ prev_line = 1
13
+
14
+ tokens.each do |token|
15
+ cur_line = token.pos.line
16
+ line_diff = cur_line - prev_line
17
+
18
+ if line_diff > LINE_OFFSET
19
+ # we need to be wary of comments since they
20
+ # don't show up in the tokens
21
+ ((prev_line + 1)...cur_line).each do |line|
22
+ # we check if the prev and current lines are empty
23
+ if source[line - 2].empty? && source[line - 1].empty?
24
+ add_offence(:convention, line, MSG)
25
+ end
19
26
  end
20
- current_row_ix = next_row_ix
21
27
  end
28
+
29
+ prev_line = cur_line
22
30
  end
23
31
  end
24
32
  end
@@ -0,0 +1,47 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class EmptyLiteral < Cop
6
+ ARR_MSG = 'Use array literal [] instead of Array.new.'
7
+ HASH_MSG = 'Use hash literal {} instead of Hash.new.'
8
+ STR_MSG = "Use string literal '' instead of String.new."
9
+
10
+ # Empty array node
11
+ #
12
+ # (send
13
+ # (const nil :Array) :new)
14
+ ARRAY_NODE = s(:send, s(:const, nil, :Array), :new)
15
+
16
+ # Empty hash node
17
+ #
18
+ # (send
19
+ # (const nil :Hash) :new)
20
+ HASH_NODE = s(:send, s(:const, nil, :Hash), :new)
21
+
22
+ # Empty string node
23
+ #
24
+ # (send
25
+ # (const nil :String) :new)
26
+ STR_NODE = s(:send, s(:const, nil, :String), :new)
27
+
28
+ def inspect(source, tokens, ast, comments)
29
+ on_node(:send, ast, :block) do |node|
30
+ if node == ARRAY_NODE
31
+ add_offence(:convention,
32
+ node.loc.line,
33
+ ARR_MSG)
34
+ elsif node == HASH_NODE
35
+ add_offence(:convention,
36
+ node.loc.line,
37
+ HASH_MSG)
38
+ elsif node == STR_NODE
39
+ add_offence(:convention,
40
+ node.loc.line,
41
+ STR_MSG)
42
+ end
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -3,14 +3,14 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class Encoding < Cop
6
- ERROR_MESSAGE = 'Missing encoding comment.'
6
+ MSG = 'Missing utf-8 encoding comment.'
7
7
 
8
- def inspect(file, source, tokens, sexp)
8
+ def inspect(source, tokens, ast, comments)
9
9
  unless RUBY_VERSION >= '2.0.0'
10
10
  expected_line = 0
11
11
  expected_line += 1 if source[expected_line] =~ /^#!/
12
12
  unless source[expected_line] =~ /#.*coding: (UTF|utf)-8/
13
- add_offence(:convention, 1, ERROR_MESSAGE)
13
+ add_offence(:convention, 1, MSG)
14
14
  end
15
15
  end
16
16
  end
@@ -3,11 +3,11 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  class EndOfLine < Cop
6
- ERROR_MESSAGE = 'Carriage return character detected.'
6
+ MSG = 'Carriage return character detected.'
7
7
 
8
- def inspect(file, source, tokens, sexp)
8
+ def inspect(source, tokens, ast, comments)
9
9
  source.each_with_index do |line, index|
10
- add_offence(:convention, index + 1, ERROR_MESSAGE) if line =~ /\r$/
10
+ add_offence(:convention, index + 1, MSG) if line =~ /\r$/
11
11
  end
12
12
  end
13
13
  end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class EnsureReturn < Cop
6
+ MSG = 'Never return from an ensure block.'
7
+
8
+ def on_ensure(node)
9
+ _body, ensure_body = *node
10
+
11
+ on_node(:return, ensure_body) do |e|
12
+ add_offence(:warning, e.loc.line, MSG)
13
+ end
14
+
15
+ super
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class Eval < Cop
6
+ MSG = 'The use of eval is a serious security risk.'
7
+
8
+ def on_send(node)
9
+ receiver, method_name, = *node
10
+
11
+ if receiver.nil? && method_name == :eval
12
+ add_offence(:security, node.loc.line, MSG)
13
+ end
14
+
15
+ super
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,22 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class FavorJoin < Cop
6
+ MSG = 'Favor Array#join over Array#*.'
7
+
8
+ def on_send(node)
9
+ receiver_node, method_name, *arg_nodes = *node
10
+
11
+ if receiver_node && receiver_node.type == :array &&
12
+ method_name == :* && arg_nodes[0].type == :str
13
+ add_offence(:convention,
14
+ node.loc.expression.line,
15
+ MSG)
16
+ end
17
+
18
+ super
19
+ end
20
+ end
21
+ end
22
+ end
@@ -3,53 +3,36 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  module FavorModifier
6
- def check(kind, tokens, sexp)
7
- token_positions = tokens.map(&:pos)
8
- token_texts = tokens.map(&:text)
9
- each(kind, sexp) do |s|
10
- # If it contains an else, it can't be written as a modifier.
11
- next if s[3] && s[3][0] == :else
6
+ # TODO extremely ugly solution that needs lots of polish
7
+ def check(sexp)
8
+ # discard if/then/else
9
+ return false if sexp.loc.respond_to?(:else) && sexp.loc.else
12
10
 
13
- sexp_positions = all_positions(s)
14
- ix = token_positions.index(sexp_positions.first)
15
- if_ix = token_texts[0..ix].rindex(kind.to_s) # index of if/unless/...
16
- ix = token_positions.index(sexp_positions.last)
17
- end_ix = ix + token_texts[ix..-1].index('end')
11
+ if %w(if while).include?(sexp.loc.keyword.source)
12
+ cond, body = *sexp
13
+ else
14
+ cond, _else, body = *sexp
15
+ end
18
16
 
19
- # If there's a comment anywhere between
20
- # if/unless/while/until and end, we don't report. It's
21
- # possible that the comment will be less clear if put above
22
- # a one liner rather than inside.
23
- next if tokens[if_ix...end_ix].map(&:type).include?(:on_comment)
17
+ if length(sexp) > 3
18
+ false
19
+ else
20
+ cond_length = sexp.loc.keyword.size + cond.loc.expression.size + 1
21
+ body_length = body_length(body)
24
22
 
25
- if token_positions[end_ix].lineno - token_positions[if_ix].lineno > 2
26
- next # not a single-line body
27
- end
28
- # The start ix is the index of the leftmost token on the
29
- # line of the if/unless, i.e. the index of if/unless itself,
30
- # or of the indentation space.
31
- start_ix = if_ix.downto(0).find do |block_ix|
32
- block_ix == 0 || tokens[block_ix - 1].text =~ /\n/
33
- end
34
- # The stop index is the index of the token just before
35
- # 'end', not counting whitespace tokens.
36
- stop_ix = (end_ix - 1).downto(0).find do |block_ix|
37
- tokens[block_ix].text !~ /\s/
38
- end
39
- if length(tokens, start_ix, stop_ix) <= LineLength.max
40
- add_offence(:convention, token_positions[if_ix].lineno,
41
- error_message)
42
- end
23
+ (cond_length + body_length) <= LineLength.max
43
24
  end
44
25
  end
45
26
 
46
- def length(tokens, start_ix, stop_ix)
47
- (start_ix..stop_ix).reduce(0) do |acc, ix|
48
- acc + if ix > start_ix && tokens[ix - 1].text =~ /\n/
49
- 0
50
- else
51
- tokens[ix].text.length
52
- end
27
+ def length(sexp)
28
+ sexp.loc.expression.source.split("\n").size
29
+ end
30
+
31
+ def body_length(body)
32
+ if body
33
+ body.loc.expression.column + body.loc.expression.size
34
+ else
35
+ 0
53
36
  end
54
37
  end
55
38
  end
@@ -59,23 +42,30 @@ module Rubocop
59
42
 
60
43
  def error_message
61
44
  'Favor modifier if/unless usage when you have a single-line body. ' +
62
- 'Another good alternative is the usage of control flow and/or.'
45
+ 'Another good alternative is the usage of control flow &&/||.'
63
46
  end
64
47
 
65
- def inspect(file, source, tokens, sexp)
66
- [:if, :unless].each { |kind| check(kind, tokens, sexp) }
48
+ def on_if(node)
49
+ # discard ternary ops and modifier if/unless nodes
50
+ return unless node.loc.respond_to?(:keyword) &&
51
+ node.loc.respond_to?(:else)
52
+
53
+ add_offence(:convention, node.loc.line, error_message) if check(node)
54
+
55
+ super
67
56
  end
68
57
  end
69
58
 
70
59
  class WhileUntilModifier < Cop
71
60
  include FavorModifier
72
61
 
73
- def error_message
62
+ MSG =
74
63
  'Favor modifier while/until usage when you have a single-line body.'
75
- end
76
64
 
77
- def inspect(file, source, tokens, sexp)
78
- [:while, :until].each { |kind| check(kind, tokens, sexp) }
65
+ def inspect(source, tokens, ast, comments)
66
+ on_node([:while, :until], ast) do |node|
67
+ add_offence(:convention, node.loc.line, MSG) if check(node)
68
+ end
79
69
  end
80
70
  end
81
71
  end
@@ -0,0 +1,19 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class FavorPercentR < Cop
6
+ MSG = 'Use %r for regular expressions matching more ' +
7
+ "than one '/' character."
8
+
9
+ def on_regexp(node)
10
+ if node.loc.begin.source == '/' &&
11
+ node.loc.expression.source[1...-1].scan(/\//).size > 1
12
+ add_offence(:convention, node.loc.line, MSG)
13
+ end
14
+
15
+ super
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class FavorSprintf < Cop
6
+ MSG = 'Favor sprintf over String#%.'
7
+
8
+ def on_send(node)
9
+ receiver_node, method_name, *arg_nodes = *node
10
+
11
+ if method_name == :% &&
12
+ ([:str, :dstr].include?(receiver_node.type) ||
13
+ arg_nodes[0].type == :array)
14
+ add_offence(:convention, node.loc.expression.line, MSG)
15
+ end
16
+
17
+ super
18
+ end
19
+ end
20
+ end
21
+ end
@@ -3,17 +3,17 @@
3
3
  module Rubocop
4
4
  module Cop
5
5
  module FavorOtherKeywordOverNegation
6
- private
7
- def check(grammar_part, sexp)
8
- each(grammar_part, sexp) do |s|
9
- # Don't complain about negative if/else. We don't want unless/else.
10
- next if s[3] && [:else, :elsif].include?(s[3][0])
6
+ def check(node)
7
+ condition, _body, _rest = *node
11
8
 
12
- condition = s[1]
13
- condition = condition[1][0] while condition[0] == :paren
9
+ # Look at last expression of contents if there's a parenthesis
10
+ # around condition.
11
+ *_, condition = *condition while condition.type == :begin
14
12
 
15
- if condition[0] == :unary && [:!, :not].include?(condition[1])
16
- add_offence(:convention, all_positions(s).first.lineno,
13
+ if condition.type == :send
14
+ _object, method = *condition
15
+ if method == :! && !(node.loc.respond_to?(:else) && node.loc.else)
16
+ add_offence(:convention, node.loc.expression.line,
17
17
  error_message)
18
18
  end
19
19
  end
@@ -23,24 +23,26 @@ module Rubocop
23
23
  class FavorUnlessOverNegatedIf < Cop
24
24
  include FavorOtherKeywordOverNegation
25
25
 
26
- def error_message
27
- 'Favor unless (or control flow or) over if for negative conditions.'
26
+ def on_if(node)
27
+ check(node)
28
+ super
28
29
  end
29
30
 
30
- def inspect(file, source, tokens, sexp)
31
- [:if, :if_mod].each { |grammar_part| check(grammar_part, sexp) }
31
+ def error_message
32
+ 'Favor unless (or control flow or) over if for negative conditions.'
32
33
  end
33
34
  end
34
35
 
35
36
  class FavorUntilOverNegatedWhile < Cop
36
37
  include FavorOtherKeywordOverNegation
37
38
 
38
- def error_message
39
- 'Favor until over while for negative conditions.'
39
+ def on_while(node)
40
+ check(node)
41
+ super
40
42
  end
41
43
 
42
- def inspect(file, source, tokens, sexp)
43
- [:while, :while_mod].each { |grammar_part| check(grammar_part, sexp) }
44
+ def error_message
45
+ 'Favor until over while for negative conditions.'
44
46
  end
45
47
  end
46
48
  end
@@ -0,0 +1,17 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ class HandleExceptions < Cop
6
+ MSG = 'Do not suppress exceptions.'
7
+
8
+ def on_resbody(node)
9
+ _exc_list_node, _exc_var_node, body_node = *node
10
+
11
+ add_offence(:warning, node.loc.line, MSG) if body_node.type == :nil
12
+
13
+ super
14
+ end
15
+ end
16
+ end
17
+ end