rubocop 0.79.0 → 0.80.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. checksums.yaml +4 -4
  2. data/LICENSE.txt +1 -1
  3. data/README.md +3 -3
  4. data/config/default.yml +33 -19
  5. data/lib/rubocop.rb +5 -1
  6. data/lib/rubocop/ast/node.rb +0 -12
  7. data/lib/rubocop/ast/node/regexp_node.rb +2 -4
  8. data/lib/rubocop/ast/traversal.rb +9 -0
  9. data/lib/rubocop/comment_config.rb +6 -1
  10. data/lib/rubocop/config_obsoletion.rb +2 -1
  11. data/lib/rubocop/cop/layout/empty_line_between_defs.rb +2 -1
  12. data/lib/rubocop/cop/layout/leading_comment_space.rb +33 -2
  13. data/lib/rubocop/cop/layout/line_length.rb +30 -1
  14. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +0 -4
  15. data/lib/rubocop/cop/layout/space_around_operators.rb +18 -0
  16. data/lib/rubocop/cop/layout/space_before_first_arg.rb +8 -0
  17. data/lib/rubocop/cop/layout/space_inside_hash_literal_braces.rb +2 -9
  18. data/lib/rubocop/cop/lint/debugger.rb +1 -1
  19. data/lib/rubocop/cop/lint/redundant_cop_enable_directive.rb +12 -7
  20. data/lib/rubocop/cop/lint/useless_setter_call.rb +4 -0
  21. data/lib/rubocop/cop/migration/department_name.rb +14 -1
  22. data/lib/rubocop/cop/mixin/configurable_enforced_style.rb +4 -0
  23. data/lib/rubocop/cop/mixin/frozen_string_literal.rb +6 -0
  24. data/lib/rubocop/cop/mixin/hash_transform_method.rb +172 -0
  25. data/lib/rubocop/cop/mixin/trailing_comma.rb +2 -9
  26. data/lib/rubocop/cop/naming/memoized_instance_variable_name.rb +1 -1
  27. data/lib/rubocop/cop/style/block_delimiters.rb +60 -1
  28. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +89 -11
  29. data/lib/rubocop/cop/style/hash_each_methods.rb +87 -0
  30. data/lib/rubocop/cop/style/hash_transform_keys.rb +79 -0
  31. data/lib/rubocop/cop/style/hash_transform_values.rb +79 -0
  32. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +5 -0
  33. data/lib/rubocop/cop/style/method_call_with_args_parentheses/omit_parentheses.rb +5 -4
  34. data/lib/rubocop/cop/style/or_assignment.rb +3 -2
  35. data/lib/rubocop/cop/style/symbol_array.rb +2 -2
  36. data/lib/rubocop/cop/style/ternary_parentheses.rb +1 -1
  37. data/lib/rubocop/cop/style/trailing_comma_in_arguments.rb +0 -22
  38. data/lib/rubocop/cop/variable_force.rb +4 -1
  39. data/lib/rubocop/formatter/formatter_set.rb +1 -0
  40. data/lib/rubocop/formatter/junit_formatter.rb +63 -0
  41. data/lib/rubocop/node_pattern.rb +96 -10
  42. data/lib/rubocop/version.rb +1 -1
  43. metadata +21 -3
  44. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +0 -209
@@ -11,8 +11,8 @@ module RuboCop
11
11
  #
12
12
  # Configuration option: MinSize
13
13
  # If set, arrays with fewer elements than this value will not trigger the
14
- # cop. For example, a `MinSize of `3` will not enforce a style on an array
15
- # of 2 or fewer elements.
14
+ # cop. For example, a `MinSize` of `3` will not enforce a style on an
15
+ # array of 2 or fewer elements.
16
16
  #
17
17
  # @example EnforcedStyle: percent (default)
18
18
  # # good
@@ -162,7 +162,7 @@ module RuboCop
162
162
  # `RedundantParentheses` cop is enabled, it will cause an infinite loop
163
163
  # as they compete to add and remove the parentheses respectively.
164
164
  def infinite_loop?
165
- require_parentheses? &&
165
+ (require_parentheses? || require_parentheses_when_complex?) &&
166
166
  redundant_parentheses_enabled?
167
167
  end
168
168
 
@@ -68,28 +68,6 @@ module RuboCop
68
68
  def self.autocorrect_incompatible_with
69
69
  [Layout::HeredocArgumentClosingParenthesis]
70
70
  end
71
-
72
- private
73
-
74
- def avoid_autocorrect?(args)
75
- args.last.hash_type? && args.last.braces? &&
76
- braces_will_be_removed?(args)
77
- end
78
-
79
- # Returns true if running with --auto-correct would remove the braces
80
- # of the last argument.
81
- def braces_will_be_removed?(args)
82
- brace_config = config.for_cop('Style/BracesAroundHashParameters')
83
- return false unless brace_config.fetch('Enabled')
84
- return false if brace_config['AutoCorrect'] == false
85
-
86
- brace_style = brace_config['EnforcedStyle']
87
- return true if brace_style == 'no_braces'
88
-
89
- return false unless brace_style == 'context_dependent'
90
-
91
- args.one? || !args[-2].hash_type?
92
- end
93
71
  end
94
72
  end
95
73
  end
@@ -190,7 +190,10 @@ module RuboCop
190
190
  end
191
191
 
192
192
  def regexp_captured_names(node)
193
- regexp_string = node.children[0].children[0] || ''
193
+ regexp_string = node.children.select(&:str_type?).map do |child|
194
+ child.children.first
195
+ end.join || ''
196
+
194
197
  regexp = Regexp.new(regexp_string)
195
198
 
196
199
  regexp.named_captures.keys
@@ -17,6 +17,7 @@ module RuboCop
17
17
  '[fu]ubar' => FuubarStyleFormatter,
18
18
  '[h]tml' => HTMLFormatter,
19
19
  '[j]son' => JSONFormatter,
20
+ '[ju]nit' => JUnitFormatter,
20
21
  '[o]ffenses' => OffenseCountFormatter,
21
22
  '[pa]cman' => PacmanFormatter,
22
23
  '[p]rogress' => ProgressFormatter,
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'rexml/document'
4
+
5
+ #
6
+ # This code is based on https://github.com/mikian/rubocop-junit-formatter.
7
+ #
8
+ # Copyright (c) 2015 Mikko Kokkonen
9
+ #
10
+ # MIT License
11
+ #
12
+ # https://github.com/mikian/rubocop-junit-formatter/blob/master/LICENSE.txt
13
+ #
14
+ module RuboCop
15
+ module Formatter
16
+ # This formatter formats the report data in JUnit format.
17
+ class JUnitFormatter < BaseFormatter
18
+ def initialize(output, options = {})
19
+ super
20
+
21
+ @document = REXML::Document.new.tap do |document|
22
+ document << REXML::XMLDecl.new
23
+ end
24
+ testsuites = REXML::Element.new('testsuites', @document)
25
+ testsuite = REXML::Element.new('testsuite', testsuites)
26
+ @testsuite = testsuite.tap do |element|
27
+ element.add_attributes('name' => 'rubocop')
28
+ end
29
+ end
30
+
31
+ def file_finished(file, offenses)
32
+ offenses.group_by(&:cop_name).each do |cop_name, grouped_offenses|
33
+ REXML::Element.new('testcase', @testsuite).tap do |testcase|
34
+ testcase.attributes['classname'] = file.gsub(
35
+ /\.rb\Z/, ''
36
+ ).gsub("#{Dir.pwd}/", '').tr('/', '.')
37
+ testcase.attributes['name'] = cop_name
38
+
39
+ add_failure_to(testcase, grouped_offenses, cop_name)
40
+ end
41
+ end
42
+ end
43
+
44
+ def finished(_inspected_files)
45
+ @document.write(output, 2)
46
+ end
47
+
48
+ private
49
+
50
+ def add_failure_to(testcase, offenses, cop_name)
51
+ # One failure per offense. Zero failures is a passing test case,
52
+ # for most surefire/nUnit parsers.
53
+ offenses.each do |offense|
54
+ REXML::Element.new('failure', testcase).tap do |failure|
55
+ failure.attributes['type'] = cop_name
56
+ failure.attributes['message'] = offense.message
57
+ failure.add_text(offense.location.to_s)
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -78,6 +78,8 @@ module RuboCop
78
78
  # # matching process starts
79
79
  # '^^send' # each ^ ascends one level in the AST
80
80
  # # so this matches against the grandparent node
81
+ # '`send' # descends any number of level in the AST
82
+ # # so this matches against any descendant node
81
83
  # '#method' # we call this a 'funcall'; it calls a method in the
82
84
  # # context where a pattern-matching method is defined
83
85
  # # if that returns a truthy value, the match succeeds
@@ -112,7 +114,7 @@ module RuboCop
112
114
  SYMBOL = %r{:(?:[\w+@*/?!<>=~|%^-]+|\[\]=?)}.freeze
113
115
  IDENTIFIER = /[a-zA-Z_][a-zA-Z0-9_-]*/.freeze
114
116
  META = Regexp.union(
115
- %w"( ) { } [ ] $< < > $... $ ! ^ ... + * ?"
117
+ %w"( ) { } [ ] $< < > $... $ ! ^ ` ... + * ?"
116
118
  ).freeze
117
119
  NUMBER = /-?\d+(?:\.\d+)?/.freeze
118
120
  STRING = /".+?"/.freeze
@@ -188,7 +190,7 @@ module RuboCop
188
190
 
189
191
  @temps = 0 # avoid name clashes between temp variables
190
192
  @captures = 0 # number of captures seen
191
- @unify = {} # named wildcard -> temp variable number
193
+ @unify = {} # named wildcard -> temp variable
192
194
  @params = 0 # highest % (param) number seen
193
195
  run(node_var)
194
196
  end
@@ -223,6 +225,7 @@ module RuboCop
223
225
  when '!' then compile_negation
224
226
  when '$' then compile_capture
225
227
  when '^' then compile_ascend
228
+ when '`' then compile_descend
226
229
  when WILDCARD then compile_wildcard(token[1..-1])
227
230
  when FUNCALL then compile_funcall(token)
228
231
  when LITERAL then compile_literal(token)
@@ -466,12 +469,67 @@ module RuboCop
466
469
  end
467
470
  end
468
471
 
472
+ def access_unify(name)
473
+ var = @unify[name]
474
+
475
+ if var == :forbidden_unification
476
+ fail_due_to "Wildcard #{name} was first seen in a subset of a" \
477
+ " union and can't be used outside that union"
478
+ end
479
+ var
480
+ end
481
+
482
+ def forbid_unification(*names)
483
+ names.each do |name|
484
+ @unify[name] = :forbidden_unification
485
+ end
486
+ end
487
+
488
+ # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
489
+ def unify_in_union(enum)
490
+ # We need to reset @unify before each branch is processed.
491
+ # Moreover we need to keep track of newly encountered wildcards.
492
+ # Var `new_unify_intersection` will hold those that are encountered
493
+ # in all branches; these are not a problem.
494
+ # Var `partial_unify` will hold those encountered in only a subset
495
+ # of the branches; these can't be used outside of the union.
496
+
497
+ return to_enum __method__, enum unless block_given?
498
+
499
+ new_unify_intersection = nil
500
+ partial_unify = []
501
+ unify_before = @unify.dup
502
+
503
+ result = enum.each do |e|
504
+ @unify = unify_before.dup if new_unify_intersection
505
+ yield e
506
+ new_unify = @unify.keys - unify_before.keys
507
+ if new_unify_intersection.nil?
508
+ # First iteration
509
+ new_unify_intersection = new_unify
510
+ else
511
+ union = new_unify_intersection | new_unify
512
+ new_unify_intersection &= new_unify
513
+ partial_unify |= union - new_unify_intersection
514
+ end
515
+ end
516
+
517
+ # At this point, all members of `new_unify_intersection` can be used
518
+ # for unification outside of the union, but partial_unify may not
519
+
520
+ forbid_unification(*partial_unify)
521
+
522
+ result
523
+ end
524
+ # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
525
+
469
526
  def compile_union
470
527
  # we need to ensure that each branch of the {} contains the same
471
528
  # number of captures (since only one branch of the {} can actually
472
529
  # match, the same variables are used to hold the captures for each
473
530
  # branch)
474
531
  enum = tokens_until('}', 'union')
532
+ enum = unify_in_union(enum)
475
533
  terms = insure_same_captures(enum, 'branch of {}')
476
534
  .map { compile_expr }
477
535
 
@@ -496,6 +554,19 @@ module RuboCop
496
554
  with_context("#{CUR_NODE} && #{compile_expr}", "#{CUR_NODE}.parent")
497
555
  end
498
556
 
557
+ def compile_descend
558
+ with_temp_variables do |descendant|
559
+ pattern = with_context(compile_expr, descendant,
560
+ use_temp_node: false)
561
+ [
562
+ "RuboCop::NodePattern.descend(#{CUR_ELEMENT}).",
563
+ "any? do |#{descendant}|",
564
+ " #{pattern}",
565
+ 'end'
566
+ ].join("\n")
567
+ end
568
+ end
569
+
499
570
  def compile_wildcard(name)
500
571
  if name.empty?
501
572
  'true'
@@ -503,12 +574,12 @@ module RuboCop
503
574
  # we have already seen a wildcard with this name before
504
575
  # so the value it matched the first time will already be stored
505
576
  # in a temp. check if this value matches the one stored in the temp
506
- "#{CUR_ELEMENT} == temp#{@unify[name]}"
577
+ "#{CUR_ELEMENT} == #{access_unify(name)}"
507
578
  else
508
- n = @unify[name] = next_temp_value
509
- # double assign to temp#{n} to avoid "assigned but unused variable"
510
- "(temp#{n} = #{CUR_ELEMENT}; " \
511
- "temp#{n} = temp#{n}; true)"
579
+ n = @unify[name] = "unify_#{name.gsub('-', '__')}"
580
+ # double assign to avoid "assigned but unused variable"
581
+ "(#{n} = #{CUR_ELEMENT}; " \
582
+ "#{n} = #{n}; true)"
512
583
  end
513
584
  end
514
585
 
@@ -560,9 +631,8 @@ module RuboCop
560
631
  def compile_arg(token)
561
632
  case token
562
633
  when WILDCARD then
563
- name = token[1..-1]
564
- number = @unify[name] || fail_due_to('invalid in arglist: ' + token)
565
- "temp#{number}"
634
+ name = token[1..-1]
635
+ access_unify(name) || fail_due_to('invalid in arglist: ' + token)
566
636
  when LITERAL then token
567
637
  when PARAM then get_param(token[1..-1])
568
638
  when CLOSING then fail_due_to("#{token} in invalid position")
@@ -796,6 +866,22 @@ module RuboCop
796
866
  def to_s
797
867
  "#<#{self.class} #{pattern}>"
798
868
  end
869
+
870
+ # Yields its argument and any descendants, depth-first.
871
+ #
872
+ def self.descend(element, &block)
873
+ return to_enum(__method__, element) unless block_given?
874
+
875
+ yield element
876
+
877
+ if element.is_a?(::RuboCop::AST::Node)
878
+ element.children.each do |child|
879
+ descend(child, &block)
880
+ end
881
+ end
882
+
883
+ nil
884
+ end
799
885
  end
800
886
  end
801
887
  # rubocop:enable Metrics/ClassLength, Metrics/CyclomaticComplexity
@@ -3,7 +3,7 @@
3
3
  module RuboCop
4
4
  # This module holds the RuboCop version information.
5
5
  module Version
6
- STRING = '0.79.0'
6
+ STRING = '0.80.0'
7
7
 
8
8
  MSG = '%<version>s (using Parser %<parser_version>s, running on ' \
9
9
  '%<ruby_engine>s %<ruby_version>s %<ruby_platform>s)'
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rubocop
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.79.0
4
+ version: 0.80.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Bozhidar Batsov
@@ -10,7 +10,7 @@ authors:
10
10
  autorequire:
11
11
  bindir: exe
12
12
  cert_chain: []
13
- date: 2020-01-06 00:00:00.000000000 Z
13
+ date: 2020-02-18 00:00:00.000000000 Z
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
16
16
  name: jaro_winkler
@@ -74,6 +74,20 @@ dependencies:
74
74
  - - "<"
75
75
  - !ruby/object:Gem::Version
76
76
  version: '4.0'
77
+ - !ruby/object:Gem::Dependency
78
+ name: rexml
79
+ requirement: !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ version: '0'
84
+ type: :runtime
85
+ prerelease: false
86
+ version_requirements: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ">="
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
77
91
  - !ruby/object:Gem::Dependency
78
92
  name: ruby-progressbar
79
93
  requirement: !ruby/object:Gem::Requirement
@@ -461,6 +475,7 @@ files:
461
475
  - lib/rubocop/cop/mixin/first_element_line_break.rb
462
476
  - lib/rubocop/cop/mixin/frozen_string_literal.rb
463
477
  - lib/rubocop/cop/mixin/hash_alignment_styles.rb
478
+ - lib/rubocop/cop/mixin/hash_transform_method.rb
464
479
  - lib/rubocop/cop/mixin/heredoc.rb
465
480
  - lib/rubocop/cop/mixin/ignored_methods.rb
466
481
  - lib/rubocop/cop/mixin/ignored_pattern.rb
@@ -536,7 +551,6 @@ files:
536
551
  - lib/rubocop/cop/style/begin_block.rb
537
552
  - lib/rubocop/cop/style/block_comments.rb
538
553
  - lib/rubocop/cop/style/block_delimiters.rb
539
- - lib/rubocop/cop/style/braces_around_hash_parameters.rb
540
554
  - lib/rubocop/cop/style/case_equality.rb
541
555
  - lib/rubocop/cop/style/character_literal.rb
542
556
  - lib/rubocop/cop/style/class_and_module_children.rb
@@ -579,7 +593,10 @@ files:
579
593
  - lib/rubocop/cop/style/frozen_string_literal_comment.rb
580
594
  - lib/rubocop/cop/style/global_vars.rb
581
595
  - lib/rubocop/cop/style/guard_clause.rb
596
+ - lib/rubocop/cop/style/hash_each_methods.rb
582
597
  - lib/rubocop/cop/style/hash_syntax.rb
598
+ - lib/rubocop/cop/style/hash_transform_keys.rb
599
+ - lib/rubocop/cop/style/hash_transform_values.rb
583
600
  - lib/rubocop/cop/style/identical_conditional_branches.rb
584
601
  - lib/rubocop/cop/style/if_inside_else.rb
585
602
  - lib/rubocop/cop/style/if_unless_modifier.rb
@@ -723,6 +740,7 @@ files:
723
740
  - lib/rubocop/formatter/fuubar_style_formatter.rb
724
741
  - lib/rubocop/formatter/html_formatter.rb
725
742
  - lib/rubocop/formatter/json_formatter.rb
743
+ - lib/rubocop/formatter/junit_formatter.rb
726
744
  - lib/rubocop/formatter/offense_count_formatter.rb
727
745
  - lib/rubocop/formatter/pacman_formatter.rb
728
746
  - lib/rubocop/formatter/progress_formatter.rb
@@ -1,209 +0,0 @@
1
- # frozen_string_literal: true
2
-
3
- module RuboCop
4
- module Cop
5
- module Style
6
- # This cop checks for braces around the last parameter in a method call
7
- # if the last parameter is a hash.
8
- # It supports `braces`, `no_braces` and `context_dependent` styles.
9
- #
10
- # @example EnforcedStyle: braces
11
- # # The `braces` style enforces braces around all method
12
- # # parameters that are hashes.
13
- #
14
- # # bad
15
- # some_method(x, y, a: 1, b: 2)
16
- #
17
- # # good
18
- # some_method(x, y, {a: 1, b: 2})
19
- #
20
- # @example EnforcedStyle: no_braces (default)
21
- # # The `no_braces` style checks that the last parameter doesn't
22
- # # have braces around it.
23
- #
24
- # # bad
25
- # some_method(x, y, {a: 1, b: 2})
26
- #
27
- # # good
28
- # some_method(x, y, a: 1, b: 2)
29
- #
30
- # @example EnforcedStyle: context_dependent
31
- # # The `context_dependent` style checks that the last parameter
32
- # # doesn't have braces around it, but requires braces if the
33
- # # second to last parameter is also a hash literal.
34
- #
35
- # # bad
36
- # some_method(x, y, {a: 1, b: 2})
37
- # some_method(x, y, {a: 1, b: 2}, a: 1, b: 2)
38
- #
39
- # # good
40
- # some_method(x, y, a: 1, b: 2)
41
- # some_method(x, y, {a: 1, b: 2}, {a: 1, b: 2})
42
- class BracesAroundHashParameters < Cop
43
- include ConfigurableEnforcedStyle
44
- include RangeHelp
45
-
46
- MSG = '%<type>s curly braces around a hash parameter.'
47
-
48
- def on_send(node)
49
- return if node.assignment_method? || node.operator_method?
50
-
51
- return unless node.arguments? && node.last_argument.hash_type? &&
52
- !node.last_argument.empty?
53
-
54
- check(node.last_argument, node.arguments)
55
- end
56
- alias on_csend on_send
57
-
58
- def autocorrect(send_node)
59
- hash_node = send_node.last_argument
60
-
61
- lambda do |corrector|
62
- if hash_node.braces?
63
- remove_braces_with_whitespace(corrector,
64
- hash_node,
65
- extra_space(hash_node))
66
- else
67
- add_braces(corrector, hash_node)
68
- end
69
- end
70
- end
71
-
72
- private
73
-
74
- def check(arg, args)
75
- case style
76
- when :braces
77
- check_braces(arg)
78
- when :no_braces
79
- check_no_braces(arg)
80
- when :context_dependent
81
- check_context_dependent(arg, args)
82
- end
83
- end
84
-
85
- def check_braces(arg)
86
- add_arg_offense(arg, :missing) unless arg.braces?
87
- end
88
-
89
- def check_no_braces(arg)
90
- return unless arg.braces? && !braces_needed_for_semantics?(arg)
91
-
92
- add_arg_offense(arg, :redundant)
93
- end
94
-
95
- def check_context_dependent(arg, args)
96
- braces_around_second_from_end = args.size > 1 && args[-2].hash_type?
97
-
98
- if arg.braces?
99
- unless braces_around_second_from_end ||
100
- braces_needed_for_semantics?(arg)
101
- add_arg_offense(arg, :redundant)
102
- end
103
- elsif braces_around_second_from_end
104
- add_arg_offense(arg, :missing)
105
- end
106
- end
107
-
108
- # Returns true if there's block inside the braces of the given hash arg
109
- # and that block uses do..end. The reason for wanting to check this is
110
- # that the do..end could bind to a different method invocation if the
111
- # hash braces were removed.
112
- def braces_needed_for_semantics?(arg)
113
- arg.each_pair do |_key, value|
114
- return true if value.block_type? && !value.braces?
115
- end
116
- false
117
- end
118
-
119
- def add_arg_offense(arg, type)
120
- add_offense(arg.parent, location: arg.source_range,
121
- message: format(MSG,
122
- type: type.to_s.capitalize))
123
- end
124
-
125
- def extra_space(hash_node)
126
- {
127
- newlines: extra_left_space?(hash_node) &&
128
- extra_right_space?(hash_node),
129
- left: extra_left_space?(hash_node),
130
- right: extra_right_space?(hash_node)
131
- }
132
- end
133
-
134
- def extra_left_space?(hash_node)
135
- @extra_left_space ||= begin
136
- top_line = hash_node.source_range.source_line
137
- top_line.delete(' ') == '{'
138
- end
139
- end
140
-
141
- def extra_right_space?(hash_node)
142
- @extra_right_space ||= begin
143
- bottom_line_number = hash_node.source_range.last_line
144
- bottom_line = processed_source.lines[bottom_line_number - 1]
145
- bottom_line.delete(' ') == '}'
146
- end
147
- end
148
-
149
- def remove_braces_with_whitespace(corrector, node, space)
150
- loc = node.loc
151
-
152
- if node.multiline?
153
- remove_braces_with_range(corrector,
154
- left_whole_line_range(loc.begin),
155
- right_whole_line_range(loc.end))
156
- else
157
- remove_braces_with_range(corrector,
158
- left_brace_and_space(loc.begin, space),
159
- right_brace_and_space(loc.end, space))
160
- end
161
- end
162
-
163
- def remove_braces_with_range(corrector, left_range, right_range)
164
- corrector.remove(left_range)
165
- corrector.remove(right_range)
166
- end
167
-
168
- def left_whole_line_range(loc_begin)
169
- if range_by_whole_lines(loc_begin).source.strip == '{'
170
- range_by_whole_lines(loc_begin, include_final_newline: true)
171
- else
172
- loc_begin
173
- end
174
- end
175
-
176
- def right_whole_line_range(loc_end)
177
- if range_by_whole_lines(loc_end).source.strip =~ /\A}\s*,?\z/
178
- range_by_whole_lines(loc_end, include_final_newline: true)
179
- else
180
- loc_end
181
- end
182
- end
183
-
184
- def left_brace_and_space(loc_begin, space)
185
- range_with_surrounding_space(range: loc_begin,
186
- side: :right,
187
- newlines: space[:newlines],
188
- whitespace: space[:left])
189
- end
190
-
191
- def right_brace_and_space(loc_end, space)
192
- brace_and_space =
193
- range_with_surrounding_space(
194
- range: loc_end,
195
- side: :left,
196
- newlines: space[:newlines],
197
- whitespace: space[:right]
198
- )
199
- range_with_surrounding_comma(brace_and_space, :left)
200
- end
201
-
202
- def add_braces(corrector, node)
203
- corrector.insert_before(node.source_range, '{')
204
- corrector.insert_after(node.source_range, '}')
205
- end
206
- end
207
- end
208
- end
209
- end