rubocop 0.28.0 → 0.29.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 (211) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop_todo.yml +7 -7
  3. data/.travis.yml +4 -0
  4. data/CHANGELOG.md +59 -0
  5. data/README.md +62 -28
  6. data/config/default.yml +31 -0
  7. data/config/disabled.yml +1 -1
  8. data/config/enabled.yml +17 -0
  9. data/lib/rubocop.rb +4 -0
  10. data/lib/rubocop/cli.rb +1 -1
  11. data/lib/rubocop/config.rb +12 -8
  12. data/lib/rubocop/config_loader.rb +20 -10
  13. data/lib/rubocop/cop/cop.rb +13 -7
  14. data/lib/rubocop/cop/corrector.rb +10 -10
  15. data/lib/rubocop/cop/lint/assignment_in_condition.rb +6 -1
  16. data/lib/rubocop/cop/lint/block_alignment.rb +9 -2
  17. data/lib/rubocop/cop/lint/debugger.rb +13 -1
  18. data/lib/rubocop/cop/lint/duplicate_methods.rb +104 -0
  19. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  20. data/lib/rubocop/cop/lint/require_parentheses.rb +3 -3
  21. data/lib/rubocop/cop/mixin/access_modifier_node.rb +27 -0
  22. data/lib/rubocop/cop/mixin/on_normal_if_unless.rb +0 -4
  23. data/lib/rubocop/cop/rails/delegate.rb +4 -5
  24. data/lib/rubocop/cop/rails/read_write_attribute.rb +33 -0
  25. data/lib/rubocop/cop/style/access_modifier_indentation.rb +0 -7
  26. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +4 -2
  27. data/lib/rubocop/cop/style/class_methods.rb +25 -9
  28. data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +7 -1
  29. data/lib/rubocop/cop/style/empty_literal.rb +25 -10
  30. data/lib/rubocop/cop/style/even_odd.rb +32 -14
  31. data/lib/rubocop/cop/style/first_parameter_indentation.rb +106 -0
  32. data/lib/rubocop/cop/style/format_string.rb +2 -2
  33. data/lib/rubocop/cop/style/global_vars.rb +1 -5
  34. data/lib/rubocop/cop/style/hash_syntax.rb +0 -4
  35. data/lib/rubocop/cop/style/indentation_consistency.rb +5 -5
  36. data/lib/rubocop/cop/style/indentation_width.rb +13 -14
  37. data/lib/rubocop/cop/style/lambda.rb +48 -2
  38. data/lib/rubocop/cop/style/line_end_concatenation.rb +43 -47
  39. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -3
  40. data/lib/rubocop/cop/style/module_function.rb +3 -3
  41. data/lib/rubocop/cop/style/multiline_block_layout.rb +65 -17
  42. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +2 -1
  43. data/lib/rubocop/cop/style/perl_backrefs.rb +2 -2
  44. data/lib/rubocop/cop/style/redundant_exception.rb +12 -0
  45. data/lib/rubocop/cop/style/self_assignment.rb +27 -0
  46. data/lib/rubocop/cop/style/semicolon.rb +2 -1
  47. data/lib/rubocop/cop/style/space_around_block_parameters.rb +92 -0
  48. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +0 -8
  49. data/lib/rubocop/cop/style/struct_inheritance.rb +42 -0
  50. data/lib/rubocop/cop/style/trivial_accessors.rb +10 -4
  51. data/lib/rubocop/cop/util.rb +32 -7
  52. data/lib/rubocop/formatter/simple_text_formatter.rb +0 -15
  53. data/lib/rubocop/options.rb +28 -41
  54. data/lib/rubocop/processed_source.rb +6 -0
  55. data/lib/rubocop/rake_task.rb +6 -3
  56. data/lib/rubocop/runner.rb +55 -15
  57. data/lib/rubocop/version.rb +1 -1
  58. data/relnotes/v0.29.0.md +116 -0
  59. data/rubocop.gemspec +3 -3
  60. data/spec/rubocop/cli_spec.rb +329 -25
  61. data/spec/rubocop/config_loader_spec.rb +20 -0
  62. data/spec/rubocop/cop/lint/assignment_in_condition_spec.rb +27 -3
  63. data/spec/rubocop/cop/lint/block_alignment_spec.rb +3 -4
  64. data/spec/rubocop/cop/lint/condition_position_spec.rb +1 -1
  65. data/spec/rubocop/cop/lint/debugger_spec.rb +20 -7
  66. data/spec/rubocop/cop/lint/duplicate_methods_spec.rb +189 -0
  67. data/spec/rubocop/cop/lint/empty_interpolation_spec.rb +1 -1
  68. data/spec/rubocop/cop/lint/end_in_method_spec.rb +1 -1
  69. data/spec/rubocop/cop/lint/eval_spec.rb +4 -4
  70. data/spec/rubocop/cop/lint/literal_in_condition_spec.rb +18 -0
  71. data/spec/rubocop/cop/lint/literal_in_interpolation_spec.rb +2 -2
  72. data/spec/rubocop/cop/lint/loop_spec.rb +4 -4
  73. data/spec/rubocop/cop/lint/parentheses_as_grouped_expression_spec.rb +7 -7
  74. data/spec/rubocop/cop/lint/space_before_first_arg_spec.rb +5 -4
  75. data/spec/rubocop/cop/lint/useless_assignment_spec.rb +3 -9
  76. data/spec/rubocop/cop/lint/useless_comparison_spec.rb +1 -1
  77. data/spec/rubocop/cop/lint/void_spec.rb +1 -1
  78. data/spec/rubocop/cop/metrics/abc_size_spec.rb +10 -0
  79. data/spec/rubocop/cop/metrics/line_length_spec.rb +2 -2
  80. data/spec/rubocop/cop/metrics/parameter_lists_spec.rb +2 -2
  81. data/spec/rubocop/cop/rails/action_filter_spec.rb +6 -12
  82. data/spec/rubocop/cop/rails/default_scope_spec.rb +5 -5
  83. data/spec/rubocop/cop/rails/delegate_spec.rb +8 -0
  84. data/spec/rubocop/cop/rails/has_and_belongs_to_many_spec.rb +1 -1
  85. data/spec/rubocop/cop/rails/read_write_attribute_spec.rb +119 -8
  86. data/spec/rubocop/cop/rails/scope_args_spec.rb +3 -3
  87. data/spec/rubocop/cop/rails/validation_spec.rb +3 -3
  88. data/spec/rubocop/cop/style/alias_spec.rb +5 -5
  89. data/spec/rubocop/cop/style/align_hash_spec.rb +1 -1
  90. data/spec/rubocop/cop/style/align_parameters_spec.rb +8 -8
  91. data/spec/rubocop/cop/style/and_or_spec.rb +15 -30
  92. data/spec/rubocop/cop/style/array_join_spec.rb +4 -4
  93. data/spec/rubocop/cop/style/ascii_comments_spec.rb +1 -2
  94. data/spec/rubocop/cop/style/ascii_identifiers_spec.rb +2 -2
  95. data/spec/rubocop/cop/style/begin_block_spec.rb +1 -1
  96. data/spec/rubocop/cop/style/block_comments_spec.rb +1 -1
  97. data/spec/rubocop/cop/style/block_end_newline_spec.rb +1 -1
  98. data/spec/rubocop/cop/style/blocks_spec.rb +2 -2
  99. data/spec/rubocop/cop/style/braces_around_hash_parameters_spec.rb +38 -33
  100. data/spec/rubocop/cop/style/case_equality_spec.rb +1 -1
  101. data/spec/rubocop/cop/style/character_literal_spec.rb +4 -4
  102. data/spec/rubocop/cop/style/class_and_module_children_spec.rb +4 -2
  103. data/spec/rubocop/cop/style/class_methods_spec.rb +12 -0
  104. data/spec/rubocop/cop/style/class_vars_spec.rb +2 -2
  105. data/spec/rubocop/cop/style/collection_methods_spec.rb +4 -4
  106. data/spec/rubocop/cop/style/colon_method_call_spec.rb +8 -8
  107. data/spec/rubocop/cop/style/comment_annotation_spec.rb +10 -10
  108. data/spec/rubocop/cop/style/constant_name_spec.rb +7 -7
  109. data/spec/rubocop/cop/style/def_with_parentheses_spec.rb +1 -1
  110. data/spec/rubocop/cop/style/deprecated_hash_methods_spec.rb +4 -4
  111. data/spec/rubocop/cop/style/dot_position_spec.rb +8 -6
  112. data/spec/rubocop/cop/style/each_with_object_spec.rb +2 -2
  113. data/spec/rubocop/cop/style/else_alignment_spec.rb +2 -4
  114. data/spec/rubocop/cop/style/empty_lines_around_access_modifier_spec.rb +78 -0
  115. data/spec/rubocop/cop/style/empty_lines_around_class_body_spec.rb +60 -0
  116. data/spec/rubocop/cop/style/empty_lines_spec.rb +3 -3
  117. data/spec/rubocop/cop/style/empty_literal_spec.rb +29 -12
  118. data/spec/rubocop/cop/style/encoding_spec.rb +3 -3
  119. data/spec/rubocop/cop/style/end_block_spec.rb +1 -1
  120. data/spec/rubocop/cop/style/end_of_line_spec.rb +2 -2
  121. data/spec/rubocop/cop/style/even_odd_spec.rb +109 -20
  122. data/spec/rubocop/cop/style/extra_spacing_spec.rb +3 -3
  123. data/spec/rubocop/cop/style/first_parameter_indentation_spec.rb +293 -0
  124. data/spec/rubocop/cop/style/for_spec.rb +2 -2
  125. data/spec/rubocop/cop/style/format_string_spec.rb +45 -21
  126. data/spec/rubocop/cop/style/global_vars_spec.rb +4 -4
  127. data/spec/rubocop/cop/style/guard_clause_spec.rb +17 -0
  128. data/spec/rubocop/cop/style/hash_syntax_spec.rb +15 -15
  129. data/spec/rubocop/cop/{metrics → style}/if_unless_modifier_spec.rb +2 -2
  130. data/spec/rubocop/cop/style/if_with_semicolon_spec.rb +2 -2
  131. data/spec/rubocop/cop/style/indent_array_spec.rb +3 -6
  132. data/spec/rubocop/cop/style/indent_hash_spec.rb +4 -4
  133. data/spec/rubocop/cop/style/indentation_consistency_spec.rb +1 -2
  134. data/spec/rubocop/cop/style/indentation_width_spec.rb +1 -2
  135. data/spec/rubocop/cop/style/infinite_loop_spec.rb +1 -1
  136. data/spec/rubocop/cop/style/lambda_call_spec.rb +4 -4
  137. data/spec/rubocop/cop/style/lambda_spec.rb +37 -2
  138. data/spec/rubocop/cop/style/leading_comment_space_spec.rb +7 -12
  139. data/spec/rubocop/cop/style/line_end_concatenation_spec.rb +41 -1
  140. data/spec/rubocop/cop/style/method_call_parentheses_spec.rb +4 -4
  141. data/spec/rubocop/cop/style/method_called_on_do_end_block_spec.rb +3 -3
  142. data/spec/rubocop/cop/style/method_name_spec.rb +1 -1
  143. data/spec/rubocop/cop/style/multiline_block_layout_spec.rb +61 -0
  144. data/spec/rubocop/cop/style/multiline_if_then_spec.rb +1 -3
  145. data/spec/rubocop/cop/style/multiline_operation_indentation_spec.rb +8 -0
  146. data/spec/rubocop/cop/style/multiline_ternary_operator_spec.rb +1 -1
  147. data/spec/rubocop/cop/style/nested_ternary_operator_spec.rb +1 -1
  148. data/spec/rubocop/cop/style/next_spec.rb +16 -0
  149. data/spec/rubocop/cop/style/numeric_literals_spec.rb +5 -5
  150. data/spec/rubocop/cop/style/one_line_conditional_spec.rb +1 -1
  151. data/spec/rubocop/cop/style/parentheses_around_condition_spec.rb +22 -4
  152. data/spec/rubocop/cop/style/percent_literal_delimiters_spec.rb +31 -31
  153. data/spec/rubocop/cop/style/percent_q_literals_spec.rb +12 -12
  154. data/spec/rubocop/cop/style/perl_backrefs_spec.rb +3 -3
  155. data/spec/rubocop/cop/style/proc_spec.rb +3 -3
  156. data/spec/rubocop/cop/style/raise_args_spec.rb +9 -9
  157. data/spec/rubocop/cop/style/redundant_begin_spec.rb +1 -1
  158. data/spec/rubocop/cop/style/redundant_exception_spec.rb +36 -4
  159. data/spec/rubocop/cop/style/redundant_self_spec.rb +89 -45
  160. data/spec/rubocop/cop/style/regexp_literal_spec.rb +9 -9
  161. data/spec/rubocop/cop/style/rescue_modifier_spec.rb +2 -2
  162. data/spec/rubocop/cop/style/self_assignment_spec.rb +16 -10
  163. data/spec/rubocop/cop/style/semicolon_spec.rb +9 -9
  164. data/spec/rubocop/cop/style/single_line_block_params_spec.rb +2 -2
  165. data/spec/rubocop/cop/style/single_space_before_first_arg_spec.rb +1 -1
  166. data/spec/rubocop/cop/style/space_after_colon_spec.rb +5 -5
  167. data/spec/rubocop/cop/style/space_after_comma_spec.rb +3 -3
  168. data/spec/rubocop/cop/style/space_after_control_keyword_spec.rb +4 -4
  169. data/spec/rubocop/cop/style/space_after_not_spec.rb +2 -2
  170. data/spec/rubocop/cop/style/space_after_semicolon_spec.rb +2 -2
  171. data/spec/rubocop/cop/style/space_around_block_parameters_spec.rb +150 -0
  172. data/spec/rubocop/cop/style/space_around_equals_in_parameter_default_spec.rb +18 -9
  173. data/spec/rubocop/cop/style/space_around_operators_spec.rb +24 -21
  174. data/spec/rubocop/cop/style/space_before_block_braces_spec.rb +4 -4
  175. data/spec/rubocop/cop/style/space_before_comma_spec.rb +4 -4
  176. data/spec/rubocop/cop/style/space_before_comment_spec.rb +3 -3
  177. data/spec/rubocop/cop/style/space_before_semicolon_spec.rb +2 -2
  178. data/spec/rubocop/cop/style/space_inside_block_braces_spec.rb +33 -24
  179. data/spec/rubocop/cop/style/space_inside_brackets_spec.rb +2 -2
  180. data/spec/rubocop/cop/style/space_inside_hash_literal_braces_spec.rb +9 -9
  181. data/spec/rubocop/cop/style/space_inside_parens_spec.rb +1 -1
  182. data/spec/rubocop/cop/style/special_global_vars_spec.rb +6 -6
  183. data/spec/rubocop/cop/style/string_literals_in_interpolation_spec.rb +3 -3
  184. data/spec/rubocop/cop/style/string_literals_spec.rb +16 -16
  185. data/spec/rubocop/cop/style/struct_inheritance_spec.rb +44 -0
  186. data/spec/rubocop/cop/style/symbol_array_spec.rb +9 -9
  187. data/spec/rubocop/cop/style/symbol_proc_spec.rb +12 -12
  188. data/spec/rubocop/cop/style/tab_spec.rb +4 -4
  189. data/spec/rubocop/cop/style/trailing_blank_lines_spec.rb +2 -2
  190. data/spec/rubocop/cop/style/trailing_whitespace_spec.rb +2 -2
  191. data/spec/rubocop/cop/style/trivial_accessors_spec.rb +16 -0
  192. data/spec/rubocop/cop/style/unneeded_capital_w_spec.rb +11 -22
  193. data/spec/rubocop/cop/style/variable_interpolation_spec.rb +7 -7
  194. data/spec/rubocop/cop/style/while_until_do_spec.rb +2 -2
  195. data/spec/rubocop/cop/{metrics → style}/while_until_modifier_spec.rb +2 -2
  196. data/spec/rubocop/cop/style/word_array_spec.rb +11 -11
  197. data/spec/rubocop/cop/util_spec.rb +51 -0
  198. data/spec/rubocop/cop/variable_force/reference_spec.rb +19 -0
  199. data/spec/rubocop/cop/variable_force/variable_table_spec.rb +7 -0
  200. data/spec/rubocop/formatter/disabled_lines_formatter_spec.rb +7 -8
  201. data/spec/rubocop/formatter/text_util_spec.rb +55 -0
  202. data/spec/rubocop/options_spec.rb +26 -20
  203. data/spec/rubocop/rake_task_spec.rb +122 -0
  204. data/spec/rubocop/runner_spec.rb +37 -2
  205. data/spec/rubocop/token_spec.rb +5 -1
  206. data/spec/spec_helper.rb +5 -2
  207. data/spec/support/cop_helper.rb +3 -0
  208. data/spec/support/cops/class_must_be_a_module_cop.rb +19 -0
  209. data/spec/support/cops/module_must_be_a_class_cop.rb +19 -0
  210. data/spec/support/custom_matchers.rb +1 -1
  211. metadata +35 -12
@@ -36,6 +36,39 @@ module RuboCop
36
36
  format(MSG, 'self[:attr] = val', 'write_attribute(:attr, var)')
37
37
  end
38
38
  end
39
+
40
+ def autocorrect(node)
41
+ _receiver, method_name, _body = *node
42
+
43
+ case method_name
44
+ when :read_attribute
45
+ replacement = read_attribute_replacement(node)
46
+ when :write_attribute
47
+ replacement = write_attribute_replacement(node)
48
+ end
49
+
50
+ @corrections << lambda do |corrector|
51
+ corrector.replace(node.loc.expression, replacement)
52
+ end
53
+ end
54
+
55
+ private
56
+
57
+ def read_attribute_replacement(node)
58
+ _receiver, _method_name, body = *node
59
+
60
+ "self[#{body.loc.expression.source}]"
61
+ end
62
+
63
+ def write_attribute_replacement(node)
64
+ _receiver, _method_name, *args = *node
65
+ name, value = *args
66
+
67
+ name_source = name.loc.expression.source
68
+ value_source = value.loc.expression.source
69
+
70
+ "self[#{name_source}] = #{value_source}"
71
+ end
39
72
  end
40
73
  end
41
74
  end
@@ -65,13 +65,6 @@ module RuboCop
65
65
  format(MSG, style.capitalize, node.loc.selector.source)
66
66
  end
67
67
 
68
- def class_constructor?(block_node)
69
- send_node = block_node.children.first
70
- receiver_node, method_name, *_ = *send_node
71
- return false unless method_name == :new
72
- %w(Class Module).include?(Util.const_name(receiver_node))
73
- end
74
-
75
68
  def expected_indent_offset
76
69
  style == :outdent ? 0 : configured_indentation_width
77
70
  end
@@ -50,8 +50,10 @@ module RuboCop
50
50
  def autocorrect(node)
51
51
  @corrections << lambda do |corrector|
52
52
  if braces?(node)
53
- corrector.remove(node.loc.begin)
54
- corrector.remove(node.loc.end)
53
+ right_range = range_with_surrounding_space(node.loc.begin, :right)
54
+ corrector.remove(right_range)
55
+ left_range = range_with_surrounding_space(node.loc.end, :left)
56
+ corrector.remove(left_range)
55
57
  else
56
58
  corrector.insert_before(node.loc.expression, '{')
57
59
  corrector.insert_after(node.loc.expression, '}')
@@ -5,35 +5,51 @@ module RuboCop
5
5
  module Style
6
6
  # This cop checks for uses of the class/module name instead of
7
7
  # self, when defining class/module methods.
8
+ #
9
+ # @example
10
+ # # bad
11
+ # class SomeClass
12
+ # def SomeClass.class_method
13
+ # ...
14
+ # end
15
+ # end
16
+ #
17
+ # # good
18
+ # class SomeClass
19
+ # def self.class_method
20
+ # ...
21
+ # end
22
+ # end
8
23
  class ClassMethods < Cop
9
24
  MSG = 'Use `self.%s` instead of `%s.%s`.'
10
25
 
11
26
  def on_class(node)
12
- _name, _superclass, body = *node
13
- check(body)
27
+ name, _superclass, body = *node
28
+ check(name, body)
14
29
  end
15
30
 
16
31
  def on_module(node)
17
- _name, body = *node
18
- check(body)
32
+ name, body = *node
33
+ check(name, body)
19
34
  end
20
35
 
21
36
  private
22
37
 
23
- def check(node)
38
+ def check(name, node)
24
39
  return unless node
25
40
 
26
41
  if node.type == :defs
27
- check_defs(node)
42
+ check_defs(name, node)
28
43
  elsif node.type == :begin
29
44
  defs_nodes = node.children.compact.select { |n| n.type == :defs }
30
- defs_nodes.each { |n| check_defs(n) }
45
+ defs_nodes.each { |n| check_defs(name, n) }
31
46
  end
32
47
  end
33
48
 
34
- def check_defs(node)
49
+ def check_defs(name, node)
35
50
  definee, method_name, _args, _body = *node
36
- return unless definee.type == :const
51
+ # check if the class/module name matches the definee for the defs node
52
+ return unless name == definee
37
53
 
38
54
  _, class_name = *definee
39
55
  add_offense(definee, :name, message(class_name, method_name))
@@ -42,7 +42,9 @@ module RuboCop
42
42
  private
43
43
 
44
44
  def previous_line_empty?(previous_line)
45
- class_def?(previous_line.lstrip) || previous_line.blank?
45
+ block_start?(previous_line.lstrip) ||
46
+ class_def?(previous_line.lstrip) ||
47
+ previous_line.blank?
46
48
  end
47
49
 
48
50
  def next_line_empty?(next_line)
@@ -61,6 +63,10 @@ module RuboCop
61
63
  %w(class module).any? { |keyword| line.start_with?(keyword) }
62
64
  end
63
65
 
66
+ def block_start?(line)
67
+ line.match(/ (do|{)( \|.*?\|)?\s?$/)
68
+ end
69
+
64
70
  def body_end?(line)
65
71
  line.start_with?('end')
66
72
  end
@@ -29,31 +29,46 @@ module RuboCop
29
29
  STR_NODE = s(:send, s(:const, nil, :String), :new)
30
30
 
31
31
  def on_send(node)
32
- return if part_of_ignored_node?(node)
33
-
34
32
  case node
35
33
  when ARRAY_NODE
36
34
  add_offense(node, :expression, ARR_MSG)
37
35
  when HASH_NODE
36
+ # If Hash.new takes a block, it can't be changed to {}.
37
+ return if node.parent && node.parent.block_type?
38
+
38
39
  add_offense(node, :expression, HASH_MSG)
39
40
  when STR_NODE
40
41
  add_offense(node, :expression, STR_MSG)
41
42
  end
42
43
  end
43
44
 
44
- # TODO: Check block contents as well.
45
- alias_method :on_block, :ignore_node
46
-
47
45
  def autocorrect(node)
48
- @corrections << lambda do |corrector|
49
- name = case node
50
- when ARRAY_NODE then '[]'
51
- when HASH_NODE then '{}'
52
- when STR_NODE then "''"
46
+ name = case node
47
+ when ARRAY_NODE
48
+ '[]'
49
+ when HASH_NODE
50
+ # `some_method {}` is not same as `some_method Hash.new`
51
+ # because the braces are interpreted as a block, so we avoid
52
+ # the correction. Parentheses around the arguments would
53
+ # solve the problem, but we let the user add those manually.
54
+ if first_arg_in_method_call_without_parentheses?(node)
55
+ fail CorrectionNotPossible
53
56
  end
57
+ '{}'
58
+ when STR_NODE
59
+ "''"
60
+ end
61
+ @corrections << lambda do |corrector|
54
62
  corrector.replace(node.loc.expression, name)
55
63
  end
56
64
  end
65
+
66
+ def first_arg_in_method_call_without_parentheses?(node)
67
+ return false unless node.parent && node.parent.send_type?
68
+
69
+ _receiver, _method_name, *args = *node.parent
70
+ node.object_id == args.first.object_id && !parentheses?(node.parent)
71
+ end
57
72
  end
58
73
  end
59
74
  end
@@ -14,33 +14,54 @@ module RuboCop
14
14
  # # good
15
15
  # if x.even?
16
16
  class EvenOdd < Cop
17
- MSG_EVEN = 'Replace with `Fixnum#even?`.'
18
- MSG_ODD = 'Replace with `Fixnum#odd?`.'
17
+ MSG = 'Replace with `Fixnum#%s?`.'
19
18
 
20
19
  ZERO = s(:int, 0)
21
20
  ONE = s(:int, 1)
22
21
  TWO = s(:int, 2)
23
22
 
24
23
  def on_send(node)
24
+ offense = offense_type(node)
25
+ add_offense(node, :expression, format(MSG, offense)) if offense
26
+ end
27
+
28
+ def autocorrect(node)
29
+ @corrections << lambda do |corrector|
30
+ correction = "#{base_number(node)}.#{offense_type(node)}?"
31
+ corrector.replace(node.loc.expression, correction)
32
+ end
33
+ end
34
+
35
+ private
36
+
37
+ def base_number(node)
38
+ receiver, = *node
39
+ node = expression(receiver)
40
+ node.children[0].loc.expression.source
41
+ end
42
+
43
+ def offense_type(node)
25
44
  receiver, method, args = *node
26
45
 
27
46
  return unless [:==, :!=].include?(method)
28
47
  return unless div_by_2?(receiver)
29
48
 
30
49
  if args == ZERO
31
- add_offense(node,
32
- :expression,
33
- method == :== ? MSG_EVEN : MSG_ODD)
50
+ method == :== ? :even : :odd
34
51
  elsif args == ONE
35
- add_offense(node,
36
- :expression,
37
- method == :== ? MSG_ODD : MSG_EVEN)
52
+ method == :== ? :odd : :even
38
53
  end
39
54
  end
40
55
 
41
- private
42
-
43
56
  def div_by_2?(node)
57
+ node = expression(node)
58
+
59
+ _receiver, method, args = *node
60
+
61
+ method == :% && args == TWO
62
+ end
63
+
64
+ def expression(node)
44
65
  return unless node
45
66
 
46
67
  # check for scenarios like (x % 2) == 0
@@ -49,10 +70,7 @@ module RuboCop
49
70
  end
50
71
 
51
72
  return unless node.type == :send
52
-
53
- _receiver, method, args = *node
54
-
55
- method == :% && args == TWO
73
+ node
56
74
  end
57
75
  end
58
76
  end
@@ -0,0 +1,106 @@
1
+ # encoding: utf-8
2
+
3
+ module RuboCop
4
+ module Cop
5
+ module Style
6
+ # This cop checks the indentation of the first parameter in a method call.
7
+ # Parameters after the first one are checked by Style/AlignParameters, not
8
+ # by this cop.
9
+ #
10
+ # @example
11
+ #
12
+ # # bad
13
+ # some_method(
14
+ # first_param,
15
+ # second_param)
16
+ #
17
+ # # good
18
+ # some_method(
19
+ # first_param,
20
+ # second_param)
21
+ class FirstParameterIndentation < Cop
22
+ include AutocorrectAlignment
23
+ include ConfigurableEnforcedStyle
24
+
25
+ COMMENT_OR_BLANK_LINE = /^\s*(#.*)?$/
26
+
27
+ def on_send(node)
28
+ _receiver, method_name, *args = *node
29
+ return if args.empty?
30
+ return if operator?(method_name)
31
+
32
+ base_indentation = if special_inner_call_indentation?(node)
33
+ column_of(base_range(node, args.first))
34
+ else
35
+ previous_code_line(args.first.loc.line) =~ /\S/
36
+ end
37
+ check_alignment([args.first],
38
+ base_indentation + configured_indentation_width)
39
+ end
40
+
41
+ private
42
+
43
+ def message(arg_node)
44
+ send_node = arg_node.parent
45
+ text = base_range(send_node, arg_node).source.strip
46
+ base = if text !~ /\n/ && special_inner_call_indentation?(send_node)
47
+ "`#{text}`"
48
+ elsif text.lines.reverse_each.first =~ /^\s*#/
49
+ 'the previous line (not counting the comment)'
50
+ else
51
+ 'the previous line'
52
+ end
53
+ format('Indent the first parameter one step more than %s.', base)
54
+ end
55
+
56
+ def special_inner_call_indentation?(node)
57
+ return false if style == :consistent
58
+
59
+ parent = node.parent
60
+ return false unless parent
61
+ return false unless parent.send_type?
62
+
63
+ _receiver, method_name, *_args = *parent
64
+ # :[]= is a send node, but we want to treat it as an assignment.
65
+ return false if method_name == :[]=
66
+
67
+ return false if !parentheses?(parent) &&
68
+ style == :special_for_inner_method_call_in_parentheses
69
+
70
+ # The node must begin inside the parent, otherwise node is the first
71
+ # part of a chained method call.
72
+ node.loc.expression.begin_pos > parent.loc.expression.begin_pos
73
+ end
74
+
75
+ def base_range(send_node, arg_node)
76
+ Parser::Source::Range.new(processed_source.buffer,
77
+ send_node.loc.expression.begin_pos,
78
+ arg_node.loc.expression.begin_pos)
79
+ end
80
+
81
+ # Returns the column of the given range. For single line ranges, this
82
+ # is simple. For ranges with line breaks, we look a the last code line.
83
+ def column_of(range)
84
+ source = range.source.strip
85
+ if source.include?("\n")
86
+ previous_code_line(range.line + source.count("\n") + 1) =~ /\S/
87
+ else
88
+ range.column
89
+ end
90
+ end
91
+
92
+ # Takes the line number of a given code line and returns a string
93
+ # containing the previous line that's not a comment line or a blank
94
+ # line.
95
+ def previous_code_line(line_number)
96
+ line = ''
97
+ while line =~ COMMENT_OR_BLANK_LINE
98
+ line_number -= 1
99
+ line = processed_source.lines[line_number - 1]
100
+ end
101
+ line
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end
@@ -31,13 +31,13 @@ module RuboCop
31
31
  end
32
32
 
33
33
  def format_method?(name, node)
34
- receiver, method_name, args = *node
34
+ receiver, method_name, *args = *node
35
35
 
36
36
  # commands have no explicit receiver
37
37
  return false unless !receiver && method_name == name
38
38
 
39
39
  # we do an argument count check to reduce false positives
40
- args && args.children.size >= 2
40
+ args.size >= 2
41
41
  end
42
42
 
43
43
  def format?(node)
@@ -44,11 +44,7 @@ module RuboCop
44
44
  ).map(&:to_sym)
45
45
 
46
46
  def user_vars
47
- if cop_config['AllowedVariables']
48
- cop_config['AllowedVariables'].map(&:to_sym)
49
- else
50
- []
51
- end
47
+ cop_config['AllowedVariables'].map(&:to_sym)
52
48
  end
53
49
 
54
50
  def allowed_var?(global_var)
@@ -54,10 +54,6 @@ module RuboCop
54
54
 
55
55
  private
56
56
 
57
- def space_before_operator?(op, key)
58
- op.begin_pos - key.begin_pos - key.source.length > 0
59
- end
60
-
61
57
  def check(pairs, delim, msg)
62
58
  pairs.each do |pair|
63
59
  if pair.loc.operator && pair.loc.operator.is?(delim)
@@ -7,12 +7,12 @@ module RuboCop
7
7
  #
8
8
  # @example
9
9
  #
10
- # class A
11
- # def test
12
- # puts 'hello'
13
- # puts 'world'
10
+ # class A
11
+ # def test
12
+ # puts 'hello'
13
+ # puts 'world'
14
+ # end
14
15
  # end
15
- # end
16
16
  class IndentationConsistency < Cop
17
17
  include AutocorrectAlignment
18
18
  include AccessModifierNode