leftovers 0.2.2 → 0.4.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (146) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +41 -0
  3. data/README.md +35 -49
  4. data/docs/Configuration.md +627 -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 -4
  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 +160 -97
  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 -49
  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 +61 -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 +66 -107
  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 +38 -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 +496 -0
  33. data/lib/leftovers/definition.rb +16 -41
  34. data/lib/leftovers/definition_node.rb +36 -0
  35. data/lib/leftovers/definition_set.rb +17 -24
  36. data/lib/leftovers/dynamic_processors.rb +11 -0
  37. data/lib/leftovers/dynamic_processors/call.rb +25 -0
  38. data/lib/leftovers/dynamic_processors/call_definition.rb +31 -0
  39. data/lib/leftovers/dynamic_processors/definition.rb +26 -0
  40. data/lib/leftovers/dynamic_processors/each.rb +19 -0
  41. data/lib/leftovers/dynamic_processors/null.rb +9 -0
  42. data/lib/leftovers/erb.rb +2 -2
  43. data/lib/leftovers/file.rb +3 -5
  44. data/lib/leftovers/file_collector.rb +82 -62
  45. data/lib/leftovers/file_list.rb +9 -15
  46. data/lib/leftovers/haml.rb +9 -12
  47. data/lib/leftovers/matcher_builders.rb +24 -0
  48. data/lib/leftovers/matcher_builders/and.rb +19 -0
  49. data/lib/leftovers/matcher_builders/and_not.rb +14 -0
  50. data/lib/leftovers/matcher_builders/argument_node_value.rb +21 -0
  51. data/lib/leftovers/matcher_builders/name.rb +29 -0
  52. data/lib/leftovers/matcher_builders/node.rb +40 -0
  53. data/lib/leftovers/matcher_builders/node_has_argument.rb +71 -0
  54. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +22 -0
  55. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +24 -0
  56. data/lib/leftovers/matcher_builders/node_name.rb +15 -0
  57. data/lib/leftovers/matcher_builders/node_pair_name.rb +18 -0
  58. data/lib/leftovers/matcher_builders/node_pair_value.rb +16 -0
  59. data/lib/leftovers/matcher_builders/node_path.rb +14 -0
  60. data/lib/leftovers/matcher_builders/node_type.rb +28 -0
  61. data/lib/leftovers/matcher_builders/or.rb +73 -0
  62. data/lib/leftovers/matcher_builders/path.rb +15 -0
  63. data/lib/leftovers/matcher_builders/string.rb +11 -0
  64. data/lib/leftovers/matcher_builders/string_pattern.rb +19 -0
  65. data/lib/leftovers/matcher_builders/unless.rb +13 -0
  66. data/lib/leftovers/matchers.rb +26 -0
  67. data/lib/leftovers/matchers/all.rb +25 -0
  68. data/lib/leftovers/matchers/and.rb +24 -0
  69. data/lib/leftovers/matchers/any.rb +27 -0
  70. data/lib/leftovers/matchers/node_has_any_keyword_argument.rb +28 -0
  71. data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +25 -0
  72. data/lib/leftovers/matchers/node_has_positional_argument.rb +23 -0
  73. data/lib/leftovers/matchers/node_has_positional_argument_with_value.rb +25 -0
  74. data/lib/leftovers/matchers/node_name.rb +23 -0
  75. data/lib/leftovers/matchers/node_pair_value.rb +23 -0
  76. data/lib/leftovers/matchers/node_path.rb +23 -0
  77. data/lib/leftovers/matchers/node_scalar_value.rb +25 -0
  78. data/lib/leftovers/matchers/node_type.rb +23 -0
  79. data/lib/leftovers/matchers/not.rb +23 -0
  80. data/lib/leftovers/matchers/or.rb +26 -0
  81. data/lib/leftovers/merged_config.rb +24 -14
  82. data/lib/leftovers/parser.rb +2 -5
  83. data/lib/leftovers/processor_builders.rb +22 -0
  84. data/lib/leftovers/processor_builders/action.rb +63 -0
  85. data/lib/leftovers/processor_builders/add_prefix.rb +20 -0
  86. data/lib/leftovers/processor_builders/add_suffix.rb +20 -0
  87. data/lib/leftovers/processor_builders/argument.rb +25 -0
  88. data/lib/leftovers/processor_builders/dynamic.rb +27 -0
  89. data/lib/leftovers/processor_builders/each.rb +36 -0
  90. data/lib/leftovers/processor_builders/each_action.rb +51 -0
  91. data/lib/leftovers/processor_builders/each_dynamic.rb +54 -0
  92. data/lib/leftovers/processor_builders/each_for_definition_set.rb +36 -0
  93. data/lib/leftovers/processor_builders/itself.rb +13 -0
  94. data/lib/leftovers/processor_builders/keyword.rb +24 -0
  95. data/lib/leftovers/processor_builders/keyword_argument.rb +14 -0
  96. data/lib/leftovers/processor_builders/transform.rb +55 -0
  97. data/lib/leftovers/processor_builders/transform_chain.rb +24 -0
  98. data/lib/leftovers/processor_builders/transform_set.rb +47 -0
  99. data/lib/leftovers/processor_builders/value.rb +13 -0
  100. data/lib/leftovers/rake_task.rb +4 -4
  101. data/lib/leftovers/reporter.rb +1 -1
  102. data/lib/leftovers/value_processors.rb +40 -0
  103. data/lib/leftovers/value_processors/add_dynamic_prefix.rb +31 -0
  104. data/lib/leftovers/value_processors/add_dynamic_suffix.rb +31 -0
  105. data/lib/leftovers/value_processors/add_prefix.rb +20 -0
  106. data/lib/leftovers/value_processors/add_suffix.rb +20 -0
  107. data/lib/leftovers/value_processors/camelize.rb +24 -0
  108. data/lib/leftovers/value_processors/capitalize.rb +19 -0
  109. data/lib/leftovers/value_processors/deconstantize.rb +24 -0
  110. data/lib/leftovers/value_processors/delete_after.rb +22 -0
  111. data/lib/leftovers/value_processors/delete_before.rb +22 -0
  112. data/lib/leftovers/value_processors/delete_prefix.rb +26 -0
  113. data/lib/leftovers/value_processors/delete_suffix.rb +26 -0
  114. data/lib/leftovers/value_processors/demodulize.rb +24 -0
  115. data/lib/leftovers/value_processors/downcase.rb +19 -0
  116. data/lib/leftovers/value_processors/each.rb +21 -0
  117. data/lib/leftovers/value_processors/each_for_definition_set.rb +29 -0
  118. data/lib/leftovers/value_processors/each_keyword.rb +27 -0
  119. data/lib/leftovers/value_processors/each_keyword_argument.rb +27 -0
  120. data/lib/leftovers/value_processors/each_positional_argument.rb +24 -0
  121. data/lib/leftovers/value_processors/itself.rb +17 -0
  122. data/lib/leftovers/value_processors/keyword.rb +36 -0
  123. data/lib/leftovers/value_processors/keyword_argument.rb +36 -0
  124. data/lib/leftovers/value_processors/parameterize.rb +24 -0
  125. data/lib/leftovers/value_processors/placeholder.rb +18 -0
  126. data/lib/leftovers/value_processors/pluralize.rb +24 -0
  127. data/lib/leftovers/value_processors/positional_argument.rb +26 -0
  128. data/lib/leftovers/value_processors/replace_value.rb +18 -0
  129. data/lib/leftovers/value_processors/return_definition.rb +26 -0
  130. data/lib/leftovers/value_processors/return_string.rb +14 -0
  131. data/lib/leftovers/value_processors/singularize.rb +24 -0
  132. data/lib/leftovers/value_processors/split.rb +22 -0
  133. data/lib/leftovers/value_processors/swapcase.rb +19 -0
  134. data/lib/leftovers/value_processors/titleize.rb +24 -0
  135. data/lib/leftovers/value_processors/underscore.rb +24 -0
  136. data/lib/leftovers/value_processors/upcase.rb +19 -0
  137. data/lib/leftovers/version.rb +1 -1
  138. metadata +190 -28
  139. data/lib/config/selenium.yml +0 -21
  140. data/lib/leftovers/argument_rule.rb +0 -219
  141. data/lib/leftovers/core_ext.rb +0 -13
  142. data/lib/leftovers/hash_rule.rb +0 -40
  143. data/lib/leftovers/name_rule.rb +0 -53
  144. data/lib/leftovers/rule.rb +0 -74
  145. data/lib/leftovers/transform_rule.rb +0 -171
  146. 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
- method_node: nil,
16
12
  location: method_node.loc.expression,
17
- file: method_node.file,
18
- test: method_node.test?
13
+ test: method_node.test_line?
19
14
  )
20
15
  @name = name
21
- @name_s = name.to_s.freeze
22
-
23
- @location = location
24
- @file = file
16
+ @path = location.source_buffer.name.to_s
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
@@ -0,0 +1,36 @@
1
+ # frozen-string-literal: true
2
+
3
+ # To give to matchers before creating a Definition
4
+
5
+ module Leftovers
6
+ class DefinitionNode
7
+ attr_reader :path, :name
8
+
9
+ def initialize(name, path)
10
+ @name = name
11
+ @path = path
12
+
13
+ freeze
14
+ end
15
+
16
+ # these are the methods checked by things in lib/leftovers/matchers
17
+ def kwargs
18
+ nil
19
+ end
20
+
21
+ def positional_arguments
22
+ nil
23
+ end
24
+
25
+ # these two i'm not sure are possible with the current config flags
26
+ # :nocov:
27
+ def scalar?
28
+ false
29
+ end
30
+
31
+ def type
32
+ :leftovers_definition
33
+ end
34
+ # :nocov:
35
+ end
36
+ end
@@ -1,28 +1,13 @@
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,
8
- method_node: nil,
9
- location: method_node.loc.expression,
10
- file: method_node.file,
11
- test: method_node.test?
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
4
+ class DefinitionSet
5
+ attr_reader :definitions
20
6
 
21
- freeze
22
- end
7
+ def initialize(definitions)
8
+ @definitions = definitions
23
9
 
24
- def full_name
25
- names.join(', ')
10
+ freeze
26
11
  end
27
12
 
28
13
  def names
@@ -33,16 +18,24 @@ module Leftovers
33
18
  @definitions.map(&:to_s).join(', ')
34
19
  end
35
20
 
21
+ def location_s
22
+ @definitions.first.location_s
23
+ end
24
+
25
+ def highlighted_source(*args)
26
+ @definitions.first.highlighted_source(*args)
27
+ end
28
+
36
29
  def in_collection?
37
30
  @definitions.any?(&:in_collection?)
38
31
  end
39
32
 
40
- def in_test_collection?
41
- @definitions.any?(&:in_test_collection?)
33
+ def test?
34
+ @definitions.any?(&:test?)
42
35
  end
43
36
 
44
- def skipped?
45
- @definitions.any?(&:skipped?)
37
+ def in_test_collection?
38
+ @definitions.any?(&:in_test_collection?)
46
39
  end
47
40
  end
48
41
  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,16 +1,13 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'fast_ignore'
4
3
  require 'set'
5
- require_relative 'parser'
6
- require_relative 'definition'
4
+ require 'parser'
7
5
 
8
6
  module Leftovers
9
7
  class FileCollector < ::Parser::AST::Processor # rubocop:disable Metrics/ClassLength
10
- attr_reader :calls
11
- attr_reader :definitions
8
+ attr_reader :calls, :definitions
12
9
 
13
- def initialize(ruby, file) # rubocop:disable Metrics/MethodLength
10
+ def initialize(ruby, file) # rubocop:disable Lint/MissingSuper
14
11
  @calls = []
15
12
  @definitions = []
16
13
  @allow_lines = Set.new.compare_by_identity
@@ -24,6 +21,8 @@ module Leftovers
24
21
  end
25
22
 
26
23
  def to_h
24
+ squash!
25
+
27
26
  {
28
27
  test?: @file.test?,
29
28
  calls: calls,
@@ -31,15 +30,25 @@ module Leftovers
31
30
  }
32
31
  end
33
32
 
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 }
41
+ end
42
+
34
43
  def collect
35
- ast, comments = Leftovers::Parser.parse_with_comments(@ruby, @file)
44
+ ast, comments = Leftovers::Parser.parse_with_comments(@ruby, @file.relative_path)
36
45
  process_comments(comments)
37
46
  process(ast)
38
- rescue Parser::SyntaxError => e
39
- 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
40
49
  end
41
50
 
42
- METHOD_NAME_RE = /[[:alpha:]_][[:alnum:]_]*\b[\?!=]?/.freeze
51
+ METHOD_NAME_RE = /[[:alpha:]_][[:alnum:]_]*\b[?!=]?/.freeze
43
52
  NON_ALNUM_METHOD_NAME_RE = Regexp.union(%w{
44
53
  []= [] ** ~ +@ -@ * / % + - >> << &
45
54
  ^ | <=> <= >= < > === == != =~ !~ !
@@ -48,15 +57,13 @@ module Leftovers
48
57
  NAME_RE = Regexp.union(METHOD_NAME_RE, NON_ALNUM_METHOD_NAME_RE, CONSTANT_NAME_RE)
49
58
  LEFTOVERS_CALL_RE = /\bleftovers:call(?:s|ed|er|ers|) (#{NAME_RE}(?:[, :]+#{NAME_RE})*)/.freeze
50
59
  LEFTOVERS_ALLOW_RE = /\bleftovers:(?:keeps?|skip(?:s|ped|)|allow(?:s|ed|))\b/.freeze
51
- LEFTOVERS_TEST_RE = /\bleftovers:(?:for_tests?|tests?|testing)\b/.freeze
52
- def process_comments(comments) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
60
+ LEFTOVERS_TEST_RE = /\bleftovers:(?:for_tests?|tests?|testing|test_only)\b/.freeze
61
+ def process_comments(comments) # rubocop:disable Metrics/AbcSize
53
62
  comments.each do |comment|
54
63
  @allow_lines << comment.loc.line if comment.text.match?(LEFTOVERS_ALLOW_RE)
55
-
56
64
  @test_lines << comment.loc.line if comment.text.match?(LEFTOVERS_TEST_RE)
57
65
 
58
66
  next unless (match = comment.text.match(LEFTOVERS_CALL_RE))
59
- next unless match[1]
60
67
 
61
68
  match[1].scan(NAME_RE).each { |s| add_call(s.to_sym) }
62
69
  end
@@ -64,66 +71,75 @@ module Leftovers
64
71
 
65
72
  # grab method definitions
66
73
  def on_def(node)
67
- add_definition(node.children.first, node.loc.name)
68
-
74
+ add_definition(node)
69
75
  super
70
76
  end
71
77
 
72
78
  def on_ivasgn(node)
73
- add_definition(node.children.first, node.loc.name)
79
+ collect_variable_assign(node)
80
+ super
81
+ end
82
+
83
+ def on_gvasgn(node)
84
+ collect_variable_assign(node)
85
+ super
86
+ end
74
87
 
88
+ def on_cvasgn(node)
89
+ collect_variable_assign(node)
75
90
  super
76
91
  end
77
- alias_method :on_gvasgn, :on_ivasgn
78
- alias_method :on_cvasgn, :on_ivasgn
79
92
 
80
93
  def on_ivar(node)
81
- 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
82
102
 
103
+ def on_cvar(node)
104
+ add_call(node.name)
83
105
  super
84
106
  end
85
- alias_method :on_gvar, :on_ivar
86
- alias_method :on_cvar, :on_ivar
87
107
 
88
108
  def on_op_asgn(node)
89
109
  collect_op_asgn(node)
90
-
91
110
  super
92
111
  end
93
112
 
94
113
  def on_and_asgn(node)
95
114
  collect_op_asgn(node)
96
-
97
115
  super
98
116
  end
99
117
 
100
118
  def on_or_asgn(node)
101
119
  collect_op_asgn(node)
102
-
103
120
  super
104
121
  end
105
122
 
106
123
  # grab method calls
107
124
  def on_send(node)
108
125
  super
126
+ collect_send(node)
127
+ end
109
128
 
110
- add_call(node.children[1])
111
-
112
- collect_rules(node)
129
+ def on_csend(node)
130
+ super
131
+ collect_send(node)
113
132
  end
114
- alias_method :on_csend, :on_send
115
133
 
116
134
  def on_const(node)
117
135
  super
118
-
119
- add_call(node.children[1])
136
+ add_call(node.name)
120
137
  end
121
138
 
122
139
  # grab e.g. :to_s in each(&:to_s)
123
140
  def on_block_pass(node)
124
141
  super
125
-
126
- 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?
127
143
  end
128
144
 
129
145
  # grab class Constant or module Constant
@@ -134,84 +150,88 @@ module Leftovers
134
150
 
135
151
  node = node.children.first
136
152
 
137
- add_definition(node.children[1], node.loc.name)
153
+ add_definition(node)
138
154
  end
139
155
  alias_method :on_module, :on_class
140
156
 
141
157
  # grab Constant = Class.new or CONSTANT = 'string'.freeze
142
158
  def on_casgn(node)
143
159
  super
144
-
145
- add_definition(node.children[1], node.loc.name)
146
-
147
- collect_rules(node)
160
+ add_definition(node)
161
+ collect_dynamic(node)
148
162
  end
149
163
 
150
164
  # grab calls to `alias new_method original_method`
151
165
  def on_alias(node)
152
166
  super
153
-
154
167
  new_method, original_method = node.children
155
-
156
- 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)
157
169
  add_call(original_method.children.first)
158
170
  end
159
171
 
160
172
  private
161
173
 
162
- def test?(loc)
163
- @file.test? || @test_lines.include?(loc.line)
174
+ def test_line?(loc)
175
+ @file.test? ||
176
+ @test_lines.include?(loc.line)
164
177
  end
165
178
 
166
- def add_definition(name, loc)
179
+ def test_node?(node, loc)
180
+ test_line?(loc) || ::Leftovers.config.test_only === node
181
+ end
182
+
183
+ def add_definition(node, name: node.name, loc: node.loc.name)
167
184
  return if @allow_lines.include?(loc.line)
185
+ return if Leftovers.config.keep === node
168
186
 
169
- definitions << Leftovers::Definition.new(name, location: loc, file: @file, test: test?(loc))
187
+ definitions << Leftovers::Definition.new(name, location: loc, test: test_node?(node, loc))
170
188
  end
171
189
 
172
190
  def add_call(name)
173
191
  calls << name
174
192
  end
175
193
 
194
+ def collect_send(node)
195
+ add_call(node.name)
196
+ collect_dynamic(node)
197
+ end
198
+
176
199
  # just collects the call, super will collect the definition
177
200
  def collect_var_op_asgn(node)
178
201
  name = node.children.first
179
202
 
180
- return unless name
181
-
182
203
  add_call(name)
183
204
  end
184
205
 
185
206
  def collect_send_op_asgn(node)
186
207
  name = node.children[1]
187
208
 
188
- return unless name
189
-
190
209
  add_call(:"#{name}=")
191
210
  end
192
211
 
212
+ def collect_variable_assign(node)
213
+ add_definition(node)
214
+
215
+ collect_dynamic(node)
216
+ end
217
+
193
218
  def collect_op_asgn(node)
194
219
  node = node.children.first
220
+ # :nocov: # don't need else, it's exhaustive for callers
195
221
  case node.type
222
+ # :nocov:
196
223
  when :send then collect_send_op_asgn(node)
197
224
  when :ivasgn, :gvasgn, :cvasgn then collect_var_op_asgn(node)
198
225
  end
199
226
  end
200
227
 
201
- def collect_rules(node) # rubocop:disable Metrics/MethodLength, Metrics/AbcSize
202
- Leftovers.config.rules.each do |rule|
203
- next unless rule.match?(node.name, node.name_s, filename)
204
-
205
- next if rule.skip?
206
-
207
- calls.concat(rule.calls(node))
228
+ def collect_dynamic(node) # rubocop:disable Metrics/AbcSize
229
+ node.keep_line = @allow_lines.include?(node.loc.line)
230
+ node.test_line = test_line?(node.loc) unless node.keep_line?
208
231
 
209
- next if @allow_lines.include?(node.loc.line)
210
-
211
- node.file = @file
212
- node.test = test?(node.loc)
213
- definitions.concat(rule.definitions(node))
214
- end
232
+ Leftovers.config.dynamic.process(node, self)
233
+ rescue StandardError => e
234
+ raise ::Leftovers::Error, "#{e.class}: #{e.message}\nwhen processing #{node} at #{filename}:#{node.loc.line}:#{node.loc.column}", e.backtrace # rubocop:disable Layout/LineLength
215
235
  end
216
236
  end
217
237
  end