leftovers 0.2.3 → 0.4.3

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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -0
  3. data/README.md +65 -49
  4. data/docs/Configuration.md +627 -0
  5. data/exe/leftovers +2 -2
  6. data/leftovers.gemspec +13 -6
  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 +126 -107
  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 +4 -8
  21. data/lib/config/will_paginate.yml +12 -14
  22. data/lib/leftovers.rb +66 -54
  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 +27 -15
  28. data/lib/leftovers/collector.rb +8 -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 +79 -61
  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 +29 -14
  82. data/lib/leftovers/parser.rb +1 -4
  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 +56 -4
  102. data/lib/leftovers/todo_reporter.rb +124 -0
  103. data/lib/leftovers/value_processors.rb +40 -0
  104. data/lib/leftovers/value_processors/add_dynamic_prefix.rb +31 -0
  105. data/lib/leftovers/value_processors/add_dynamic_suffix.rb +31 -0
  106. data/lib/leftovers/value_processors/add_prefix.rb +20 -0
  107. data/lib/leftovers/value_processors/add_suffix.rb +20 -0
  108. data/lib/leftovers/value_processors/camelize.rb +24 -0
  109. data/lib/leftovers/value_processors/capitalize.rb +19 -0
  110. data/lib/leftovers/value_processors/deconstantize.rb +24 -0
  111. data/lib/leftovers/value_processors/delete_after.rb +22 -0
  112. data/lib/leftovers/value_processors/delete_before.rb +22 -0
  113. data/lib/leftovers/value_processors/delete_prefix.rb +26 -0
  114. data/lib/leftovers/value_processors/delete_suffix.rb +26 -0
  115. data/lib/leftovers/value_processors/demodulize.rb +24 -0
  116. data/lib/leftovers/value_processors/downcase.rb +19 -0
  117. data/lib/leftovers/value_processors/each.rb +21 -0
  118. data/lib/leftovers/value_processors/each_for_definition_set.rb +29 -0
  119. data/lib/leftovers/value_processors/each_keyword.rb +27 -0
  120. data/lib/leftovers/value_processors/each_keyword_argument.rb +27 -0
  121. data/lib/leftovers/value_processors/each_positional_argument.rb +24 -0
  122. data/lib/leftovers/value_processors/itself.rb +17 -0
  123. data/lib/leftovers/value_processors/keyword.rb +36 -0
  124. data/lib/leftovers/value_processors/keyword_argument.rb +36 -0
  125. data/lib/leftovers/value_processors/parameterize.rb +24 -0
  126. data/lib/leftovers/value_processors/placeholder.rb +18 -0
  127. data/lib/leftovers/value_processors/pluralize.rb +24 -0
  128. data/lib/leftovers/value_processors/positional_argument.rb +26 -0
  129. data/lib/leftovers/value_processors/replace_value.rb +18 -0
  130. data/lib/leftovers/value_processors/return_definition.rb +26 -0
  131. data/lib/leftovers/value_processors/return_string.rb +14 -0
  132. data/lib/leftovers/value_processors/singularize.rb +24 -0
  133. data/lib/leftovers/value_processors/split.rb +22 -0
  134. data/lib/leftovers/value_processors/swapcase.rb +19 -0
  135. data/lib/leftovers/value_processors/titleize.rb +24 -0
  136. data/lib/leftovers/value_processors/underscore.rb +24 -0
  137. data/lib/leftovers/value_processors/upcase.rb +19 -0
  138. data/lib/leftovers/version.rb +1 -1
  139. metadata +201 -25
  140. data/lib/config/selenium.yml +0 -21
  141. data/lib/leftovers/argument_rule.rb +0 -219
  142. data/lib/leftovers/core_ext.rb +0 -13
  143. data/lib/leftovers/hash_rule.rb +0 -40
  144. data/lib/leftovers/name_rule.rb +0 -53
  145. data/lib/leftovers/rule.rb +0 -74
  146. data/lib/leftovers/transform_rule.rb +0 -171
  147. data/lib/leftovers/value_rule.rb +0 -56
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module Matchers
5
+ class NodeType
6
+ # :nocov:
7
+ using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
8
+ # :nocov:
9
+
10
+ def initialize(type_matcher)
11
+ @type_matcher = type_matcher
12
+
13
+ freeze
14
+ end
15
+
16
+ def ===(node)
17
+ @type_matcher === node.type
18
+ end
19
+
20
+ freeze
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,23 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module Matchers
5
+ class Not
6
+ # :nocov:
7
+ using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
8
+ # :nocov:
9
+
10
+ def initialize(matcher)
11
+ @matcher = matcher
12
+
13
+ freeze
14
+ end
15
+
16
+ def ===(value)
17
+ !(@matcher === value)
18
+ end
19
+
20
+ freeze
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,26 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module Matchers
5
+ class Or
6
+ # :nocov:
7
+ using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
8
+ # :nocov:
9
+
10
+ attr_reader :lhs, :rhs
11
+
12
+ def initialize(lhs, rhs)
13
+ @lhs = lhs
14
+ @rhs = rhs
15
+
16
+ freeze
17
+ end
18
+
19
+ def ===(value)
20
+ @lhs === value || @rhs === value
21
+ end
22
+
23
+ freeze
24
+ end
25
+ end
26
+ end
@@ -1,37 +1,48 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'set'
4
- require_relative 'config'
5
4
  require 'fast_ignore'
6
5
 
7
6
  module Leftovers
8
7
  class MergedConfig
9
- def initialize
8
+ def initialize(load_defaults: false)
10
9
  @configs = []
11
10
  @loaded_configs = Set.new
12
- self.<< Leftovers::Config.new(:ruby)
13
- self.<< project_config
11
+ return unless load_defaults
12
+
13
+ self << :ruby
14
+ self << project_config
15
+ self << project_todo
14
16
  load_bundled_gem_config
15
17
  end
16
18
 
17
19
  def <<(config)
20
+ config = Leftovers::Config.new(config) unless config.is_a?(Leftovers::Config)
18
21
  return if @loaded_configs.include?(config.name)
19
22
 
20
23
  unmemoize
21
24
  @configs << config
22
25
  @loaded_configs << config.name
23
- config.gems.each { |gem| self.<< Leftovers::Config.new(gem) }
26
+ config.gems.each { |gem| self << gem }
27
+ config.requires.each do |req|
28
+ Leftovers.try_require(req, message: "cannot require '#{req}' from #{config.name}.yml")
29
+ end
24
30
  end
25
31
 
26
32
  def project_config
27
33
  Leftovers::Config.new(:'.leftovers.yml', path: Leftovers.pwd + '.leftovers.yml')
28
34
  end
29
35
 
36
+ def project_todo
37
+ Leftovers::Config.new(:'.leftovers_todo.yml', path: Leftovers.pwd + '.leftovers_todo.yml')
38
+ end
39
+
30
40
  def unmemoize
31
41
  remove_instance_variable(:@exclude_paths) if defined?(@exclude_paths)
32
42
  remove_instance_variable(:@include_paths) if defined?(@include_paths)
33
43
  remove_instance_variable(:@test_paths) if defined?(@test_paths)
34
- remove_instance_variable(:@rules) if defined?(@rules)
44
+ remove_instance_variable(:@dynamic) if defined?(@dynamic)
45
+ remove_instance_variable(:@keep) if defined?(@keep)
35
46
  end
36
47
 
37
48
  def exclude_paths
@@ -45,26 +56,30 @@ module Leftovers
45
56
  def test_paths
46
57
  @test_paths ||= FastIgnore.new(
47
58
  include_rules: @configs.flat_map(&:test_paths),
48
- gitignore: false
59
+ gitignore: false,
60
+ root: Leftovers.pwd
49
61
  )
50
62
  end
51
63
 
52
- def skip_rules
53
- @skip_rules ||= rules.select(&:skip?)
64
+ def dynamic
65
+ @dynamic ||= ::Leftovers::ProcessorBuilders::EachDynamic.build(@configs.map(&:dynamic))
66
+ end
67
+
68
+ def keep
69
+ @keep ||= ::Leftovers::MatcherBuilders::Or.build(@configs.map(&:keep))
54
70
  end
55
71
 
56
- def rules
57
- @rules ||= @configs.flat_map(&:rules)
72
+ def test_only
73
+ @test_only ||= ::Leftovers::MatcherBuilders::Or.build(@configs.map(&:test_only))
58
74
  end
59
75
 
60
76
  private
61
77
 
62
78
  def load_bundled_gem_config
63
- Leftovers.try_require('bundler')
64
- return unless defined?(Bundler)
79
+ return unless Leftovers.try_require('bundler')
65
80
 
66
81
  Bundler.locked_gems.specs.each do |spec|
67
- self.<< Leftovers::Config.new(spec.name.to_sym)
82
+ self << spec.name
68
83
  end
69
84
  end
70
85
  end
@@ -3,9 +3,6 @@
3
3
  require 'parser'
4
4
  require 'parser/current'
5
5
 
6
- require_relative 'ast/builder'
7
- require_relative 'ast/node'
8
-
9
6
  module Leftovers
10
7
  module Parser
11
8
  class << self
@@ -23,7 +20,7 @@ module Leftovers
23
20
 
24
21
  # mostly copied from https://github.com/whitequark/parser/blob/master/lib/parser/base.rb
25
22
  # but with our builder
26
- def parser # rubocop:disable Metrics/MethodLength
23
+ def parser
27
24
  p = ::Parser::CurrentRuby.new(Leftovers::AST::Builder.new)
28
25
  p.diagnostics.all_errors_are_fatal = true
29
26
  p.diagnostics.ignore_warnings = true
@@ -0,0 +1,22 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ autoload(:Action, "#{__dir__}/processor_builders/action")
6
+ autoload(:AddPrefix, "#{__dir__}/processor_builders/add_prefix")
7
+ autoload(:AddSuffix, "#{__dir__}/processor_builders/add_suffix")
8
+ autoload(:Argument, "#{__dir__}/processor_builders/argument")
9
+ autoload(:Dynamic, "#{__dir__}/processor_builders/dynamic")
10
+ autoload(:EachAction, "#{__dir__}/processor_builders/each_action")
11
+ autoload(:EachDynamic, "#{__dir__}/processor_builders/each_dynamic")
12
+ autoload(:EachForDefinitionSet, "#{__dir__}/processor_builders/each_for_definition_set")
13
+ autoload(:Each, "#{__dir__}/processor_builders/each")
14
+ autoload(:Itself, "#{__dir__}/processor_builders/itself")
15
+ autoload(:Keyword, "#{__dir__}/processor_builders/keyword")
16
+ autoload(:KeywordArgument, "#{__dir__}/processor_builders/keyword_argument")
17
+ autoload(:TransformChain, "#{__dir__}/processor_builders/transform_chain")
18
+ autoload(:TransformSet, "#{__dir__}/processor_builders/transform_set")
19
+ autoload(:Transform, "#{__dir__}/processor_builders/transform")
20
+ autoload(:Value, "#{__dir__}/processor_builders/value")
21
+ end
22
+ end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module Action
6
+ def self.build(patterns, action)
7
+ ::Leftovers::ProcessorBuilders::EachAction.each_or_self(patterns) do |pattern|
8
+ case pattern
9
+ when ::String, ::Integer
10
+ ::Leftovers::ProcessorBuilders::Argument.build(pattern, final_transformer(action))
11
+ when ::Hash
12
+ build_from_hash_value(action, **pattern)
13
+ # :nocov:
14
+ else raise
15
+ # :nocov:
16
+ end
17
+ end
18
+ end
19
+
20
+ def self.final_transformer(action)
21
+ ::Leftovers::ProcessorBuilders::TransformSet.build_final(action)
22
+ end
23
+
24
+ def self.build_from_hash_value( # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
25
+ action,
26
+ arguments: nil,
27
+ keywords: nil,
28
+ itself: nil,
29
+ value: nil,
30
+ nested: nil,
31
+ recursive: nil,
32
+ **transform_args
33
+ )
34
+ transformer = ::Leftovers::ProcessorBuilders::TransformSet.build(transform_args, action)
35
+ if nested
36
+ transformer = ::Leftovers::ProcessorBuilders::Each.build([
37
+ ::Leftovers::ProcessorBuilders::Action.build(nested, action),
38
+ transformer
39
+ ])
40
+ end
41
+
42
+ if recursive
43
+ placeholder = ::Leftovers::ValueProcessors::Placeholder.new
44
+ transformer = ::Leftovers::ProcessorBuilders::Each.build(
45
+ [placeholder, transformer]
46
+ )
47
+ end
48
+
49
+ processor = ::Leftovers::ProcessorBuilders::EachAction.build([
50
+ ::Leftovers::ProcessorBuilders::Argument.build(arguments, transformer),
51
+ ::Leftovers::ProcessorBuilders::Keyword.build(keywords, transformer),
52
+ ::Leftovers::ProcessorBuilders::Itself.build(itself, transformer),
53
+ ::Leftovers::ProcessorBuilders::Value.build(value, transformer)
54
+ ])
55
+
56
+ return processor unless recursive
57
+
58
+ placeholder.processor = processor
59
+ placeholder
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module AddPrefix
6
+ def self.build(argument, then_processor)
7
+ case argument
8
+ when ::Hash
9
+ dynamic_prefix = ::Leftovers::ProcessorBuilders::Action.build(argument, :call)
10
+ ::Leftovers::ValueProcessors::AddDynamicPrefix.new(dynamic_prefix, then_processor)
11
+ when ::String
12
+ ::Leftovers::ValueProcessors::AddPrefix.new(argument, then_processor)
13
+ # :nocov:
14
+ else raise
15
+ # :nocov:
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module AddSuffix
6
+ def self.build(argument, then_processor)
7
+ case argument
8
+ when ::Hash
9
+ dynamic_suffix = ::Leftovers::ProcessorBuilders::Action.build(argument, :call)
10
+ ::Leftovers::ValueProcessors::AddDynamicSuffix.new(dynamic_suffix, then_processor)
11
+ when ::String
12
+ ::Leftovers::ValueProcessors::AddSuffix.new(argument, then_processor)
13
+ # :nocov:
14
+ else raise
15
+ # :nocov:
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module Argument
6
+ def self.build(patterns, then_processor) # rubocop:disable Metrics/MethodLength
7
+ ::Leftovers::ProcessorBuilders::EachAction.each_or_self(patterns) do |pattern|
8
+ case pattern
9
+ when ::Integer
10
+ ::Leftovers::ValueProcessors::PositionalArgument.new(pattern, then_processor)
11
+ when '*'
12
+ ::Leftovers::ValueProcessors::EachPositionalArgument.new(then_processor)
13
+ when '**'
14
+ ::Leftovers::ValueProcessors::EachKeywordArgument.new(then_processor)
15
+ when ::String, ::Hash
16
+ ::Leftovers::ProcessorBuilders::KeywordArgument.build(pattern, then_processor)
17
+ # :nocov:
18
+ else raise
19
+ # :nocov:
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
25
+ end
@@ -0,0 +1,27 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module Dynamic
6
+ def self.build(dynamic_rules) # rubocop:disable Metrics/MethodLength
7
+ ::Leftovers::ProcessorBuilders::EachDynamic.each_or_self(dynamic_rules) do |dynamic|
8
+ call = ::Leftovers::ProcessorBuilders::Action.build(dynamic.delete(:call), :call)
9
+ define = ::Leftovers::ProcessorBuilders::Action.build(dynamic.delete(:define), :define)
10
+ matcher = ::Leftovers::MatcherBuilders::Node.build(**dynamic)
11
+
12
+ # this nonsense saves a method call and array instantiation per method
13
+ if call && define
14
+ ::Leftovers::DynamicProcessors::CallDefinition.new(matcher, call, define)
15
+ elsif define
16
+ ::Leftovers::DynamicProcessors::Definition.new(matcher, define)
17
+ elsif call
18
+ ::Leftovers::DynamicProcessors::Call.new(matcher, call)
19
+ # :nocov:
20
+ else raise
21
+ # :nocov:
22
+ end
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module Each
6
+ def self.each_or_self(value, &block)
7
+ case value
8
+ # :nocov:
9
+ when nil then raise
10
+ # :nocov:
11
+ when Array then build(value.map(&block))
12
+ else build([yield(value)])
13
+ end
14
+ end
15
+
16
+ def self.build(processors)
17
+ processors = compact(processors)
18
+
19
+ case processors.length
20
+ # :nocov:
21
+ when 0 then raise
22
+ # :nocov:
23
+ when 1 then processors.first
24
+ else ::Leftovers::ValueProcessors::Each.new(processors)
25
+ end
26
+ end
27
+
28
+ def self.compact(processors)
29
+ processors.flatten!
30
+ processors.compact!
31
+
32
+ processors
33
+ end
34
+ end
35
+ end
36
+ end
@@ -0,0 +1,51 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module EachAction
6
+ def self.each_or_self(value, &block)
7
+ case value
8
+ when nil then nil
9
+ when Array then build(value.map(&block))
10
+ else build([yield(value)])
11
+ end
12
+ end
13
+
14
+ def self.build(processors)
15
+ processors = compact(processors)
16
+
17
+ case processors.length
18
+ # :nocov:
19
+ when 0 then raise
20
+ # :nocov:
21
+ when 1 then processors.first
22
+ else ::Leftovers::ValueProcessors::Each.new(processors)
23
+ end
24
+ end
25
+
26
+ def self.flatten(value) # rubocop:disable Metrics/MethodLength
27
+ case value
28
+ when ::Leftovers::ValueProcessors::Each
29
+ ret = value.processors.map { |v| flatten(v) }
30
+ ret.flatten!(1)
31
+ ret
32
+ when Array
33
+ ret = value.map { |v| flatten(v) }
34
+ ret.flatten!(1)
35
+ ret
36
+ else
37
+ value
38
+ end
39
+ end
40
+
41
+ def self.compact(processors)
42
+ return processors if processors.length <= 1
43
+
44
+ processors = flatten(processors)
45
+ processors.compact!
46
+
47
+ processors
48
+ end
49
+ end
50
+ end
51
+ end