rubocop 0.15.0 → 0.16.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 (221) hide show
  1. checksums.yaml +4 -4
  2. data/.rubocop.yml +1 -10
  3. data/.travis.yml +2 -1
  4. data/CHANGELOG.md +55 -0
  5. data/Gemfile +3 -0
  6. data/README.md +37 -0
  7. data/config/default.yml +99 -16
  8. data/config/enabled.yml +28 -16
  9. data/lib/rubocop.rb +16 -2
  10. data/lib/rubocop/cli.rb +10 -91
  11. data/lib/rubocop/config.rb +4 -1
  12. data/lib/rubocop/config_loader.rb +18 -10
  13. data/lib/rubocop/config_store.rb +3 -2
  14. data/lib/rubocop/cop/check_assignment.rb +43 -0
  15. data/lib/rubocop/cop/check_methods.rb +18 -0
  16. data/lib/rubocop/cop/commissioner.rb +15 -3
  17. data/lib/rubocop/cop/cop.rb +51 -43
  18. data/lib/rubocop/cop/lint/assignment_in_condition.rb +1 -1
  19. data/lib/rubocop/cop/lint/block_alignment.rb +7 -7
  20. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  21. data/lib/rubocop/cop/lint/empty_ensure.rb +1 -1
  22. data/lib/rubocop/cop/lint/end_alignment.rb +56 -19
  23. data/lib/rubocop/cop/lint/end_in_method.rb +4 -10
  24. data/lib/rubocop/cop/lint/ensure_return.rb +1 -1
  25. data/lib/rubocop/cop/lint/eval.rb +1 -1
  26. data/lib/rubocop/cop/lint/handle_exceptions.rb +1 -1
  27. data/lib/rubocop/cop/lint/literal_in_condition.rb +2 -2
  28. data/lib/rubocop/cop/lint/loop.rb +1 -1
  29. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +1 -1
  30. data/lib/rubocop/cop/lint/rescue_exception.rb +1 -1
  31. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +1 -1
  32. data/lib/rubocop/cop/lint/syntax.rb +1 -1
  33. data/lib/rubocop/cop/lint/unreachable_code.rb +1 -1
  34. data/lib/rubocop/cop/lint/useless_assignment.rb +2 -2
  35. data/lib/rubocop/cop/lint/useless_comparison.rb +1 -1
  36. data/lib/rubocop/cop/lint/useless_setter_call.rb +6 -16
  37. data/lib/rubocop/cop/lint/void.rb +5 -5
  38. data/lib/rubocop/cop/rails/default_scope.rb +33 -0
  39. data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +2 -4
  40. data/lib/rubocop/cop/rails/output.rb +1 -1
  41. data/lib/rubocop/cop/rails/read_attribute.rb +1 -1
  42. data/lib/rubocop/cop/rails/validation.rb +1 -1
  43. data/lib/rubocop/cop/style/access_modifier_indentation.rb +31 -16
  44. data/lib/rubocop/cop/style/accessor_method_name.rb +53 -0
  45. data/lib/rubocop/cop/style/alias.rb +14 -2
  46. data/lib/rubocop/cop/style/align_hash.rb +15 -16
  47. data/lib/rubocop/cop/style/and_or.rb +3 -3
  48. data/lib/rubocop/cop/style/array_syntax.rb +22 -0
  49. data/lib/rubocop/cop/style/ascii_comments.rb +1 -1
  50. data/lib/rubocop/cop/style/ascii_identifiers.rb +1 -3
  51. data/lib/rubocop/cop/style/attr.rb +1 -1
  52. data/lib/rubocop/cop/style/autocorrect_alignment.rb +13 -12
  53. data/lib/rubocop/cop/style/begin_block.rb +1 -1
  54. data/lib/rubocop/cop/style/block_comments.rb +1 -1
  55. data/lib/rubocop/cop/style/block_nesting.rb +5 -1
  56. data/lib/rubocop/cop/style/blocks.rb +4 -4
  57. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +48 -22
  58. data/lib/rubocop/cop/style/case_equality.rb +1 -1
  59. data/lib/rubocop/cop/style/case_indentation.rb +25 -6
  60. data/lib/rubocop/cop/style/class_and_module_camel_case.rb +1 -1
  61. data/lib/rubocop/cop/style/class_length.rb +7 -19
  62. data/lib/rubocop/cop/style/class_methods.rb +1 -1
  63. data/lib/rubocop/cop/style/class_vars.rb +1 -1
  64. data/lib/rubocop/cop/style/code_length.rb +35 -0
  65. data/lib/rubocop/cop/style/collection_methods.rb +1 -1
  66. data/lib/rubocop/cop/style/colon_method_call.rb +1 -1
  67. data/lib/rubocop/cop/style/comment_annotation.rb +1 -1
  68. data/lib/rubocop/cop/style/configurable_enforced_style.rb +51 -0
  69. data/lib/rubocop/cop/style/configurable_max.rb +17 -0
  70. data/lib/rubocop/cop/style/configurable_naming.rb +4 -10
  71. data/lib/rubocop/cop/style/constant_name.rb +5 -3
  72. data/lib/rubocop/cop/style/cyclomatic_complexity.rb +8 -13
  73. data/lib/rubocop/cop/style/def_parentheses.rb +4 -43
  74. data/lib/rubocop/cop/style/documentation.rb +1 -1
  75. data/lib/rubocop/cop/style/dot_position.rb +6 -2
  76. data/lib/rubocop/cop/style/empty_line_between_defs.rb +1 -1
  77. data/lib/rubocop/cop/style/empty_lines.rb +5 -1
  78. data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +1 -1
  79. data/lib/rubocop/cop/style/empty_lines_around_body.rb +28 -13
  80. data/lib/rubocop/cop/style/empty_literal.rb +3 -3
  81. data/lib/rubocop/cop/style/encoding.rb +5 -5
  82. data/lib/rubocop/cop/style/end_block.rb +1 -1
  83. data/lib/rubocop/cop/style/end_of_line.rb +8 -6
  84. data/lib/rubocop/cop/style/even_odd.rb +6 -6
  85. data/lib/rubocop/cop/style/favor_join.rb +1 -1
  86. data/lib/rubocop/cop/style/favor_modifier.rb +20 -34
  87. data/lib/rubocop/cop/style/favor_sprintf.rb +1 -1
  88. data/lib/rubocop/cop/style/favor_unless_over_negated_if.rb +1 -1
  89. data/lib/rubocop/cop/style/final_newline.rb +1 -1
  90. data/lib/rubocop/cop/style/flip_flop.rb +20 -0
  91. data/lib/rubocop/cop/style/for.rb +34 -3
  92. data/lib/rubocop/cop/style/global_vars.rb +1 -1
  93. data/lib/rubocop/cop/style/hash_methods.rb +3 -3
  94. data/lib/rubocop/cop/style/hash_syntax.rb +8 -11
  95. data/lib/rubocop/cop/style/if_node.rb +25 -0
  96. data/lib/rubocop/cop/style/if_then_else.rb +1 -1
  97. data/lib/rubocop/cop/style/indentation_width.rb +77 -43
  98. data/lib/rubocop/cop/style/lambda.rb +2 -2
  99. data/lib/rubocop/cop/style/lambda_call.rb +4 -12
  100. data/lib/rubocop/cop/style/leading_comment_space.rb +1 -1
  101. data/lib/rubocop/cop/style/line_length.rb +9 -5
  102. data/lib/rubocop/cop/style/method_call_parentheses.rb +1 -1
  103. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +1 -1
  104. data/lib/rubocop/cop/style/method_def_parentheses.rb +52 -0
  105. data/lib/rubocop/cop/style/method_length.rb +9 -22
  106. data/lib/rubocop/cop/style/module_function.rb +1 -1
  107. data/lib/rubocop/cop/style/multiline_block_chain.rb +1 -1
  108. data/lib/rubocop/cop/style/multiline_if_then.rb +11 -1
  109. data/lib/rubocop/cop/style/nil_comparison.rb +1 -1
  110. data/lib/rubocop/cop/style/not.rb +1 -1
  111. data/lib/rubocop/cop/style/numeric_literals.rb +2 -2
  112. data/lib/rubocop/cop/style/op_method.rb +2 -2
  113. data/lib/rubocop/cop/style/parameter_lists.rb +2 -2
  114. data/lib/rubocop/cop/style/parentheses_around_condition.rb +8 -1
  115. data/lib/rubocop/cop/style/perl_backrefs.rb +1 -1
  116. data/lib/rubocop/cop/style/predicate_name.rb +54 -0
  117. data/lib/rubocop/cop/style/proc.rb +1 -1
  118. data/lib/rubocop/cop/style/raise_args.rb +4 -10
  119. data/lib/rubocop/cop/style/redundant_begin.rb +5 -15
  120. data/lib/rubocop/cop/style/redundant_exception.rb +1 -1
  121. data/lib/rubocop/cop/style/redundant_return.rb +9 -19
  122. data/lib/rubocop/cop/style/redundant_self.rb +8 -3
  123. data/lib/rubocop/cop/style/regexp_literal.rb +4 -3
  124. data/lib/rubocop/cop/style/rescue_modifier.rb +9 -17
  125. data/lib/rubocop/cop/style/semicolon.rb +20 -22
  126. data/lib/rubocop/cop/style/signal_exception.rb +10 -17
  127. data/lib/rubocop/cop/style/single_line_block_params.rb +62 -0
  128. data/lib/rubocop/cop/style/single_line_methods.rb +5 -15
  129. data/lib/rubocop/cop/style/space_after_comma_etc.rb +1 -3
  130. data/lib/rubocop/cop/style/space_after_control_keyword.rb +1 -1
  131. data/lib/rubocop/cop/style/space_after_method_name.rb +4 -12
  132. data/lib/rubocop/cop/style/space_after_not.rb +1 -1
  133. data/lib/rubocop/cop/style/space_around_block_braces.rb +105 -94
  134. data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +1 -1
  135. data/lib/rubocop/cop/style/space_around_operators.rb +38 -123
  136. data/lib/rubocop/cop/style/space_before_modifier_keyword.rb +1 -1
  137. data/lib/rubocop/cop/style/space_inside.rb +1 -3
  138. data/lib/rubocop/cop/style/space_inside_brackets.rb +0 -2
  139. data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +5 -5
  140. data/lib/rubocop/cop/style/space_inside_parens.rb +0 -2
  141. data/lib/rubocop/cop/style/special_global_vars.rb +1 -1
  142. data/lib/rubocop/cop/style/string_help.rb +1 -1
  143. data/lib/rubocop/cop/style/string_literals.rb +4 -11
  144. data/lib/rubocop/cop/style/surrounding_space.rb +0 -2
  145. data/lib/rubocop/cop/style/symbol_array.rb +3 -10
  146. data/lib/rubocop/cop/style/tab.rb +5 -5
  147. data/lib/rubocop/cop/style/ternary_operator.rb +2 -2
  148. data/lib/rubocop/cop/style/trailing_blank_lines.rb +1 -1
  149. data/lib/rubocop/cop/style/trailing_whitespace.rb +1 -1
  150. data/lib/rubocop/cop/style/trivial_accessors.rb +4 -14
  151. data/lib/rubocop/cop/style/unless_else.rb +1 -1
  152. data/lib/rubocop/cop/style/variable_interpolation.rb +1 -1
  153. data/lib/rubocop/cop/style/when_then.rb +3 -1
  154. data/lib/rubocop/cop/style/while_until_do.rb +2 -2
  155. data/lib/rubocop/cop/style/word_array.rb +4 -10
  156. data/lib/rubocop/cop/util.rb +85 -12
  157. data/lib/rubocop/cop/variable_inspector.rb +4 -2
  158. data/lib/rubocop/file_inspector.rb +98 -0
  159. data/lib/rubocop/formatter/base_formatter.rb +2 -2
  160. data/lib/rubocop/formatter/disabled_config_formatter.rb +10 -2
  161. data/lib/rubocop/rake_task.rb +5 -1
  162. data/lib/rubocop/target_finder.rb +3 -3
  163. data/lib/rubocop/version.rb +1 -1
  164. data/rubocop-todo.yml +12 -0
  165. data/rubocop.gemspec +1 -1
  166. data/spec/isolated_environment_spec.rb +24 -0
  167. data/spec/rubocop/cli_spec.rb +120 -27
  168. data/spec/rubocop/config_loader_spec.rb +25 -11
  169. data/spec/rubocop/config_spec.rb +25 -9
  170. data/spec/rubocop/config_store_spec.rb +1 -1
  171. data/spec/rubocop/cop/cop_spec.rb +22 -3
  172. data/spec/rubocop/cop/lint/block_alignment_spec.rb +4 -4
  173. data/spec/rubocop/cop/lint/end_alignment_spec.rb +79 -47
  174. data/spec/rubocop/cop/lint/syntax_spec.rb +4 -3
  175. data/spec/rubocop/cop/rails/default_scope_spec.rb +31 -0
  176. data/spec/rubocop/cop/style/access_modifier_indentation_spec.rb +37 -2
  177. data/spec/rubocop/cop/style/accessor_method_name_spec.rb +81 -0
  178. data/spec/rubocop/cop/style/alias_spec.rb +10 -0
  179. data/spec/rubocop/cop/style/align_parameters_spec.rb +3 -3
  180. data/spec/rubocop/cop/style/block_nesting_spec.rb +4 -1
  181. data/spec/rubocop/cop/style/braces_around_hash_parameters_spec.rb +83 -0
  182. data/spec/rubocop/cop/style/case_indentation_spec.rb +227 -71
  183. data/spec/rubocop/cop/style/class_length_spec.rb +2 -0
  184. data/spec/rubocop/cop/style/constant_name_spec.rb +6 -0
  185. data/spec/rubocop/cop/style/cyclomatic_complexity_spec.rb +1 -0
  186. data/spec/rubocop/cop/style/documentation_spec.rb +12 -0
  187. data/spec/rubocop/cop/style/dot_position_spec.rb +10 -0
  188. data/spec/rubocop/cop/style/empty_lines_around_body_spec.rb +22 -0
  189. data/spec/rubocop/cop/style/empty_lines_spec.rb +6 -0
  190. data/spec/rubocop/cop/style/end_of_line_spec.rb +17 -0
  191. data/spec/rubocop/cop/style/favor_modifier_spec.rb +15 -0
  192. data/spec/rubocop/cop/style/flip_flop_spec.rb +23 -0
  193. data/spec/rubocop/cop/style/for_spec.rb +96 -18
  194. data/spec/rubocop/cop/style/hash_syntax_spec.rb +8 -2
  195. data/spec/rubocop/cop/style/indentation_width_spec.rb +185 -20
  196. data/spec/rubocop/cop/style/line_length_spec.rb +1 -0
  197. data/spec/rubocop/cop/style/method_def_parentheses_spec.rb +72 -0
  198. data/spec/rubocop/cop/style/multiline_if_then_spec.rb +16 -0
  199. data/spec/rubocop/cop/style/parentheses_around_condition_spec.rb +34 -3
  200. data/spec/rubocop/cop/style/predicate_name_spec.rb +25 -0
  201. data/spec/rubocop/cop/style/redundant_self_spec.rb +15 -0
  202. data/spec/rubocop/cop/style/regexp_literal_spec.rb +5 -0
  203. data/spec/rubocop/cop/style/semicolon_spec.rb +16 -16
  204. data/spec/rubocop/cop/style/{reduce_arguments_spec.rb → single_line_block_params_spec.rb} +12 -4
  205. data/spec/rubocop/cop/style/space_around_block_braces_spec.rb +58 -8
  206. data/spec/rubocop/cop/style/space_around_operators_spec.rb +71 -0
  207. data/spec/rubocop/cop/style/string_literals_spec.rb +18 -0
  208. data/spec/rubocop/file_inspector_spec.rb +78 -0
  209. data/spec/rubocop/formatter/clang_style_formatter_spec.rb +7 -7
  210. data/spec/rubocop/formatter/emacs_style_formatter_spec.rb +3 -3
  211. data/spec/rubocop/formatter/file_list_formatter_spec.rb +2 -2
  212. data/spec/rubocop/processed_source_spec.rb +7 -3
  213. data/spec/rubocop/token_spec.rb +1 -1
  214. data/spec/spec_helper.rb +3 -2
  215. data/spec/support/isolated_environment.rb +7 -0
  216. data/spec/support/shared_context.rb +5 -1
  217. metadata +35 -12
  218. data/lib/rubocop/cop/style/reduce_arguments.rb +0 -34
  219. data/lib/rubocop/cop/style/symbol_name.rb +0 -45
  220. data/spec/rubocop/cop/style/def_without_parentheses_spec.rb +0 -33
  221. data/spec/rubocop/cop/style/symbol_name_spec.rb +0 -138
@@ -5,6 +5,8 @@ module Rubocop
5
5
  module Style
6
6
  # This cop checks for uses of `fail` and `raise`.
7
7
  class SignalException < Cop
8
+ include ConfigurableEnforcedStyle
9
+
8
10
  FAIL_MSG = 'Use `fail` instead of `raise` to signal exceptions.'
9
11
  RAISE_MSG = 'Use `raise` instead of `fail` to rethrow exceptions.'
10
12
 
@@ -22,9 +24,9 @@ module Rubocop
22
24
  case style
23
25
  when :semantic
24
26
  check_for(:raise, node) unless ignored_node?(node)
25
- when :raise
27
+ when :only_raise
26
28
  check_for(:raise, node)
27
- when :fail
29
+ when :only_fail
28
30
  check_for(:fail, node)
29
31
  end
30
32
  end
@@ -34,8 +36,8 @@ module Rubocop
34
36
  name =
35
37
  case style
36
38
  when :semantic then command?(:raise, node) ? 'fail' : 'raise'
37
- when :raise then 'raise'
38
- when :fail then 'fail'
39
+ when :only_raise then 'raise'
40
+ when :only_fail then 'fail'
39
41
  end
40
42
 
41
43
  corrector.replace(node.loc.selector, name)
@@ -44,22 +46,13 @@ module Rubocop
44
46
 
45
47
  private
46
48
 
47
- def style
48
- case cop_config['EnforcedStyle']
49
- when 'only_raise' then :raise
50
- when 'only_fail' then :fail
51
- when 'semantic' then :semantic
52
- else fail 'Unknown style selected!'
53
- end
54
- end
55
-
56
49
  def message(method_name)
57
50
  case style
58
51
  when :semantic
59
52
  method_name == :fail ? RAISE_MSG : FAIL_MSG
60
- when :raise
53
+ when :only_raise
61
54
  'Always use `raise` to signal exceptions.'
62
- when :fail
55
+ when :only_fail
63
56
  'Always use `fail` to signal exceptions.'
64
57
  end
65
58
  end
@@ -70,7 +63,7 @@ module Rubocop
70
63
  if style == :semantic
71
64
  each_command(method_name, node) do |send_node|
72
65
  unless ignored_node?(send_node)
73
- convention(send_node, :selector, message(method_name))
66
+ add_offence(send_node, :selector, message(method_name))
74
67
  ignore_node(send_node)
75
68
  end
76
69
  end
@@ -78,7 +71,7 @@ module Rubocop
78
71
  _receiver, selector, _args = *node
79
72
 
80
73
  if [:raise, :fail].include?(selector) && selector != method_name
81
- convention(node, :selector, message(method_name))
74
+ add_offence(node, :selector, message(method_name))
82
75
  end
83
76
  end
84
77
  end
@@ -0,0 +1,62 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cop checks whether the block parameters of a single-line
7
+ # method accepting a block match the names specified via configuration.
8
+ #
9
+ # For instance one can configure `reduce`(`inject`) to use |a, e| as
10
+ # parameters.
11
+ class SingleLineBlockParams < Cop
12
+ def on_block(node)
13
+ # we care only for single line blocks
14
+ return unless Util.block_length(node) == 0
15
+
16
+ method_node, args_node, _body_node = *node
17
+ receiver, method_name, _method_args = *method_node
18
+
19
+ # discard other scenarios
20
+ return unless receiver
21
+ return unless method_names.include?(method_name)
22
+
23
+ # discard cases with argument destructuring
24
+ args = *args_node
25
+
26
+ return true unless args.all? { |n| n.type == :arg }
27
+
28
+ unless args_match?(method_name, args)
29
+ add_offence(args_node, :expression, message(method_name))
30
+ end
31
+ end
32
+
33
+ private
34
+
35
+ def message(method_name)
36
+ args = target_args(method_name).join(', ')
37
+ "Name `#{method_name}` block params |#{args}|."
38
+ end
39
+
40
+ def methods
41
+ cop_config['Methods']
42
+ end
43
+
44
+ def method_names
45
+ methods.map { |e| e.keys.first.to_sym }
46
+ end
47
+
48
+ def target_args(method_name)
49
+ method_name = method_name.to_s
50
+ method_hash = methods.find { |m| m.keys.first == method_name }
51
+ method_hash[method_name]
52
+ end
53
+
54
+ def args_match?(method_name, args)
55
+ actual_args = args.flat_map { |a| a.to_a }
56
+
57
+ actual_args == target_args(method_name).map(&:to_sym)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -6,34 +6,24 @@ module Rubocop
6
6
  # This cop checks for single-line method definitions.
7
7
  # It can optionally accept single-line methods with no body.
8
8
  class SingleLineMethods < Cop
9
+ include CheckMethods
10
+
9
11
  MSG = 'Avoid single-line method definitions.'
10
12
 
11
13
  def allow_empty?
12
14
  cop_config['AllowIfMethodIsEmpty']
13
15
  end
14
16
 
15
- def on_def(node)
16
- check(node)
17
- end
18
-
19
- def on_defs(node)
20
- check(node)
21
- end
22
-
23
17
  private
24
18
 
25
- def check(node)
19
+ def check(node, _method_name, _args, body)
26
20
  start_line = node.loc.keyword.line
27
21
  end_line = node.loc.end.line
28
22
 
29
- if node.type == :def
30
- empty_body = node.children[2].nil?
31
- else
32
- empty_body = node.children[3].nil?
33
- end
23
+ empty_body = body.nil?
34
24
 
35
25
  if start_line == end_line && !(allow_empty? && empty_body)
36
- convention(node, :expression)
26
+ add_offence(node, :expression)
37
27
  end
38
28
  end
39
29
  end
@@ -1,7 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
- # rubocop:disable SymbolName
4
-
5
3
  module Rubocop
6
4
  module Cop
7
5
  module Style
@@ -14,7 +12,7 @@ module Rubocop
14
12
  processed_source.tokens.each_cons(2) do |t1, t2|
15
13
  if kind(t1) && t1.pos.line == t2.pos.line &&
16
14
  t2.pos.column == t1.pos.column + offset(t1)
17
- convention(t1, t1.pos, sprintf(MSG, kind(t1)))
15
+ add_offence(t1, t1.pos, sprintf(MSG, kind(t1)))
18
16
  end
19
17
  end
20
18
  end
@@ -16,7 +16,7 @@ module Rubocop
16
16
  kw = node.loc.keyword
17
17
  kw_offset = kw.begin_pos - exp.begin_pos
18
18
  if exp.source[kw_offset..-1].start_with?(kw.source + '(')
19
- convention(node, kw)
19
+ add_offence(node, kw)
20
20
  end
21
21
  end
22
22
 
@@ -5,27 +5,19 @@ module Rubocop
5
5
  module Style
6
6
  # Checks for space between a method name and a left parenthesis.
7
7
  class SpaceAfterMethodName < Cop
8
+ include CheckMethods
9
+
8
10
  MSG = 'Never put a space between a method name and the opening ' +
9
11
  'parenthesis.'
10
12
 
11
- def on_def(node)
12
- _method_name, args, _body = *node
13
- check(args)
14
- end
15
-
16
- def on_defs(node)
17
- _scope, _method_name, args, _body = *node
18
- check(args)
19
- end
20
-
21
- def check(args)
13
+ def check(_node, _method_name, args, body)
22
14
  return unless args.loc.begin && args.loc.begin.is?('(')
23
15
  expr = args.loc.expression
24
16
  pos_before_left_paren = Parser::Source::Range.new(expr.source_buffer,
25
17
  expr.begin_pos - 1,
26
18
  expr.begin_pos)
27
19
  if pos_before_left_paren.source =~ /\s/
28
- convention(pos_before_left_paren, pos_before_left_paren)
20
+ add_offence(pos_before_left_paren, pos_before_left_paren)
29
21
  end
30
22
  end
31
23
 
@@ -21,7 +21,7 @@ module Rubocop
21
21
 
22
22
  if node.loc.expression.source =~ /^!\s+\w+/
23
23
  # TODO: Improve source range to highlight the redundant whitespace.
24
- convention(node, :selector)
24
+ add_offence(node, :selector)
25
25
  end
26
26
  end
27
27
 
@@ -1,145 +1,156 @@
1
1
  # encoding: utf-8
2
2
 
3
- # rubocop:disable SymbolName
4
-
5
3
  module Rubocop
6
4
  module Cop
7
5
  module Style
8
6
  # Checks that block braces have or don't have surrounding space depending
9
7
  # on configuration. For blocks taking parameters, it checks that the left
10
8
  # brace has or doesn't have trailing space depending on configuration.
9
+ # Also checks that the left brace is preceded by a space and this is not
10
+ # configurable.
11
11
  class SpaceAroundBlockBraces < Cop
12
+ include ConfigurableEnforcedStyle
12
13
  include SurroundingSpace
13
14
 
14
- def investigate(processed_source)
15
- return unless processed_source.ast
16
- @processed_source = processed_source
15
+ def on_block(node)
16
+ return if node.loc.begin.is?('do') # No braces.
17
+
18
+ # If braces are on separate lines, and the Blocks cop is enabled,
19
+ # those braces will be changed to do..end by the user or by
20
+ # auto-correct, so reporting space issues is not useful, and it
21
+ # creates auto-correct conflicts.
22
+ if config.for_cop('Blocks')['Enabled'] && Util.block_length(node) > 0
23
+ return
24
+ end
25
+
26
+ left_brace, right_brace = node.loc.begin, node.loc.end
27
+
28
+ check_outside(left_brace)
29
+ check_inside(node, left_brace, right_brace)
30
+ end
31
+
32
+ private
33
+
34
+ def check_outside(left_brace)
35
+ if range_with_surrounding_space(left_brace).source.start_with?('{')
36
+ add_offence(left_brace, left_brace,
37
+ 'Space missing to the left of {.')
38
+ end
39
+ end
17
40
 
18
- processed_source.tokens.each_cons(2) do |t1, t2|
19
- next if ([t1.pos, t2.pos] - positions_not_to_check).size < 2
41
+ def check_inside(node, left_brace, right_brace)
42
+ sb = node.loc.expression.source_buffer
20
43
 
21
- type1, type2 = t1.type, t2.type
22
- if [:tLCURLY, :tRCURLY].include?(type2)
23
- check(t1, t2)
24
- elsif type1 == :tLCURLY
25
- if type2 == :tPIPE
26
- check_pipe(t1, t2)
44
+ if left_brace.end_pos == right_brace.begin_pos
45
+ no_space(style_for_empty_braces, sb, left_brace.begin_pos,
46
+ right_brace.end_pos, 'Space missing inside empty braces.')
47
+ else
48
+ range = Parser::Source::Range.new(sb, left_brace.end_pos,
49
+ right_brace.begin_pos)
50
+ inner = range.source
51
+ unless inner =~ /\n/
52
+ if inner =~ /\S/
53
+ braces_with_contents_inside(node, inner)
27
54
  else
28
- check(t1, t2)
55
+ space(style_for_empty_braces, sb, range.begin_pos,
56
+ range.end_pos, 'Space inside empty braces detected.')
29
57
  end
30
58
  end
31
59
  end
32
60
  end
33
61
 
34
- def positions_not_to_check
35
- @positions_not_to_check ||= begin
36
- positions = []
37
- ast = @processed_source.ast
38
- tokens = @processed_source.tokens
39
-
40
- on_node(:hash, ast) do |hash|
41
- b_ix = index_of_first_token(hash)
42
- e_ix = index_of_last_token(hash)
43
- positions << tokens[b_ix].pos << tokens[e_ix].pos
44
- end
62
+ def braces_with_contents_inside(node, inner)
63
+ _method, args, _body = *node
64
+ left_brace, right_brace = node.loc.begin, node.loc.end
65
+ pipe = args.loc.begin
66
+ sb = node.loc.expression.source_buffer
45
67
 
46
- # TODO: Check braces inside string/symbol/regexp/xstr
47
- # interpolation.
48
- on_node([:dstr, :dsym, :regexp, :xstr], ast) do |s|
49
- b_ix = index_of_first_token(s)
50
- e_ix = index_of_last_token(s)
51
- tokens[b_ix..e_ix].each do |t|
52
- positions << t.pos if t.type == :tRCURLY
53
- end
54
- end
68
+ if inner =~ /^\S/
69
+ no_space_inside_left_brace(left_brace, pipe, sb)
70
+ else
71
+ space_inside_left_brace(left_brace, pipe, sb)
72
+ end
55
73
 
56
- positions
74
+ if inner =~ /\S$/
75
+ no_space(style_for_inside_braces, sb, right_brace.begin_pos,
76
+ right_brace.end_pos, 'Space missing inside }.')
77
+ else
78
+ space_inside_right_brace(right_brace, sb)
57
79
  end
58
80
  end
59
81
 
60
- def check(t1, t2)
61
- if t2.text == '{'
62
- check_space_outside_left_brace(t1, t2)
63
- elsif t1.text == '{' && t2.text == '}'
64
- check_empty_braces(t1, t2)
65
- elsif cop_config['EnforcedStyle'] == 'space_inside_braces'
66
- check_space_inside_braces(t1, t2)
82
+ def no_space_inside_left_brace(left_brace, pipe, sb)
83
+ if pipe
84
+ if left_brace.end_pos == pipe.begin_pos
85
+ no_space(style_for_block_parameters, sb, left_brace.begin_pos,
86
+ pipe.end_pos, 'Space between { and | missing.')
87
+ end
67
88
  else
68
- check_no_space_inside_braces(t1, t2)
89
+ # We indicate the position after the left brace. Otherwise it's
90
+ # difficult to distinguish between space missing to the left and to
91
+ # the right of the brace in autocorrect.
92
+ no_space(style_for_inside_braces, sb, left_brace.end_pos,
93
+ left_brace.end_pos + 1, 'Space missing inside {.')
69
94
  end
70
95
  end
71
96
 
72
- def check_empty_braces(t1, t2)
73
- if cop_config['EnforcedStyleForEmptyBraces'] == 'space'
74
- check_space_inside_braces(t1, t2)
97
+ def space_inside_left_brace(left_brace, pipe, sb)
98
+ if pipe
99
+ space(style_for_block_parameters, sb, left_brace.end_pos,
100
+ pipe.begin_pos, 'Space between { and | detected.')
75
101
  else
76
- check_no_space_inside_braces(t1, t2)
102
+ brace_with_space = range_with_surrounding_space(left_brace, :right)
103
+ space(style_for_inside_braces, sb, brace_with_space.begin_pos + 1,
104
+ brace_with_space.end_pos, 'Space inside { detected.')
77
105
  end
78
106
  end
79
107
 
80
- def check_space_inside_braces(t1, t2)
81
- unless space_between?(t1, t2)
82
- token, what = problem_details(t1, t2)
83
- convention(token.pos, token.pos, "Space missing inside #{what}.")
84
- end
108
+ def space_inside_right_brace(right_brace, sb)
109
+ brace_with_space = range_with_surrounding_space(right_brace, :left)
110
+ space(style_for_inside_braces, sb, brace_with_space.begin_pos,
111
+ brace_with_space.end_pos - 1, 'Space inside } detected.')
85
112
  end
86
113
 
87
- def check_no_space_inside_braces(t1, t2)
88
- if space_between?(t1, t2)
89
- token, what = problem_details(t1, t2)
90
- s = space_range(token)
91
- convention(s, s, "Space inside #{what} detected.")
92
- end
114
+ def no_space(specific_style, sb, begin_pos, end_pos, msg)
115
+ offence(sb, begin_pos, end_pos, msg) if specific_style == :space
93
116
  end
94
117
 
95
- def problem_details(t1, t2)
96
- if t1.text == '{'
97
- token = t1
98
- what = t2.text == '}' ? 'empty braces' : '{'
99
- else
100
- token = t2
101
- what = '}'
102
- end
103
- [token, what]
118
+ def space(specific_style, sb, begin_pos, end_pos, msg)
119
+ offence(sb, begin_pos, end_pos, msg) if specific_style == :no_space
104
120
  end
105
121
 
106
- def check_space_outside_left_brace(t1, t2)
107
- if t2.text == '{' && !space_between?(t1, t2)
108
- convention(t1.pos, t2.pos, 'Space missing to the left of {.')
109
- end
122
+ def offence(sb, begin_pos, end_pos, msg)
123
+ range = Parser::Source::Range.new(sb, begin_pos, end_pos)
124
+ add_offence(range, range, msg)
110
125
  end
111
126
 
112
- def check_pipe(t1, t2)
113
- if cop_config['SpaceBeforeBlockParameters']
114
- unless space_between?(t1, t2)
115
- convention(t2.pos, t1.pos, 'Space between { and | missing.')
116
- end
117
- elsif space_between?(t1, t2)
118
- s = space_range(t1)
119
- convention(s, s, 'Space between { and | detected.')
120
- end
127
+ def available_styles
128
+ %w(space_inside_braces no_space_inside_braces)
121
129
  end
122
130
 
123
- def space_range(token)
124
- src = @processed_source.buffer.source
125
- if token.text == '{'
126
- b = token.pos.begin_pos + 1
127
- e = b + 1
128
- e += 1 while src[e] =~ /\s/
129
- else
130
- e = token.pos.begin_pos
131
- b = e - 1
132
- b -= 1 while src[b - 1] =~ /\s/
131
+ def style_for_inside_braces
132
+ style == :space_inside_braces ? :space : :no_space
133
+ end
134
+
135
+ def style_for_empty_braces
136
+ case cop_config['EnforcedStyleForEmptyBraces']
137
+ when 'space' then :space
138
+ when 'no_space' then :no_space
139
+ else fail 'Unknown EnforcedStyleForEmptyBraces selected!'
133
140
  end
134
- Parser::Source::Range.new(@processed_source.buffer, b, e)
141
+ end
142
+
143
+ def style_for_block_parameters
144
+ cop_config['SpaceBeforeBlockParameters'] ? :space : :no_space
135
145
  end
136
146
 
137
147
  def autocorrect(range)
138
148
  @corrections << lambda do |corrector|
139
149
  case range.source
140
- when '}', '|' then corrector.insert_before(range, ' ')
141
- when ' ' then corrector.remove(range)
142
- else corrector.insert_after(range, ' ')
150
+ when /\s/ then corrector.remove(range)
151
+ when '{}' then corrector.replace(range, '{ }')
152
+ when '{|' then corrector.replace(range, '{ |')
153
+ else corrector.insert_before(range, ' ')
143
154
  end
144
155
  end
145
156
  end