rubocop 0.35.1 → 0.36.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 (385) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +164 -0
  3. data/LICENSE.txt +1 -1
  4. data/README.md +72 -21
  5. data/bin/rubocop +1 -0
  6. data/config/default.yml +167 -18
  7. data/config/disabled.yml +19 -6
  8. data/config/enabled.yml +159 -14
  9. data/lib/rubocop.rb +67 -26
  10. data/lib/rubocop/ast_node.rb +488 -14
  11. data/lib/rubocop/ast_node/builder.rb +24 -0
  12. data/lib/rubocop/ast_node/sexp.rb +13 -0
  13. data/lib/rubocop/cached_data.rb +58 -0
  14. data/lib/rubocop/cli.rb +47 -10
  15. data/lib/rubocop/comment_config.rb +9 -2
  16. data/lib/rubocop/config.rb +99 -31
  17. data/lib/rubocop/config_loader.rb +23 -14
  18. data/lib/rubocop/config_store.rb +1 -0
  19. data/lib/rubocop/cop/autocorrect_logic.rb +2 -1
  20. data/lib/rubocop/cop/commissioner.rb +3 -5
  21. data/lib/rubocop/cop/cop.rb +23 -17
  22. data/lib/rubocop/cop/corrector.rb +25 -0
  23. data/lib/rubocop/cop/force.rb +1 -0
  24. data/lib/rubocop/cop/ignored_node.rb +3 -2
  25. data/lib/rubocop/cop/lint/ambiguous_operator.rb +2 -1
  26. data/lib/rubocop/cop/lint/ambiguous_regexp_literal.rb +2 -1
  27. data/lib/rubocop/cop/lint/assignment_in_condition.rb +4 -3
  28. data/lib/rubocop/cop/lint/block_alignment.rb +29 -91
  29. data/lib/rubocop/cop/lint/circular_argument_reference.rb +2 -1
  30. data/lib/rubocop/cop/lint/condition_position.rb +2 -1
  31. data/lib/rubocop/cop/lint/debugger.rb +29 -12
  32. data/lib/rubocop/cop/lint/def_end_alignment.rb +16 -18
  33. data/lib/rubocop/cop/lint/deprecated_class_methods.rb +6 -6
  34. data/lib/rubocop/cop/lint/duplicate_methods.rb +98 -74
  35. data/lib/rubocop/cop/lint/duplicated_key.rb +3 -2
  36. data/lib/rubocop/cop/lint/each_with_object_argument.rb +3 -2
  37. data/lib/rubocop/cop/lint/else_layout.rb +2 -1
  38. data/lib/rubocop/cop/lint/empty_ensure.rb +2 -1
  39. data/lib/rubocop/cop/lint/empty_interpolation.rb +2 -1
  40. data/lib/rubocop/cop/lint/end_alignment.rb +77 -39
  41. data/lib/rubocop/cop/lint/end_in_method.rb +2 -1
  42. data/lib/rubocop/cop/lint/ensure_return.rb +2 -1
  43. data/lib/rubocop/cop/lint/eval.rb +2 -1
  44. data/lib/rubocop/cop/lint/float_out_of_range.rb +31 -0
  45. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +14 -30
  46. data/lib/rubocop/cop/lint/handle_exceptions.rb +2 -1
  47. data/lib/rubocop/cop/lint/implicit_string_concatenation.rb +85 -0
  48. data/lib/rubocop/cop/lint/ineffective_access_modifier.rb +120 -0
  49. data/lib/rubocop/cop/lint/invalid_character_literal.rb +3 -1
  50. data/lib/rubocop/cop/lint/literal_in_condition.rb +6 -9
  51. data/lib/rubocop/cop/lint/literal_in_interpolation.rb +6 -9
  52. data/lib/rubocop/cop/lint/loop.rb +2 -1
  53. data/lib/rubocop/cop/lint/nested_method_definition.rb +19 -3
  54. data/lib/rubocop/cop/lint/next_without_accumulator.rb +38 -0
  55. data/lib/rubocop/cop/lint/non_local_exit_from_iterator.rb +5 -8
  56. data/lib/rubocop/cop/lint/parentheses_as_grouped_expression.rb +8 -6
  57. data/lib/rubocop/cop/lint/rand_one.rb +36 -0
  58. data/lib/rubocop/cop/lint/require_parentheses.rb +6 -5
  59. data/lib/rubocop/cop/lint/rescue_exception.rb +3 -2
  60. data/lib/rubocop/cop/lint/shadowing_outer_local_variable.rb +2 -1
  61. data/lib/rubocop/cop/lint/string_conversion_in_interpolation.rb +6 -4
  62. data/lib/rubocop/cop/lint/syntax.rb +9 -5
  63. data/lib/rubocop/cop/lint/underscore_prefixed_variable_name.rb +3 -2
  64. data/lib/rubocop/cop/lint/unneeded_disable.rb +121 -18
  65. data/lib/rubocop/cop/lint/unreachable_code.rb +5 -4
  66. data/lib/rubocop/cop/lint/unused_block_argument.rb +9 -7
  67. data/lib/rubocop/cop/lint/unused_method_argument.rb +2 -1
  68. data/lib/rubocop/cop/lint/useless_access_modifier.rb +56 -29
  69. data/lib/rubocop/cop/lint/useless_assignment.rb +4 -16
  70. data/lib/rubocop/cop/lint/useless_comparison.rb +3 -2
  71. data/lib/rubocop/cop/lint/useless_else_without_rescue.rb +2 -1
  72. data/lib/rubocop/cop/lint/useless_setter_call.rb +14 -20
  73. data/lib/rubocop/cop/lint/void.rb +10 -11
  74. data/lib/rubocop/cop/metrics/abc_size.rb +3 -1
  75. data/lib/rubocop/cop/metrics/block_nesting.rb +2 -1
  76. data/lib/rubocop/cop/metrics/class_length.rb +1 -0
  77. data/lib/rubocop/cop/metrics/cyclomatic_complexity.rb +4 -2
  78. data/lib/rubocop/cop/metrics/line_length.rb +35 -13
  79. data/lib/rubocop/cop/metrics/method_length.rb +2 -1
  80. data/lib/rubocop/cop/metrics/module_length.rb +1 -0
  81. data/lib/rubocop/cop/metrics/parameter_lists.rb +2 -1
  82. data/lib/rubocop/cop/metrics/perceived_complexity.rb +4 -2
  83. data/lib/rubocop/cop/mixin/access_modifier_node.rb +3 -10
  84. data/lib/rubocop/cop/mixin/annotation_comment.rb +1 -0
  85. data/lib/rubocop/cop/mixin/array_hash_indentation.rb +80 -0
  86. data/lib/rubocop/cop/mixin/array_syntax.rb +2 -1
  87. data/lib/rubocop/cop/mixin/autocorrect_alignment.rb +14 -20
  88. data/lib/rubocop/cop/mixin/autocorrect_unless_changing_ast.rb +5 -4
  89. data/lib/rubocop/cop/mixin/check_assignment.rb +20 -15
  90. data/lib/rubocop/cop/mixin/classish_length.rb +1 -0
  91. data/lib/rubocop/cop/mixin/code_length.rb +1 -0
  92. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +17 -15
  93. data/lib/rubocop/cop/mixin/configurable_max.rb +1 -0
  94. data/lib/rubocop/cop/mixin/configurable_naming.rb +4 -0
  95. data/lib/rubocop/cop/mixin/empty_lines_around_body.rb +9 -4
  96. data/lib/rubocop/cop/mixin/end_keyword_alignment.rb +24 -16
  97. data/lib/rubocop/cop/mixin/first_element_line_break.rb +3 -2
  98. data/lib/rubocop/cop/mixin/hash_node.rb +15 -0
  99. data/lib/rubocop/cop/mixin/if_node.rb +1 -0
  100. data/lib/rubocop/cop/mixin/method_complexity.rb +1 -0
  101. data/lib/rubocop/cop/mixin/method_preference.rb +1 -0
  102. data/lib/rubocop/cop/mixin/min_body_length.rb +1 -0
  103. data/lib/rubocop/cop/mixin/multiline_expression_indentation.rb +177 -0
  104. data/lib/rubocop/cop/mixin/negative_conditional.rb +1 -0
  105. data/lib/rubocop/cop/mixin/on_method_def.rb +6 -5
  106. data/lib/rubocop/cop/mixin/on_normal_if_unless.rb +1 -0
  107. data/lib/rubocop/cop/mixin/parentheses.rb +22 -0
  108. data/lib/rubocop/cop/mixin/parser_diagnostic.rb +1 -0
  109. data/lib/rubocop/cop/mixin/percent_literal.rb +1 -0
  110. data/lib/rubocop/cop/mixin/preceding_following_alignment.rb +79 -0
  111. data/lib/rubocop/cop/mixin/safe_assignment.rb +1 -0
  112. data/lib/rubocop/cop/mixin/space_after_punctuation.rb +2 -1
  113. data/lib/rubocop/cop/mixin/space_before_punctuation.rb +2 -1
  114. data/lib/rubocop/cop/mixin/space_inside.rb +2 -1
  115. data/lib/rubocop/cop/mixin/statement_modifier.rb +6 -5
  116. data/lib/rubocop/cop/mixin/string_help.rb +2 -9
  117. data/lib/rubocop/cop/mixin/string_literals_help.rb +13 -7
  118. data/lib/rubocop/cop/mixin/surrounding_space.rb +3 -2
  119. data/lib/rubocop/cop/mixin/trailing_comma.rb +134 -0
  120. data/lib/rubocop/cop/mixin/unused_argument.rb +1 -0
  121. data/lib/rubocop/cop/offense.rb +19 -14
  122. data/lib/rubocop/cop/performance/case_when_splat.rb +8 -8
  123. data/lib/rubocop/cop/performance/casecmp.rb +54 -0
  124. data/lib/rubocop/cop/performance/count.rb +10 -9
  125. data/lib/rubocop/cop/performance/detect.rb +6 -5
  126. data/lib/rubocop/cop/performance/double_start_end_with.rb +65 -0
  127. data/lib/rubocop/cop/performance/end_with.rb +55 -0
  128. data/lib/rubocop/cop/performance/fixed_size.rb +1 -0
  129. data/lib/rubocop/cop/performance/flat_map.rb +9 -8
  130. data/lib/rubocop/cop/performance/hash_each.rb +86 -0
  131. data/lib/rubocop/cop/performance/lstrip_rstrip.rb +44 -0
  132. data/lib/rubocop/cop/performance/range_include.rb +40 -0
  133. data/lib/rubocop/cop/performance/redundant_block_call.rb +57 -0
  134. data/lib/rubocop/cop/performance/redundant_match.rb +51 -0
  135. data/lib/rubocop/cop/performance/redundant_merge.rb +85 -0
  136. data/lib/rubocop/cop/performance/redundant_sort_by.rb +45 -0
  137. data/lib/rubocop/cop/performance/reverse_each.rb +3 -2
  138. data/lib/rubocop/cop/performance/sample.rb +6 -5
  139. data/lib/rubocop/cop/performance/size.rb +2 -1
  140. data/lib/rubocop/cop/performance/start_with.rb +58 -0
  141. data/lib/rubocop/cop/performance/string_replacement.rb +18 -23
  142. data/lib/rubocop/cop/performance/times_map.rb +49 -0
  143. data/lib/rubocop/cop/rails/action_filter.rb +4 -3
  144. data/lib/rubocop/cop/rails/date.rb +5 -4
  145. data/lib/rubocop/cop/rails/delegate.rb +3 -2
  146. data/lib/rubocop/cop/rails/find_by.rb +20 -14
  147. data/lib/rubocop/cop/rails/find_each.rb +23 -2
  148. data/lib/rubocop/cop/rails/has_and_belongs_to_many.rb +3 -2
  149. data/lib/rubocop/cop/rails/output.rb +4 -2
  150. data/lib/rubocop/cop/rails/pluralization_grammar.rb +3 -2
  151. data/lib/rubocop/cop/rails/read_write_attribute.rb +5 -7
  152. data/lib/rubocop/cop/rails/scope_args.rb +3 -2
  153. data/lib/rubocop/cop/rails/time_zone.rb +14 -10
  154. data/lib/rubocop/cop/rails/validation.rb +4 -3
  155. data/lib/rubocop/cop/severity.rb +8 -7
  156. data/lib/rubocop/cop/style/access_modifier_indentation.rb +5 -4
  157. data/lib/rubocop/cop/style/accessor_method_name.rb +1 -0
  158. data/lib/rubocop/cop/style/alias.rb +84 -24
  159. data/lib/rubocop/cop/style/align_array.rb +2 -1
  160. data/lib/rubocop/cop/style/align_hash.rb +13 -14
  161. data/lib/rubocop/cop/style/align_parameters.rb +3 -2
  162. data/lib/rubocop/cop/style/and_or.rb +9 -7
  163. data/lib/rubocop/cop/style/array_join.rb +5 -5
  164. data/lib/rubocop/cop/style/ascii_comments.rb +2 -1
  165. data/lib/rubocop/cop/style/ascii_identifiers.rb +2 -1
  166. data/lib/rubocop/cop/style/attr.rb +30 -5
  167. data/lib/rubocop/cop/style/auto_resource_cleanup.rb +3 -3
  168. data/lib/rubocop/cop/style/bare_percent_literals.rb +2 -1
  169. data/lib/rubocop/cop/style/begin_block.rb +2 -1
  170. data/lib/rubocop/cop/style/block_comments.rb +2 -1
  171. data/lib/rubocop/cop/style/block_delimiters.rb +10 -9
  172. data/lib/rubocop/cop/style/block_end_newline.rb +3 -2
  173. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +9 -8
  174. data/lib/rubocop/cop/style/case_equality.rb +2 -1
  175. data/lib/rubocop/cop/style/case_indentation.rb +2 -1
  176. data/lib/rubocop/cop/style/character_literal.rb +11 -7
  177. data/lib/rubocop/cop/style/class_and_module_camel_case.rb +2 -1
  178. data/lib/rubocop/cop/style/class_and_module_children.rb +3 -2
  179. data/lib/rubocop/cop/style/class_check.rb +2 -1
  180. data/lib/rubocop/cop/style/class_methods.rb +2 -1
  181. data/lib/rubocop/cop/style/class_vars.rb +2 -1
  182. data/lib/rubocop/cop/style/closing_parenthesis_indentation.rb +3 -2
  183. data/lib/rubocop/cop/style/collection_methods.rb +2 -1
  184. data/lib/rubocop/cop/style/colon_method_call.rb +3 -2
  185. data/lib/rubocop/cop/style/command_literal.rb +8 -7
  186. data/lib/rubocop/cop/style/comment_annotation.rb +3 -2
  187. data/lib/rubocop/cop/style/comment_indentation.rb +4 -6
  188. data/lib/rubocop/cop/style/conditional_assignment.rb +362 -0
  189. data/lib/rubocop/cop/style/constant_name.rb +2 -1
  190. data/lib/rubocop/cop/style/copyright.rb +7 -6
  191. data/lib/rubocop/cop/style/def_with_parentheses.rb +2 -1
  192. data/lib/rubocop/cop/style/deprecated_hash_methods.rb +3 -2
  193. data/lib/rubocop/cop/style/documentation.rb +7 -11
  194. data/lib/rubocop/cop/style/dot_position.rb +3 -2
  195. data/lib/rubocop/cop/style/double_negation.rb +2 -1
  196. data/lib/rubocop/cop/style/each_with_object.rb +4 -3
  197. data/lib/rubocop/cop/style/else_alignment.rb +3 -2
  198. data/lib/rubocop/cop/style/empty_else.rb +4 -3
  199. data/lib/rubocop/cop/style/empty_line_between_defs.rb +2 -1
  200. data/lib/rubocop/cop/style/empty_lines.rb +10 -4
  201. data/lib/rubocop/cop/style/empty_lines_around_access_modifier.rb +13 -5
  202. data/lib/rubocop/cop/style/empty_lines_around_block_body.rb +7 -3
  203. data/lib/rubocop/cop/style/empty_lines_around_class_body.rb +6 -3
  204. data/lib/rubocop/cop/style/empty_lines_around_method_body.rb +4 -3
  205. data/lib/rubocop/cop/style/empty_lines_around_module_body.rb +4 -2
  206. data/lib/rubocop/cop/style/empty_literal.rb +20 -5
  207. data/lib/rubocop/cop/style/encoding.rb +8 -11
  208. data/lib/rubocop/cop/style/end_block.rb +3 -1
  209. data/lib/rubocop/cop/style/end_of_line.rb +2 -1
  210. data/lib/rubocop/cop/style/even_odd.rb +4 -3
  211. data/lib/rubocop/cop/style/extra_spacing.rb +110 -74
  212. data/lib/rubocop/cop/style/file_name.rb +103 -6
  213. data/lib/rubocop/cop/style/first_array_element_line_break.rb +3 -2
  214. data/lib/rubocop/cop/style/first_hash_element_line_break.rb +5 -6
  215. data/lib/rubocop/cop/style/first_method_argument_line_break.rb +14 -1
  216. data/lib/rubocop/cop/style/first_method_parameter_line_break.rb +2 -1
  217. data/lib/rubocop/cop/style/first_parameter_indentation.rb +6 -4
  218. data/lib/rubocop/cop/style/flip_flop.rb +2 -1
  219. data/lib/rubocop/cop/style/for.rb +2 -1
  220. data/lib/rubocop/cop/style/format_string.rb +1 -0
  221. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +89 -0
  222. data/lib/rubocop/cop/style/global_vars.rb +2 -1
  223. data/lib/rubocop/cop/style/guard_clause.rb +63 -11
  224. data/lib/rubocop/cop/style/hash_syntax.rb +10 -10
  225. data/lib/rubocop/cop/style/identical_conditional_branches.rb +93 -0
  226. data/lib/rubocop/cop/style/if_inside_else.rb +49 -0
  227. data/lib/rubocop/cop/style/if_unless_modifier.rb +6 -5
  228. data/lib/rubocop/cop/style/if_with_semicolon.rb +2 -1
  229. data/lib/rubocop/cop/style/indent_array.rb +89 -38
  230. data/lib/rubocop/cop/style/indent_assignment.rb +43 -0
  231. data/lib/rubocop/cop/style/indent_hash.rb +16 -77
  232. data/lib/rubocop/cop/style/indentation_consistency.rb +2 -1
  233. data/lib/rubocop/cop/style/indentation_width.rb +11 -11
  234. data/lib/rubocop/cop/style/infinite_loop.rb +5 -9
  235. data/lib/rubocop/cop/style/initial_indentation.rb +2 -1
  236. data/lib/rubocop/cop/style/inline_comment.rb +2 -1
  237. data/lib/rubocop/cop/style/lambda.rb +14 -11
  238. data/lib/rubocop/cop/style/lambda_call.rb +4 -4
  239. data/lib/rubocop/cop/style/leading_comment_space.rb +2 -1
  240. data/lib/rubocop/cop/style/line_end_concatenation.rb +3 -1
  241. data/lib/rubocop/cop/style/method_call_parentheses.rb +9 -1
  242. data/lib/rubocop/cop/style/method_called_on_do_end_block.rb +3 -2
  243. data/lib/rubocop/cop/style/method_def_parentheses.rb +4 -4
  244. data/lib/rubocop/cop/style/method_name.rb +1 -0
  245. data/lib/rubocop/cop/style/missing_else.rb +5 -3
  246. data/lib/rubocop/cop/style/module_function.rb +2 -1
  247. data/lib/rubocop/cop/style/multiline_array_brace_layout.rb +95 -0
  248. data/lib/rubocop/cop/style/multiline_assignment_layout.rb +91 -0
  249. data/lib/rubocop/cop/style/multiline_block_chain.rb +3 -2
  250. data/lib/rubocop/cop/style/multiline_block_layout.rb +11 -9
  251. data/lib/rubocop/cop/style/multiline_if_then.rb +1 -0
  252. data/lib/rubocop/cop/style/multiline_method_call_indentation.rb +137 -0
  253. data/lib/rubocop/cop/style/multiline_operation_indentation.rb +25 -135
  254. data/lib/rubocop/cop/style/multiline_ternary_operator.rb +2 -1
  255. data/lib/rubocop/cop/style/mutable_constant.rb +4 -5
  256. data/lib/rubocop/cop/style/negated_if.rb +3 -3
  257. data/lib/rubocop/cop/style/negated_while.rb +3 -3
  258. data/lib/rubocop/cop/style/nested_modifier.rb +6 -5
  259. data/lib/rubocop/cop/style/nested_parenthesized_calls.rb +48 -0
  260. data/lib/rubocop/cop/style/nested_ternary_operator.rb +2 -1
  261. data/lib/rubocop/cop/style/next.rb +79 -15
  262. data/lib/rubocop/cop/style/nil_comparison.rb +5 -5
  263. data/lib/rubocop/cop/style/non_nil_check.rb +5 -5
  264. data/lib/rubocop/cop/style/not.rb +5 -9
  265. data/lib/rubocop/cop/style/numeric_literals.rb +5 -4
  266. data/lib/rubocop/cop/style/one_line_conditional.rb +3 -2
  267. data/lib/rubocop/cop/style/op_method.rb +7 -4
  268. data/lib/rubocop/cop/style/option_hash.rb +13 -7
  269. data/lib/rubocop/cop/style/optional_arguments.rb +3 -2
  270. data/lib/rubocop/cop/style/parallel_assignment.rb +40 -16
  271. data/lib/rubocop/cop/style/parentheses_around_condition.rb +3 -16
  272. data/lib/rubocop/cop/style/percent_literal_delimiters.rb +3 -2
  273. data/lib/rubocop/cop/style/percent_q_literals.rb +3 -6
  274. data/lib/rubocop/cop/style/perl_backrefs.rb +4 -3
  275. data/lib/rubocop/cop/style/predicate_name.rb +1 -0
  276. data/lib/rubocop/cop/style/proc.rb +3 -2
  277. data/lib/rubocop/cop/style/raise_args.rb +2 -1
  278. data/lib/rubocop/cop/style/redundant_begin.rb +2 -1
  279. data/lib/rubocop/cop/style/redundant_exception.rb +5 -5
  280. data/lib/rubocop/cop/style/redundant_freeze.rb +5 -4
  281. data/lib/rubocop/cop/style/redundant_parentheses.rb +80 -0
  282. data/lib/rubocop/cop/style/redundant_return.rb +5 -4
  283. data/lib/rubocop/cop/style/redundant_self.rb +7 -8
  284. data/lib/rubocop/cop/style/regexp_literal.rb +9 -8
  285. data/lib/rubocop/cop/style/rescue_ensure_alignment.rb +3 -2
  286. data/lib/rubocop/cop/style/rescue_modifier.rb +11 -9
  287. data/lib/rubocop/cop/style/self_assignment.rb +4 -5
  288. data/lib/rubocop/cop/style/semicolon.rb +3 -2
  289. data/lib/rubocop/cop/style/send.rb +3 -1
  290. data/lib/rubocop/cop/style/signal_exception.rb +5 -3
  291. data/lib/rubocop/cop/style/single_line_block_params.rb +2 -1
  292. data/lib/rubocop/cop/style/single_line_methods.rb +7 -7
  293. data/lib/rubocop/cop/style/space_after_colon.rb +2 -1
  294. data/lib/rubocop/cop/style/space_after_comma.rb +1 -0
  295. data/lib/rubocop/cop/style/space_after_control_keyword.rb +5 -5
  296. data/lib/rubocop/cop/style/space_after_method_name.rb +3 -2
  297. data/lib/rubocop/cop/style/space_after_not.rb +4 -3
  298. data/lib/rubocop/cop/style/space_after_semicolon.rb +1 -0
  299. data/lib/rubocop/cop/style/space_around_block_parameters.rb +8 -7
  300. data/lib/rubocop/cop/style/space_around_equals_in_parameter_default.rb +1 -0
  301. data/lib/rubocop/cop/style/space_around_operators.rb +72 -32
  302. data/lib/rubocop/cop/style/space_before_block_braces.rb +2 -1
  303. data/lib/rubocop/cop/style/space_before_comma.rb +1 -0
  304. data/lib/rubocop/cop/style/space_before_comment.rb +2 -1
  305. data/lib/rubocop/cop/style/{single_space_before_first_arg.rb → space_before_first_arg.rb} +13 -4
  306. data/lib/rubocop/cop/style/space_before_modifier_keyword.rb +4 -3
  307. data/lib/rubocop/cop/style/space_before_semicolon.rb +1 -0
  308. data/lib/rubocop/cop/style/space_inside_block_braces.rb +3 -2
  309. data/lib/rubocop/cop/style/space_inside_brackets.rb +1 -0
  310. data/lib/rubocop/cop/style/space_inside_hash_literal_braces.rb +4 -1
  311. data/lib/rubocop/cop/style/space_inside_parens.rb +1 -0
  312. data/lib/rubocop/cop/style/space_inside_range_literal.rb +5 -4
  313. data/lib/rubocop/cop/style/space_inside_string_interpolation.rb +8 -17
  314. data/lib/rubocop/cop/style/special_global_vars.rb +97 -52
  315. data/lib/rubocop/cop/style/stabby_lambda_parentheses.rb +16 -9
  316. data/lib/rubocop/cop/style/string_literals.rb +41 -1
  317. data/lib/rubocop/cop/style/string_literals_in_interpolation.rb +2 -1
  318. data/lib/rubocop/cop/style/string_methods.rb +2 -1
  319. data/lib/rubocop/cop/style/struct_inheritance.rb +3 -2
  320. data/lib/rubocop/cop/style/symbol_array.rb +74 -7
  321. data/lib/rubocop/cop/style/symbol_literal.rb +4 -7
  322. data/lib/rubocop/cop/style/symbol_proc.rb +11 -7
  323. data/lib/rubocop/cop/style/tab.rb +25 -2
  324. data/lib/rubocop/cop/style/trailing_blank_lines.rb +1 -2
  325. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +45 -0
  326. data/lib/rubocop/cop/style/trailing_comma_in_literal.rb +56 -0
  327. data/lib/rubocop/cop/style/trailing_underscore_variable.rb +8 -7
  328. data/lib/rubocop/cop/style/trailing_whitespace.rb +2 -1
  329. data/lib/rubocop/cop/style/trivial_accessors.rb +18 -9
  330. data/lib/rubocop/cop/style/unless_else.rb +2 -1
  331. data/lib/rubocop/cop/style/unneeded_capital_w.rb +4 -3
  332. data/lib/rubocop/cop/style/unneeded_interpolation.rb +87 -0
  333. data/lib/rubocop/cop/style/unneeded_percent_q.rb +23 -7
  334. data/lib/rubocop/cop/style/variable_interpolation.rb +8 -6
  335. data/lib/rubocop/cop/style/variable_name.rb +1 -0
  336. data/lib/rubocop/cop/style/when_then.rb +2 -1
  337. data/lib/rubocop/cop/style/while_until_do.rb +3 -2
  338. data/lib/rubocop/cop/style/while_until_modifier.rb +3 -4
  339. data/lib/rubocop/cop/style/word_array.rb +74 -51
  340. data/lib/rubocop/cop/team.rb +21 -15
  341. data/lib/rubocop/cop/util.rb +102 -69
  342. data/lib/rubocop/cop/variable_force.rb +2 -1
  343. data/lib/rubocop/cop/variable_force/assignment.rb +2 -1
  344. data/lib/rubocop/cop/variable_force/locatable.rb +1 -0
  345. data/lib/rubocop/cop/variable_force/reference.rb +1 -0
  346. data/lib/rubocop/cop/variable_force/scope.rb +2 -1
  347. data/lib/rubocop/cop/variable_force/variable.rb +2 -1
  348. data/lib/rubocop/cop/variable_force/variable_table.rb +2 -1
  349. data/lib/rubocop/error.rb +12 -0
  350. data/lib/rubocop/formatter/base_formatter.rb +10 -1
  351. data/lib/rubocop/formatter/clang_style_formatter.rb +1 -0
  352. data/lib/rubocop/formatter/colorizable.rb +6 -1
  353. data/lib/rubocop/formatter/disabled_config_formatter.rb +29 -15
  354. data/lib/rubocop/formatter/disabled_lines_formatter.rb +3 -1
  355. data/lib/rubocop/formatter/emacs_style_formatter.rb +7 -3
  356. data/lib/rubocop/formatter/file_list_formatter.rb +1 -0
  357. data/lib/rubocop/formatter/formatter_set.rb +10 -19
  358. data/lib/rubocop/formatter/fuubar_style_formatter.rb +2 -1
  359. data/lib/rubocop/formatter/html_formatter.rb +15 -14
  360. data/lib/rubocop/formatter/json_formatter.rb +2 -1
  361. data/lib/rubocop/formatter/offense_count_formatter.rb +1 -0
  362. data/lib/rubocop/formatter/progress_formatter.rb +3 -3
  363. data/lib/rubocop/formatter/simple_text_formatter.rb +50 -17
  364. data/lib/rubocop/formatter/text_util.rb +8 -10
  365. data/lib/rubocop/formatter/worst_offenders_formatter.rb +61 -0
  366. data/lib/rubocop/name_similarity.rb +22 -0
  367. data/lib/rubocop/node_pattern.rb +126 -35
  368. data/lib/rubocop/options.rb +28 -19
  369. data/lib/rubocop/path_util.rb +1 -0
  370. data/lib/rubocop/processed_source.rb +41 -16
  371. data/lib/rubocop/rake_task.rb +6 -9
  372. data/lib/rubocop/remote_config.rb +1 -0
  373. data/lib/rubocop/result_cache.rb +60 -43
  374. data/lib/rubocop/runner.rb +48 -45
  375. data/lib/rubocop/string_util.rb +1 -0
  376. data/lib/rubocop/target_finder.rb +2 -1
  377. data/lib/rubocop/token.rb +1 -0
  378. data/lib/rubocop/version.rb +3 -2
  379. data/lib/rubocop/warning.rb +1 -0
  380. data/relnotes/v0.36.0.md +306 -0
  381. data/rubocop.gemspec +3 -9
  382. metadata +48 -92
  383. data/lib/rubocop/cop/lint/space_before_first_arg.rb +0 -44
  384. data/lib/rubocop/cop/rails/default_scope.rb +0 -33
  385. data/lib/rubocop/cop/style/trailing_comma.rb +0 -182
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module RuboCop
4
5
  module Cop
@@ -6,7 +7,7 @@ module RuboCop
6
7
  # This cop checks whether the source file has a utf-8 encoding
7
8
  # comment or not. This check makes sense only for code that
8
9
  # should support Ruby 1.9, since in 2.0+ utf-8 is the default
9
- # source file encoding. There are two style:
10
+ # source file encoding. There are two styles:
10
11
  #
11
12
  # when_needed - only enforce an encoding comment if there are non ASCII
12
13
  # characters, otherwise report an offense
@@ -14,9 +15,9 @@ module RuboCop
14
15
  class Encoding < Cop
15
16
  include ConfigurableEnforcedStyle
16
17
 
17
- MSG_MISSING = 'Missing utf-8 encoding comment.'
18
- MSG_UNNECESSARY = 'Unnecessary utf-8 encoding comment.'
19
- ENCODING_PATTERN = /#.*coding\s?[:=]\s?(?:UTF|utf)-8/.freeze
18
+ MSG_MISSING = 'Missing utf-8 encoding comment.'.freeze
19
+ MSG_UNNECESSARY = 'Unnecessary utf-8 encoding comment.'.freeze
20
+ ENCODING_PATTERN = /#.*coding\s?[:=]\s?(?:UTF|utf)-8/
20
21
  AUTO_CORRECT_ENCODING_COMMENT = 'AutoCorrectEncodingComment'.freeze
21
22
  SHEBANG = '#!'.freeze
22
23
 
@@ -29,18 +30,14 @@ module RuboCop
29
30
  return unless message
30
31
 
31
32
  range = source_range(processed_source.buffer, line_number + 1, 0)
32
- add_offense(processed_source.tokens.first, range, message)
33
+ add_offense(range, range, message)
33
34
  end
34
35
 
35
- def autocorrect(node)
36
+ def autocorrect(range)
36
37
  encoding = cop_config[AUTO_CORRECT_ENCODING_COMMENT]
37
38
  if encoding && encoding =~ ENCODING_PATTERN
38
39
  lambda do |corrector|
39
- if encoding_line_number(processed_source) == 0
40
- corrector.insert_before(node.pos, "#{encoding}\n")
41
- else
42
- corrector.insert_after(node.pos, "\n#{encoding}")
43
- end
40
+ corrector.insert_before(range, "#{encoding}\n")
44
41
  end
45
42
  else
46
43
  fail "#{encoding} does not match #{ENCODING_PATTERN}"
@@ -1,11 +1,13 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module RuboCop
4
5
  module Cop
5
6
  module Style
6
7
  # This cop checks for END blocks.
7
8
  class EndBlock < Cop
8
- MSG = 'Avoid the use of `END` blocks. Use `Kernel#at_exit` instead.'
9
+ MSG = 'Avoid the use of `END` blocks. ' \
10
+ 'Use `Kernel#at_exit` instead.'.freeze
9
11
 
10
12
  def on_postexe(node)
11
13
  add_offense(node, :keyword)
@@ -1,11 +1,12 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module RuboCop
4
5
  module Cop
5
6
  module Style
6
7
  # This cop checks for Windows-style line endings in the source code.
7
8
  class EndOfLine < Cop
8
- MSG = 'Carriage return character detected.'
9
+ MSG = 'Carriage return character detected.'.freeze
9
10
 
10
11
  def investigate(processed_source)
11
12
  last_token = processed_source.tokens.last
@@ -1,4 +1,5 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
2
3
 
3
4
  module RuboCop
4
5
  module Cop
@@ -14,7 +15,7 @@ module RuboCop
14
15
  # # good
15
16
  # if x.even?
16
17
  class EvenOdd < Cop
17
- MSG = 'Replace with `Fixnum#%s?`.'
18
+ MSG = 'Replace with `Fixnum#%s?`.'.freeze
18
19
 
19
20
  ZERO = s(:int, 0)
20
21
  ONE = s(:int, 1)
@@ -27,7 +28,7 @@ module RuboCop
27
28
 
28
29
  def autocorrect(node)
29
30
  correction = "#{base_number(node)}.#{offense_type(node)}?"
30
- ->(corrector) { corrector.replace(node.loc.expression, correction) }
31
+ ->(corrector) { corrector.replace(node.source_range, correction) }
31
32
  end
32
33
 
33
34
  private
@@ -35,7 +36,7 @@ module RuboCop
35
36
  def base_number(node)
36
37
  receiver, = *node
37
38
  node = expression(receiver)
38
- node.children[0].loc.expression.source
39
+ node.children[0].source
39
40
  end
40
41
 
41
42
  def offense_type(node)
@@ -1,4 +1,7 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require 'set'
2
5
 
3
6
  module RuboCop
4
7
  module Cop
@@ -18,35 +21,85 @@ module RuboCop
18
21
  # set_app("RuboCop")
19
22
  # website = "https://github.com/bbatsov/rubocop"
20
23
  class ExtraSpacing < Cop
21
- MSG = 'Unnecessary spacing detected.'
24
+ include PrecedingFollowingAlignment
25
+
26
+ MSG_UNNECESSARY = 'Unnecessary spacing detected.'.freeze
27
+ MSG_UNALIGNED_ASGN = '`=` is not aligned with the %s assignment.'.freeze
22
28
 
23
29
  def investigate(processed_source)
24
30
  ast = processed_source.ast
25
31
 
32
+ if force_equal_sign_alignment?
33
+ @asgn_tokens = processed_source.tokens.select { |t| equal_sign?(t) }
34
+ # Only attempt to align the first = on each line
35
+ @asgn_tokens = Set.new(@asgn_tokens.uniq { |t| t.pos.line })
36
+ @asgn_lines = @asgn_tokens.map { |t| t.pos.line }
37
+ # Don't attempt to correct the same = more than once
38
+ @corrected = Set.new
39
+ end
40
+
26
41
  processed_source.tokens.each_cons(2) do |t1, t2|
27
42
  next if t2.type == :tNL
28
- next if t1.pos.line != t2.pos.line
29
- next if t2.pos.begin_pos - 1 <= t1.pos.end_pos
30
- next if allow_for_alignment? && aligned_with_something?(t2)
31
- start_pos = t1.pos.end_pos
32
- next if ignored_ranges(ast).find { |r| r.include?(start_pos) }
33
-
34
- end_pos = t2.pos.begin_pos - 1
35
- range = Parser::Source::Range.new(processed_source.buffer,
36
- start_pos, end_pos)
37
- # Unary + doesn't appear as a token and needs special handling.
38
- next if unary_plus_non_offense?(range)
39
-
40
- add_offense(range, range, MSG)
43
+
44
+ if force_equal_sign_alignment? &&
45
+ @asgn_tokens.include?(t2) &&
46
+ (@asgn_lines.include?(t2.pos.line - 1) ||
47
+ @asgn_lines.include?(t2.pos.line + 1))
48
+ check_assignment(t2)
49
+ else
50
+ check_other(t1, t2, ast)
51
+ end
41
52
  end
42
53
  end
43
54
 
44
55
  def autocorrect(range)
45
- ->(corrector) { corrector.remove(range) }
56
+ lambda do |corrector|
57
+ if range.source.end_with?('=')
58
+ align_equal_sign(range, corrector)
59
+ else
60
+ corrector.remove(range)
61
+ end
62
+ end
46
63
  end
47
64
 
48
65
  private
49
66
 
67
+ def check_assignment(token)
68
+ # minus 2 is because pos.line is zero-based
69
+ line = processed_source.lines[token.pos.line - 2]
70
+ return if aligned_assignment?(token.pos, line)
71
+
72
+ preceding = @asgn_lines.include?(token.pos.line - 1)
73
+ align_with = preceding ? 'preceding' : 'following'
74
+ message = format(MSG_UNALIGNED_ASGN, align_with)
75
+ add_offense(token.pos, token.pos, message)
76
+ end
77
+
78
+ def check_other(t1, t2, ast)
79
+ return if t1.pos.line != t2.pos.line
80
+ return if t2.pos.begin_pos - 1 <= t1.pos.end_pos
81
+ return if allow_for_alignment? && aligned_tok?(t2)
82
+
83
+ start_pos = t1.pos.end_pos
84
+ return if ignored_ranges(ast).find { |r| r.include?(start_pos) }
85
+
86
+ end_pos = t2.pos.begin_pos - 1
87
+ range = Parser::Source::Range.new(processed_source.buffer,
88
+ start_pos, end_pos)
89
+ # Unary + doesn't appear as a token and needs special handling.
90
+ return if unary_plus_non_offense?(range)
91
+
92
+ add_offense(range, range, MSG_UNNECESSARY)
93
+ end
94
+
95
+ def aligned_tok?(token)
96
+ if token.type == :tCOMMENT
97
+ aligned_comments?(token)
98
+ else
99
+ aligned_with_something?(token.pos)
100
+ end
101
+ end
102
+
50
103
  def unary_plus_non_offense?(range)
51
104
  range.resize(range.size + 1).source =~ /^ ?\+$/
52
105
  end
@@ -57,35 +110,12 @@ module RuboCop
57
110
  def ignored_ranges(ast)
58
111
  return [] unless ast
59
112
 
60
- @ignored_ranges ||= begin
61
- ranges = []
62
- on_node(:pair, ast) do |pair|
63
- key, value = *pair
64
- r = key.loc.expression.end_pos...value.loc.expression.begin_pos
65
- ranges << r
66
- end
67
- ranges
113
+ @ignored_ranges ||= on_node(:pair, ast).map do |pair|
114
+ key, value = *pair
115
+ key.source_range.end_pos...value.source_range.begin_pos
68
116
  end
69
117
  end
70
118
 
71
- def allow_for_alignment?
72
- cop_config['AllowForAlignment']
73
- end
74
-
75
- def aligned_with_something?(token)
76
- return aligned_comments?(token) if token.type == :tCOMMENT
77
-
78
- pre = (token.pos.line - 2).downto(0)
79
- post = token.pos.line.upto(processed_source.lines.size - 1)
80
- return true if aligned_with?(pre, token) || aligned_with?(post, token)
81
-
82
- # If no aligned token was found, search for an aligned token on the
83
- # nearest line with the same indentation as the checked line.
84
- base_indentation = processed_source.lines[token.pos.line - 1] =~ /\S/
85
- aligned_with?(pre, token, base_indentation) ||
86
- aligned_with?(post, token, base_indentation)
87
- end
88
-
89
119
  def aligned_comments?(token)
90
120
  ix = processed_source.comments.index do |c|
91
121
  c.loc.expression.begin_pos == token.pos.begin_pos
@@ -106,47 +136,53 @@ module RuboCop
106
136
  processed_source.comments[ix].loc.column
107
137
  end
108
138
 
109
- # Returns true if the previous or next line, not counting empty or
110
- # comment lines, contains a token that's aligned with the given
111
- # token. If base_indentation is given, lines with different indentation
112
- # than the base indentation are also skipped.
113
- def aligned_with?(indices_to_check, token, base_indentation = nil)
114
- indices_to_check.each do |ix|
115
- next if comment_lines.include?(ix + 1)
116
- line = processed_source.lines[ix]
117
- next if line.strip.empty?
118
- if base_indentation
119
- indentation = line =~ /\S/
120
- next if indentation != base_indentation
121
- end
122
- return (aligned_words?(token, line) ||
123
- aligned_assignments?(token, line) ||
124
- aligned_same_character?(token, line))
125
- end
126
- false # No line to check was found.
139
+ def force_equal_sign_alignment?
140
+ cop_config['ForceEqualSignAlignment']
127
141
  end
128
142
 
129
- def comment_lines
130
- @comment_lines ||=
131
- begin
132
- whole_line_comments = processed_source.comments.select do |c|
133
- begins_its_line?(c.loc.expression)
134
- end
135
- whole_line_comments.map { |c| c.loc.line }
136
- end
143
+ def equal_sign?(token)
144
+ token.type == :tEQL || token.type == :tOP_ASGN
137
145
  end
138
146
 
139
- def aligned_words?(token, line)
140
- line[token.pos.column - 1, 2] =~ /\s\S/
147
+ def align_equal_sign(range, corrector)
148
+ lines = contiguous_assignment_lines(range)
149
+ tokens = @asgn_tokens.select { |t| lines.include?(t.pos.line) }
150
+
151
+ columns = tokens.map { |t| align_column(t) }
152
+ align_to = columns.max
153
+
154
+ tokens.each do |token|
155
+ next unless @corrected.add?(token)
156
+ diff = align_to - token.pos.last_column
157
+
158
+ if diff > 0
159
+ corrector.insert_before(token.pos, ' ' * diff)
160
+ elsif diff < 0
161
+ corrector.remove_preceding(token.pos, -diff)
162
+ end
163
+ end
141
164
  end
142
165
 
143
- def aligned_assignments?(token, line)
144
- token.type == :tOP_ASGN &&
145
- line[token.pos.column + token.text.length] == '='
166
+ def contiguous_assignment_lines(range)
167
+ result = [range.line]
168
+
169
+ range.line.downto(1) do |lineno|
170
+ @asgn_lines.include?(lineno) ? result << lineno : break
171
+ end
172
+ range.line.upto(processed_source.lines.size) do |lineno|
173
+ @asgn_lines.include?(lineno) ? result << lineno : break
174
+ end
175
+
176
+ result.sort!
146
177
  end
147
178
 
148
- def aligned_same_character?(token, line)
149
- line[token.pos.column] == token.text.to_s[0]
179
+ def align_column(asgn_token)
180
+ # if we removed unneeded spaces from the beginning of this =,
181
+ # what column would it end from?
182
+ line = processed_source.lines[asgn_token.pos.line - 1]
183
+ leading = line[0...asgn_token.pos.column]
184
+ spaces = leading.size - (leading =~ / *\Z/)
185
+ asgn_token.pos.last_column - spaces + 1
150
186
  end
151
187
  end
152
188
  end
@@ -1,11 +1,19 @@
1
1
  # encoding: utf-8
2
+ # frozen_string_literal: true
3
+
4
+ require 'pathname'
2
5
 
3
6
  module RuboCop
4
7
  module Cop
5
8
  module Style
6
- # This cop makes sure that Ruby source files have snake_case names.
9
+ # This cop makes sure that Ruby source files have snake_case
10
+ # names. Ruby scripts (i.e. source files with a shebang in the
11
+ # first line) are ignored.
7
12
  class FileName < Cop
8
- MSG = 'Use snake_case for source file names.'
13
+ MSG_SNAKE_CASE = 'Use snake_case for source file names.'.freeze
14
+ MSG_NO_DEFINITION = '%s should define a class or module ' \
15
+ 'called `%s`.'.freeze
16
+ MSG_REGEX = '`%s` should match `%s`.'.freeze
9
17
 
10
18
  SNAKE_CASE = /^[\da-z_]+$/
11
19
 
@@ -13,11 +21,25 @@ module RuboCop
13
21
  file_path = processed_source.buffer.name
14
22
  return if config.file_to_include?(file_path)
15
23
 
16
- basename = File.basename(file_path).sub(/\.[^\.]+$/, '')
17
- return if snake_case?(basename)
24
+ basename = File.basename(file_path)
25
+ if filename_good?(basename)
26
+ return unless expect_matching_definition?
27
+ return if find_class_or_module(processed_source.ast,
28
+ to_namespace(file_path))
29
+ range = source_range(processed_source.buffer, 1, 0)
30
+ msg = format(MSG_NO_DEFINITION,
31
+ basename,
32
+ to_namespace(file_path).join('::'))
33
+ else
34
+ first_line = processed_source.lines.first
35
+ return if cop_config['IgnoreExecutableScripts'] &&
36
+ shebang?(first_line)
37
+
38
+ range = source_range(processed_source.buffer, 1, 0)
39
+ msg = regex ? format(MSG_REGEX, basename, regex) : MSG_SNAKE_CASE
40
+ end
18
41
 
19
- range = source_range(processed_source.buffer, 1, 0)
20
- add_offense(nil, range)
42
+ add_offense(nil, range, msg)
21
43
  end
22
44
 
23
45
  private
@@ -25,6 +47,81 @@ module RuboCop
25
47
  def snake_case?(basename)
26
48
  basename.split('.').all? { |fragment| fragment =~ SNAKE_CASE }
27
49
  end
50
+
51
+ def shebang?(line)
52
+ line.start_with?('#!')
53
+ end
54
+
55
+ def expect_matching_definition?
56
+ cop_config['ExpectMatchingDefinition']
57
+ end
58
+
59
+ def regex
60
+ cop_config['Regex']
61
+ end
62
+
63
+ def filename_good?(basename)
64
+ basename = basename.sub(/\.[^\.]+$/, '')
65
+ regex ? basename =~ regex : snake_case?(basename)
66
+ end
67
+
68
+ def find_class_or_module(node, namespace)
69
+ return nil if node.nil?
70
+ name = namespace.pop
71
+
72
+ on_node([:class, :module, :casgn], node) do |child|
73
+ next unless (const = child.defined_module)
74
+
75
+ const_namespace, const_name = *const
76
+ next unless name == const_name
77
+
78
+ return node if namespace.empty?
79
+ return node if match_namespace(child, const_namespace, namespace)
80
+ end
81
+ nil
82
+ end
83
+
84
+ def match_namespace(node, namespace, expected)
85
+ expected = expected.dup
86
+
87
+ match_partial = lambda do |ns|
88
+ next if ns.nil?
89
+ while ns
90
+ return expected.empty? || expected == [:Object] if ns.cbase_type?
91
+ ns, name = *ns
92
+ name == expected.last ? expected.pop : (return false)
93
+ end
94
+ end
95
+
96
+ match_partial.call(namespace)
97
+
98
+ node.each_ancestor(:class, :module, :sclass, :casgn) do |ancestor|
99
+ return false if ancestor.sclass_type?
100
+ match_partial.call(ancestor.defined_module)
101
+ end
102
+
103
+ expected.empty? || expected == [:Object]
104
+ end
105
+
106
+ def to_namespace(path)
107
+ components = Pathname(path).each_filename.to_a
108
+ # To convert a pathname to a Ruby namespace, we need a starting point
109
+ # But RC can be run from any working directory, and can check any path
110
+ # We can't assume that the working directory, or any other, is the
111
+ # "starting point" to build a namespace
112
+ start = %w(lib spec test src)
113
+ if components.find { |c| start.include?(c) }
114
+ components = components.drop_while { |c| !start.include?(c) }
115
+ components.drop(1).map { |fn| to_module_name(fn) }
116
+ else
117
+ [to_module_name(components.last)]
118
+ end
119
+ end
120
+
121
+ def to_module_name(basename)
122
+ words = basename.sub(/\..*/, '').split('_')
123
+ words.map(&:capitalize).join.to_sym
124
+ end
28
125
  end
29
126
  end
30
127
  end