sabat-rubocop 0.9.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.
Files changed (239) hide show
  1. data/.gitignore +50 -0
  2. data/.rspec +1 -0
  3. data/.rubocop.yml +7 -0
  4. data/.travis.yml +7 -0
  5. data/.yardopts +2 -0
  6. data/CHANGELOG.md +268 -0
  7. data/CONTRIBUTING.md +16 -0
  8. data/Gemfile +7 -0
  9. data/LICENSE.txt +20 -0
  10. data/README.md +324 -0
  11. data/Rakefile +29 -0
  12. data/bin/rubocop +22 -0
  13. data/config/default.yml +58 -0
  14. data/config/disabled.yml +5 -0
  15. data/config/enabled.yml +403 -0
  16. data/lib/rubocop.rb +116 -0
  17. data/lib/rubocop/cli.rb +407 -0
  18. data/lib/rubocop/config.rb +250 -0
  19. data/lib/rubocop/config_store.rb +39 -0
  20. data/lib/rubocop/cop/cop.rb +138 -0
  21. data/lib/rubocop/cop/lint/assignment_in_condition.rb +54 -0
  22. data/lib/rubocop/cop/lint/end_alignment.rb +189 -0
  23. data/lib/rubocop/cop/lint/end_in_method.rb +30 -0
  24. data/lib/rubocop/cop/lint/ensure_return.rb +22 -0
  25. data/lib/rubocop/cop/lint/eval.rb +22 -0
  26. data/lib/rubocop/cop/lint/handle_exceptions.rb +20 -0
  27. data/lib/rubocop/cop/lint/literal_in_condition.rb +81 -0
  28. data/lib/rubocop/cop/lint/loop.rb +29 -0
  29. data/lib/rubocop/cop/lint/rescue_exception.rb +29 -0
  30. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +34 -0
  31. data/lib/rubocop/cop/lint/unreachable_code.rb +35 -0
  32. data/lib/rubocop/cop/lint/unused_local_variable.rb +32 -0
  33. data/lib/rubocop/cop/lint/void.rb +58 -0
  34. data/lib/rubocop/cop/offence.rb +136 -0
  35. data/lib/rubocop/cop/rails/validation.rb +30 -0
  36. data/lib/rubocop/cop/style/access_control.rb +58 -0
  37. data/lib/rubocop/cop/style/alias.rb +28 -0
  38. data/lib/rubocop/cop/style/align_parameters.rb +39 -0
  39. data/lib/rubocop/cop/style/and_or.rb +45 -0
  40. data/lib/rubocop/cop/style/ascii_comments.rb +21 -0
  41. data/lib/rubocop/cop/style/ascii_identifiers.rb +22 -0
  42. data/lib/rubocop/cop/style/attr.rb +20 -0
  43. data/lib/rubocop/cop/style/avoid_class_vars.rb +20 -0
  44. data/lib/rubocop/cop/style/avoid_for.rb +18 -0
  45. data/lib/rubocop/cop/style/avoid_global_vars.rb +65 -0
  46. data/lib/rubocop/cop/style/avoid_perl_backrefs.rb +21 -0
  47. data/lib/rubocop/cop/style/avoid_perlisms.rb +50 -0
  48. data/lib/rubocop/cop/style/begin_block.rb +18 -0
  49. data/lib/rubocop/cop/style/block_comments.rb +20 -0
  50. data/lib/rubocop/cop/style/block_nesting.rb +47 -0
  51. data/lib/rubocop/cop/style/blocks.rb +27 -0
  52. data/lib/rubocop/cop/style/case_equality.rb +22 -0
  53. data/lib/rubocop/cop/style/case_indentation.rb +28 -0
  54. data/lib/rubocop/cop/style/character_literal.rb +37 -0
  55. data/lib/rubocop/cop/style/class_and_module_camel_case.rb +33 -0
  56. data/lib/rubocop/cop/style/class_methods.rb +22 -0
  57. data/lib/rubocop/cop/style/collection_methods.rb +56 -0
  58. data/lib/rubocop/cop/style/colon_method_call.rb +29 -0
  59. data/lib/rubocop/cop/style/constant_name.rb +31 -0
  60. data/lib/rubocop/cop/style/def_parentheses.rb +70 -0
  61. data/lib/rubocop/cop/style/documentation.rb +58 -0
  62. data/lib/rubocop/cop/style/dot_position.rb +25 -0
  63. data/lib/rubocop/cop/style/empty_line_between_defs.rb +26 -0
  64. data/lib/rubocop/cop/style/empty_lines.rb +40 -0
  65. data/lib/rubocop/cop/style/empty_literal.rb +53 -0
  66. data/lib/rubocop/cop/style/encoding.rb +29 -0
  67. data/lib/rubocop/cop/style/end_block.rb +18 -0
  68. data/lib/rubocop/cop/style/end_of_line.rb +23 -0
  69. data/lib/rubocop/cop/style/favor_join.rb +29 -0
  70. data/lib/rubocop/cop/style/favor_modifier.rb +118 -0
  71. data/lib/rubocop/cop/style/favor_sprintf.rb +28 -0
  72. data/lib/rubocop/cop/style/favor_unless_over_negated_if.rb +54 -0
  73. data/lib/rubocop/cop/style/hash_syntax.rb +47 -0
  74. data/lib/rubocop/cop/style/if_then_else.rb +29 -0
  75. data/lib/rubocop/cop/style/if_with_semicolon.rb +20 -0
  76. data/lib/rubocop/cop/style/lambda.rb +47 -0
  77. data/lib/rubocop/cop/style/leading_comment_space.rb +25 -0
  78. data/lib/rubocop/cop/style/line_continuation.rb +26 -0
  79. data/lib/rubocop/cop/style/line_length.rb +30 -0
  80. data/lib/rubocop/cop/style/method_and_variable_snake_case.rb +61 -0
  81. data/lib/rubocop/cop/style/method_call_parentheses.rb +22 -0
  82. data/lib/rubocop/cop/style/method_length.rb +57 -0
  83. data/lib/rubocop/cop/style/multiline_if_then.rb +47 -0
  84. data/lib/rubocop/cop/style/not.rb +24 -0
  85. data/lib/rubocop/cop/style/numeric_literals.rb +25 -0
  86. data/lib/rubocop/cop/style/one_line_conditional.rb +20 -0
  87. data/lib/rubocop/cop/style/op_method.rb +29 -0
  88. data/lib/rubocop/cop/style/parameter_lists.rb +42 -0
  89. data/lib/rubocop/cop/style/parentheses_around_condition.rb +42 -0
  90. data/lib/rubocop/cop/style/proc.rb +30 -0
  91. data/lib/rubocop/cop/style/reduce_arguments.rb +34 -0
  92. data/lib/rubocop/cop/style/regexp_literal.rb +39 -0
  93. data/lib/rubocop/cop/style/rescue_modifier.rb +55 -0
  94. data/lib/rubocop/cop/style/semicolon.rb +51 -0
  95. data/lib/rubocop/cop/style/single_line_methods.rb +48 -0
  96. data/lib/rubocop/cop/style/space_after_comma_etc.rb +69 -0
  97. data/lib/rubocop/cop/style/space_after_control_keyword.rb +32 -0
  98. data/lib/rubocop/cop/style/string_literals.rb +36 -0
  99. data/lib/rubocop/cop/style/surrounding_space.rb +314 -0
  100. data/lib/rubocop/cop/style/symbol_array.rb +31 -0
  101. data/lib/rubocop/cop/style/symbol_name.rb +27 -0
  102. data/lib/rubocop/cop/style/tab.rb +25 -0
  103. data/lib/rubocop/cop/style/ternary_operator.rb +49 -0
  104. data/lib/rubocop/cop/style/trailing_whitespace.rb +24 -0
  105. data/lib/rubocop/cop/style/trivial_accessors.rb +32 -0
  106. data/lib/rubocop/cop/style/unless_else.rb +26 -0
  107. data/lib/rubocop/cop/style/variable_interpolation.rb +32 -0
  108. data/lib/rubocop/cop/style/when_then.rb +25 -0
  109. data/lib/rubocop/cop/style/while_until_do.rb +45 -0
  110. data/lib/rubocop/cop/style/word_array.rb +44 -0
  111. data/lib/rubocop/cop/util.rb +27 -0
  112. data/lib/rubocop/cop/variable_inspector.rb +280 -0
  113. data/lib/rubocop/formatter/base_formatter.rb +119 -0
  114. data/lib/rubocop/formatter/clang_style_formatter.rb +21 -0
  115. data/lib/rubocop/formatter/emacs_style_formatter.rb +17 -0
  116. data/lib/rubocop/formatter/formatter_set.rb +77 -0
  117. data/lib/rubocop/formatter/json_formatter.rb +76 -0
  118. data/lib/rubocop/formatter/progress_formatter.rb +63 -0
  119. data/lib/rubocop/formatter/simple_text_formatter.rb +62 -0
  120. data/lib/rubocop/version.rb +21 -0
  121. data/rubocop.gemspec +36 -0
  122. data/spec/.rubocop.yml +5 -0
  123. data/spec/project_spec.rb +24 -0
  124. data/spec/rubocop/cli_spec.rb +906 -0
  125. data/spec/rubocop/config_spec.rb +470 -0
  126. data/spec/rubocop/config_store_spec.rb +66 -0
  127. data/spec/rubocop/cops/cop_spec.rb +38 -0
  128. data/spec/rubocop/cops/lint/assignment_in_condition_spec.rb +111 -0
  129. data/spec/rubocop/cops/lint/end_alignment_spec.rb +333 -0
  130. data/spec/rubocop/cops/lint/end_in_method_spec.rb +35 -0
  131. data/spec/rubocop/cops/lint/ensure_return_spec.rb +37 -0
  132. data/spec/rubocop/cops/lint/eval_spec.rb +41 -0
  133. data/spec/rubocop/cops/lint/handle_exceptions_spec.rb +36 -0
  134. data/spec/rubocop/cops/lint/literal_in_condition_spec.rb +42 -0
  135. data/spec/rubocop/cops/lint/loop_spec.rb +33 -0
  136. data/spec/rubocop/cops/lint/rescue_exception_spec.rb +127 -0
  137. data/spec/rubocop/cops/lint/shadowing_outer_local_variable_spec.rb +243 -0
  138. data/spec/rubocop/cops/lint/unreachable_code_spec.rb +69 -0
  139. data/spec/rubocop/cops/lint/unused_local_variable_spec.rb +497 -0
  140. data/spec/rubocop/cops/lint/void_spec.rb +63 -0
  141. data/spec/rubocop/cops/offence_spec.rb +133 -0
  142. data/spec/rubocop/cops/rails/validation_spec.rb +27 -0
  143. data/spec/rubocop/cops/style/access_control_spec.rb +142 -0
  144. data/spec/rubocop/cops/style/alias_spec.rb +47 -0
  145. data/spec/rubocop/cops/style/align_parameters_spec.rb +199 -0
  146. data/spec/rubocop/cops/style/and_or_spec.rb +39 -0
  147. data/spec/rubocop/cops/style/ascii_comments_spec.rb +28 -0
  148. data/spec/rubocop/cops/style/ascii_identifiers_spec.rb +28 -0
  149. data/spec/rubocop/cops/style/attr_spec.rb +20 -0
  150. data/spec/rubocop/cops/style/avoid_class_vars_spec.rb +27 -0
  151. data/spec/rubocop/cops/style/avoid_for_spec.rb +37 -0
  152. data/spec/rubocop/cops/style/avoid_global_vars_spec.rb +34 -0
  153. data/spec/rubocop/cops/style/avoid_perl_backrefs_spec.rb +20 -0
  154. data/spec/rubocop/cops/style/avoid_perlisms_spec.rb +47 -0
  155. data/spec/rubocop/cops/style/begin_block_spec.rb +19 -0
  156. data/spec/rubocop/cops/style/block_comments_spec.rb +27 -0
  157. data/spec/rubocop/cops/style/block_nesting_spec.rb +159 -0
  158. data/spec/rubocop/cops/style/blocks_spec.rb +35 -0
  159. data/spec/rubocop/cops/style/case_equality_spec.rb +18 -0
  160. data/spec/rubocop/cops/style/case_indentation_spec.rb +88 -0
  161. data/spec/rubocop/cops/style/character_literal_spec.rb +28 -0
  162. data/spec/rubocop/cops/style/class_and_module_camel_case_spec.rb +46 -0
  163. data/spec/rubocop/cops/style/class_methods_spec.rb +51 -0
  164. data/spec/rubocop/cops/style/collection_methods_spec.rb +41 -0
  165. data/spec/rubocop/cops/style/colon_method_call_spec.rb +55 -0
  166. data/spec/rubocop/cops/style/constant_name_spec.rb +56 -0
  167. data/spec/rubocop/cops/style/def_with_parentheses_spec.rb +40 -0
  168. data/spec/rubocop/cops/style/def_without_parentheses_spec.rb +34 -0
  169. data/spec/rubocop/cops/style/documentation_spec.rb +79 -0
  170. data/spec/rubocop/cops/style/dot_position_spec.rb +30 -0
  171. data/spec/rubocop/cops/style/empty_line_between_defs_spec.rb +85 -0
  172. data/spec/rubocop/cops/style/empty_lines_spec.rb +40 -0
  173. data/spec/rubocop/cops/style/empty_literal_spec.rb +91 -0
  174. data/spec/rubocop/cops/style/encoding_spec.rb +49 -0
  175. data/spec/rubocop/cops/style/end_block_spec.rb +19 -0
  176. data/spec/rubocop/cops/style/end_of_line_spec.rb +25 -0
  177. data/spec/rubocop/cops/style/favor_join_spec.rb +37 -0
  178. data/spec/rubocop/cops/style/favor_modifier_spec.rb +160 -0
  179. data/spec/rubocop/cops/style/favor_sprintf_spec.rb +53 -0
  180. data/spec/rubocop/cops/style/favor_unless_over_negated_if_spec.rb +64 -0
  181. data/spec/rubocop/cops/style/favor_until_over_negated_while_spec.rb +47 -0
  182. data/spec/rubocop/cops/style/hash_syntax_spec.rb +51 -0
  183. data/spec/rubocop/cops/style/if_with_semicolon_spec.rb +25 -0
  184. data/spec/rubocop/cops/style/lambda_spec.rb +45 -0
  185. data/spec/rubocop/cops/style/leading_comment_space_spec.rb +65 -0
  186. data/spec/rubocop/cops/style/line_continuation_spec.rb +26 -0
  187. data/spec/rubocop/cops/style/line_length_spec.rb +25 -0
  188. data/spec/rubocop/cops/style/method_and_variable_snake_case_spec.rb +95 -0
  189. data/spec/rubocop/cops/style/method_call_parentheses_spec.rb +25 -0
  190. data/spec/rubocop/cops/style/method_length_spec.rb +151 -0
  191. data/spec/rubocop/cops/style/multiline_if_then_spec.rb +97 -0
  192. data/spec/rubocop/cops/style/not_spec.rb +28 -0
  193. data/spec/rubocop/cops/style/numeric_literals_spec.rb +51 -0
  194. data/spec/rubocop/cops/style/one_line_conditional_spec.rb +18 -0
  195. data/spec/rubocop/cops/style/op_method_spec.rb +80 -0
  196. data/spec/rubocop/cops/style/parameter_lists_spec.rb +49 -0
  197. data/spec/rubocop/cops/style/parentheses_around_condition_spec.rb +59 -0
  198. data/spec/rubocop/cops/style/proc_spec.rb +28 -0
  199. data/spec/rubocop/cops/style/reduce_arguments_spec.rb +59 -0
  200. data/spec/rubocop/cops/style/regexp_literal_spec.rb +83 -0
  201. data/spec/rubocop/cops/style/rescue_modifier_spec.rb +122 -0
  202. data/spec/rubocop/cops/style/semicolon_spec.rb +95 -0
  203. data/spec/rubocop/cops/style/single_line_methods_spec.rb +54 -0
  204. data/spec/rubocop/cops/style/space_after_colon_spec.rb +29 -0
  205. data/spec/rubocop/cops/style/space_after_comma_spec.rb +31 -0
  206. data/spec/rubocop/cops/style/space_after_control_keyword_spec.rb +69 -0
  207. data/spec/rubocop/cops/style/space_after_semicolon_spec.rb +24 -0
  208. data/spec/rubocop/cops/style/space_around_braces_spec.rb +49 -0
  209. data/spec/rubocop/cops/style/space_around_equals_in_default_parameter_spec.rb +34 -0
  210. data/spec/rubocop/cops/style/space_around_operators_spec.rb +216 -0
  211. data/spec/rubocop/cops/style/space_inside_brackets_spec.rb +51 -0
  212. data/spec/rubocop/cops/style/space_inside_hash_literal_braces_spec.rb +99 -0
  213. data/spec/rubocop/cops/style/space_inside_parens_spec.rb +33 -0
  214. data/spec/rubocop/cops/style/string_literals_spec.rb +62 -0
  215. data/spec/rubocop/cops/style/symbol_array_spec.rb +45 -0
  216. data/spec/rubocop/cops/style/symbol_name_spec.rb +122 -0
  217. data/spec/rubocop/cops/style/tab_spec.rb +23 -0
  218. data/spec/rubocop/cops/style/ternary_operator_spec.rb +42 -0
  219. data/spec/rubocop/cops/style/trailing_whitespace_spec.rb +29 -0
  220. data/spec/rubocop/cops/style/trivial_accessors_spec.rb +338 -0
  221. data/spec/rubocop/cops/style/unless_else_spec.rb +31 -0
  222. data/spec/rubocop/cops/style/variable_interpolation_spec.rb +53 -0
  223. data/spec/rubocop/cops/style/when_then_spec.rb +40 -0
  224. data/spec/rubocop/cops/style/while_until_do_spec.rb +47 -0
  225. data/spec/rubocop/cops/style/word_array_spec.rb +61 -0
  226. data/spec/rubocop/cops/variable_inspector_spec.rb +374 -0
  227. data/spec/rubocop/formatter/base_formatter_spec.rb +190 -0
  228. data/spec/rubocop/formatter/clang_style_formatter_spec.rb +70 -0
  229. data/spec/rubocop/formatter/emacs_style_formatter_spec.rb +32 -0
  230. data/spec/rubocop/formatter/formatter_set_spec.rb +132 -0
  231. data/spec/rubocop/formatter/json_formatter_spec.rb +142 -0
  232. data/spec/rubocop/formatter/progress_formatter_spec.rb +196 -0
  233. data/spec/rubocop/formatter/simple_text_formatter_spec.rb +74 -0
  234. data/spec/spec_helper.rb +92 -0
  235. data/spec/support/file_helper.rb +21 -0
  236. data/spec/support/isolated_environment.rb +27 -0
  237. data/spec/support/mri_syntax_checker.rb +69 -0
  238. data/spec/support/shared_examples.rb +33 -0
  239. metadata +517 -0
@@ -0,0 +1,30 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cops checks for uses of Proc.new where Kernel#proc
7
+ # would be more appropriate.
8
+ class Proc < Cop
9
+ MSG = 'Use proc instead of Proc.new.'
10
+
11
+ TARGET = s(:send, s(:const, nil, :Proc), :new)
12
+
13
+ def on_block(node)
14
+ # We're looking for
15
+ # (block
16
+ # (send
17
+ # (const nil :Proc) :new)
18
+ # ...)
19
+ block_method, = *node
20
+
21
+ if block_method == TARGET
22
+ add_offence(:convention, block_method.loc.expression, MSG)
23
+ end
24
+
25
+ super
26
+ end
27
+ end
28
+ end
29
+ end
30
+ end
@@ -0,0 +1,34 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cop checks whether the block arguments of a single-line
7
+ # reduce(inject) call are named *a*(for accumulator) and *e*
8
+ # (for element)
9
+ class ReduceArguments < Cop
10
+ MSG = 'Name reduce arguments |a, e| (accumulator, element).'
11
+
12
+ ARGS_NODE = s(:args, s(:arg, :a), s(:arg, :e))
13
+
14
+ def on_block(node)
15
+ # we care only for single line blocks
16
+ return unless Util.block_length(node) == 0
17
+
18
+ method_node, args_node, _body_node = *node
19
+ receiver, method_name, _method_args = *method_node
20
+
21
+ # discard other scenarios
22
+ return unless receiver
23
+ return unless [:reduce, :inject].include?(method_name)
24
+
25
+ unless args_node == ARGS_NODE
26
+ add_offence(:convention, node.loc.expression, MSG)
27
+ end
28
+
29
+ super
30
+ end
31
+ end
32
+ end
33
+ end
34
+ end
@@ -0,0 +1,39 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for regexp literals and reports offences based
7
+ # on how many escaped slashes there are in the regexp and on the
8
+ # value of the configuration parameter MaxSlashes.
9
+ class RegexpLiteral < Cop
10
+ def on_regexp(node)
11
+ slashes = node.loc.expression.source[1...-1].scan(/\//).size
12
+ max = RegexpLiteral.max_slashes
13
+ msg = if node.loc.begin.is?('/')
14
+ error_message('') if slashes > max
15
+ else
16
+ error_message('only ') if slashes <= max
17
+ end
18
+ add_offence(:convention, node.loc.expression, msg) if msg
19
+
20
+ super
21
+ end
22
+
23
+ def self.max_slashes
24
+ RegexpLiteral.config['MaxSlashes']
25
+ end
26
+
27
+ private
28
+
29
+ def error_message(word)
30
+ sprintf('Use %%r %sfor regular expressions matching more ' +
31
+ "than %d '/' character%s.",
32
+ word,
33
+ RegexpLiteral.max_slashes,
34
+ RegexpLiteral.max_slashes == 1 ? '' : 's')
35
+ end
36
+ end
37
+ end
38
+ end
39
+ end
@@ -0,0 +1,55 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for uses of rescue in its modifier form.
7
+ class RescueModifier < Cop
8
+ MSG = 'Avoid using rescue in its modifier form.'
9
+
10
+ def on_kwbegin(node)
11
+ body, *_ = *node
12
+ return if normal_rescue?(body)
13
+ super
14
+ end
15
+
16
+ def on_def(node)
17
+ _method_name, _args, body = *node
18
+ return if normal_rescue?(body)
19
+ super
20
+ end
21
+
22
+ def on_defs(node)
23
+ _receiver, _method_name, _args, body = *node
24
+ return if normal_rescue?(body)
25
+ super
26
+ end
27
+
28
+ def normal_rescue?(node)
29
+ return false unless node
30
+
31
+ case node.type
32
+ when :rescue
33
+ # Skip only the rescue node and continue processing its children.
34
+ process_regular_node(node)
35
+ true
36
+ when :ensure
37
+ first_child = node.children.first
38
+ if first_child && first_child.type == :rescue
39
+ process_regular_node(first_child)
40
+ true
41
+ else
42
+ false
43
+ end
44
+ else
45
+ false
46
+ end
47
+ end
48
+
49
+ def on_rescue(node)
50
+ add_offence(:convention, node.loc.expression, MSG)
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,51 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for multiple expressions placed on the same line.
7
+ # It also checks for lines terminated with a semicolon.
8
+ class Semicolon < Cop
9
+ MSG = 'Do not use semicolons to terminate expressions.'
10
+
11
+ def inspect(source_buffer, source, tokens, ast, comments)
12
+ return unless ast
13
+
14
+ on_node(:begin, ast) do |node|
15
+ exprs = node.children
16
+
17
+ next if exprs.size < 2
18
+
19
+ # create a map matching lines to the number of expressions on them
20
+ exprs_lines = exprs.map { |e| e.loc.expression.line }
21
+ lines = exprs_lines.group_by { |i| i }
22
+
23
+ # every line with more than 1 expression on it is an offence
24
+ lines.each do |line, expr_on_line|
25
+ if expr_on_line.size > 1
26
+ # TODO: Find the correct position of the semicolon. We don't
27
+ # know if the first semicolon on the line is a separator of
28
+ # expressions. It's just a guess.
29
+ column = source[line - 1].index(';')
30
+ add_offence(:convention,
31
+ source_range(source_buffer, source[0...(line - 1)],
32
+ column, 1),
33
+ MSG)
34
+ end
35
+ end
36
+ end
37
+
38
+ tokens.group_by { |t| t.pos.line }.each do |line, line_tokens|
39
+ if line_tokens.last.type == :tSEMI # rubocop:disable SymbolName
40
+ column = line_tokens.last.pos.column
41
+ add_offence(:convention,
42
+ source_range(source_buffer, source[0...(line - 1)],
43
+ column, 1),
44
+ MSG)
45
+ end
46
+ end
47
+ end
48
+ end
49
+ end
50
+ end
51
+ end
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # This cop checks for single-line method definitions.
7
+ # It can optionally accept single-line methods with no body.
8
+ class SingleLineMethods < Cop
9
+ MSG = 'Avoid single-line method definitions.'
10
+
11
+ def allow_empty?
12
+ SingleLineMethods.config['AllowIfMethodIsEmpty']
13
+ end
14
+
15
+ def on_def(node)
16
+ check(node)
17
+
18
+ super
19
+ end
20
+
21
+ def on_defs(node)
22
+ check(node)
23
+
24
+ super
25
+ end
26
+
27
+ private
28
+
29
+ def check(node)
30
+ start_line = node.loc.keyword.line
31
+ end_line = node.loc.end.line
32
+
33
+ if node.type == :def
34
+ empty_body = node.children[2].nil?
35
+ else
36
+ empty_body = node.children[3].nil?
37
+ end
38
+
39
+ if start_line == end_line && !(allow_empty? && empty_body)
40
+ add_offence(:convention,
41
+ node.loc.expression,
42
+ MSG)
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,69 @@
1
+ # encoding: utf-8
2
+
3
+ # rubocop:disable SymbolName
4
+
5
+ module Rubocop
6
+ module Cop
7
+ module Style
8
+ # Common functionality for cops checking for missing space after
9
+ # punctuation.
10
+ module SpaceAfterCommaEtc
11
+ MSG = 'Space missing after %s.'
12
+
13
+ def inspect(source_buffer, source, tokens, ast, comments)
14
+ tokens.each_cons(2) do |t1, t2|
15
+ if kind(t1) && t1.pos.line == t2.pos.line &&
16
+ t2.pos.column == t1.pos.column + offset(t1)
17
+ add_offence(:convention, t1.pos, sprintf(MSG, kind(t1)))
18
+ end
19
+ end
20
+ end
21
+
22
+ # The normal offset, i.e., the distance from the punctuation
23
+ # token where a space should be, is 1.
24
+ def offset(token)
25
+ 1
26
+ end
27
+ end
28
+
29
+ # Checks for comma (,) not follwed by some kind of space.
30
+ class SpaceAfterComma < Cop
31
+ include SpaceAfterCommaEtc
32
+
33
+ def kind(token)
34
+ 'comma' if token.type == :tCOMMA
35
+ end
36
+ end
37
+
38
+ # Checks for semicolon (;) not follwed by some kind of space.
39
+ class SpaceAfterSemicolon < Cop
40
+ include SpaceAfterCommaEtc
41
+
42
+ def kind(token)
43
+ 'semicolon' if token.type == :tSEMI
44
+ end
45
+ end
46
+
47
+ # Checks for colon (:) not follwed by some kind of space.
48
+ class SpaceAfterColon < Cop
49
+ include SpaceAfterCommaEtc
50
+
51
+ # The colon following a label will not appear in the token
52
+ # array. Instad we get a tLABEL token, whose length we use to
53
+ # calculate where we expect a space.
54
+ def offset(token)
55
+ case token.type
56
+ when :tLABEL then token.text.length + 1
57
+ when :tCOLON then 1
58
+ end
59
+ end
60
+
61
+ def kind(token)
62
+ case token.type
63
+ when :tLABEL, :tCOLON then 'colon'
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
@@ -0,0 +1,32 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # Checks for various control keywords missing a space after them.
7
+ class SpaceAfterControlKeyword < Cop
8
+ MSG = 'Use space after control keywords.'
9
+ # elsif and unless are handled by on_if.
10
+ KEYWORDS = %w(if case when while until)
11
+
12
+ def on_keyword(node)
13
+ return if node.loc.is_a?(Parser::Source::Map::Ternary)
14
+
15
+ exp = node.loc.expression
16
+ kw = node.loc.keyword
17
+ kw_offset = kw.begin_pos - exp.begin_pos
18
+ if exp.source[kw_offset..-1].start_with?(kw.source + '(')
19
+ add_offence(:convention, kw, MSG)
20
+ end
21
+ end
22
+
23
+ KEYWORDS.each do |keyword|
24
+ define_method(:"on_#{keyword}") do |node|
25
+ on_keyword(node)
26
+ super(node)
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
32
+ end
@@ -0,0 +1,36 @@
1
+ # encoding: utf-8
2
+
3
+ module Rubocop
4
+ module Cop
5
+ module Style
6
+ # Checks for uses of double quotes where single quotes would do.
7
+ class StringLiterals < Cop
8
+ MSG = "Prefer single-quoted strings when you don't need " +
9
+ 'string interpolation or special symbols.'
10
+
11
+ def on_str(node)
12
+ # Constants like __FILE__ are handled as strings,
13
+ # but don't respond to begin.
14
+ return unless node.loc.respond_to?(:begin)
15
+
16
+ # regex matches IF there is a ' or there is a \\ in the string that
17
+ # is not preceeded/followed by another \\ (e.g. "\\x34") but not
18
+ # "\\\\"
19
+ if node.loc.expression.source !~ /('|([^\\]|\A)\\([^\\]|\Z))/ &&
20
+ node.loc.begin.is?('"')
21
+ add_offence(:convention, node.loc.expression, MSG)
22
+ do_autocorrect(node)
23
+ end
24
+ end
25
+
26
+ alias_method :on_dstr, :ignore_node
27
+ alias_method :on_regexp, :ignore_node
28
+
29
+ def autocorrect_action(node)
30
+ replace(node.loc.begin, "'")
31
+ replace(node.loc.end, "'")
32
+ end
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,314 @@
1
+ # encoding: utf-8
2
+
3
+ # rubocop:disable SymbolName
4
+
5
+ module Rubocop
6
+ module Cop
7
+ module Style
8
+ # Common functionality for checking surrounding space.
9
+ module SurroundingSpace
10
+ def space_between?(t1, t2)
11
+ char_preceding_2nd_token =
12
+ @source[t2.pos.line - 1][t2.pos.column - 1]
13
+ if char_preceding_2nd_token == '+' && t1.type != :tPLUS
14
+ # Special case. A unary plus is not present in the tokens.
15
+ char_preceding_2nd_token =
16
+ @source[t2.pos.line - 1][t2.pos.column - 2]
17
+ end
18
+ t2.pos.line > t1.pos.line || char_preceding_2nd_token == ' '
19
+ end
20
+
21
+ def index_of_first_token(node, tokens)
22
+ @token_table ||= build_token_table(tokens)
23
+ b = node.loc.expression.begin
24
+ @token_table[[b.line, b.column]]
25
+ end
26
+
27
+ def index_of_last_token(node, tokens)
28
+ @token_table ||= build_token_table(tokens)
29
+ e = node.loc.expression.end
30
+ (0...e.column).to_a.reverse.find do |c|
31
+ ix = @token_table[[e.line, c]]
32
+ return ix if ix
33
+ end
34
+ end
35
+
36
+ def build_token_table(tokens)
37
+ table = {}
38
+ tokens.each_with_index do |t, ix|
39
+ table[[t.pos.line, t.pos.column]] = ix
40
+ end
41
+ table
42
+ end
43
+ end
44
+
45
+ # Checks that operators have space around them, except for **
46
+ # which should not have surrounding space.
47
+ class SpaceAroundOperators < Cop
48
+ include SurroundingSpace
49
+ MSG_MISSING = "Surrounding space missing for operator '%s'."
50
+ MSG_DETECTED = 'Space around operator ** detected.'
51
+
52
+ BINARY_OPERATORS =
53
+ [:tEQL, :tAMPER2, :tPIPE, :tCARET, :tPLUS, :tMINUS, :tSTAR2,
54
+ :tDIVIDE, :tPERCENT, :tEH, :tCOLON, :tANDOP, :tOROP, :tMATCH,
55
+ :tNMATCH, :tEQ, :tNEQ, :tGT, :tRSHFT, :tGEQ, :tLT,
56
+ :tLSHFT, :tLEQ, :tASSOC, :tEQQ, :tCMP, :tOP_ASGN]
57
+
58
+ def inspect(source_buffer, source, tokens, sexp, comments)
59
+ return unless sexp
60
+
61
+ @source = source
62
+ positions_not_to_check = get_positions_not_to_check(tokens, sexp)
63
+
64
+ tokens.each_cons(3) do |token_before, token, token_after|
65
+ next if token_before.type == :kDEF # TODO: remove?
66
+ next if token_before.type == :tDOT # Called as method.
67
+ next if positions_not_to_check.include?(token.pos)
68
+
69
+ case token.type
70
+ when :tPOW
71
+ if has_space?(token_before, token, token_after)
72
+ add_offence(:convention, token.pos, MSG_DETECTED)
73
+ end
74
+ when *BINARY_OPERATORS
75
+ check_missing_space(token_before, token, token_after)
76
+ end
77
+ end
78
+ end
79
+
80
+ # Returns an array of positions marking the tokens that this cop
81
+ # should not check, either because the token is not an operator
82
+ # or because another cop does the check.
83
+ def get_positions_not_to_check(tokens, sexp)
84
+ positions_not_to_check = []
85
+ do_not_check_block_arg_pipes(sexp, positions_not_to_check)
86
+ do_not_check_param_default(tokens, sexp, positions_not_to_check)
87
+ do_not_check_class_lshift_self(tokens, sexp, positions_not_to_check)
88
+ do_not_check_def_things(tokens, sexp, positions_not_to_check)
89
+ do_not_check_singleton_operator_defs(tokens, sexp,
90
+ positions_not_to_check)
91
+ positions_not_to_check
92
+ end
93
+
94
+ def do_not_check_block_arg_pipes(sexp, positions_not_to_check)
95
+ # each { |a| }
96
+ # ^ ^
97
+ on_node(:block, sexp) do |b|
98
+ on_node(:args, b) do |a|
99
+ positions_not_to_check << a.loc.begin << a.loc.end if a.loc.begin
100
+ end
101
+ end
102
+ end
103
+
104
+ def do_not_check_param_default(tokens, sexp, positions_not_to_check)
105
+ # func(a, b=nil)
106
+ # ^
107
+ on_node(:optarg, sexp) do |optarg|
108
+ _arg, equals, _value = tokens[index_of_first_token(optarg, tokens),
109
+ 3]
110
+ positions_not_to_check << equals.pos
111
+ end
112
+ end
113
+
114
+ def do_not_check_class_lshift_self(tokens,
115
+ sexp,
116
+ positions_not_to_check)
117
+ # class <<self
118
+ # ^
119
+ on_node(:sclass, sexp) do |sclass|
120
+ ix = index_of_first_token(sclass, tokens)
121
+ if tokens[ix, 2].map(&:type) == [:kCLASS, :tLSHFT]
122
+ positions_not_to_check << tokens[ix + 1].pos
123
+ end
124
+ end
125
+ end
126
+
127
+ def do_not_check_def_things(tokens, sexp, positions_not_to_check)
128
+ # def +(other)
129
+ # ^
130
+ on_node(:def, sexp) do |def_node|
131
+ # def each &block
132
+ # ^
133
+ # def each *args
134
+ # ^
135
+ on_node([:blockarg, :restarg], def_node) do |arg_node|
136
+ positions_not_to_check <<
137
+ tokens[index_of_first_token(arg_node, tokens)].pos
138
+ end
139
+ positions_not_to_check <<
140
+ tokens[index_of_first_token(def_node, tokens) + 1].pos
141
+ end
142
+ end
143
+
144
+ def do_not_check_singleton_operator_defs(tokens, sexp,
145
+ positions_not_to_check)
146
+ # def self.===(other)
147
+ # ^
148
+ on_node(:defs, sexp) do |defs_node|
149
+ _receiver, name, _args = *defs_node
150
+ ix = index_of_first_token(defs_node, tokens)
151
+ name_token = tokens[ix..-1].find { |t| t.text == name.to_s }
152
+ positions_not_to_check << name_token.pos
153
+ end
154
+ end
155
+
156
+ def check_missing_space(token_before, token, token_after)
157
+ unless has_space?(token_before, token, token_after)
158
+ text = token.text.to_s + (token.type == :tOP_ASGN ? '=' : '')
159
+ add_offence(:convention, token.pos, MSG_MISSING % text)
160
+ end
161
+ end
162
+
163
+ def has_space?(token_before, token, token_after)
164
+ space_between?(token_before, token) && space_between?(token,
165
+ token_after)
166
+ end
167
+ end
168
+
169
+ # Checks that block braces have surrounding space.
170
+ class SpaceAroundBraces < Cop
171
+ include SurroundingSpace
172
+ MSG_LEFT = "Surrounding space missing for '{'."
173
+ MSG_RIGHT = "Space missing to the left of '}'."
174
+
175
+ def inspect(source_buffer, source, tokens, sexp, comments)
176
+ return unless sexp
177
+ @source = source
178
+ positions_not_to_check = get_positions_not_to_check(tokens, sexp)
179
+ tokens.each_cons(2) do |t1, t2|
180
+ next if ([t1.pos, t2.pos] - positions_not_to_check).size < 2
181
+
182
+ type1, type2 = t1.type, t2.type
183
+ # :tLBRACE in hash literals, :tLCURLY otherwise.
184
+ next if [:tLCURLY, :tLBRACE].include?(type1) && type2 == :tRCURLY
185
+ check(t1, t2, MSG_LEFT) if type1 == :tLCURLY || type2 == :tLCURLY
186
+ check(t1, t2, MSG_RIGHT) if type2 == :tRCURLY
187
+ end
188
+ end
189
+
190
+ def get_positions_not_to_check(tokens, sexp)
191
+ positions_not_to_check = []
192
+
193
+ on_node(:hash, sexp) do |hash|
194
+ b_ix = index_of_first_token(hash, tokens)
195
+ e_ix = index_of_last_token(hash, tokens)
196
+ positions_not_to_check << tokens[b_ix].pos << tokens[e_ix].pos
197
+ end
198
+
199
+ # TODO: Check braces inside string/symbol/regexp/xstr interpolation.
200
+ on_node([:dstr, :dsym, :regexp, :xstr], sexp) do |s|
201
+ b_ix = index_of_first_token(s, tokens)
202
+ e_ix = index_of_last_token(s, tokens)
203
+ tokens[b_ix..e_ix].each do |t|
204
+ positions_not_to_check << t.pos if t.type == :tRCURLY
205
+ end
206
+ end
207
+
208
+ positions_not_to_check
209
+ end
210
+
211
+ def check(t1, t2, msg)
212
+ unless space_between?(t1, t2)
213
+ brace_token = msg == MSG_LEFT ? t1 : t2
214
+ add_offence(:convention, brace_token.pos, msg)
215
+ end
216
+ end
217
+ end
218
+
219
+ # Common functionality for checking for spaces inside various
220
+ # kinds of parentheses.
221
+ module SpaceInside
222
+ include SurroundingSpace
223
+ MSG = 'Space inside %s detected.'
224
+
225
+ def inspect(source_buffer, source, tokens, sexp, comments)
226
+ @source = source
227
+ left, right, kind = specifics
228
+ tokens.each_cons(2) do |t1, t2|
229
+ if t1.type == left || t2.type == right
230
+ if t2.pos.line == t1.pos.line && space_between?(t1, t2)
231
+ space_range = Parser::Source::Range.new(source_buffer,
232
+ t1.pos.end_pos,
233
+ t2.pos.begin_pos)
234
+ add_offence(:convention, space_range, format(MSG, kind))
235
+ end
236
+ end
237
+ end
238
+ end
239
+ end
240
+
241
+ # Checks for spaces inside ordinary round parentheses.
242
+ class SpaceInsideParens < Cop
243
+ include SpaceInside
244
+
245
+ def specifics
246
+ [:tLPAREN2, :tRPAREN, 'parentheses']
247
+ end
248
+ end
249
+
250
+ # Checks for spaces inside square brackets.
251
+ class SpaceInsideBrackets < Cop
252
+ include SpaceInside
253
+
254
+ def specifics
255
+ [:tLBRACK, :tRBRACK, 'square brackets']
256
+ end
257
+ end
258
+
259
+ # Checks that braces used for hash literals have or don't have
260
+ # surrounding space depending on configuration.
261
+ class SpaceInsideHashLiteralBraces < Cop
262
+ include SurroundingSpace
263
+ MSG = 'Space inside hash literal braces %s.'
264
+
265
+ def inspect(source_buffer, source, tokens, sexp, comments)
266
+ return unless sexp
267
+ @source = source
268
+ on_node(:hash, sexp) do |hash|
269
+ b_ix = index_of_first_token(hash, tokens)
270
+ e_ix = index_of_last_token(hash, tokens)
271
+ if tokens[b_ix].type == :tLBRACE # Hash literal with braces?
272
+ check(tokens[b_ix], tokens[b_ix + 1])
273
+ check(tokens[e_ix - 1], tokens[e_ix])
274
+ end
275
+ end
276
+ end
277
+
278
+ def check(t1, t2)
279
+ types = [t1, t2].map(&:type)
280
+ braces = [:tLBRACE, :tRCURLY]
281
+ return if types == braces || (braces - types).size == 2
282
+ # No offence if line break inside.
283
+ return if t1.pos.line < t2.pos.line
284
+ has_space = space_between?(t1, t2)
285
+ is_offence, word = if self.class.config['EnforcedStyleIsWithSpaces']
286
+ [!has_space, 'missing']
287
+ else
288
+ [has_space, 'detected']
289
+ end
290
+ add_offence(:convention, t1.pos, sprintf(MSG, word)) if is_offence
291
+ end
292
+ end
293
+
294
+ # Checks that the equals signs in parameter default assignments
295
+ # have surrounding space.
296
+ class SpaceAroundEqualsInParameterDefault < Cop
297
+ include SurroundingSpace
298
+ MSG = 'Surrounding space missing in default value assignment.'
299
+
300
+ def inspect(source_buffer, source, tokens, sexp, comments)
301
+ return unless sexp
302
+ @source = source
303
+ on_node(:optarg, sexp) do |optarg|
304
+ index = index_of_first_token(optarg, tokens)
305
+ arg, equals, value = tokens[index, 3]
306
+ unless space_between?(arg, equals) && space_between?(equals, value)
307
+ add_offence(:convention, equals.pos, MSG)
308
+ end
309
+ end
310
+ end
311
+ end
312
+ end
313
+ end
314
+ end