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,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
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module EachForDefinitionSet
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::EachForDefinitionSet.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,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module Itself
6
+ def self.build(value, then_processor)
7
+ return unless value && then_processor
8
+
9
+ ::Leftovers::ValueProcessors::Itself.new(then_processor)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,24 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module Keyword
6
+ def self.build(value, then_processor) # rubocop:disable Metrics/MethodLength
7
+ return unless value && then_processor
8
+
9
+ case value
10
+ when true, '**'
11
+ ::Leftovers::ValueProcessors::EachKeyword.new(then_processor)
12
+ when ::String, ::Hash, ::Array
13
+ ::Leftovers::ValueProcessors::Keyword.new(
14
+ ::Leftovers::MatcherBuilders::NodePairName.build(value),
15
+ then_processor
16
+ )
17
+ # :nocov:
18
+ else raise
19
+ # :nocov:
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,14 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module KeywordArgument
6
+ def self.build(pattern, then_processor)
7
+ ::Leftovers::ValueProcessors::KeywordArgument.new(
8
+ ::Leftovers::MatcherBuilders::NodePairName.build(pattern),
9
+ then_processor
10
+ )
11
+ end
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,55 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module Transform
6
+ def self.build(transform, argument, then_processor) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize
7
+ case transform.to_s
8
+ when 'original', nil
9
+ then_processor
10
+ when 'downcase'
11
+ ::Leftovers::ValueProcessors::Downcase.new(then_processor)
12
+ when 'upcase'
13
+ ::Leftovers::ValueProcessors::Upcase.new(then_processor)
14
+ when 'capitalize'
15
+ ::Leftovers::ValueProcessors::Capitalize.new(then_processor)
16
+ when 'swapcase'
17
+ ::Leftovers::ValueProcessors::Swapcase.new(then_processor)
18
+ when 'pluralize'
19
+ ::Leftovers::ValueProcessors::Pluralize.new(then_processor)
20
+ when 'singularize'
21
+ ::Leftovers::ValueProcessors::Singularize.new(then_processor)
22
+ when 'camelize', 'camelcase'
23
+ ::Leftovers::ValueProcessors::Camelize.new(then_processor)
24
+ when 'titleize', 'titlecase'
25
+ ::Leftovers::ValueProcessors::Titleize.new(then_processor)
26
+ when 'demodulize'
27
+ ::Leftovers::ValueProcessors::Demodulize.new(then_processor)
28
+ when 'deconstantize'
29
+ ::Leftovers::ValueProcessors::Deconstantize.new(then_processor)
30
+ when 'parameterize'
31
+ ::Leftovers::ValueProcessors::Parameterize.new(then_processor)
32
+ when 'underscore'
33
+ ::Leftovers::ValueProcessors::Underscore.new(then_processor)
34
+ when 'split'
35
+ ::Leftovers::ValueProcessors::Split.new(argument, then_processor)
36
+ when 'delete_before'
37
+ ::Leftovers::ValueProcessors::DeleteBefore.new(argument, then_processor)
38
+ when 'delete_after'
39
+ ::Leftovers::ValueProcessors::DeleteAfter.new(argument, then_processor)
40
+ when 'add_prefix'
41
+ ::Leftovers::ProcessorBuilders::AddPrefix.build(argument, then_processor)
42
+ when 'add_suffix'
43
+ ::Leftovers::ProcessorBuilders::AddSuffix.build(argument, then_processor)
44
+ when 'delete_prefix'
45
+ ::Leftovers::ValueProcessors::DeletePrefix.new(argument, then_processor)
46
+ when 'delete_suffix'
47
+ ::Leftovers::ValueProcessors::DeleteSuffix.new(argument, then_processor)
48
+ # :nocov:
49
+ else raise
50
+ # :nocov:
51
+ end
52
+ end
53
+ end
54
+ end
55
+ end
@@ -0,0 +1,24 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module TransformChain
6
+ def self.build(transforms, next_transform) # rubocop:disable Metrics/MethodLength
7
+ case transforms
8
+ when ::Hash
9
+ transforms.reverse_each do |(transform, transform_arg)|
10
+ next_transform = ::Leftovers::ProcessorBuilders::Transform.build(
11
+ transform, transform_arg, next_transform
12
+ )
13
+ end
14
+ next_transform
15
+ when ::String
16
+ ::Leftovers::ProcessorBuilders::Transform.build(transforms, true, next_transform)
17
+ # :nocov:
18
+ else raise
19
+ # :nocov:
20
+ end
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,47 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
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]
11
+
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
17
+ # :nocov:
18
+ end
19
+ end
20
+ end
21
+
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
30
+ # :nocov:
31
+ end
32
+ end
33
+
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
42
+ # :nocov:
43
+ end
44
+ end
45
+ end
46
+ end
47
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module ProcessorBuilders
5
+ module Value
6
+ def self.build(value, then_processor)
7
+ return unless value && then_processor
8
+
9
+ ::Leftovers::ValueProcessors::ReplaceValue.new(value, then_processor)
10
+ end
11
+ end
12
+ end
13
+ end
@@ -2,7 +2,7 @@
2
2
 
3
3
  require 'rake'
4
4
  require 'shellwords'
5
- require_relative 'cli'
5
+ require_relative '../leftovers'
6
6
 
7
7
  module Leftovers
8
8
  class RakeTask
@@ -49,9 +49,9 @@ module Leftovers
49
49
  end
50
50
 
51
51
  def run(argv)
52
- Leftovers::CLI.new(argv: argv)
53
- rescue SystemExit => e
54
- raise unless e.status == 0
52
+ exitstatus = Leftovers::CLI.new(argv: argv).run
53
+
54
+ exit exitstatus unless exitstatus == 0
55
55
  end
56
56
 
57
57
  def argv_or_default(task_argv)
@@ -2,10 +2,62 @@
2
2
 
3
3
  module Leftovers
4
4
  class Reporter
5
- def call(definition)
6
- Leftovers.puts(
7
- "\e[36m#{definition.full_location}\e[0m #{definition.full_name} \e[2m#{definition.highlighted_source("\e[33m", "\e[0;2m")}\e[0m" # rubocop:disable Layout/LineLength
8
- )
5
+ def prepare; end
6
+
7
+ def report(only_test:, none:)
8
+ report_list('Only directly called in tests:', only_test)
9
+ report_list('Not directly called at all:', none)
10
+ report_instructions
11
+
12
+ 1
13
+ end
14
+
15
+ def report_success
16
+ puts green('Everything is used')
17
+
18
+ 0
19
+ end
20
+
21
+ private
22
+
23
+ def report_instructions
24
+ puts <<~HELP
25
+
26
+ how to resolve: #{green Leftovers.resolution_instructions_link}
27
+ HELP
28
+ end
29
+
30
+ def report_list(title, list)
31
+ return if list.empty?
32
+
33
+ puts red(title)
34
+ list.each { |d| print_definition(d) }
35
+ end
36
+
37
+ def print_definition(definition)
38
+ puts "#{aqua definition.location_s} "\
39
+ "#{definition} "\
40
+ "#{grey definition.highlighted_source("\e[33m", "\e[0;2m")}"
41
+ end
42
+
43
+ def puts(string)
44
+ Leftovers.puts(string)
45
+ end
46
+
47
+ def red(string)
48
+ "\e[31m#{string}\e[0m"
49
+ end
50
+
51
+ def green(string)
52
+ "\e[32m#{string}\e[0m"
53
+ end
54
+
55
+ def aqua(string)
56
+ "\e[36m#{string}\e[0m"
57
+ end
58
+
59
+ def grey(string)
60
+ "\e[2m#{string}\e[0m"
9
61
  end
10
62
  end
11
63
  end
@@ -0,0 +1,124 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'pathname'
4
+
5
+ module Leftovers
6
+ class TodoReporter
7
+ def prepare
8
+ return unless path.exist?
9
+
10
+ puts "Removing previous #{path.basename} file"
11
+ puts ''
12
+ path.delete
13
+ end
14
+
15
+ def report(only_test:, none:)
16
+ path.write(generate_file_body(only_test, none))
17
+ report_instructions
18
+
19
+ 0
20
+ end
21
+
22
+ def report_success
23
+ puts "No #{path.basename} file generated, everything is used"
24
+
25
+ 0
26
+ end
27
+
28
+ private
29
+
30
+ def report_instructions
31
+ puts <<~MESSAGE
32
+ generated #{path.basename}.
33
+ running leftovers again will read this file and
34
+ not alert you to any unused items mentioned in it.
35
+
36
+ commit this file so you/your team can gradually
37
+ address these items while still having leftovers
38
+ alert you to any newly unused items.
39
+ MESSAGE
40
+ end
41
+
42
+ def path
43
+ Leftovers.pwd.join('.leftovers_todo.yml')
44
+ end
45
+
46
+ def generate_file_body(only_test, none)
47
+ <<~YML.chomp
48
+ #{generation_message.chomp}
49
+ #
50
+ #{resolution_instructions}
51
+ #{todo_data(only_test, none).chomp}
52
+ YML
53
+ end
54
+
55
+ def generation_message
56
+ <<~YML
57
+ # This file was generated by `leftovers --write-todo`
58
+ # Generated at: #{Time.now.utc.strftime('%F %T')} UTC
59
+ YML
60
+ end
61
+
62
+ def resolution_instructions
63
+ <<~YML
64
+ # for instructions on how to address these
65
+ # see #{Leftovers.resolution_instructions_link}
66
+ YML
67
+ end
68
+
69
+ def todo_data(only_test, none)
70
+ none_test = none.select(&:test?)
71
+ none_non_test = none.reject(&:test?)
72
+ [
73
+ test_only_data(none_test),
74
+ keep_data(only_test, none_non_test)
75
+ ].compact.join
76
+ end
77
+
78
+ def test_only_data(list)
79
+ return if list.empty?
80
+
81
+ <<~YML
82
+ test_only:
83
+ #{generate_list('Defined in tests:', list).chomp}
84
+ YML
85
+ end
86
+
87
+ def keep_data(only_test, none_non_test)
88
+ return if only_test.empty? && none_non_test.empty?
89
+
90
+ <<~YML.chomp
91
+ keep:
92
+ #{keep_test_called_data(only_test)}#{keep_never_called_data(none_non_test)}
93
+ YML
94
+ end
95
+
96
+ def keep_test_called_data(list)
97
+ return if list.empty?
98
+
99
+ generate_list('Only directly called in tests:', list)
100
+ end
101
+
102
+ def keep_never_called_data(list)
103
+ return if list.empty?
104
+
105
+ generate_list('Not directly called at all:', list)
106
+ end
107
+
108
+ def generate_list(title, list)
109
+ <<~YML
110
+ # #{title}
111
+ #{list.map { |d| print_definition(d) }.join("\n")}
112
+
113
+ YML
114
+ end
115
+
116
+ def print_definition(definition)
117
+ " - #{definition.to_s.inspect} # #{definition.location_s} #{definition.source_line.strip}"
118
+ end
119
+
120
+ def puts(string)
121
+ Leftovers.puts(string)
122
+ end
123
+ end
124
+ end