leftovers 0.2.2 → 0.4.2

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 (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
@@ -1,27 +1,21 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'fast_ignore'
4
- require_relative 'file'
5
4
 
6
5
  module Leftovers
7
- class FileList
8
- include Enumerable
6
+ class FileList < ::FastIgnore
7
+ def initialize
8
+ super(
9
+ ignore_rules: Leftovers.config.exclude_paths,
10
+ include_rules: Leftovers.config.include_paths,
11
+ root: Leftovers.pwd
12
+ )
13
+ end
9
14
 
10
15
  def each
11
- fast_ignore.each do |file|
16
+ super do |file|
12
17
  yield(Leftovers::File.new(file))
13
18
  end
14
19
  end
15
-
16
- def to_a
17
- enum_for(:each).to_a
18
- end
19
-
20
- def fast_ignore
21
- FastIgnore.new(
22
- ignore_rules: Leftovers.config.exclude_paths,
23
- include_rules: ['#!:ruby'] + Leftovers.config.include_paths
24
- )
25
- end
26
20
  end
27
21
  end
@@ -4,19 +4,16 @@ module Leftovers
4
4
  module Haml
5
5
  module_function
6
6
 
7
- def precompile(file) # rubocop:disable Metrics/MethodLength
8
- Leftovers.try_require('haml', message: <<~MESSAGE)
9
- Skipped parsing a haml file, because the haml gem was not available
10
- `gem install Haml`
7
+ def precompile(file, name)
8
+ return '' unless Leftovers.try_require('haml', message: <<~MESSAGE) # rubocop:disable Layout/EmptyLineAfterGuardClause
9
+ Skipped parsing #{name.relative_path}, because the haml gem was not available
10
+ `gem install haml`
11
11
  MESSAGE
12
- if defined?(::Haml)
13
- begin
14
- ::Haml::Engine.new(file).precompiled
15
- rescue ::Haml::SyntaxError => e
16
- Leftovers.warn "#{e.class}: #{e.message} #{filename}:#{e.line}"
17
- ''
18
- end
19
- else
12
+
13
+ begin
14
+ ::Haml::Engine.new(file).precompiled
15
+ rescue ::Haml::SyntaxError => e
16
+ Leftovers.warn "#{e.class}: #{e.message} #{name.relative_path}:#{e.line}"
20
17
  ''
21
18
  end
22
19
  end
@@ -0,0 +1,24 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ autoload(:AndNot, "#{__dir__}/matcher_builders/and_not")
6
+ autoload(:And, "#{__dir__}/matcher_builders/and")
7
+ autoload(:ArgumentNodeValue, "#{__dir__}/matcher_builders/argument_node_value")
8
+ autoload(:Name, "#{__dir__}/matcher_builders/name")
9
+ autoload(:NodeHasArgument, "#{__dir__}/matcher_builders/node_has_argument")
10
+ autoload(:NodeHasKeywordArgument, "#{__dir__}/matcher_builders/node_has_keyword_argument")
11
+ autoload(:NodeHasPositionalArgument, "#{__dir__}/matcher_builders/node_has_positional_argument")
12
+ autoload(:NodeName, "#{__dir__}/matcher_builders/node_name")
13
+ autoload(:NodePairName, "#{__dir__}/matcher_builders/node_pair_name")
14
+ autoload(:NodePairValue, "#{__dir__}/matcher_builders/node_pair_value")
15
+ autoload(:NodePath, "#{__dir__}/matcher_builders/node_path")
16
+ autoload(:NodeType, "#{__dir__}/matcher_builders/node_type")
17
+ autoload(:Node, "#{__dir__}/matcher_builders/node")
18
+ autoload(:Or, "#{__dir__}/matcher_builders/or")
19
+ autoload(:Path, "#{__dir__}/matcher_builders/path")
20
+ autoload(:StringPattern, "#{__dir__}/matcher_builders/string_pattern")
21
+ autoload(:String, "#{__dir__}/matcher_builders/string")
22
+ autoload(:Unless, "#{__dir__}/matcher_builders/unless")
23
+ end
24
+ end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module And
6
+ def self.build(matchers)
7
+ matchers = matchers.compact
8
+ case matchers.length
9
+ # :nocov:
10
+ when 0 then nil
11
+ # :nocov:
12
+ when 1 then matchers.first
13
+ when 2 then ::Leftovers::Matchers::And.new(matchers.first, matchers[1])
14
+ else ::Leftovers::Matchers::All.new(matchers.dup)
15
+ end
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,14 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module AndNot
6
+ def self.build(positive_matcher, negative_matcher)
7
+ ::Leftovers::MatcherBuilders::And.build([
8
+ positive_matcher,
9
+ ::Leftovers::MatcherBuilders::Unless.build(negative_matcher)
10
+ ])
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,21 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module ArgumentNodeValue
6
+ def self.build(pattern)
7
+ ::Leftovers::MatcherBuilders::Or.each_or_self(pattern) do |pat|
8
+ case pat
9
+ when ::Integer, true, false, nil
10
+ ::Leftovers::Matchers::NodeScalarValue.new(pat)
11
+ when ::String, ::Hash
12
+ ::Leftovers::MatcherBuilders::NodeName.build(pat)
13
+ # :nocov:
14
+ else raise
15
+ # :nocov:
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module Name
6
+ def self.build(patterns) # rubocop:disable Metrics/MethodLength
7
+ ::Leftovers::MatcherBuilders::Or.each_or_self(patterns) do |pat|
8
+ case pat
9
+ when nil
10
+ when ::Array
11
+ ::Leftovers::MatcherBuilders::Name.build(pat)
12
+ when ::String
13
+ ::Leftovers::MatcherBuilders::String.build(pat)
14
+ when ::Hash
15
+ unless_arg = pat.delete(:unless_arg)
16
+
17
+ ::Leftovers::MatcherBuilders::AndNot.build(
18
+ ::Leftovers::MatcherBuilders::StringPattern.build(**pat),
19
+ ::Leftovers::MatcherBuilders::Name.build(unless_arg)
20
+ )
21
+ # :nocov:
22
+ else raise
23
+ # :nocov:
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
@@ -0,0 +1,40 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module Node
6
+ def self.build(pattern)
7
+ ::Leftovers::MatcherBuilders::Or.each_or_self(pattern) do |pat|
8
+ case pat
9
+ when ::String
10
+ ::Leftovers::MatcherBuilders::NodeName.build(pat)
11
+ when ::Hash
12
+ build_from_hash(**pat)
13
+ # :nocov:
14
+ else raise
15
+ # :nocov:
16
+ end
17
+ end
18
+ end
19
+
20
+ def self.build_from_hash( # rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
21
+ names: nil, match: nil, has_prefix: nil, has_suffix: nil,
22
+ paths: nil,
23
+ has_arguments: nil,
24
+ unless_arg: nil
25
+ )
26
+ ::Leftovers::MatcherBuilders::And.build([
27
+ ::Leftovers::MatcherBuilders::NodeName.build([
28
+ names,
29
+ { match: match, has_prefix: has_prefix, has_suffix: has_suffix }.compact
30
+ ]),
31
+ ::Leftovers::MatcherBuilders::NodePath.build(paths),
32
+ ::Leftovers::MatcherBuilders::NodeHasArgument.build(has_arguments),
33
+ ::Leftovers::MatcherBuilders::Unless.build(
34
+ (::Leftovers::MatcherBuilders::Node.build(unless_arg) if unless_arg)
35
+ )
36
+ ])
37
+ end
38
+ end
39
+ end
40
+ end
@@ -0,0 +1,71 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module NodeHasArgument
6
+ def self.build(patterns) # rubocop:disable Metrics/MethodLength
7
+ ::Leftovers::MatcherBuilders::Or.each_or_self(patterns) do |pat|
8
+ case pat
9
+ when ::String
10
+ ::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(pat, nil)
11
+ when ::Integer
12
+ ::Leftovers::MatcherBuilders::NodeHasPositionalArgument.build(pat, nil)
13
+ when ::Hash
14
+ build_from_hash(**pat)
15
+ # :nocov:
16
+ else
17
+ raise
18
+ # :nocov:
19
+ end
20
+ end
21
+ end
22
+
23
+ def self.separate_argument_types(at) # rubocop:disable Metrics/MethodLength
24
+ keys = []
25
+ positions = []
26
+
27
+ ::Leftovers.each_or_self(at) do |k|
28
+ case k
29
+ when ::String, ::Hash
30
+ keys << k
31
+ when ::Integer
32
+ positions << k
33
+ # :nocov:
34
+ else raise
35
+ # :nocov:
36
+ end
37
+ end
38
+ keys = nil if keys.empty?
39
+ positions = nil if positions.empty?
40
+
41
+ [keys, positions]
42
+ end
43
+
44
+ def self.build_from_hash(at: nil, has_value: nil, has_value_type: nil, unless_arg: nil) # rubocop:disable Metrics/MethodLength
45
+ keys, positions = separate_argument_types(at)
46
+
47
+ value_matcher = ::Leftovers::MatcherBuilders::And.build([
48
+ ::Leftovers::MatcherBuilders::ArgumentNodeValue.build(has_value),
49
+ ::Leftovers::MatcherBuilders::NodeType.build(has_value_type)
50
+ ])
51
+ matcher = if (keys && positions) || (!keys && !positions)
52
+ ::Leftovers::MatcherBuilders::Or.build([
53
+ ::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(keys, value_matcher),
54
+ ::Leftovers::MatcherBuilders::NodeHasPositionalArgument.build(positions, value_matcher)
55
+ ])
56
+ elsif keys
57
+ ::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(keys, value_matcher)
58
+ elsif positions
59
+ ::Leftovers::MatcherBuilders::NodeHasPositionalArgument.build(positions, value_matcher)
60
+ # :nocov:
61
+ else raise
62
+ # :nocov:
63
+ end
64
+
65
+ ::Leftovers::MatcherBuilders::AndNot.build(
66
+ matcher, ::Leftovers::MatcherBuilders::NodeHasArgument.build(unless_arg)
67
+ )
68
+ end
69
+ end
70
+ end
71
+ end
@@ -0,0 +1,22 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module NodeHasKeywordArgument
6
+ def self.build(keywords, value_matcher)
7
+ value_matcher = ::Leftovers::MatcherBuilders::NodePairValue.build(value_matcher)
8
+ keyword_matcher = ::Leftovers::MatcherBuilders::NodePairName.build(keywords)
9
+
10
+ pair_matcher = ::Leftovers::MatcherBuilders::And.build([
11
+ keyword_matcher, value_matcher
12
+ ])
13
+ # :nocov:
14
+ raise unless pair_matcher
15
+
16
+ # :nocov:
17
+
18
+ ::Leftovers::Matchers::NodeHasAnyKeywordArgument.new(pair_matcher)
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,24 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module NodeHasPositionalArgument
6
+ def self.build(positions, value_matcher) # rubocop:disable Metrics/MethodLength
7
+ if positions && value_matcher
8
+ ::Leftovers::MatcherBuilders::Or.each_or_self(positions) do |position|
9
+ ::Leftovers::Matchers::NodeHasPositionalArgumentWithValue.new(position, value_matcher)
10
+ end
11
+ elsif positions
12
+ position = positions.is_a?(Array) ? positions.min : positions
13
+
14
+ ::Leftovers::Matchers::NodeHasPositionalArgument.new(position)
15
+ elsif value_matcher
16
+ ::Leftovers::Matchers::NodeHasAnyPositionalArgumentWithValue.new(value_matcher)
17
+ # :nocov:
18
+ else raise
19
+ # :nocov:
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,15 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module NodeName
6
+ def self.build(name_pattern)
7
+ matcher = ::Leftovers::MatcherBuilders::Name.build(name_pattern)
8
+
9
+ return unless matcher
10
+
11
+ ::Leftovers::Matchers::NodeName.new(matcher)
12
+ end
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,18 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module NodePairName
6
+ def self.build(name_pattern)
7
+ matcher = ::Leftovers::MatcherBuilders::Name.build(name_pattern)
8
+
9
+ return unless matcher
10
+
11
+ ::Leftovers::MatcherBuilders::And.build([
12
+ ::Leftovers::Matchers::NodeType.new(:pair),
13
+ ::Leftovers::Matchers::NodeName.new(matcher)
14
+ ])
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,16 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module NodePairValue
6
+ def self.build(value_matcher)
7
+ return unless value_matcher
8
+
9
+ ::Leftovers::MatcherBuilders::And.build([
10
+ ::Leftovers::Matchers::NodeType.new(:pair),
11
+ ::Leftovers::Matchers::NodePairValue.new(value_matcher)
12
+ ])
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,14 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module NodePath
6
+ def self.build(path_pattern)
7
+ matcher = ::Leftovers::MatcherBuilders::Path.build(path_pattern)
8
+ return unless matcher
9
+
10
+ ::Leftovers::Matchers::NodePath.new(matcher)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,28 @@
1
+ # frozen-string-literal: true
2
+
3
+ require 'set'
4
+
5
+ module Leftovers
6
+ module MatcherBuilders
7
+ module NodeType
8
+ def self.build(types_pattern)
9
+ ::Leftovers::MatcherBuilders::Or.each_or_self(types_pattern) do |type|
10
+ case type
11
+ when 'Symbol' then ::Leftovers::Matchers::NodeType.new(:sym)
12
+ when 'String' then ::Leftovers::Matchers::NodeType.new(:str)
13
+ when 'Integer' then ::Leftovers::Matchers::NodeType.new(:int)
14
+ when 'Float' then ::Leftovers::Matchers::NodeType.new(:float)
15
+ # these would be neat but i can't think of a use-case
16
+ # when 'Array' then :array
17
+ # when 'Hash' then :hash
18
+ # when 'Method' then Set[:send, :csend, :def]
19
+ # when 'Constant' then Set[:const, :class, :module]
20
+ # :nocov:
21
+ else raise
22
+ # :nocov:
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'set'
4
+
5
+ module Leftovers
6
+ module MatcherBuilders
7
+ module Or
8
+ def self.each_or_self(value, &block)
9
+ case value
10
+ when nil then nil
11
+ when Array then build(value.map(&block))
12
+ else build([yield(value)])
13
+ end
14
+ end
15
+
16
+ def self.build(matchers)
17
+ matchers = compact(matchers)
18
+ case matchers.length
19
+ # :nocov:
20
+ when 0 then nil
21
+ # :nocov:
22
+ when 1 then matchers.first
23
+ when 2 then ::Leftovers::Matchers::Or.new(matchers.first, matchers[1])
24
+ else ::Leftovers::Matchers::Any.new(matchers.dup)
25
+ end
26
+ end
27
+
28
+ def self.flatten(value) # rubocop:disable Metrics/MethodLength
29
+ case value
30
+ when ::Leftovers::Matchers::Or
31
+ [*flatten(value.lhs), *flatten(value.rhs)]
32
+ when ::Leftovers::Matchers::Any
33
+ flatten(value.matchers)
34
+ when Array
35
+ ret = value.map { |v| flatten(v) }
36
+ ret.flatten!(1)
37
+ ret
38
+ else
39
+ value
40
+ end
41
+ end
42
+
43
+ def self.compact(matchers) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize,
44
+ return matchers if matchers.length <= 1
45
+
46
+ set = Set.new
47
+ regexps = []
48
+ uncompactable = []
49
+
50
+ matchers = flatten(matchers)
51
+
52
+ matchers.each do |matcher|
53
+ case matcher
54
+ when nil then nil
55
+ when ::Integer, ::Symbol then set << matcher
56
+ # when ::Set then set.merge(matcher) # may not be necessary
57
+ when ::Regexp then regexps << matcher
58
+ else uncompactable << matcher
59
+ end
60
+ end
61
+
62
+ set = set.first if set.length <= 1
63
+ regexps = if regexps.length <= 1
64
+ regexps.first
65
+ else
66
+ Regexp.union(regexps)
67
+ end
68
+
69
+ [set, regexps].compact.concat(uncompactable)
70
+ end
71
+ end
72
+ end
73
+ end