leftovers 0.5.4 → 0.7.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (107) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +29 -1
  3. data/README.md +21 -1
  4. data/docs/Configuration.md +188 -20
  5. data/leftovers.gemspec +8 -5
  6. data/lib/config/actionmailer.yml +11 -11
  7. data/lib/config/actionpack.yml +11 -0
  8. data/lib/config/activesupport.yml +1 -1
  9. data/lib/config/rails.yml +1 -1
  10. data/lib/config/railties.yml +11 -0
  11. data/lib/config/ruby.yml +79 -0
  12. data/lib/leftovers/ast/node.rb +16 -11
  13. data/lib/leftovers/collector.rb +3 -1
  14. data/lib/leftovers/config.rb +9 -28
  15. data/lib/leftovers/config_loader/argument_position_schema.rb +11 -0
  16. data/lib/leftovers/config_loader/argumentless_transform_schema.rb +21 -0
  17. data/lib/leftovers/config_loader/attribute.rb +30 -0
  18. data/lib/leftovers/config_loader/document_schema.rb +21 -0
  19. data/lib/leftovers/config_loader/dynamic_schema.rb +17 -0
  20. data/lib/leftovers/config_loader/has_argument_schema.rb +13 -0
  21. data/lib/leftovers/config_loader/has_value_schema.rb +18 -0
  22. data/lib/leftovers/config_loader/keep_test_only_schema.rb +13 -0
  23. data/lib/leftovers/config_loader/node.rb +106 -0
  24. data/lib/leftovers/config_loader/object_schema.rb +189 -0
  25. data/lib/leftovers/config_loader/privacy_processor_schema.rb +12 -0
  26. data/lib/leftovers/config_loader/privacy_schema.rb +15 -0
  27. data/lib/leftovers/config_loader/require_schema.rb +11 -0
  28. data/lib/leftovers/config_loader/rule_pattern_schema.rb +18 -0
  29. data/lib/leftovers/config_loader/scalar_argument_schema.rb +14 -0
  30. data/lib/leftovers/config_loader/scalar_value_schema.rb +14 -0
  31. data/lib/leftovers/config_loader/schema.rb +21 -0
  32. data/lib/leftovers/config_loader/string_enum_schema.rb +62 -0
  33. data/lib/leftovers/config_loader/string_pattern_schema.rb +14 -0
  34. data/lib/leftovers/config_loader/string_schema.rb +14 -0
  35. data/lib/leftovers/config_loader/string_value_processor_schema.rb +11 -0
  36. data/lib/leftovers/config_loader/suggester.rb +22 -0
  37. data/lib/leftovers/config_loader/transform_schema.rb +28 -0
  38. data/lib/leftovers/config_loader/true_schema.rb +18 -0
  39. data/lib/leftovers/config_loader/value_matcher_schema.rb +18 -0
  40. data/lib/leftovers/config_loader/value_or_array_schema.rb +64 -0
  41. data/lib/leftovers/config_loader/value_processor_schema.rb +14 -0
  42. data/lib/leftovers/config_loader/value_type_schema.rb +17 -0
  43. data/lib/leftovers/config_loader.rb +82 -0
  44. data/lib/leftovers/definition.rb +1 -1
  45. data/lib/leftovers/definition_node.rb +6 -17
  46. data/lib/leftovers/definition_node_set.rb +11 -0
  47. data/lib/leftovers/definition_to_add.rb +31 -0
  48. data/lib/leftovers/dynamic_processors/call.rb +4 -7
  49. data/lib/leftovers/dynamic_processors/call_definition.rb +14 -11
  50. data/lib/leftovers/dynamic_processors/definition.rb +8 -7
  51. data/lib/leftovers/dynamic_processors/set_default_privacy.rb +18 -0
  52. data/lib/leftovers/dynamic_processors/set_privacy.rb +23 -0
  53. data/lib/leftovers/dynamic_processors.rb +2 -0
  54. data/lib/leftovers/file.rb +57 -11
  55. data/lib/leftovers/file_collector.rb +77 -19
  56. data/lib/leftovers/json.rb +28 -0
  57. data/lib/leftovers/matcher_builders/document.rb +13 -0
  58. data/lib/leftovers/matcher_builders/node.rb +7 -1
  59. data/lib/leftovers/matcher_builders/node_has_argument.rb +3 -4
  60. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +1 -1
  61. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +1 -1
  62. data/lib/leftovers/matcher_builders/node_privacy.rb +13 -0
  63. data/lib/leftovers/matcher_builders/node_type.rb +4 -4
  64. data/lib/leftovers/matcher_builders/node_value.rb +1 -1
  65. data/lib/leftovers/matcher_builders/string_pattern.rb +14 -5
  66. data/lib/leftovers/matcher_builders.rb +2 -0
  67. data/lib/leftovers/matchers/all.rb +0 -4
  68. data/lib/leftovers/matchers/and.rb +0 -4
  69. data/lib/leftovers/matchers/any.rb +0 -4
  70. data/lib/leftovers/matchers/node_has_any_keyword_argument.rb +1 -7
  71. data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +1 -7
  72. data/lib/leftovers/matchers/node_has_positional_argument_with_value.rb +0 -4
  73. data/lib/leftovers/matchers/node_name.rb +0 -4
  74. data/lib/leftovers/matchers/node_pair_value.rb +0 -4
  75. data/lib/leftovers/matchers/node_path.rb +0 -4
  76. data/lib/leftovers/matchers/node_privacy.rb +19 -0
  77. data/lib/leftovers/matchers/node_scalar_value.rb +0 -4
  78. data/lib/leftovers/matchers/node_type.rb +0 -4
  79. data/lib/leftovers/matchers/not.rb +0 -4
  80. data/lib/leftovers/matchers/or.rb +0 -4
  81. data/lib/leftovers/matchers.rb +1 -0
  82. data/lib/leftovers/merged_config.rb +25 -23
  83. data/lib/leftovers/processor_builders/add_prefix.rb +1 -1
  84. data/lib/leftovers/processor_builders/add_suffix.rb +1 -1
  85. data/lib/leftovers/processor_builders/dynamic.rb +51 -16
  86. data/lib/leftovers/processor_builders/transform.rb +2 -2
  87. data/lib/leftovers/processor_builders/transform_set.rb +8 -8
  88. data/lib/leftovers/todo_reporter.rb +10 -35
  89. data/lib/leftovers/value_processors/delete_prefix.rb +0 -6
  90. data/lib/leftovers/value_processors/delete_suffix.rb +0 -6
  91. data/lib/leftovers/value_processors/each_for_definition_set.rb +2 -5
  92. data/lib/leftovers/value_processors/each_positional_argument.rb +1 -1
  93. data/lib/leftovers/value_processors/keyword.rb +0 -4
  94. data/lib/leftovers/value_processors/keyword_argument.rb +0 -4
  95. data/lib/leftovers/value_processors/return_definition_node.rb +14 -0
  96. data/lib/leftovers/value_processors/{return_string.rb → return_sym.rb} +1 -1
  97. data/lib/leftovers/value_processors.rb +2 -2
  98. data/lib/leftovers/version.rb +1 -1
  99. data/lib/leftovers/yaml.rb +73 -0
  100. data/lib/leftovers.rb +29 -21
  101. metadata +85 -36
  102. data/lib/config/actioncable.yml +0 -4
  103. data/lib/leftovers/backports.rb +0 -40
  104. data/lib/leftovers/config_validator/error_processor.rb +0 -196
  105. data/lib/leftovers/config_validator/schema_hash.rb +0 -530
  106. data/lib/leftovers/config_validator.rb +0 -60
  107. data/lib/leftovers/value_processors/return_definition.rb +0 -26
@@ -24,9 +24,7 @@ module Leftovers
24
24
  @configs << config
25
25
  @loaded_configs << config.name
26
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
27
+ require_requires(config)
30
28
  end
31
29
 
32
30
  def project_config
@@ -43,6 +41,8 @@ module Leftovers
43
41
  @test_paths
44
42
  @haml_paths
45
43
  @slim_paths
44
+ @yaml_paths
45
+ @json_paths
46
46
  @erb_paths
47
47
  @dynamic
48
48
  @keep
@@ -64,35 +64,27 @@ module Leftovers
64
64
  end
65
65
 
66
66
  def test_paths
67
- @test_paths ||= FastIgnore.new(
68
- include_rules: @configs.flat_map(&:test_paths),
69
- gitignore: false,
70
- root: Leftovers.pwd
71
- )
67
+ @test_paths ||= Leftovers::MatcherBuilders::Path.build(@configs.flat_map(&:test_paths))
72
68
  end
73
69
 
74
70
  def haml_paths
75
- @haml_paths ||= FastIgnore.new(
76
- include_rules: @configs.flat_map(&:haml_paths),
77
- gitignore: false,
78
- root: Leftovers.pwd
79
- )
71
+ @haml_paths ||= Leftovers::MatcherBuilders::Path.build(@configs.flat_map(&:haml_paths))
80
72
  end
81
73
 
82
74
  def slim_paths
83
- @slim_paths ||= FastIgnore.new(
84
- include_rules: @configs.flat_map(&:slim_paths),
85
- gitignore: false,
86
- root: Leftovers.pwd
87
- )
75
+ @slim_paths ||= Leftovers::MatcherBuilders::Path.build(@configs.flat_map(&:slim_paths))
76
+ end
77
+
78
+ def yaml_paths
79
+ @yaml_paths ||= Leftovers::MatcherBuilders::Path.build(@configs.flat_map(&:yaml_paths))
80
+ end
81
+
82
+ def json_paths
83
+ @json_paths ||= Leftovers::MatcherBuilders::Path.build(@configs.flat_map(&:json_paths))
88
84
  end
89
85
 
90
86
  def erb_paths
91
- @erb_paths ||= FastIgnore.new(
92
- include_rules: @configs.flat_map(&:erb_paths),
93
- gitignore: false,
94
- root: Leftovers.pwd
95
- )
87
+ @erb_paths ||= Leftovers::MatcherBuilders::Path.build(@configs.flat_map(&:erb_paths))
96
88
  end
97
89
 
98
90
  def dynamic
@@ -109,6 +101,16 @@ module Leftovers
109
101
 
110
102
  private
111
103
 
104
+ def require_requires(config)
105
+ config.requires.each do |req|
106
+ if req.is_a?(Hash) && req[:quiet]
107
+ Leftovers.try_require(req[:quiet])
108
+ else
109
+ Leftovers.try_require(req, message: "cannot require '#{req}' from #{config.name}.yml")
110
+ end
111
+ end
112
+ end
113
+
112
114
  def load_bundled_gem_config
113
115
  return unless Leftovers.try_require('bundler')
114
116
 
@@ -6,7 +6,7 @@ module Leftovers
6
6
  def self.build(argument, then_processor)
7
7
  case argument
8
8
  when ::Hash
9
- dynamic_prefix = ::Leftovers::ProcessorBuilders::Action.build(argument, :call)
9
+ dynamic_prefix = ::Leftovers::ProcessorBuilders::Action.build(argument, :sym)
10
10
  ::Leftovers::ValueProcessors::AddDynamicPrefix.new(dynamic_prefix, then_processor)
11
11
  when ::String
12
12
  ::Leftovers::ValueProcessors::AddPrefix.new(argument, then_processor)
@@ -6,7 +6,7 @@ module Leftovers
6
6
  def self.build(argument, then_processor)
7
7
  case argument
8
8
  when ::Hash
9
- dynamic_suffix = ::Leftovers::ProcessorBuilders::Action.build(argument, :call)
9
+ dynamic_suffix = ::Leftovers::ProcessorBuilders::Action.build(argument, :sym)
10
10
  ::Leftovers::ValueProcessors::AddDynamicSuffix.new(dynamic_suffix, then_processor)
11
11
  when ::String
12
12
  ::Leftovers::ValueProcessors::AddSuffix.new(argument, then_processor)
@@ -3,22 +3,57 @@
3
3
  module Leftovers
4
4
  module ProcessorBuilders
5
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:
6
+ class << self
7
+ def build(dynamic_rules)
8
+ ::Leftovers::ProcessorBuilders::EachDynamic.each_or_self(dynamic_rules) do |dynamic|
9
+ build_processors(**dynamic)
10
+ end
11
+ end
12
+
13
+ private
14
+
15
+ def build_processors(
16
+ call: nil, define: nil, set_privacy: nil, set_default_privacy: nil, **matcher_rules
17
+ )
18
+ matcher = ::Leftovers::MatcherBuilders::Node.build(**matcher_rules)
19
+
20
+ ::Leftovers::ProcessorBuilders::EachDynamic.build([
21
+ build_call_define_processor(matcher, call, define),
22
+ build_set_privacy_processor(matcher, set_privacy),
23
+ build_set_default_privacy_processor(matcher, set_default_privacy)
24
+ ])
25
+ end
26
+
27
+ def build_action(processor_rules, return_type:)
28
+ ::Leftovers::ProcessorBuilders::Action.build(processor_rules, return_type)
29
+ end
30
+
31
+ def build_set_privacy_processor(matcher, set_privacy)
32
+ ::Leftovers::ProcessorBuilders::EachDynamic.each_or_self(set_privacy) do |action_values|
33
+ to = action_values.delete(:to)
34
+ action = build_action(action_values, return_type: :sym)
35
+
36
+ ::Leftovers::DynamicProcessors::SetPrivacy.new(matcher, action, to)
37
+ end
38
+ end
39
+
40
+ def build_set_default_privacy_processor(matcher, set_default_privacy)
41
+ ::Leftovers::DynamicProcessors::SetDefaultPrivacy.new(matcher, set_default_privacy)
42
+ end
43
+
44
+ def build_call_define_processor(matcher, call, define) # rubocop:disable Metrics/MethodLength
45
+ call_action = build_action(call, return_type: :sym)
46
+ define_action = build_action(define, return_type: :definition_node)
47
+
48
+ if call_action && define_action
49
+ # this nonsense saves a method call and array instantiation per method
50
+ ::Leftovers::DynamicProcessors::CallDefinition.new(matcher, call_action, define_action)
51
+ elsif define_action
52
+ ::Leftovers::DynamicProcessors::Definition.new(matcher, define_action)
53
+ elsif call_action
54
+ ::Leftovers::DynamicProcessors::Call.new(matcher, call_action)
55
+ else
56
+ ::Leftovers::DynamicProcessors::Null
22
57
  end
23
58
  end
24
59
  end
@@ -19,9 +19,9 @@ module Leftovers
19
19
  ::Leftovers::ValueProcessors::Pluralize.new(then_processor)
20
20
  when 'singularize'
21
21
  ::Leftovers::ValueProcessors::Singularize.new(then_processor)
22
- when 'camelize', 'camelcase'
22
+ when 'camelize'
23
23
  ::Leftovers::ValueProcessors::Camelize.new(then_processor)
24
- when 'titleize', 'titlecase'
24
+ when 'titleize'
25
25
  ::Leftovers::ValueProcessors::Titleize.new(then_processor)
26
26
  when 'demodulize'
27
27
  ::Leftovers::ValueProcessors::Demodulize.new(then_processor)
@@ -21,24 +21,24 @@ module Leftovers
21
21
 
22
22
  def self.each_builder(action)
23
23
  case action
24
- when :call
24
+ when :sym
25
25
  ::Leftovers::ProcessorBuilders::Each
26
- when :define
26
+ when :definition_node
27
27
  ::Leftovers::ProcessorBuilders::EachForDefinitionSet
28
28
  # :nocov:
29
- else raise
29
+ else raise "Unknown action #{action}"
30
30
  # :nocov:
31
31
  end
32
32
  end
33
33
 
34
34
  def self.build_final(action)
35
35
  case action
36
- when :call
37
- ::Leftovers::ValueProcessors::ReturnString
38
- when :define
39
- ::Leftovers::ValueProcessors::ReturnDefinition
36
+ when :sym
37
+ ::Leftovers::ValueProcessors::ReturnSym
38
+ when :definition_node
39
+ ::Leftovers::ValueProcessors::ReturnDefinitionNode
40
40
  # :nocov:
41
- else raise
41
+ else raise "Unknown action #{action}"
42
42
  # :nocov:
43
43
  end
44
44
  end
@@ -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)
@@ -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
@@ -11,10 +11,7 @@ module Leftovers
11
11
 
12
12
  def process(str, node, method_node)
13
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
14
+ then_processor.process(str, node, method_node)
18
15
  end
19
16
 
20
17
  definitions.flatten!
@@ -22,7 +19,7 @@ module Leftovers
22
19
 
23
20
  return definitions.first if definitions.length <= 1
24
21
 
25
- ::Leftovers::DefinitionSet.new(definitions)
22
+ ::Leftovers::DefinitionNodeSet.new(definitions)
26
23
  end
27
24
  end
28
25
  end
@@ -14,7 +14,7 @@ module Leftovers
14
14
  return unless positional_arguments
15
15
 
16
16
  positional_arguments.map do |argument_node|
17
- str = argument_node.to_s if argument_node.string_or_symbol?
17
+ str = argument_node.to_s if argument_node.string_or_symbol_or_def?
18
18
 
19
19
  @then_processor.process(str, argument_node, method_node)
20
20
  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
@@ -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
@@ -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?
@@ -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.4'
4
+ VERSION = '0.7.0'
5
5
  end
@@ -0,0 +1,73 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'yaml'
4
+
5
+ module Leftovers
6
+ module YAML
7
+ class Builder < ::Psych::TreeBuilder
8
+ def initialize
9
+ @constants = []
10
+
11
+ super
12
+ end
13
+
14
+ def add_constant_for_tag(tag, value = nil)
15
+ match = %r{\A!ruby/[^:]*(?::(.*))?\z}.match(tag)
16
+ return unless match
17
+
18
+ @constants << (match[1] || value)
19
+ end
20
+
21
+ def start_mapping(_anchor, tag, *rest) # leftovers:keep
22
+ add_constant_for_tag(tag)
23
+ tag = nil
24
+
25
+ super
26
+ end
27
+
28
+ def start_sequence(_anchor, tag, *rest) # leftovers:keep
29
+ add_constant_for_tag(tag)
30
+ tag = nil
31
+
32
+ super
33
+ end
34
+
35
+ def scalar(value, _anchor, tag, *rest) # leftovers:keep
36
+ add_constant_for_tag(tag, value)
37
+ tag = nil
38
+
39
+ super
40
+ end
41
+
42
+ def to_ruby_file
43
+ <<~RUBY
44
+ __leftovers_document(#{to_ruby_argument(root.to_ruby.first)})
45
+ #{@constants.join("\n")}
46
+ RUBY
47
+ end
48
+
49
+ private
50
+
51
+ def to_ruby_argument(value)
52
+ ruby = value.inspect
53
+ return ruby unless value.is_a?(Array)
54
+
55
+ ruby.delete_prefix!('[')
56
+ ruby.delete_suffix!(']')
57
+
58
+ ruby
59
+ end
60
+ end
61
+
62
+ def self.precompile(yaml, name)
63
+ builder = ::Leftovers::YAML::Builder.new
64
+ parser = ::Psych::Parser.new(builder)
65
+ parser.parse(yaml, name.relative_path)
66
+
67
+ builder.to_ruby_file
68
+ rescue ::Psych::SyntaxError => e
69
+ Leftovers.warn "#{e.class}: #{e.message}"
70
+ ''
71
+ end
72
+ end
73
+ end
data/lib/leftovers.rb CHANGED
@@ -4,19 +4,22 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
4
4
  class Error < ::StandardError; end
5
5
 
6
6
  autoload(:AST, "#{__dir__}/leftovers/ast")
7
- autoload(:Backports, "#{__dir__}/leftovers/backports")
8
7
  autoload(:CLI, "#{__dir__}/leftovers/cli")
9
8
  autoload(:Collector, "#{__dir__}/leftovers/collector")
10
- autoload(:ConfigValidator, "#{__dir__}/leftovers/config_validator")
9
+ autoload(:ConfigLoader, "#{__dir__}/leftovers/config_loader")
11
10
  autoload(:Config, "#{__dir__}/leftovers/config")
11
+ autoload(:Definition, "#{__dir__}/leftovers/definition")
12
12
  autoload(:DefinitionNode, "#{__dir__}/leftovers/definition_node")
13
+ autoload(:DefinitionNodeSet, "#{__dir__}/leftovers/definition_node_set")
13
14
  autoload(:DefinitionSet, "#{__dir__}/leftovers/definition_set")
14
- autoload(:Definition, "#{__dir__}/leftovers/definition")
15
+ autoload(:DefinitionToAdd, "#{__dir__}/leftovers/definition_to_add")
15
16
  autoload(:ERB, "#{__dir__}/leftovers/erb")
16
17
  autoload(:FileCollector, "#{__dir__}/leftovers/file_collector")
17
18
  autoload(:FileList, "#{__dir__}/leftovers/file_list")
18
19
  autoload(:File, "#{__dir__}/leftovers/file")
19
20
  autoload(:Haml, "#{__dir__}/leftovers/haml")
21
+ autoload(:YAML, "#{__dir__}/leftovers/yaml")
22
+ autoload(:JSON, "#{__dir__}/leftovers/json")
20
23
  autoload(:MatcherBuilders, "#{__dir__}/leftovers/matcher_builders")
21
24
  autoload(:Matchers, "#{__dir__}/leftovers/matchers")
22
25
  autoload(:MergedConfig, "#{__dir__}/leftovers/merged_config")
@@ -30,6 +33,19 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
30
33
  autoload(:ValueProcessors, "#{__dir__}/leftovers/value_processors")
31
34
  autoload(:VERSION, "#{__dir__}/leftovers/version")
32
35
 
36
+ MEMOIZED_IVARS = %i{
37
+ @config
38
+ @collector
39
+ @reporter
40
+ @leftovers
41
+ @try_require_cache
42
+ @stdout
43
+ @stderr
44
+ @parallel
45
+ @pwd
46
+ @progress
47
+ }.freeze
48
+
33
49
  class << self
34
50
  attr_accessor :parallel, :progress
35
51
  attr_writer :reporter
@@ -81,16 +97,10 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
81
97
  reporter.report(only_test: only_test, none: none)
82
98
  end
83
99
 
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)
100
+ def reset
101
+ MEMOIZED_IVARS.each do |ivar|
102
+ remove_instance_variable(ivar) if instance_variable_get(ivar)
103
+ end
94
104
  end
95
105
 
96
106
  def resolution_instructions_link
@@ -102,7 +112,7 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
102
112
  end
103
113
 
104
114
  def error(message)
105
- warn(message)
115
+ warn("\e[31m#{message}\e[0m")
106
116
  exit 1
107
117
  end
108
118
 
@@ -136,7 +146,7 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
136
146
 
137
147
  case value
138
148
  when nil then nil
139
- when Array then value.each(&block)
149
+ when Array then value.each { |i| each_or_self(i, &block) }
140
150
  else yield(value)
141
151
  end
142
152
  end
@@ -147,12 +157,10 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
147
157
  @try_require_cache ||= {}
148
158
 
149
159
  @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
160
+ require requirable
161
+ @try_require_cache[requirable] = true
162
+ rescue LoadError
163
+ @try_require_cache[requirable] = false
156
164
  end
157
165
  end
158
166
  end