leftovers 0.2.0 → 0.4.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 (145) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +49 -0
  3. data/README.md +28 -45
  4. data/docs/Configuration.md +598 -0
  5. data/exe/leftovers +2 -2
  6. data/leftovers.gemspec +13 -7
  7. data/lib/config/attr_encrypted.yml +3 -4
  8. data/lib/config/audited.yml +9 -0
  9. data/lib/config/datagrid.yml +1 -1
  10. data/lib/config/flipper.yml +1 -3
  11. data/lib/config/graphql.yml +15 -13
  12. data/lib/config/okcomputer.yml +1 -3
  13. data/lib/config/parser.yml +89 -91
  14. data/lib/config/rails.yml +162 -92
  15. data/lib/config/redcarpet.yml +35 -38
  16. data/lib/config/rollbar.yml +1 -3
  17. data/lib/config/rspec.yml +18 -10
  18. data/lib/config/ruby.yml +42 -39
  19. data/lib/config/selenium-webdriver.yml +19 -0
  20. data/lib/config/sidekiq.yml +9 -0
  21. data/lib/config/will_paginate.yml +12 -14
  22. data/lib/leftovers.rb +60 -43
  23. data/lib/leftovers/ast.rb +8 -0
  24. data/lib/leftovers/ast/builder.rb +6 -3
  25. data/lib/leftovers/ast/node.rb +63 -104
  26. data/lib/leftovers/backports.rb +24 -40
  27. data/lib/leftovers/cli.rb +17 -14
  28. data/lib/leftovers/collector.rb +7 -11
  29. data/lib/leftovers/config.rb +34 -13
  30. data/lib/leftovers/config_validator.rb +60 -0
  31. data/lib/leftovers/config_validator/error_processor.rb +196 -0
  32. data/lib/leftovers/config_validator/schema_hash.rb +495 -0
  33. data/lib/leftovers/definition.rb +14 -39
  34. data/lib/leftovers/definition_set.rb +7 -17
  35. data/lib/leftovers/dynamic_processors.rb +11 -0
  36. data/lib/leftovers/dynamic_processors/call.rb +25 -0
  37. data/lib/leftovers/dynamic_processors/call_definition.rb +31 -0
  38. data/lib/leftovers/dynamic_processors/definition.rb +26 -0
  39. data/lib/leftovers/dynamic_processors/each.rb +19 -0
  40. data/lib/leftovers/dynamic_processors/null.rb +9 -0
  41. data/lib/leftovers/erb.rb +2 -2
  42. data/lib/leftovers/file.rb +3 -5
  43. data/lib/leftovers/file_collector.rb +72 -85
  44. data/lib/leftovers/file_list.rb +9 -12
  45. data/lib/leftovers/haml.rb +9 -12
  46. data/lib/leftovers/matcher_builders.rb +24 -0
  47. data/lib/leftovers/matcher_builders/and.rb +19 -0
  48. data/lib/leftovers/matcher_builders/and_not.rb +14 -0
  49. data/lib/leftovers/matcher_builders/argument_node_value.rb +21 -0
  50. data/lib/leftovers/matcher_builders/name.rb +29 -0
  51. data/lib/leftovers/matcher_builders/node.rb +40 -0
  52. data/lib/leftovers/matcher_builders/node_has_argument.rb +71 -0
  53. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +22 -0
  54. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +24 -0
  55. data/lib/leftovers/matcher_builders/node_name.rb +15 -0
  56. data/lib/leftovers/matcher_builders/node_pair_name.rb +18 -0
  57. data/lib/leftovers/matcher_builders/node_pair_value.rb +16 -0
  58. data/lib/leftovers/matcher_builders/node_path.rb +14 -0
  59. data/lib/leftovers/matcher_builders/node_type.rb +28 -0
  60. data/lib/leftovers/matcher_builders/or.rb +73 -0
  61. data/lib/leftovers/matcher_builders/path.rb +15 -0
  62. data/lib/leftovers/matcher_builders/string.rb +11 -0
  63. data/lib/leftovers/matcher_builders/string_pattern.rb +19 -0
  64. data/lib/leftovers/matcher_builders/unless.rb +13 -0
  65. data/lib/leftovers/matchers.rb +26 -0
  66. data/lib/leftovers/matchers/all.rb +25 -0
  67. data/lib/leftovers/matchers/and.rb +24 -0
  68. data/lib/leftovers/matchers/any.rb +27 -0
  69. data/lib/leftovers/matchers/node_has_any_keyword_argument.rb +28 -0
  70. data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +25 -0
  71. data/lib/leftovers/matchers/node_has_positional_argument.rb +23 -0
  72. data/lib/leftovers/matchers/node_has_positional_argument_with_value.rb +25 -0
  73. data/lib/leftovers/matchers/node_name.rb +23 -0
  74. data/lib/leftovers/matchers/node_pair_value.rb +23 -0
  75. data/lib/leftovers/matchers/node_path.rb +23 -0
  76. data/lib/leftovers/matchers/node_scalar_value.rb +25 -0
  77. data/lib/leftovers/matchers/node_type.rb +23 -0
  78. data/lib/leftovers/matchers/not.rb +23 -0
  79. data/lib/leftovers/matchers/or.rb +26 -0
  80. data/lib/leftovers/merged_config.rb +20 -14
  81. data/lib/leftovers/parser.rb +37 -0
  82. data/lib/leftovers/processor_builders.rb +22 -0
  83. data/lib/leftovers/processor_builders/action.rb +63 -0
  84. data/lib/leftovers/processor_builders/add_prefix.rb +20 -0
  85. data/lib/leftovers/processor_builders/add_suffix.rb +20 -0
  86. data/lib/leftovers/processor_builders/argument.rb +25 -0
  87. data/lib/leftovers/processor_builders/dynamic.rb +27 -0
  88. data/lib/leftovers/processor_builders/each.rb +36 -0
  89. data/lib/leftovers/processor_builders/each_action.rb +51 -0
  90. data/lib/leftovers/processor_builders/each_dynamic.rb +54 -0
  91. data/lib/leftovers/processor_builders/each_for_definition_set.rb +36 -0
  92. data/lib/leftovers/processor_builders/itself.rb +13 -0
  93. data/lib/leftovers/processor_builders/keyword.rb +24 -0
  94. data/lib/leftovers/processor_builders/keyword_argument.rb +14 -0
  95. data/lib/leftovers/processor_builders/transform.rb +55 -0
  96. data/lib/leftovers/processor_builders/transform_chain.rb +24 -0
  97. data/lib/leftovers/processor_builders/transform_set.rb +47 -0
  98. data/lib/leftovers/processor_builders/value.rb +13 -0
  99. data/lib/leftovers/rake_task.rb +4 -4
  100. data/lib/leftovers/reporter.rb +1 -1
  101. data/lib/leftovers/value_processors.rb +40 -0
  102. data/lib/leftovers/value_processors/add_dynamic_prefix.rb +31 -0
  103. data/lib/leftovers/value_processors/add_dynamic_suffix.rb +31 -0
  104. data/lib/leftovers/value_processors/add_prefix.rb +20 -0
  105. data/lib/leftovers/value_processors/add_suffix.rb +20 -0
  106. data/lib/leftovers/value_processors/camelize.rb +24 -0
  107. data/lib/leftovers/value_processors/capitalize.rb +19 -0
  108. data/lib/leftovers/value_processors/deconstantize.rb +24 -0
  109. data/lib/leftovers/value_processors/delete_after.rb +22 -0
  110. data/lib/leftovers/value_processors/delete_before.rb +22 -0
  111. data/lib/leftovers/value_processors/delete_prefix.rb +26 -0
  112. data/lib/leftovers/value_processors/delete_suffix.rb +26 -0
  113. data/lib/leftovers/value_processors/demodulize.rb +24 -0
  114. data/lib/leftovers/value_processors/downcase.rb +19 -0
  115. data/lib/leftovers/value_processors/each.rb +21 -0
  116. data/lib/leftovers/value_processors/each_for_definition_set.rb +33 -0
  117. data/lib/leftovers/value_processors/each_keyword.rb +27 -0
  118. data/lib/leftovers/value_processors/each_keyword_argument.rb +27 -0
  119. data/lib/leftovers/value_processors/each_positional_argument.rb +24 -0
  120. data/lib/leftovers/value_processors/itself.rb +17 -0
  121. data/lib/leftovers/value_processors/keyword.rb +36 -0
  122. data/lib/leftovers/value_processors/keyword_argument.rb +36 -0
  123. data/lib/leftovers/value_processors/parameterize.rb +24 -0
  124. data/lib/leftovers/value_processors/placeholder.rb +18 -0
  125. data/lib/leftovers/value_processors/pluralize.rb +24 -0
  126. data/lib/leftovers/value_processors/positional_argument.rb +26 -0
  127. data/lib/leftovers/value_processors/replace_value.rb +18 -0
  128. data/lib/leftovers/value_processors/return_definition.rb +24 -0
  129. data/lib/leftovers/value_processors/return_string.rb +14 -0
  130. data/lib/leftovers/value_processors/singularize.rb +24 -0
  131. data/lib/leftovers/value_processors/split.rb +22 -0
  132. data/lib/leftovers/value_processors/swapcase.rb +19 -0
  133. data/lib/leftovers/value_processors/titleize.rb +24 -0
  134. data/lib/leftovers/value_processors/underscore.rb +24 -0
  135. data/lib/leftovers/value_processors/upcase.rb +19 -0
  136. data/lib/leftovers/version.rb +1 -1
  137. metadata +193 -29
  138. data/lib/config/selenium.yml +0 -21
  139. data/lib/leftovers/argument_rule.rb +0 -218
  140. data/lib/leftovers/core_ext.rb +0 -13
  141. data/lib/leftovers/hash_rule.rb +0 -40
  142. data/lib/leftovers/name_rule.rb +0 -53
  143. data/lib/leftovers/rule.rb +0 -74
  144. data/lib/leftovers/transform_rule.rb +0 -171
  145. data/lib/leftovers/value_rule.rb +0 -56
@@ -2,57 +2,36 @@
2
2
 
3
3
  module Leftovers
4
4
  class Definition
5
- attr_reader :name
5
+ attr_reader :name, :test, :location_s
6
6
  alias_method :names, :name
7
- alias_method :full_name, :name
8
- attr_reader :name_s
9
- alias_method :to_s, :name_s
10
- attr_reader :test
7
+
11
8
  alias_method :test?, :test
12
9
 
13
- def initialize( # rubocop:disable Metrics/MethodLength
10
+ def initialize(
14
11
  name,
15
12
  method_node: nil,
16
13
  location: method_node.loc.expression,
17
- file: method_node.file,
18
14
  test: method_node.test?
19
15
  )
20
16
  @name = name
21
- @name_s = name.to_s.freeze
22
-
23
- @location = location
24
- @file = file
17
+ @location_source_line = location.source_line.to_s
18
+ @location_column_range_begin = location.column_range.begin.to_i
19
+ @location_column_range_end = location.column_range.end.to_i
20
+ @location_source = location.source.to_s
21
+ @location_s = location.to_s
25
22
  @test = test
26
23
 
27
24
  freeze
28
25
  end
29
26
 
30
- def <=>(other)
31
- (path <=> other.path).nonzero? ||
32
- (line <=> other.line).nonzero? ||
33
- (column <=> other.column)
34
- end
35
-
36
- def path
37
- @file.relative_path
38
- end
39
-
40
- def line
41
- @location.line
27
+ def to_s
28
+ @name.to_s
42
29
  end
43
30
 
44
- def column
45
- @location.column
46
- end
47
-
48
- def full_location
49
- "#{path}:#{@location.line}:#{@location.column}"
50
- end
51
-
52
- def highlighted_source(highlight = "\e[31m", normal = "\e[0m") # rubocop:disable Metrics/AbcSize
53
- @location.source_line.to_s[0...(@location.column_range.begin)].lstrip +
54
- highlight + @location.source.to_s + normal +
55
- @location.source_line.to_s[(@location.column_range.end)..-1].rstrip
31
+ def highlighted_source(highlight = "\e[31m", normal = "\e[0m")
32
+ @location_source_line[0...@location_column_range_begin].lstrip +
33
+ highlight + @location_source + normal +
34
+ @location_source_line[@location_column_range_end..-1].rstrip
56
35
  end
57
36
 
58
37
  def in_collection?
@@ -62,9 +41,5 @@ module Leftovers
62
41
  def in_test_collection?
63
42
  Leftovers.collector.test_calls.include?(@name)
64
43
  end
65
-
66
- def skipped?
67
- Leftovers.config.skip_rules.any? { |r| r.match?(@name, @name_s, path) }
68
- end
69
44
  end
70
45
  end
@@ -1,24 +1,18 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'definition'
4
3
  module Leftovers
5
- class DefinitionSet < Leftovers::Definition
6
- def initialize( # rubocop:disable Metrics/MethodLength
7
- names,
4
+ class DefinitionSet < ::Leftovers::Definition
5
+ attr_reader :definitions
6
+
7
+ def initialize(
8
+ definitions,
8
9
  method_node: nil,
9
10
  location: method_node.loc.expression,
10
- file: method_node.file,
11
11
  test: method_node.test?
12
12
  )
13
- @definitions = names.map do |name|
14
- Leftovers::Definition.new(name, test: test, location: location, file: file)
15
- end
16
-
17
- @test = test
18
- @location = location
19
- @file = file
13
+ @definitions = definitions
20
14
 
21
- freeze
15
+ super
22
16
  end
23
17
 
24
18
  def names
@@ -36,9 +30,5 @@ module Leftovers
36
30
  def in_test_collection?
37
31
  @definitions.any?(&:in_test_collection?)
38
32
  end
39
-
40
- def skipped?
41
- @definitions.any?(&:skipped?)
42
- end
43
33
  end
44
34
  end
@@ -0,0 +1,11 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module DynamicProcessors
5
+ autoload(:CallDefinition, "#{__dir__}/dynamic_processors/call_definition")
6
+ autoload(:Call, "#{__dir__}/dynamic_processors/call")
7
+ autoload(:Definition, "#{__dir__}/dynamic_processors/definition")
8
+ autoload(:Each, "#{__dir__}/dynamic_processors/each")
9
+ autoload(:Null, "#{__dir__}/dynamic_processors/null")
10
+ end
11
+ end
@@ -0,0 +1,25 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module DynamicProcessors
5
+ class Call
6
+ # :nocov:
7
+ using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
8
+ # :nocov:
9
+
10
+ def initialize(matcher, processor)
11
+ @matcher = matcher
12
+ @processor = processor
13
+ end
14
+
15
+ def process(node, file)
16
+ return unless @matcher === node
17
+
18
+ call = @processor.process(nil, node, node)
19
+ return unless call
20
+
21
+ file.calls << call
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,31 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module DynamicProcessors
5
+ class CallDefinition
6
+ # :nocov:
7
+ using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
8
+ # :nocov:
9
+
10
+ def initialize(matcher, call_processor, definition_processor)
11
+ @matcher = matcher
12
+ @call_processor = call_processor
13
+ @definition_processor = definition_processor
14
+ end
15
+
16
+ def process(node, file)
17
+ return unless @matcher === node
18
+
19
+ call = @call_processor.process(nil, node, node)
20
+ (file.calls << call) if call
21
+
22
+ return if node.keep_line?
23
+
24
+ definition = @definition_processor.process(nil, node, node)
25
+ return unless definition
26
+
27
+ file.definitions << definition
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,26 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module DynamicProcessors
5
+ class Definition
6
+ # :nocov:
7
+ using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
8
+ # :nocov:
9
+
10
+ def initialize(matcher, processor)
11
+ @matcher = matcher
12
+ @processor = processor
13
+ end
14
+
15
+ def process(node, file)
16
+ return if node.keep_line?
17
+ return unless @matcher === node
18
+
19
+ definition = @processor.process(nil, node, node)
20
+ return unless definition
21
+
22
+ file.definitions << definition
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,19 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module DynamicProcessors
5
+ class Each
6
+ attr_reader :processors
7
+
8
+ def initialize(processors)
9
+ @processors = processors
10
+ end
11
+
12
+ def process(node, file)
13
+ @processors.each do |processor|
14
+ processor.process(node, file)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,9 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module DynamicProcessors
5
+ module Null
6
+ def self.process(_node, _file); end
7
+ end
8
+ end
9
+ end
@@ -9,11 +9,11 @@ module Leftovers
9
9
  @compiler.compile(erb).first
10
10
  end
11
11
 
12
- def add_insert_cmd(out, content)
12
+ def add_insert_cmd(out, content) # leftovers:keep
13
13
  out.push("#{content}\n")
14
14
  end
15
15
 
16
- def add_put_cmd(out, _content)
16
+ def add_put_cmd(out, _content) # leftovers:keep
17
17
  out
18
18
  end
19
19
  end
@@ -1,7 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'erb'
4
- require_relative 'haml'
5
3
  require 'pathname'
6
4
 
7
5
  module Leftovers
@@ -16,12 +14,12 @@ module Leftovers
16
14
  @test = Leftovers.config.test_paths.allowed?(relative_path)
17
15
  end
18
16
 
19
- def ruby # rubocop:disable Metrics/MethodLength
17
+ def ruby
20
18
  case extname
21
19
  when '.haml'
22
- Leftovers::Haml.precompile(read)
20
+ ::Leftovers::Haml.precompile(read, self)
23
21
  when '.rhtml', '.rjs', '.erb'
24
- Leftovers::ERB.precompile(read)
22
+ ::Leftovers::ERB.precompile(read)
25
23
  else
26
24
  read
27
25
  end
@@ -1,19 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fast_ignore'
4
3
  require 'set'
5
4
  require 'parser'
6
- require 'parser/current'
7
- require_relative 'ast/builder'
8
- require_relative 'ast/node'
9
- require_relative 'definition'
10
5
 
11
6
  module Leftovers
12
- class FileCollector < Parser::AST::Processor # rubocop:disable Metrics/ClassLength
13
- attr_reader :calls
14
- attr_reader :definitions
7
+ class FileCollector < ::Parser::AST::Processor # rubocop:disable Metrics/ClassLength
8
+ attr_reader :calls, :definitions
15
9
 
16
- def initialize(ruby, file) # rubocop:disable Metrics/MethodLength
10
+ def initialize(ruby, file) # rubocop:disable Lint/MissingSuper
17
11
  @calls = []
18
12
  @definitions = []
19
13
  @allow_lines = Set.new.compare_by_identity
@@ -27,6 +21,8 @@ module Leftovers
27
21
  end
28
22
 
29
23
  def to_h
24
+ squash!
25
+
30
26
  {
31
27
  test?: @file.test?,
32
28
  calls: calls,
@@ -34,40 +30,25 @@ module Leftovers
34
30
  }
35
31
  end
36
32
 
37
- # mostly copied from https://github.com/whitequark/parser/blob/master/lib/parser/base.rb
38
- # but with our builder
39
- def self.parser # rubocop:disable Metrics/MethodLength
40
- p = ::Parser::CurrentRuby.new(Leftovers::AST::Builder.new)
41
- p.diagnostics.all_errors_are_fatal = true
42
- p.diagnostics.ignore_warnings = true
43
-
44
- p.diagnostics.consumer = lambda do |diagnostic|
45
- warn(diagnostic.render)
46
- end
47
-
48
- p
49
- end
50
- PARSER = parser
51
-
52
- # mostly copied from https://github.com/whitequark/parser/blob/master/lib/parser/base.rb
53
- # but with our parser
54
- def parse_with_comments(string, file = '(string)', line = 1)
55
- PARSER.reset
56
- source_buffer = ::Parser::CurrentRuby.send(
57
- :setup_source_buffer, file, line, string, PARSER.default_encoding
58
- )
59
- PARSER.parse_with_comments(source_buffer)
33
+ def squash!
34
+ calls.flatten!
35
+ calls.compact!
36
+ calls.uniq!
37
+ definitions.flatten!
38
+ definitions.compact!
39
+ definitions.uniq!
40
+ definitions.reject! { |v| v == :keep }
60
41
  end
61
42
 
62
43
  def collect
63
- ast, comments = parse_with_comments(@ruby, @file)
44
+ ast, comments = Leftovers::Parser.parse_with_comments(@ruby, @file.relative_path)
64
45
  process_comments(comments)
65
46
  process(ast)
66
- rescue Parser::SyntaxError => e
67
- Leftovers.warn "#{e.class}: #{e.message} #{filename}:#{e.diagnostic.location.line}:#{e.diagnostic.location.column}" # rubocop:disable Layout/LineLength
47
+ rescue ::Parser::SyntaxError => e
48
+ Leftovers.warn "\e[31m#{filename}:#{e.diagnostic.location.line}:#{e.diagnostic.location.column} SyntaxError: #{e.message}\e[0m" # rubocop:disable Layout/LineLength
68
49
  end
69
50
 
70
- METHOD_NAME_RE = /[[:alpha:]_][[:alnum:]_]*\b[\?!=]?/.freeze
51
+ METHOD_NAME_RE = /[[:alpha:]_][[:alnum:]_]*\b[?!=]?/.freeze
71
52
  NON_ALNUM_METHOD_NAME_RE = Regexp.union(%w{
72
53
  []= [] ** ~ +@ -@ * / % + - >> << &
73
54
  ^ | <=> <= >= < > === == != =~ !~ !
@@ -77,14 +58,12 @@ module Leftovers
77
58
  LEFTOVERS_CALL_RE = /\bleftovers:call(?:s|ed|er|ers|) (#{NAME_RE}(?:[, :]+#{NAME_RE})*)/.freeze
78
59
  LEFTOVERS_ALLOW_RE = /\bleftovers:(?:keeps?|skip(?:s|ped|)|allow(?:s|ed|))\b/.freeze
79
60
  LEFTOVERS_TEST_RE = /\bleftovers:(?:for_tests?|tests?|testing)\b/.freeze
80
- def process_comments(comments) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
61
+ def process_comments(comments) # rubocop:disable Metrics/AbcSize
81
62
  comments.each do |comment|
82
63
  @allow_lines << comment.loc.line if comment.text.match?(LEFTOVERS_ALLOW_RE)
83
-
84
64
  @test_lines << comment.loc.line if comment.text.match?(LEFTOVERS_TEST_RE)
85
65
 
86
66
  next unless (match = comment.text.match(LEFTOVERS_CALL_RE))
87
- next unless match[1]
88
67
 
89
68
  match[1].scan(NAME_RE).each { |s| add_call(s.to_sym) }
90
69
  end
@@ -92,66 +71,75 @@ module Leftovers
92
71
 
93
72
  # grab method definitions
94
73
  def on_def(node)
95
- add_definition(node.children.first, node.loc.name)
96
-
74
+ add_definition(node)
97
75
  super
98
76
  end
99
77
 
100
78
  def on_ivasgn(node)
101
- add_definition(node.children.first, node.loc.name)
79
+ collect_variable_assign(node)
80
+ super
81
+ end
102
82
 
83
+ def on_gvasgn(node)
84
+ collect_variable_assign(node)
85
+ super
86
+ end
87
+
88
+ def on_cvasgn(node)
89
+ collect_variable_assign(node)
103
90
  super
104
91
  end
105
- alias_method :on_gvasgn, :on_ivasgn
106
- alias_method :on_cvasgn, :on_ivasgn
107
92
 
108
93
  def on_ivar(node)
109
- add_call(node.children.first)
94
+ add_call(node.name)
95
+ super
96
+ end
97
+
98
+ def on_gvar(node)
99
+ add_call(node.name)
100
+ super
101
+ end
110
102
 
103
+ def on_cvar(node)
104
+ add_call(node.name)
111
105
  super
112
106
  end
113
- alias_method :on_gvar, :on_ivar
114
- alias_method :on_cvar, :on_ivar
115
107
 
116
108
  def on_op_asgn(node)
117
109
  collect_op_asgn(node)
118
-
119
110
  super
120
111
  end
121
112
 
122
113
  def on_and_asgn(node)
123
114
  collect_op_asgn(node)
124
-
125
115
  super
126
116
  end
127
117
 
128
118
  def on_or_asgn(node)
129
119
  collect_op_asgn(node)
130
-
131
120
  super
132
121
  end
133
122
 
134
123
  # grab method calls
135
124
  def on_send(node)
136
125
  super
126
+ collect_send(node)
127
+ end
137
128
 
138
- add_call(node.children[1])
139
-
140
- collect_rules(node)
129
+ def on_csend(node)
130
+ super
131
+ collect_send(node)
141
132
  end
142
- alias_method :on_csend, :on_send
143
133
 
144
134
  def on_const(node)
145
135
  super
146
-
147
- add_call(node.children[1])
136
+ add_call(node.name)
148
137
  end
149
138
 
150
139
  # grab e.g. :to_s in each(&:to_s)
151
140
  def on_block_pass(node)
152
141
  super
153
-
154
- add_call(node.children.first.to_sym) if node.children.first&.string_or_symbol?
142
+ add_call(node.children.first.to_sym) if node.children.first.string_or_symbol?
155
143
  end
156
144
 
157
145
  # grab class Constant or module Constant
@@ -162,26 +150,22 @@ module Leftovers
162
150
 
163
151
  node = node.children.first
164
152
 
165
- add_definition(node.children[1], node.loc.name)
153
+ add_definition(node)
166
154
  end
167
155
  alias_method :on_module, :on_class
168
156
 
169
157
  # grab Constant = Class.new or CONSTANT = 'string'.freeze
170
158
  def on_casgn(node)
171
159
  super
172
-
173
- add_definition(node.children[1], node.loc.name)
174
-
175
- collect_rules(node)
160
+ add_definition(node)
161
+ collect_dynamic(node)
176
162
  end
177
163
 
178
164
  # grab calls to `alias new_method original_method`
179
165
  def on_alias(node)
180
166
  super
181
-
182
167
  new_method, original_method = node.children
183
-
184
- add_definition(new_method.children.first, new_method.loc.expression)
168
+ add_definition(new_method, name: new_method.children.first, loc: new_method.loc.expression)
185
169
  add_call(original_method.children.first)
186
170
  end
187
171
 
@@ -191,55 +175,58 @@ module Leftovers
191
175
  @file.test? || @test_lines.include?(loc.line)
192
176
  end
193
177
 
194
- def add_definition(name, loc)
178
+ def add_definition(node, name: node.name, loc: node.loc.name)
195
179
  return if @allow_lines.include?(loc.line)
180
+ return if Leftovers.config.keep === node
196
181
 
197
- definitions << Leftovers::Definition.new(name, location: loc, file: @file, test: test?(loc))
182
+ definitions << Leftovers::Definition.new(name, location: loc, test: test?(loc))
198
183
  end
199
184
 
200
185
  def add_call(name)
201
186
  calls << name
202
187
  end
203
188
 
189
+ def collect_send(node)
190
+ add_call(node.name)
191
+ collect_dynamic(node)
192
+ end
193
+
204
194
  # just collects the call, super will collect the definition
205
195
  def collect_var_op_asgn(node)
206
196
  name = node.children.first
207
197
 
208
- return unless name
209
-
210
198
  add_call(name)
211
199
  end
212
200
 
213
201
  def collect_send_op_asgn(node)
214
202
  name = node.children[1]
215
203
 
216
- return unless name
217
-
218
204
  add_call(:"#{name}=")
219
205
  end
220
206
 
207
+ def collect_variable_assign(node)
208
+ add_definition(node)
209
+
210
+ collect_dynamic(node)
211
+ end
212
+
221
213
  def collect_op_asgn(node)
222
214
  node = node.children.first
215
+ # :nocov: # don't need else, it's exhaustive for callers
223
216
  case node.type
217
+ # :nocov:
224
218
  when :send then collect_send_op_asgn(node)
225
219
  when :ivasgn, :gvasgn, :cvasgn then collect_var_op_asgn(node)
226
220
  end
227
221
  end
228
222
 
229
- def collect_rules(node) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
230
- Leftovers.config.rules.each do |rule|
231
- next unless rule.match?(node.name, node.name_s, filename)
232
-
233
- next if rule.skip?
234
-
235
- calls.concat(rule.calls(node))
223
+ def collect_dynamic(node) # rubocop:disable Metrics/AbcSize
224
+ node.keep_line = @allow_lines.include?(node.loc.line)
225
+ node.test = test?(node.loc) unless node.keep_line?
236
226
 
237
- next if @allow_lines.include?(node.loc.line)
238
-
239
- node.file = @file
240
- node.test = test?(node.loc)
241
- definitions.concat(rule.definitions(node))
242
- end
227
+ Leftovers.config.dynamic.process(node, self)
228
+ rescue StandardError => e
229
+ raise ::Leftovers::Error, "#{e.class}: #{e.message}\nwhen processing #{node} at #{filename}:#{node.loc.line}:#{node.loc.column}", e.backtrace # rubocop:disable Layout/LineLength
243
230
  end
244
231
  end
245
232
  end