rubocop 0.60.0 → 0.61.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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +4 -4
  3. data/config/default.yml +573 -560
  4. data/lib/rubocop.rb +5 -0
  5. data/lib/rubocop/ast/node.rb +1 -1
  6. data/lib/rubocop/ast/sexp.rb +1 -1
  7. data/lib/rubocop/cli.rb +9 -14
  8. data/lib/rubocop/config.rb +4 -3
  9. data/lib/rubocop/config_loader.rb +25 -22
  10. data/lib/rubocop/config_loader_resolver.rb +3 -2
  11. data/lib/rubocop/cop/correctors/each_to_for_corrector.rb +53 -0
  12. data/lib/rubocop/cop/correctors/for_to_each_corrector.rb +73 -0
  13. data/lib/rubocop/cop/correctors/lambda_literal_to_method_corrector.rb +138 -0
  14. data/lib/rubocop/cop/correctors/multiline_literal_brace_corrector.rb +52 -46
  15. data/lib/rubocop/cop/generator.rb +13 -17
  16. data/lib/rubocop/cop/generator/configuration_injector.rb +60 -0
  17. data/lib/rubocop/cop/layout/align_hash.rb +3 -0
  18. data/lib/rubocop/cop/layout/comment_indentation.rb +32 -2
  19. data/lib/rubocop/cop/layout/indent_heredoc.rb +11 -5
  20. data/lib/rubocop/cop/layout/indentation_width.rb +7 -1
  21. data/lib/rubocop/cop/layout/multiline_array_brace_layout.rb +11 -11
  22. data/lib/rubocop/cop/layout/multiline_hash_brace_layout.rb +1 -1
  23. data/lib/rubocop/cop/layout/multiline_method_call_brace_layout.rb +1 -1
  24. data/lib/rubocop/cop/layout/multiline_method_definition_brace_layout.rb +1 -1
  25. data/lib/rubocop/cop/layout/rescue_ensure_alignment.rb +16 -3
  26. data/lib/rubocop/cop/layout/space_around_block_parameters.rb +30 -17
  27. data/lib/rubocop/cop/lint/format_parameter_mismatch.rb +11 -0
  28. data/lib/rubocop/cop/lint/shadowed_exception.rb +2 -5
  29. data/lib/rubocop/cop/lint/useless_access_modifier.rb +1 -1
  30. data/lib/rubocop/cop/metrics/line_length.rb +2 -2
  31. data/lib/rubocop/cop/mixin/trailing_comma.rb +11 -15
  32. data/lib/rubocop/cop/offense.rb +1 -1
  33. data/lib/rubocop/cop/performance/open_struct.rb +46 -0
  34. data/lib/rubocop/cop/performance/redundant_merge.rb +18 -4
  35. data/lib/rubocop/cop/rails/bulk_change_table.rb +2 -2
  36. data/lib/rubocop/cop/rails/dynamic_find_by.rb +15 -8
  37. data/lib/rubocop/cop/rails/http_positional_arguments.rb +17 -14
  38. data/lib/rubocop/cop/rails/http_status.rb +4 -4
  39. data/lib/rubocop/cop/rails/inverse_of.rb +2 -2
  40. data/lib/rubocop/cop/rails/reversible_migration.rb +1 -1
  41. data/lib/rubocop/cop/rails/skips_model_validations.rb +1 -1
  42. data/lib/rubocop/cop/rails/validation.rb +4 -4
  43. data/lib/rubocop/cop/security/open.rb +31 -11
  44. data/lib/rubocop/cop/style/begin_block.rb +6 -0
  45. data/lib/rubocop/cop/style/braces_around_hash_parameters.rb +1 -1
  46. data/lib/rubocop/cop/style/empty_case_condition.rb +13 -7
  47. data/lib/rubocop/cop/style/for.rb +9 -78
  48. data/lib/rubocop/cop/style/frozen_string_literal_comment.rb +6 -4
  49. data/lib/rubocop/cop/style/global_vars.rb +1 -1
  50. data/lib/rubocop/cop/style/infinite_loop.rb +42 -6
  51. data/lib/rubocop/cop/style/lambda.rb +4 -87
  52. data/lib/rubocop/cop/style/method_call_with_args_parentheses.rb +221 -16
  53. data/lib/rubocop/cop/style/raise_args.rb +1 -1
  54. data/lib/rubocop/cop/style/regexp_literal.rb +62 -10
  55. data/lib/rubocop/cop/style/unneeded_condition.rb +2 -2
  56. data/lib/rubocop/cop/variable_force.rb +4 -2
  57. data/lib/rubocop/cop/variable_force/variable.rb +2 -0
  58. data/lib/rubocop/magic_comment.rb +1 -1
  59. data/lib/rubocop/remote_config.rb +13 -4
  60. data/lib/rubocop/rspec/expect_offense.rb +1 -1
  61. data/lib/rubocop/runner.rb +15 -4
  62. data/lib/rubocop/version.rb +1 -1
  63. metadata +7 -2
@@ -76,6 +76,7 @@ require_relative 'rubocop/cop/corrector'
76
76
  require_relative 'rubocop/cop/force'
77
77
  require_relative 'rubocop/cop/severity'
78
78
  require_relative 'rubocop/cop/generator'
79
+ require_relative 'rubocop/cop/generator/configuration_injector'
79
80
  require_relative 'rubocop/cop/generator/require_file_injector'
80
81
 
81
82
  require_relative 'rubocop/cop/variable_force'
@@ -150,7 +151,10 @@ require_relative 'rubocop/cop/mixin/unused_argument'
150
151
 
151
152
  require_relative 'rubocop/cop/correctors/alignment_corrector'
152
153
  require_relative 'rubocop/cop/correctors/condition_corrector'
154
+ require_relative 'rubocop/cop/correctors/each_to_for_corrector'
153
155
  require_relative 'rubocop/cop/correctors/empty_line_corrector'
156
+ require_relative 'rubocop/cop/correctors/for_to_each_corrector'
157
+ require_relative 'rubocop/cop/correctors/lambda_literal_to_method_corrector'
154
158
  require_relative 'rubocop/cop/correctors/line_break_corrector'
155
159
  require_relative 'rubocop/cop/correctors/multiline_literal_brace_corrector'
156
160
  require_relative 'rubocop/cop/correctors/ordered_gem_corrector'
@@ -368,6 +372,7 @@ require_relative 'rubocop/cop/performance/fixed_size'
368
372
  require_relative 'rubocop/cop/performance/flat_map'
369
373
  require_relative 'rubocop/cop/performance/inefficient_hash_search'
370
374
  require_relative 'rubocop/cop/performance/lstrip_rstrip'
375
+ require_relative 'rubocop/cop/performance/open_struct'
371
376
  require_relative 'rubocop/cop/performance/range_include'
372
377
  require_relative 'rubocop/cop/performance/redundant_block_call'
373
378
  require_relative 'rubocop/cop/performance/redundant_match'
@@ -54,7 +54,7 @@ module RuboCop
54
54
  OPERATOR_KEYWORDS = %i[and or].freeze
55
55
  SPECIAL_KEYWORDS = %w[__FILE__ __LINE__ __ENCODING__].freeze
56
56
 
57
- # @see http://rubydoc.info/gems/ast/AST/Node:initialize
57
+ # @see https://www.rubydoc.info/gems/ast/AST/Node:initialize
58
58
  def initialize(type, children = [], properties = {})
59
59
  @mutable_attributes = {}
60
60
 
@@ -5,7 +5,7 @@ module RuboCop
5
5
  # This module provides a shorthand method to create a {Node} like
6
6
  # `Parser::AST::Sexp`.
7
7
  #
8
- # @see http://rubydoc.info/gems/ast/AST/Sexp
8
+ # @see https://www.rubydoc.info/gems/ast/AST/Sexp
9
9
  module Sexp
10
10
  # Creates a {Node} with type `type` and children `children`.
11
11
  def s(type, *children)
@@ -10,9 +10,10 @@ module RuboCop
10
10
  SKIPPED_PHASE_1 = 'Phase 1 of 2: run Metrics/LineLength cop (skipped ' \
11
11
  'because the default Metrics/LineLength:Max is ' \
12
12
  'overridden)'.freeze
13
- STATUS_SUCCESS = 0
14
- STATUS_OFFENSES = 1
15
- STATUS_ERROR = 2
13
+ STATUS_SUCCESS = 0
14
+ STATUS_OFFENSES = 1
15
+ STATUS_ERROR = 2
16
+ STATUS_INTERRUPTED = 128 + Signal.list['INT']
16
17
 
17
18
  class Finished < RuntimeError; end
18
19
 
@@ -58,15 +59,6 @@ module RuboCop
58
59
  end
59
60
  # rubocop:enable Metrics/MethodLength, Metrics/AbcSize
60
61
 
61
- def trap_interrupt(runner)
62
- Signal.trap('INT') do
63
- exit!(1) if runner.aborting?
64
- runner.abort
65
- warn
66
- warn 'Exiting... Interrupt again to exit immediately.'
67
- end
68
- end
69
-
70
62
  private
71
63
 
72
64
  def execute_runners(paths)
@@ -118,6 +110,7 @@ module RuboCop
118
110
 
119
111
  def reset_config_and_auto_gen_file
120
112
  @config_store = ConfigStore.new
113
+ @config_store.options_config = @options[:config] if @options[:config]
121
114
  File.open(ConfigLoader::AUTO_GENERATED_FILE, 'w') {}
122
115
  ConfigLoader.add_inheritance_from_auto_generated_file
123
116
  end
@@ -135,6 +128,7 @@ module RuboCop
135
128
  ConfigLoader.debug = @options[:debug]
136
129
  ConfigLoader.auto_gen_config = @options[:auto_gen_config]
137
130
  ConfigLoader.ignore_parent_exclusion = @options[:ignore_parent_exclusion]
131
+ ConfigLoader.options_config = @options[:config]
138
132
 
139
133
  @config_store.options_config = @options[:config] if @options[:config]
140
134
  @config_store.force_default_config! if @options[:force_default_config]
@@ -153,7 +147,6 @@ module RuboCop
153
147
  def execute_runner(paths)
154
148
  runner = Runner.new(@options, @config_store)
155
149
 
156
- trap_interrupt(runner)
157
150
  all_passed = runner.run(paths)
158
151
  display_warning_summary(runner.warnings)
159
152
  display_error_summary(runner.errors)
@@ -161,7 +154,9 @@ module RuboCop
161
154
 
162
155
  all_pass_or_excluded = all_passed || @options[:auto_gen_config]
163
156
 
164
- if all_pass_or_excluded && !runner.aborting? && runner.errors.empty?
157
+ if runner.aborting?
158
+ STATUS_INTERRUPTED
159
+ elsif all_pass_or_excluded && runner.errors.empty?
165
160
  STATUS_SUCCESS
166
161
  else
167
162
  STATUS_OFFENSES
@@ -14,7 +14,7 @@ module RuboCop
14
14
  include PathUtil
15
15
  include FileFinder
16
16
 
17
- COMMON_PARAMS = %w[Exclude Include Severity
17
+ COMMON_PARAMS = %w[Exclude Include Severity inherit_mode
18
18
  AutoCorrect StyleGuide Details].freeze
19
19
  # 2.2 is the oldest officially supported Ruby version.
20
20
  DEFAULT_RUBY_VERSION = 2.2
@@ -440,11 +440,11 @@ module RuboCop
440
440
  end
441
441
 
442
442
  def target_ruby_version
443
- @target_ruby_version ||=
443
+ @target_ruby_version ||= begin
444
444
  if for_all_cops['TargetRubyVersion']
445
445
  @target_ruby_version_source = :rubocop_yml
446
446
 
447
- for_all_cops['TargetRubyVersion']
447
+ for_all_cops['TargetRubyVersion'].to_f
448
448
  elsif target_ruby_version_from_version_file
449
449
  @target_ruby_version_source = :ruby_version_file
450
450
 
@@ -456,6 +456,7 @@ module RuboCop
456
456
  else
457
457
  DEFAULT_RUBY_VERSION
458
458
  end
459
+ end
459
460
  end
460
461
 
461
462
  def target_rails_version
@@ -22,7 +22,8 @@ module RuboCop
22
22
  class << self
23
23
  include FileFinder
24
24
 
25
- attr_accessor :debug, :auto_gen_config, :ignore_parent_exclusion
25
+ attr_accessor :debug, :auto_gen_config, :ignore_parent_exclusion,
26
+ :options_config
26
27
  attr_writer :default_configuration
27
28
 
28
29
  alias debug? debug
@@ -30,7 +31,7 @@ module RuboCop
30
31
  alias ignore_parent_exclusion? ignore_parent_exclusion
31
32
 
32
33
  def clear_options
33
- @debug = @auto_gen_config = nil
34
+ @debug = @auto_gen_config = @options_config = nil
34
35
  FileFinder.root_level = nil
35
36
  end
36
37
 
@@ -43,7 +44,6 @@ module RuboCop
43
44
  resolver.resolve_requires(path, hash)
44
45
 
45
46
  add_missing_namespaces(path, hash)
46
- target_ruby_version_to_f!(hash)
47
47
 
48
48
  resolver.resolve_inheritance_from_gems(hash, hash.delete('inherit_gem'))
49
49
  resolver.resolve_inheritance(path, hash, file, debug?)
@@ -117,36 +117,38 @@ module RuboCop
117
117
  resolver.merge_with_default(config, config_file)
118
118
  end
119
119
 
120
- def target_ruby_version_to_f!(hash)
121
- version = 'TargetRubyVersion'
122
- return unless hash['AllCops'] && hash['AllCops'][version]
123
-
124
- hash['AllCops'][version] = hash['AllCops'][version].to_f
125
- end
126
-
127
120
  def add_inheritance_from_auto_generated_file
128
121
  file_string = " #{AUTO_GENERATED_FILE}"
129
122
 
130
- if File.exist?(DOTFILE)
131
- files = Array(load_yaml_configuration(DOTFILE)['inherit_from'])
123
+ config_file = options_config || DOTFILE
124
+
125
+ if File.exist?(config_file)
126
+ files = Array(load_yaml_configuration(config_file)['inherit_from'])
127
+
132
128
  return if files.include?(AUTO_GENERATED_FILE)
133
129
 
134
130
  files.unshift(AUTO_GENERATED_FILE)
135
131
  file_string = "\n - " + files.join("\n - ") if files.size > 1
136
- rubocop_yml_contents = IO.read(DOTFILE, encoding: Encoding::UTF_8)
137
- .sub(/^inherit_from: *[.\w]+/, '')
138
- .sub(/^inherit_from: *(\n *- *[.\w]+)+/, '')
132
+ rubocop_yml_contents = existing_configuration(config_file)
139
133
  end
140
- write_dotfile(file_string, rubocop_yml_contents)
134
+
135
+ write_config_file(config_file, file_string, rubocop_yml_contents)
136
+
141
137
  puts "Added inheritance from `#{AUTO_GENERATED_FILE}` in `#{DOTFILE}`."
142
138
  end
143
139
 
144
140
  private
145
141
 
146
- def write_dotfile(file_string, rubocop_yml_contents)
147
- File.open(DOTFILE, 'w') do |f|
142
+ def existing_configuration(config_file)
143
+ IO.read(config_file, encoding: Encoding::UTF_8)
144
+ .sub(%r{^inherit_from: *[.\/\w]+}, '')
145
+ .sub(%r{^inherit_from: *(\n *- *[.\/\w]+)+}, '')
146
+ end
147
+
148
+ def write_config_file(file_name, file_string, rubocop_yml_contents)
149
+ File.open(file_name, 'w') do |f|
148
150
  f.write "inherit_from:#{file_string}\n"
149
- f.write "\n#{rubocop_yml_contents}" if rubocop_yml_contents
151
+ f.write "\n#{rubocop_yml_contents}" if rubocop_yml_contents =~ /\S/
150
152
  end
151
153
  end
152
154
 
@@ -181,11 +183,12 @@ module RuboCop
181
183
  if defined?(SafeYAML) && SafeYAML.respond_to?(:load)
182
184
  SafeYAML.load(yaml_code, filename,
183
185
  whitelisted_tags: %w[!ruby/regexp])
184
- elsif RUBY_VERSION >= '2.6'
186
+ # Ruby 2.6+
187
+ elsif Gem::Version.new(Psych::VERSION) >= Gem::Version.new('3.1.0.pre1')
185
188
  YAML.safe_load(
186
189
  yaml_code,
187
- whitelist_classes: [Regexp, Symbol],
188
- whitelist_symbols: [],
190
+ permitted_classes: [Regexp, Symbol],
191
+ permitted_symbols: [],
189
192
  aliases: false,
190
193
  filename: filename
191
194
  )
@@ -76,11 +76,11 @@ module RuboCop
76
76
  config_file)
77
77
  end
78
78
 
79
- # Returns a new hash where the parameters of the given config hash have
80
- # been replaced by parameters returned by the given block.
81
79
  # Return a recursive merge of two hashes. That is, a normal hash merge,
82
80
  # with the addition that any value that is a hash, and occurs in both
83
81
  # arguments, will also be merged. And so on.
82
+ #
83
+ # rubocop:disable Metrics/AbcSize
84
84
  def merge(base_hash, derived_hash, **opts)
85
85
  result = base_hash.merge(derived_hash)
86
86
  keys_appearing_in_both = base_hash.keys & derived_hash.keys
@@ -95,6 +95,7 @@ module RuboCop
95
95
  end
96
96
  result
97
97
  end
98
+ # rubocop:enable Metrics/AbcSize
98
99
 
99
100
  private
100
101
 
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This class auto-corrects `#each` enumeration to `for` iteration.
6
+ class EachToForCorrector
7
+ extend NodePattern::Macros
8
+
9
+ CORRECTION_WITH_ARGUMENTS =
10
+ 'for %<variables>s in %<collection>s do'.freeze
11
+ CORRECTION_WITHOUT_ARGUMENTS = 'for _ in %<enumerable>s do'.freeze
12
+
13
+ def initialize(block_node)
14
+ @block_node = block_node
15
+ @collection_node = block_node.send_node.receiver
16
+ @argument_node = block_node.arguments
17
+ end
18
+
19
+ def call(corrector)
20
+ corrector.replace(offending_range, correction)
21
+ end
22
+
23
+ private
24
+
25
+ attr_reader :block_node, :collection_node, :argument_node
26
+
27
+ def correction
28
+ if block_node.arguments?
29
+ format(CORRECTION_WITH_ARGUMENTS,
30
+ collection: collection_node.source,
31
+ variables: argument_node.children.first.source)
32
+ else
33
+ format(CORRECTION_WITHOUT_ARGUMENTS,
34
+ enumerable: collection_node.source)
35
+ end
36
+ end
37
+
38
+ def offending_range
39
+ if block_node.arguments?
40
+ replacement_range(argument_node.loc.expression.end_pos)
41
+ else
42
+ replacement_range(block_node.loc.begin.end_pos)
43
+ end
44
+ end
45
+
46
+ def replacement_range(end_pos)
47
+ Parser::Source::Range.new(block_node.loc.expression.source_buffer,
48
+ block_node.loc.expression.begin_pos,
49
+ end_pos)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This class auto-corrects `for` iteration to `#each` enumeration.
6
+ class ForToEachCorrector
7
+ extend NodePattern::Macros
8
+
9
+ CORRECTION = '%<collection>s.each do |%<argument>s|'.freeze
10
+
11
+ def initialize(for_node)
12
+ @for_node = for_node
13
+ @variable_node = for_node.variable
14
+ @collection_node = for_node.collection
15
+ end
16
+
17
+ def call(corrector)
18
+ corrector.replace(offending_range, correction)
19
+ end
20
+
21
+ private
22
+
23
+ attr_reader :for_node, :variable_node, :collection_node
24
+
25
+ def correction
26
+ format(CORRECTION, collection: collection_source,
27
+ argument: variable_node.source)
28
+ end
29
+
30
+ def collection_source
31
+ if requires_parentheses?
32
+ "(#{collection_node.source})"
33
+ else
34
+ collection_node.source
35
+ end
36
+ end
37
+
38
+ def requires_parentheses?
39
+ collection_node.irange_type? || collection_node.erange_type?
40
+ end
41
+
42
+ def end_position
43
+ if for_node.do?
44
+ keyword_begin.end_pos
45
+ else
46
+ collection_end.end_pos
47
+ end
48
+ end
49
+
50
+ def keyword_begin
51
+ for_node.loc.begin
52
+ end
53
+
54
+ def collection_end
55
+ if collection_node.begin_type?
56
+ collection_node.loc.end
57
+ else
58
+ collection_node.loc.expression
59
+ end
60
+ end
61
+
62
+ def offending_range
63
+ replacement_range(end_position)
64
+ end
65
+
66
+ def replacement_range(end_pos)
67
+ Parser::Source::Range.new(for_node.loc.expression.source_buffer,
68
+ for_node.loc.expression.begin_pos,
69
+ end_pos)
70
+ end
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,138 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RuboCop
4
+ module Cop
5
+ # This class auto-corrects lambda literal to method notation.
6
+ class LambdaLiteralToMethodCorrector
7
+ def initialize(block_node)
8
+ @block_node = block_node
9
+ @method = block_node.send_node
10
+ @arguments = block_node.arguments
11
+ end
12
+
13
+ def call(corrector)
14
+ # Check for unparenthesized args' preceding and trailing whitespaces.
15
+ remove_unparenthesized_whitespace(corrector)
16
+
17
+ # Avoid correcting to `lambdado` by inserting whitespace
18
+ # if none exists before or after the lambda arguments.
19
+ insert_separating_space(corrector)
20
+
21
+ replace_selector(corrector)
22
+ remove_arguments(corrector)
23
+
24
+ replace_delimiters(corrector)
25
+
26
+ insert_arguments(corrector)
27
+ end
28
+
29
+ private
30
+
31
+ attr_reader :block_node, :method, :arguments
32
+
33
+ def remove_unparenthesized_whitespace(corrector)
34
+ return unless !arguments.empty? && !arguments.parenthesized_call?
35
+
36
+ remove_leading_whitespace(corrector)
37
+ remove_trailing_whitespace(corrector)
38
+ end
39
+
40
+ def insert_separating_space(corrector)
41
+ return unless needs_separating_space?
42
+
43
+ corrector.insert_before(block_begin, ' ')
44
+ end
45
+
46
+ def replace_selector(corrector)
47
+ corrector.replace(method.source_range, 'lambda')
48
+ end
49
+
50
+ def remove_arguments(corrector)
51
+ return if arguments.empty_and_without_delimiters?
52
+
53
+ corrector.remove(arguments.source_range)
54
+ end
55
+
56
+ def insert_arguments(corrector)
57
+ return if arguments.empty?
58
+
59
+ arg_str = " |#{lambda_arg_string}|"
60
+ corrector.insert_after(block_node.loc.begin, arg_str)
61
+ end
62
+
63
+ def remove_leading_whitespace(corrector)
64
+ corrector.remove_preceding(
65
+ arguments.source_range,
66
+ arguments.source_range.begin_pos -
67
+ block_node.send_node.source_range.end_pos
68
+ )
69
+ end
70
+
71
+ def remove_trailing_whitespace(corrector)
72
+ corrector.remove_preceding(
73
+ block_begin,
74
+ block_begin.begin_pos - arguments.source_range.end_pos - 1
75
+ )
76
+ end
77
+
78
+ def replace_delimiters(corrector)
79
+ return if block_node.braces? || !arg_to_unparenthesized_call?
80
+
81
+ corrector.insert_after(block_begin, ' ') unless separating_space?
82
+
83
+ corrector.replace(block_begin, '{')
84
+ corrector.replace(block_end, '}')
85
+ end
86
+
87
+ def lambda_arg_string
88
+ arguments.children.map(&:source).join(', ')
89
+ end
90
+
91
+ def needs_separating_space?
92
+ block_begin.begin_pos == arguments_end_pos &&
93
+ selector_end.end_pos == arguments_begin_pos ||
94
+ block_begin.begin_pos == selector_end.end_pos
95
+ end
96
+
97
+ def arguments_end_pos
98
+ arguments.loc.end && arguments.loc.end.end_pos
99
+ end
100
+
101
+ def arguments_begin_pos
102
+ arguments.loc.begin && arguments.loc.begin.begin_pos
103
+ end
104
+
105
+ def block_end
106
+ block_node.loc.end
107
+ end
108
+
109
+ def block_begin
110
+ block_node.loc.begin
111
+ end
112
+
113
+ def selector_end
114
+ method.loc.selector.end
115
+ end
116
+
117
+ def arg_to_unparenthesized_call?
118
+ current_node = block_node
119
+
120
+ parent = current_node.parent
121
+
122
+ if parent && parent.pair_type?
123
+ current_node = parent.parent
124
+ parent = current_node.parent
125
+ end
126
+
127
+ return false unless parent && parent.send_type?
128
+ return false if parent.parenthesized_call?
129
+
130
+ current_node.sibling_index > 1
131
+ end
132
+
133
+ def separating_space?
134
+ block_begin.source_buffer.source[block_begin.begin_pos + 2].match(/\s/)
135
+ end
136
+ end
137
+ end
138
+ end