leftovers 0.5.5 → 0.8.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +40 -2
  3. data/README.md +22 -1
  4. data/docs/Configuration.md +173 -42
  5. data/docs/Custom-Precompilers.md +38 -0
  6. data/leftovers.gemspec +8 -5
  7. data/lib/config/actionmailer.yml +11 -11
  8. data/lib/config/actionpack.yml +5 -3
  9. data/lib/config/activesupport.yml +1 -1
  10. data/lib/config/haml.yml +4 -2
  11. data/lib/config/rails.yml +1 -1
  12. data/lib/config/railties.yml +11 -0
  13. data/lib/config/ruby.yml +76 -8
  14. data/lib/config/slim.yml +4 -2
  15. data/lib/leftovers/ast/node.rb +16 -11
  16. data/lib/leftovers/cli.rb +5 -0
  17. data/lib/leftovers/collector.rb +5 -2
  18. data/lib/leftovers/config.rb +3 -38
  19. data/lib/leftovers/config_loader/argument_position_schema.rb +11 -0
  20. data/lib/leftovers/config_loader/argumentless_transform_schema.rb +21 -0
  21. data/lib/leftovers/config_loader/attribute.rb +56 -0
  22. data/lib/leftovers/config_loader/built_in_precompiler_schema.rb +13 -0
  23. data/lib/leftovers/config_loader/document_schema.rb +48 -0
  24. data/lib/leftovers/config_loader/dynamic_schema.rb +17 -0
  25. data/lib/leftovers/config_loader/has_argument_schema.rb +13 -0
  26. data/lib/leftovers/config_loader/has_value_schema.rb +18 -0
  27. data/lib/leftovers/config_loader/inherit_schema_attributes.rb +22 -0
  28. data/lib/leftovers/config_loader/keep_test_only_schema.rb +13 -0
  29. data/lib/leftovers/config_loader/node.rb +106 -0
  30. data/lib/leftovers/config_loader/object_schema.rb +117 -0
  31. data/lib/leftovers/config_loader/precompile_schema.rb +12 -0
  32. data/lib/leftovers/config_loader/precompiler_schema.rb +11 -0
  33. data/lib/leftovers/config_loader/privacy_processor_schema.rb +10 -0
  34. data/lib/leftovers/config_loader/privacy_schema.rb +15 -0
  35. data/lib/leftovers/config_loader/require_schema.rb +11 -0
  36. data/lib/leftovers/config_loader/rule_pattern_schema.rb +18 -0
  37. data/lib/leftovers/config_loader/scalar_argument_schema.rb +14 -0
  38. data/lib/leftovers/config_loader/scalar_value_schema.rb +14 -0
  39. data/lib/leftovers/config_loader/schema.rb +23 -0
  40. data/lib/leftovers/config_loader/string_enum_schema.rb +62 -0
  41. data/lib/leftovers/config_loader/string_pattern_schema.rb +14 -0
  42. data/lib/leftovers/config_loader/string_schema.rb +14 -0
  43. data/lib/leftovers/config_loader/string_value_processor_schema.rb +11 -0
  44. data/lib/leftovers/config_loader/suggester.rb +22 -0
  45. data/lib/leftovers/config_loader/transform_schema.rb +26 -0
  46. data/lib/leftovers/config_loader/true_schema.rb +18 -0
  47. data/lib/leftovers/config_loader/value_matcher_schema.rb +18 -0
  48. data/lib/leftovers/config_loader/value_or_array_schema.rb +66 -0
  49. data/lib/leftovers/config_loader/value_or_object_schema.rb +40 -0
  50. data/lib/leftovers/config_loader/value_processor_schema.rb +14 -0
  51. data/lib/leftovers/config_loader/value_type_schema.rb +17 -0
  52. data/lib/leftovers/config_loader.rb +86 -0
  53. data/lib/leftovers/definition.rb +1 -1
  54. data/lib/leftovers/definition_node.rb +6 -17
  55. data/lib/leftovers/definition_node_set.rb +11 -0
  56. data/lib/leftovers/definition_to_add.rb +31 -0
  57. data/lib/leftovers/dynamic_processors/call.rb +4 -7
  58. data/lib/leftovers/dynamic_processors/call_definition.rb +14 -11
  59. data/lib/leftovers/dynamic_processors/definition.rb +8 -7
  60. data/lib/leftovers/dynamic_processors/set_default_privacy.rb +18 -0
  61. data/lib/leftovers/dynamic_processors/set_privacy.rb +23 -0
  62. data/lib/leftovers/dynamic_processors.rb +2 -0
  63. data/lib/leftovers/file.rb +12 -12
  64. data/lib/leftovers/file_collector/comments_processor.rb +57 -0
  65. data/lib/leftovers/file_collector/node_processor.rb +131 -0
  66. data/lib/leftovers/file_collector.rb +66 -169
  67. data/lib/leftovers/matcher_builders/and_not.rb +7 -5
  68. data/lib/leftovers/matcher_builders/document.rb +13 -0
  69. data/lib/leftovers/matcher_builders/name.rb +18 -17
  70. data/lib/leftovers/matcher_builders/node.rb +48 -28
  71. data/lib/leftovers/matcher_builders/node_has_argument.rb +48 -53
  72. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +13 -10
  73. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +29 -15
  74. data/lib/leftovers/matcher_builders/node_privacy.rb +13 -0
  75. data/lib/leftovers/matcher_builders/node_type.rb +4 -4
  76. data/lib/leftovers/matcher_builders/node_value.rb +28 -23
  77. data/lib/leftovers/matcher_builders/or.rb +50 -50
  78. data/lib/leftovers/matcher_builders/string_pattern.rb +14 -5
  79. data/lib/leftovers/matcher_builders.rb +2 -0
  80. data/lib/leftovers/matchers/all.rb +0 -4
  81. data/lib/leftovers/matchers/and.rb +0 -4
  82. data/lib/leftovers/matchers/any.rb +0 -4
  83. data/lib/leftovers/matchers/node_has_any_keyword_argument.rb +1 -7
  84. data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +1 -7
  85. data/lib/leftovers/matchers/node_has_positional_argument_with_value.rb +0 -4
  86. data/lib/leftovers/matchers/node_name.rb +0 -4
  87. data/lib/leftovers/matchers/node_pair_value.rb +0 -4
  88. data/lib/leftovers/matchers/node_path.rb +0 -4
  89. data/lib/leftovers/matchers/node_privacy.rb +19 -0
  90. data/lib/leftovers/matchers/node_scalar_value.rb +0 -4
  91. data/lib/leftovers/matchers/node_type.rb +0 -4
  92. data/lib/leftovers/matchers/not.rb +0 -4
  93. data/lib/leftovers/matchers/or.rb +0 -4
  94. data/lib/leftovers/matchers.rb +1 -0
  95. data/lib/leftovers/merged_config.rb +15 -33
  96. data/lib/leftovers/precompilers/erb.rb +22 -0
  97. data/lib/leftovers/precompilers/haml.rb +15 -0
  98. data/lib/leftovers/precompilers/json.rb +27 -0
  99. data/lib/leftovers/precompilers/precompiler.rb +28 -0
  100. data/lib/leftovers/precompilers/slim.rb +15 -0
  101. data/lib/leftovers/precompilers/yaml.rb +75 -0
  102. data/lib/leftovers/precompilers.rb +50 -0
  103. data/lib/leftovers/processor_builders/action.rb +48 -39
  104. data/lib/leftovers/processor_builders/add_prefix.rb +2 -2
  105. data/lib/leftovers/processor_builders/add_suffix.rb +2 -2
  106. data/lib/leftovers/processor_builders/argument.rb +8 -11
  107. data/lib/leftovers/processor_builders/dynamic.rb +51 -16
  108. data/lib/leftovers/processor_builders/each.rb +2 -2
  109. data/lib/leftovers/processor_builders/each_action.rb +33 -33
  110. data/lib/leftovers/processor_builders/each_dynamic.rb +4 -8
  111. data/lib/leftovers/processor_builders/each_for_definition_set.rb +25 -21
  112. data/lib/leftovers/processor_builders/keyword.rb +3 -4
  113. data/lib/leftovers/processor_builders/transform.rb +4 -4
  114. data/lib/leftovers/processor_builders/transform_chain.rb +16 -8
  115. data/lib/leftovers/processor_builders/transform_set.rb +32 -28
  116. data/lib/leftovers/rake_task.rb +1 -1
  117. data/lib/leftovers/todo_reporter.rb +10 -35
  118. data/lib/leftovers/value_processors/add_dynamic_prefix.rb +3 -10
  119. data/lib/leftovers/value_processors/add_dynamic_suffix.rb +3 -10
  120. data/lib/leftovers/value_processors/delete_prefix.rb +0 -6
  121. data/lib/leftovers/value_processors/delete_suffix.rb +0 -6
  122. data/lib/leftovers/value_processors/each.rb +1 -1
  123. data/lib/leftovers/value_processors/each_for_definition_set.rb +4 -10
  124. data/lib/leftovers/value_processors/each_keyword.rb +1 -1
  125. data/lib/leftovers/value_processors/each_keyword_argument.rb +1 -1
  126. data/lib/leftovers/value_processors/each_positional_argument.rb +3 -2
  127. data/lib/leftovers/value_processors/keyword.rb +3 -11
  128. data/lib/leftovers/value_processors/keyword_argument.rb +2 -10
  129. data/lib/leftovers/value_processors/return_definition_node.rb +14 -0
  130. data/lib/leftovers/value_processors/{return_string.rb → return_sym.rb} +1 -1
  131. data/lib/leftovers/value_processors/split.rb +2 -2
  132. data/lib/leftovers/value_processors.rb +2 -2
  133. data/lib/leftovers/version.rb +1 -1
  134. data/lib/leftovers.rb +66 -23
  135. metadata +98 -39
  136. data/lib/config/actioncable.yml +0 -4
  137. data/lib/leftovers/backports.rb +0 -40
  138. data/lib/leftovers/config_validator/error_processor.rb +0 -196
  139. data/lib/leftovers/config_validator/schema_hash.rb +0 -530
  140. data/lib/leftovers/config_validator.rb +0 -60
  141. data/lib/leftovers/erb.rb +0 -20
  142. data/lib/leftovers/haml.rb +0 -21
  143. data/lib/leftovers/slim.rb +0 -21
  144. data/lib/leftovers/value_processors/return_definition.rb +0 -26
@@ -3,43 +3,47 @@
3
3
  module Leftovers
4
4
  module ProcessorBuilders
5
5
  module TransformSet
6
- def self.build(transforms, action)
7
- each_builder(action).each_or_self(transforms) do |transform|
8
- case transform
9
- when ::Hash
10
- next build(transform[:transforms], action) if transform[:transforms]
6
+ class << self
7
+ def build(transforms, action)
8
+ each_builder(action).each_or_self(transforms) do |transform|
9
+ case transform
10
+ when ::Hash
11
+ next build(transform[:transforms], action) if transform[:transforms]
11
12
 
12
- ::Leftovers::ProcessorBuilders::TransformChain.build(transform, build_final(action))
13
- when ::String
14
- ::Leftovers::ProcessorBuilders::TransformChain.build(transform, build_final(action))
15
- # :nocov:
16
- else raise
13
+ ::Leftovers::ProcessorBuilders::TransformChain.build(transform, build_final(action))
14
+ when ::String
15
+ ::Leftovers::ProcessorBuilders::TransformChain.build(transform, build_final(action))
17
16
  # :nocov:
17
+ else raise Leftovers::UnexpectedCase, "Unhandled value #{transform.inspect}"
18
+ # :nocov:
19
+ end
18
20
  end
19
21
  end
20
- end
21
22
 
22
- def self.each_builder(action)
23
- case action
24
- when :call
25
- ::Leftovers::ProcessorBuilders::Each
26
- when :define
27
- ::Leftovers::ProcessorBuilders::EachForDefinitionSet
28
- # :nocov:
29
- else raise
23
+ def build_final(action)
24
+ case action
25
+ when :sym
26
+ ::Leftovers::ValueProcessors::ReturnSym
27
+ when :definition_node
28
+ ::Leftovers::ValueProcessors::ReturnDefinitionNode
30
29
  # :nocov:
30
+ else raise Leftovers::UnexpectedCase, "Unhandled value #{action.inspect}"
31
+ # :nocov:
32
+ end
31
33
  end
32
- end
33
34
 
34
- def self.build_final(action)
35
- case action
36
- when :call
37
- ::Leftovers::ValueProcessors::ReturnString
38
- when :define
39
- ::Leftovers::ValueProcessors::ReturnDefinition
40
- # :nocov:
41
- else raise
35
+ private
36
+
37
+ def each_builder(action)
38
+ case action
39
+ when :sym
40
+ ::Leftovers::ProcessorBuilders::Each
41
+ when :definition_node
42
+ ::Leftovers::ProcessorBuilders::EachForDefinitionSet
42
43
  # :nocov:
44
+ else raise Leftovers::UnexpectedCase, "Unhandled value #{action.inspect}"
45
+ # :nocov:
46
+ end
43
47
  end
44
48
  end
45
49
  end
@@ -8,7 +8,7 @@ module Leftovers
8
8
  class RakeTask
9
9
  include ::Rake::DSL
10
10
 
11
- def self.generate_task(name = :leftovers, *default_argv) # rubocop:disable
11
+ def self.generate_task(name = :leftovers, *default_argv)
12
12
  new(name, default_argv)
13
13
 
14
14
  name
@@ -64,54 +64,29 @@ module Leftovers
64
64
  end
65
65
 
66
66
  def todo_data(only_test, none)
67
- none_test = none.select(&:test?)
68
- none_non_test = none.reject(&:test?)
69
67
  [
70
- test_only_data(none_test),
71
- keep_data(only_test, none_non_test)
68
+ list_data(
69
+ :test_only, 'Only directly called in tests', only_test
70
+ ),
71
+ list_data(
72
+ :keep, 'Not directly called at all', none
73
+ )
72
74
  ].compact.join
73
75
  end
74
76
 
75
- def test_only_data(list)
77
+ def list_data(key, title, list)
76
78
  return if list.empty?
77
79
 
78
80
  <<~YML
79
- test_only:
80
- #{generate_list('Defined in tests:', list).chomp}
81
- YML
82
- end
83
-
84
- def keep_data(only_test, none_non_test)
85
- return if only_test.empty? && none_non_test.empty?
86
-
87
- <<~YML.chomp
88
- keep:
89
- #{keep_test_called_data(only_test)}#{keep_never_called_data(none_non_test)}
90
- YML
91
- end
92
-
93
- def keep_test_called_data(list)
94
- return if list.empty?
95
-
96
- generate_list('Only directly called in tests:', list)
97
- end
98
-
99
- def keep_never_called_data(list)
100
- return if list.empty?
101
-
102
- generate_list('Not directly called at all:', list)
103
- end
104
-
105
- def generate_list(title, list)
106
- <<~YML
107
- # #{title}
81
+ #{key}:
82
+ # #{title}:
108
83
  #{print_definition_list(list)}
109
84
 
110
85
  YML
111
86
  end
112
87
 
113
88
  def print_definition_list(definition_list)
114
- definition_list.map { |definition| print_definition(definition) }.join("\n")
89
+ definition_list.map { |definition| print_definition(definition) }.sort.join("\n")
115
90
  end
116
91
 
117
92
  def print_definition(definition)
@@ -10,20 +10,13 @@ module Leftovers
10
10
  freeze
11
11
  end
12
12
 
13
- def process(str, node, method_node) # rubocop:disable Metrics/MethodLength
13
+ def process(str, node, method_node)
14
14
  return unless str
15
15
 
16
16
  prefixes = @prefix_processor.process(nil, method_node, method_node)
17
- if prefixes.is_a?(Array)
18
- prefixes.flatten!
19
- prefixes.compact!
20
- prefixes.uniq!
21
17
 
22
- prefixes.map do |prefix|
23
- @then_processor.process("#{prefix}#{str}", node, method_node)
24
- end
25
- else
26
- @then_processor.process("#{prefixes}#{str}", node, method_node)
18
+ Leftovers.map_or_self(prefixes) do |prefix|
19
+ @then_processor.process("#{prefix}#{str}", node, method_node)
27
20
  end
28
21
  end
29
22
  end
@@ -10,20 +10,13 @@ module Leftovers
10
10
  freeze
11
11
  end
12
12
 
13
- def process(str, node, method_node) # rubocop:disable Metrics/MethodLength
13
+ def process(str, node, method_node)
14
14
  return unless str
15
15
 
16
16
  suffixes = @suffix_processor.process(nil, method_node, method_node)
17
- if suffixes.is_a?(Array)
18
- suffixes.flatten!
19
- suffixes.compact!
20
- suffixes.uniq!
21
17
 
22
- suffixes.map do |suffix|
23
- @then_processor.process("#{str}#{suffix}", node, method_node)
24
- end
25
- else
26
- @then_processor.process("#{str}#{suffixes}", node, method_node)
18
+ Leftovers.map_or_self(suffixes) do |suffix|
19
+ @then_processor.process("#{str}#{suffix}", node, method_node)
27
20
  end
28
21
  end
29
22
  end
@@ -3,12 +3,6 @@
3
3
  module Leftovers
4
4
  module ValueProcessors
5
5
  class DeletePrefix
6
- # :nocov:
7
- if defined?(::Leftovers::Backports::StringDeletePrefixSuffix)
8
- using ::Leftovers::Backports::StringDeletePrefixSuffix
9
- end
10
- # :nocov:
11
-
12
6
  def initialize(prefix, then_processor)
13
7
  @prefix = prefix
14
8
  @then_processor = then_processor
@@ -3,12 +3,6 @@
3
3
  module Leftovers
4
4
  module ValueProcessors
5
5
  class DeleteSuffix
6
- # :nocov:
7
- if defined?(::Leftovers::Backports::StringDeletePrefixSuffix)
8
- using ::Leftovers::Backports::StringDeletePrefixSuffix
9
- end
10
- # :nocov:
11
-
12
6
  def initialize(suffix, then_processor)
13
7
  @suffix = suffix
14
8
  @then_processor = then_processor
@@ -12,7 +12,7 @@ module Leftovers
12
12
  end
13
13
 
14
14
  def process(str, node, method_node)
15
- @processors.flat_map do |processor|
15
+ Leftovers.map_or_self(@processors) do |processor|
16
16
  processor.process(str, node, method_node)
17
17
  end
18
18
  end
@@ -10,19 +10,13 @@ module Leftovers
10
10
  end
11
11
 
12
12
  def process(str, node, method_node)
13
- definitions = @then_processors.map do |then_processor|
14
- processed = then_processor.process(str, node, method_node)
15
- return if processed == :keep # rubocop:disable Lint/NonLocalExitFromIterator
16
-
17
- processed
13
+ definitions = Leftovers.map_or_self(@then_processors) do |then_processor|
14
+ then_processor.process(str, node, method_node)
18
15
  end
19
16
 
20
- definitions.flatten!
21
- definitions.compact!
22
-
23
- return definitions.first if definitions.length <= 1
17
+ return definitions unless definitions.is_a?(Array)
24
18
 
25
- ::Leftovers::DefinitionSet.new(definitions)
19
+ ::Leftovers::DefinitionNodeSet.new(definitions)
26
20
  end
27
21
  end
28
22
  end
@@ -13,7 +13,7 @@ module Leftovers
13
13
  kwargs = node.kwargs
14
14
  return unless kwargs
15
15
 
16
- kwargs.children.map do |pair|
16
+ Leftovers.map_or_self(kwargs.children) do |pair|
17
17
  next unless pair.type == :pair
18
18
 
19
19
  argument_node = pair.first
@@ -13,7 +13,7 @@ module Leftovers
13
13
  kwargs = node.kwargs
14
14
  return unless kwargs
15
15
 
16
- kwargs.children.map do |pair|
16
+ Leftovers.map_or_self(kwargs.children) do |pair|
17
17
  next unless pair.type == :pair
18
18
 
19
19
  argument_node = pair.second
@@ -11,10 +11,11 @@ module Leftovers
11
11
 
12
12
  def process(_str, node, method_node)
13
13
  positional_arguments = node.positional_arguments
14
+
14
15
  return unless positional_arguments
15
16
 
16
- positional_arguments.map do |argument_node|
17
- str = argument_node.to_s if argument_node.string_or_symbol?
17
+ Leftovers.map_or_self(positional_arguments) do |argument_node|
18
+ str = argument_node.to_s if argument_node.string_or_symbol_or_def?
18
19
 
19
20
  @then_processor.process(str, argument_node, method_node)
20
21
  end
@@ -3,10 +3,6 @@
3
3
  module Leftovers
4
4
  module ValueProcessors
5
5
  class Keyword
6
- # :nocov:
7
- using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
8
- # :nocov:
9
-
10
6
  def initialize(matcher, then_processor)
11
7
  @matcher = matcher
12
8
  @then_processor = then_processor
@@ -18,18 +14,14 @@ module Leftovers
18
14
  kwargs = node.kwargs
19
15
  return unless kwargs
20
16
 
21
- result = []
22
-
23
- kwargs.children.each do |pair|
17
+ Leftovers.map_or_self(kwargs.children) do |pair|
24
18
  next unless @matcher === pair
25
19
 
26
20
  argument_node = pair.first
27
- str = argument_node.to_s
21
+ str = argument_node.to_s if argument_node.string_or_symbol?
28
22
 
29
- result << @then_processor.process(str, argument_node, method_node)
23
+ @then_processor.process(str, argument_node, method_node)
30
24
  end
31
-
32
- result
33
25
  end
34
26
  end
35
27
  end
@@ -3,10 +3,6 @@
3
3
  module Leftovers
4
4
  module ValueProcessors
5
5
  class KeywordArgument
6
- # :nocov:
7
- using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
8
- # :nocov:
9
-
10
6
  def initialize(matcher, then_processor)
11
7
  @matcher = matcher
12
8
  @then_processor = then_processor
@@ -18,18 +14,14 @@ module Leftovers
18
14
  kwargs = node.kwargs
19
15
  return unless kwargs
20
16
 
21
- result = []
22
-
23
- kwargs.children.each do |pair|
17
+ Leftovers.map_or_self(kwargs.children) do |pair|
24
18
  next unless @matcher === pair
25
19
 
26
20
  argument_node = pair.second
27
21
  str = argument_node.to_s if argument_node.string_or_symbol?
28
22
 
29
- result << @then_processor.process(str, argument_node, method_node)
23
+ @then_processor.process(str, argument_node, method_node)
30
24
  end
31
-
32
- result
33
25
  end
34
26
  end
35
27
  end
@@ -0,0 +1,14 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module ValueProcessors
5
+ module ReturnDefinitionNode
6
+ def self.process(str, node, _method_node)
7
+ return unless str
8
+ return if str.empty?
9
+
10
+ Leftovers::DefinitionNode.new(node, name: str.to_sym)
11
+ end
12
+ end
13
+ end
14
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  module Leftovers
4
4
  module ValueProcessors
5
- module ReturnString
5
+ module ReturnSym
6
6
  def self.process(str, _node, _method_node)
7
7
  return unless str
8
8
  return if str.empty?
@@ -13,8 +13,8 @@ module Leftovers
13
13
  def process(str, node, method_node)
14
14
  return unless str
15
15
 
16
- str.split(@split_on).map do |substring|
17
- @then_processor.process(substring, node, method_node)
16
+ Leftovers.map_or_self(str.split(@split_on)) do |sub_str|
17
+ @then_processor.process(sub_str, node, method_node)
18
18
  end
19
19
  end
20
20
  end
@@ -28,8 +28,8 @@ module Leftovers
28
28
  autoload(:Pluralize, "#{__dir__}/value_processors/pluralize")
29
29
  autoload(:PositionalArgument, "#{__dir__}/value_processors/positional_argument")
30
30
  autoload(:ReplaceValue, "#{__dir__}/value_processors/replace_value")
31
- autoload(:ReturnDefinition, "#{__dir__}/value_processors/return_definition")
32
- autoload(:ReturnString, "#{__dir__}/value_processors/return_string")
31
+ autoload(:ReturnDefinitionNode, "#{__dir__}/value_processors/return_definition_node")
32
+ autoload(:ReturnSym, "#{__dir__}/value_processors/return_sym")
33
33
  autoload(:Singularize, "#{__dir__}/value_processors/singularize")
34
34
  autoload(:Split, "#{__dir__}/value_processors/split")
35
35
  autoload(:Swapcase, "#{__dir__}/value_processors/swapcase")
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leftovers
4
- VERSION = '0.5.5'
4
+ VERSION = '0.8.0'
5
5
  end
data/lib/leftovers.rb CHANGED
@@ -1,35 +1,68 @@
1
1
  # frozen_string_literal: true
2
2
 
3
+ require 'parser'
4
+ require 'parser/current' # to get the error message early and once.
5
+
3
6
  module Leftovers # rubocop:disable Metrics/ModuleLength
4
7
  class Error < ::StandardError; end
8
+ class UnexpectedCase < Error; end
9
+
10
+ class PrecompileError < Error
11
+ attr_reader :line, :column
12
+
13
+ def initialize(message, line: nil, column: nil)
14
+ @line = line
15
+ @column = column
16
+ super(message)
17
+ end
18
+
19
+ def warn(path:)
20
+ line_column = ":#{line}#{":#{column}" if column}" if line
21
+ klass = cause ? cause.class : self.class
22
+
23
+ Leftovers.warn "#{klass}: #{path}#{line_column} #{message}"
24
+ end
25
+ end
5
26
 
6
27
  autoload(:AST, "#{__dir__}/leftovers/ast")
7
- autoload(:Backports, "#{__dir__}/leftovers/backports")
8
28
  autoload(:CLI, "#{__dir__}/leftovers/cli")
9
29
  autoload(:Collector, "#{__dir__}/leftovers/collector")
10
- autoload(:ConfigValidator, "#{__dir__}/leftovers/config_validator")
30
+ autoload(:ConfigLoader, "#{__dir__}/leftovers/config_loader")
11
31
  autoload(:Config, "#{__dir__}/leftovers/config")
32
+ autoload(:Definition, "#{__dir__}/leftovers/definition")
12
33
  autoload(:DefinitionNode, "#{__dir__}/leftovers/definition_node")
34
+ autoload(:DefinitionNodeSet, "#{__dir__}/leftovers/definition_node_set")
13
35
  autoload(:DefinitionSet, "#{__dir__}/leftovers/definition_set")
14
- autoload(:Definition, "#{__dir__}/leftovers/definition")
15
- autoload(:ERB, "#{__dir__}/leftovers/erb")
36
+ autoload(:DefinitionToAdd, "#{__dir__}/leftovers/definition_to_add")
16
37
  autoload(:FileCollector, "#{__dir__}/leftovers/file_collector")
17
38
  autoload(:FileList, "#{__dir__}/leftovers/file_list")
18
39
  autoload(:File, "#{__dir__}/leftovers/file")
19
- autoload(:Haml, "#{__dir__}/leftovers/haml")
20
40
  autoload(:MatcherBuilders, "#{__dir__}/leftovers/matcher_builders")
21
41
  autoload(:Matchers, "#{__dir__}/leftovers/matchers")
22
42
  autoload(:MergedConfig, "#{__dir__}/leftovers/merged_config")
23
43
  autoload(:Parser, "#{__dir__}/leftovers/parser")
44
+ autoload(:Precompilers, "#{__dir__}/leftovers/precompilers")
24
45
  autoload(:ProcessorBuilders, "#{__dir__}/leftovers/processor_builders")
25
46
  autoload(:RakeTask, "#{__dir__}/leftovers/rake_task")
26
47
  autoload(:Reporter, "#{__dir__}/leftovers/reporter")
27
- autoload(:Slim, "#{__dir__}/leftovers/slim")
28
48
  autoload(:TodoReporter, "#{__dir__}/leftovers/todo_reporter")
29
49
  autoload(:DynamicProcessors, "#{__dir__}/leftovers/dynamic_processors")
30
50
  autoload(:ValueProcessors, "#{__dir__}/leftovers/value_processors")
31
51
  autoload(:VERSION, "#{__dir__}/leftovers/version")
32
52
 
53
+ MEMOIZED_IVARS = %i{
54
+ @config
55
+ @collector
56
+ @reporter
57
+ @leftovers
58
+ @try_require_cache
59
+ @stdout
60
+ @stderr
61
+ @parallel
62
+ @pwd
63
+ @progress
64
+ }.freeze
65
+
33
66
  class << self
34
67
  attr_accessor :parallel, :progress
35
68
  attr_writer :reporter
@@ -81,16 +114,10 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
81
114
  reporter.report(only_test: only_test, none: none)
82
115
  end
83
116
 
84
- def reset # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
85
- remove_instance_variable(:@config) if defined?(@config)
86
- remove_instance_variable(:@collector) if defined?(@collector)
87
- remove_instance_variable(:@reporter) if defined?(@reporter)
88
- remove_instance_variable(:@leftovers) if defined?(@leftovers)
89
- remove_instance_variable(:@try_require_cache) if defined?(@try_require_cache)
90
- remove_instance_variable(:@stdout) if defined?(@stdout)
91
- remove_instance_variable(:@stderr) if defined?(@stderr)
92
- remove_instance_variable(:@parallel) if defined?(@parallel)
93
- remove_instance_variable(:@pwd) if defined?(@pwd)
117
+ def reset
118
+ MEMOIZED_IVARS.each do |ivar|
119
+ remove_instance_variable(ivar) if instance_variable_get(ivar)
120
+ end
94
121
  end
95
122
 
96
123
  def resolution_instructions_link
@@ -102,7 +129,7 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
102
129
  end
103
130
 
104
131
  def error(message)
105
- warn(message)
132
+ warn("\e[31m#{message}\e[0m")
106
133
  exit 1
107
134
  end
108
135
 
@@ -141,18 +168,34 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
141
168
  end
142
169
  end
143
170
 
171
+ def map_or_self(value, &block)
172
+ # return enum_for(__method__, value) unless block
173
+
174
+ case value
175
+ when nil then nil
176
+ when Array then unwrap_array(value.flat_map(&block).compact)
177
+ else yield(value)
178
+ end
179
+ end
180
+
181
+ def unwrap_array(array)
182
+ if array.length <= 1
183
+ array.first
184
+ else
185
+ array
186
+ end
187
+ end
188
+
144
189
  private
145
190
 
146
191
  def try_require_cache(requirable)
147
192
  @try_require_cache ||= {}
148
193
 
149
194
  @try_require_cache.fetch(requirable) do
150
- begin
151
- require requirable
152
- @try_require_cache[requirable] = true
153
- rescue LoadError
154
- @try_require_cache[requirable] = false
155
- end
195
+ require requirable
196
+ @try_require_cache[requirable] = true
197
+ rescue LoadError
198
+ @try_require_cache[requirable] = false
156
199
  end
157
200
  end
158
201
  end