leftovers 0.2.0 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
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
@@ -1,26 +1,31 @@
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
14
15
  load_bundled_gem_config
15
16
  end
16
17
 
17
18
  def <<(config)
19
+ config = Leftovers::Config.new(config) unless config.is_a?(Leftovers::Config)
18
20
  return if @loaded_configs.include?(config.name)
19
21
 
20
22
  unmemoize
21
23
  @configs << config
22
24
  @loaded_configs << config.name
23
- config.gems.each { |gem| self.<< Leftovers::Config.new(gem) }
25
+ config.gems.each { |gem| self << gem }
26
+ config.requires.each do |req|
27
+ Leftovers.try_require(req, message: "cannot require '#{req}' from #{config.name}.yml")
28
+ end
24
29
  end
25
30
 
26
31
  def project_config
@@ -31,7 +36,8 @@ module Leftovers
31
36
  remove_instance_variable(:@exclude_paths) if defined?(@exclude_paths)
32
37
  remove_instance_variable(:@include_paths) if defined?(@include_paths)
33
38
  remove_instance_variable(:@test_paths) if defined?(@test_paths)
34
- remove_instance_variable(:@rules) if defined?(@rules)
39
+ remove_instance_variable(:@dynamic) if defined?(@dynamic)
40
+ remove_instance_variable(:@keep) if defined?(@keep)
35
41
  end
36
42
 
37
43
  def exclude_paths
@@ -45,26 +51,26 @@ module Leftovers
45
51
  def test_paths
46
52
  @test_paths ||= FastIgnore.new(
47
53
  include_rules: @configs.flat_map(&:test_paths),
48
- gitignore: false
54
+ gitignore: false,
55
+ root: Leftovers.pwd
49
56
  )
50
57
  end
51
58
 
52
- def skip_rules
53
- @skip_rules ||= rules.select(&:skip?)
59
+ def dynamic
60
+ @dynamic ||= ::Leftovers::ProcessorBuilders::EachDynamic.build(@configs.map(&:dynamic))
54
61
  end
55
62
 
56
- def rules
57
- @rules ||= @configs.flat_map(&:rules)
63
+ def keep
64
+ @keep ||= ::Leftovers::MatcherBuilders::Or.build(@configs.map(&:keep))
58
65
  end
59
66
 
60
67
  private
61
68
 
62
69
  def load_bundled_gem_config
63
- Leftovers.try_require('bundler')
64
- return unless defined?(Bundler)
70
+ return unless Leftovers.try_require('bundler')
65
71
 
66
72
  Bundler.locked_gems.specs.each do |spec|
67
- self.<< Leftovers::Config.new(spec.name.to_sym)
73
+ self << spec.name
68
74
  end
69
75
  end
70
76
  end
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'parser'
4
+ require 'parser/current'
5
+
6
+ module Leftovers
7
+ module Parser
8
+ class << self
9
+ # mostly copied from https://github.com/whitequark/parser/blob/master/lib/parser/base.rb
10
+ # but with our parser
11
+ def parse_with_comments(string, file = '(string)', line = 1)
12
+ PARSER.reset
13
+ source_buffer = ::Parser::CurrentRuby.send(
14
+ :setup_source_buffer, file, line, string, PARSER.default_encoding
15
+ )
16
+ PARSER.parse_with_comments(source_buffer)
17
+ end
18
+
19
+ private
20
+
21
+ # mostly copied from https://github.com/whitequark/parser/blob/master/lib/parser/base.rb
22
+ # but with our builder
23
+ def parser
24
+ p = ::Parser::CurrentRuby.new(Leftovers::AST::Builder.new)
25
+ p.diagnostics.all_errors_are_fatal = true
26
+ p.diagnostics.ignore_warnings = true
27
+
28
+ p.diagnostics.consumer = lambda do |diagnostic|
29
+ diagnostic
30
+ end
31
+
32
+ p
33
+ end
34
+ end
35
+ PARSER = parser
36
+ end
37
+ end
@@ -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
@@ -0,0 +1,54 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module EachDynamic
6
+ def self.each_or_self(value, &block)
7
+ case value
8
+ when nil then ::Leftovers::DynamicProcessors::Null
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::DynamicProcessors::Each.new(processors)
23
+ end
24
+ end
25
+
26
+ def self.flatten(value) # rubocop:disable Metrics/MethodLength
27
+ case value
28
+ when ::Leftovers::DynamicProcessors::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
+
46
+ processors.reject! do |p|
47
+ p == ::Leftovers::DynamicProcessors::Null
48
+ end
49
+
50
+ processors
51
+ end
52
+ end
53
+ end
54
+ end