leftovers 0.3.0 → 0.4.0

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 (144) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +23 -0
  3. data/README.md +28 -45
  4. data/docs/Configuration.md +598 -0
  5. data/exe/leftovers +1 -1
  6. data/leftovers.gemspec +9 -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 +125 -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 +40 -50
  19. data/lib/config/selenium-webdriver.yml +19 -21
  20. data/lib/config/sidekiq.yml +4 -8
  21. data/lib/config/will_paginate.yml +12 -14
  22. data/lib/leftovers.rb +38 -26
  23. data/lib/leftovers/ast.rb +8 -0
  24. data/lib/leftovers/ast/builder.rb +4 -4
  25. data/lib/leftovers/ast/node.rb +50 -77
  26. data/lib/leftovers/backports.rb +27 -23
  27. data/lib/leftovers/cli.rb +0 -3
  28. data/lib/leftovers/collector.rb +4 -8
  29. data/lib/leftovers/config.rb +19 -25
  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 +11 -36
  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 +65 -49
  44. data/lib/leftovers/file_list.rb +0 -1
  45. data/lib/leftovers/haml.rb +1 -1
  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 +13 -8
  81. data/lib/leftovers/parser.rb +1 -4
  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 +1 -1
  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 +143 -24
  138. data/lib/leftovers/argument_rule.rb +0 -229
  139. data/lib/leftovers/core_ext.rb +0 -15
  140. data/lib/leftovers/hash_rule.rb +0 -42
  141. data/lib/leftovers/name_rule.rb +0 -98
  142. data/lib/leftovers/rule.rb +0 -82
  143. data/lib/leftovers/transform_rule.rb +0 -169
  144. data/lib/leftovers/value_rule.rb +0 -57
@@ -0,0 +1,8 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module AST
5
+ autoload(:Builder, "#{__dir__}/ast/builder")
6
+ autoload(:Node, "#{__dir__}/ast/node")
7
+ end
8
+ end
@@ -1,6 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require_relative 'node'
3
+ require 'parser'
4
4
 
5
5
  module Leftovers
6
6
  module AST
@@ -9,12 +9,12 @@ module Leftovers
9
9
  #
10
10
  # @return [Node] the generated node
11
11
 
12
- def n(type, children, source_map)
13
- Leftovers::AST::Node.new(type, children, location: source_map)
12
+ def n(type, children, source_map) # leftovers:keep
13
+ ::Leftovers::AST::Node.new(type, children, location: source_map)
14
14
  end
15
15
 
16
16
  # Don't complain about invalid strings
17
- def string_value(token)
17
+ def string_value(token) # leftovers:keep
18
18
  value(token)
19
19
  end
20
20
  end
@@ -4,11 +4,7 @@ require 'parser'
4
4
 
5
5
  module Leftovers
6
6
  module AST
7
- class Node < Parser::AST::Node # rubocop:disable Metrics/ClassLength
8
- # :nocov:
9
- using ::Leftovers::SetCaseEq if defined?(::Leftovers::SetCaseEq)
10
- # :nocov:
11
-
7
+ class Node < ::Parser::AST::Node # rubocop:disable Metrics/ClassLength
12
8
  def initialize(type, children = [], properties = {})
13
9
  # ::AST::Node#initialize freezes itself.
14
10
  # so can't use normal memoizations
@@ -21,25 +17,31 @@ module Leftovers
21
17
  children.first
22
18
  end
23
19
 
24
- # TODO: move file to loc.
25
- def file
26
- @memo[:file]
20
+ def second
21
+ children[1]
27
22
  end
28
23
 
29
- def file=(value)
30
- @memo[:file] = value
24
+ def path
25
+ @memo[:path] ||= loc.expression.source_buffer.name.to_s
31
26
  end
32
27
 
33
- def test
28
+ def test?
34
29
  @memo[:test]
35
30
  end
36
- alias_method :test?, :test
37
31
 
38
32
  def test=(value)
39
33
  @memo[:test] = value
40
34
  end
41
35
 
42
- def to_scalar_value # rubocop:disable Metrics/MethodLength
36
+ def keep_line=(value)
37
+ @memo[:keep_line] = value
38
+ end
39
+
40
+ def keep_line?
41
+ @memo[:keep_line]
42
+ end
43
+
44
+ def to_scalar_value
43
45
  case type
44
46
  when :sym, :int, :float, :str
45
47
  first
@@ -61,7 +63,7 @@ module Leftovers
61
63
  end
62
64
 
63
65
  def to_s
64
- @memo[:to_s] ||= name&.to_s || to_scalar_value.to_s || ''
66
+ @memo[:to_s] ||= name ? name.to_s : to_scalar_value.to_s
65
67
  end
66
68
 
67
69
  def to_sym
@@ -76,20 +78,32 @@ module Leftovers
76
78
  type == :str || type == :sym
77
79
  end
78
80
 
79
- def arguments # rubocop:disable Metrics/MethodLength
80
- @memo[:arguments] ||= case type
81
- when :send, :csend then children.drop(2)
82
- when :casgn then [children[2]]
83
- when :ivasgn, :cvasgn, :gvasgn then [children[1]]
84
- else
85
- # :nocov: # these are all the nodes with collect_rules
86
- raise "Not argument node (#{type})"
87
- # :nocov:
81
+ def arguments
82
+ @memo.fetch(:arguments) do
83
+ @memo[:arguments] = case type
84
+ when :send, :csend then children.drop(2)
85
+ when :casgn then assign_arguments(children[2])
86
+ when :ivasgn, :cvasgn, :gvasgn then assign_arguments(second)
87
+ when :array then children
88
+ when :hash then [self]
89
+ end
90
+ end
91
+ end
92
+
93
+ def assign_arguments(arguments_list)
94
+ arguments_list = arguments_list.unwrap_freeze
95
+ case arguments_list.type
96
+ when :array
97
+ arguments_list.children
98
+ when :hash, :str, :sym
99
+ [arguments_list]
88
100
  end
89
101
  end
90
102
 
91
103
  def positional_arguments
92
- @memo[:positional_arguments] ||= kwargs ? arguments[0...-1] : arguments
104
+ @memo.fetch(:positional_arguments) do
105
+ @memo[:positional_arguments] = kwargs ? arguments[0...-1] : arguments
106
+ end
93
107
  end
94
108
 
95
109
  def unwrap_freeze
@@ -100,69 +114,28 @@ module Leftovers
100
114
 
101
115
  def kwargs
102
116
  @memo.fetch(:kwargs) do
103
- last_arg = arguments[-1]&.unwrap_freeze
104
- @memo[:kwargs] = (last_arg if last_arg&.type == :hash)
105
- end
106
- end
117
+ @memo[:kwargs] = begin
118
+ args = arguments
119
+ next unless args
107
120
 
108
- def keys
109
- each_pair.map { |k, _| k }
110
- end
111
-
112
- def values
113
- # :nocov:
114
- @memo[:kwargs] ||= case type
115
- # :nocov:
116
- when :hash then each_pair.map { |_, v| v }
117
- when :array then children
118
- end
119
- end
120
-
121
- def values_at_match(matcher)
122
- each_pair.with_object([]) do |(key, value), values|
123
- values << value if matcher === key.to_sym
124
- end
125
- end
126
-
127
- def positional_arguments_at(positions)
128
- positional_arguments.values_at(*positions).compact
129
- end
130
-
131
- def each_pair
132
- return enum_for(:each_pair) unless block_given?
133
-
134
- children.each do |pair|
135
- yield(*pair.children) if pair.type == :pair
121
+ last_arg = args[-1]
122
+ last_arg if last_arg && last_arg.type == :hash
123
+ end
136
124
  end
137
125
  end
138
126
 
139
- def name # rubocop:disable Metrics/MethodLength
127
+ def name
140
128
  @memo[:name] ||= case type
141
129
  when :send, :csend, :casgn, :const
142
- children[1]
143
- when :def, :ivasgn, :ivar, :gvar, :cvar, :gvasgn, :cvasgn
130
+ second
131
+ when :def, :ivasgn, :ivar, :gvar, :cvar, :gvasgn, :cvasgn, :sym
144
132
  first
145
- when :module, :class
133
+ when :str
134
+ first.to_sym
135
+ when :module, :class, :pair
146
136
  first.name
147
137
  end
148
138
  end
149
-
150
- def [](index) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
151
- # :nocov:
152
- case type
153
- # :nocov:
154
- when :send, :csend, :casgn, :cvasgn, :ivasgn, :gvasgn
155
- index.is_a?(Integer) ? arguments[index - 1] : kwargs && kwargs[index]
156
- when :hash
157
- each_pair do |key, value|
158
- next unless key.string_or_symbol?
159
-
160
- return value if key.to_sym == index
161
- end
162
-
163
- nil
164
- end
165
- end
166
139
  end
167
140
  end
168
141
  end
@@ -1,34 +1,38 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module Leftovers
4
- ruby_version = Gem::Version.new(RUBY_VERSION)
5
- unless ruby_version >= Gem::Version.new('2.5')
6
- require 'set'
7
- module SetCaseEq
8
- refine ::Set do
9
- def ===(value)
10
- include?(value)
4
+ module Backports
5
+ ruby_version = Gem::Version.new(RUBY_VERSION)
6
+
7
+ unless ruby_version >= Gem::Version.new('2.5')
8
+ require 'set'
9
+ module SetCaseEq
10
+ refine ::Set do
11
+ def ===(value)
12
+ include?(value)
13
+ end
11
14
  end
12
15
  end
13
- end
14
- module StringDeletePrefixSuffix
15
- refine ::String do
16
- def delete_prefix!(str)
17
- slice!(0..(str.length - 1)) if start_with?(str)
18
- self
19
- end
20
16
 
21
- def delete_suffix!(str)
22
- slice!(-str.length..-1) if end_with?(str)
23
- self
24
- end
17
+ module StringDeletePrefixSuffix
18
+ refine ::String do
19
+ def delete_prefix!(str)
20
+ slice!(0..(str.length - 1)) if start_with?(str)
21
+ self
22
+ end
25
23
 
26
- def delete_prefix(str)
27
- dup.delete_prefix!(str)
28
- end
24
+ def delete_suffix!(str)
25
+ slice!(-str.length..-1) if end_with?(str)
26
+ self
27
+ end
28
+
29
+ def delete_prefix(str)
30
+ dup.delete_prefix!(str)
31
+ end
29
32
 
30
- def delete_suffix(str)
31
- dup.delete_suffix!(str)
33
+ def delete_suffix(str)
34
+ dup.delete_suffix!(str)
35
+ end
32
36
  end
33
37
  end
34
38
  end
@@ -1,9 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'optparse'
4
- require_relative '../leftovers'
5
- require_relative 'version'
6
-
7
4
  module Leftovers
8
5
  class CLI
9
6
  def initialize(argv: [], stdout: $stdout, stderr: $stderr)
@@ -3,16 +3,12 @@
3
3
  require 'fast_ignore'
4
4
  require 'set'
5
5
  require 'parallel'
6
- require_relative 'file_collector'
7
- require_relative 'file_list'
8
6
 
9
7
  module Leftovers
10
8
  class Collector
11
- attr_reader :calls
12
- attr_reader :test_calls
13
- attr_reader :definitions
9
+ attr_reader :calls, :test_calls, :definitions
14
10
 
15
- def initialize # rubocop:disable Metrics/MethodLength
11
+ def initialize
16
12
  @calls = []
17
13
  @test_calls = []
18
14
  @definitions = []
@@ -38,7 +34,7 @@ module Leftovers
38
34
  end
39
35
 
40
36
  def collect_file(file)
41
- file_collector = Leftovers::FileCollector.new(file.ruby, file)
37
+ file_collector = ::Leftovers::FileCollector.new(file.ruby, file)
42
38
  file_collector.collect
43
39
 
44
40
  file_collector.to_h
@@ -50,7 +46,7 @@ module Leftovers
50
46
  )
51
47
  end
52
48
 
53
- def finish_file(_, _, result) # rubocop:disable Metrics/MethodLength
49
+ def finish_file(_, _, result)
54
50
  @count += 1
55
51
  @count_calls += result[:calls].length
56
52
  @count_definitions += result[:definitions].length
@@ -1,12 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'yaml'
4
- require_relative 'rule'
5
4
 
6
5
  module Leftovers
7
6
  class Config
8
7
  # :nocov:
9
- using ::Leftovers::SetCaseEq if defined?(::Leftovers::SetCaseEq)
8
+ using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
10
9
  # :nocov:
11
10
 
12
11
  attr_reader :name
@@ -33,11 +32,16 @@ module Leftovers
33
32
  @test_paths ||= Array(yaml[:test_paths])
34
33
  end
35
34
 
36
- def rules
37
- @rules ||= Rule.wrap(yaml[:rules])
38
- rescue Leftovers::ConfigError => e
39
- warn "\e[31mConfig Error: (#{path}): #{e.message}\e[0m"
40
- Leftovers.exit 1
35
+ def dynamic
36
+ @dynamic ||= ::Leftovers::ProcessorBuilders::Dynamic.build(yaml[:dynamic])
37
+ end
38
+
39
+ def keep
40
+ @keep ||= ::Leftovers::MatcherBuilders::Node.build(yaml[:keep])
41
+ end
42
+
43
+ def requires
44
+ @requires ||= Array(yaml[:requires])
41
45
  end
42
46
 
43
47
  private
@@ -50,31 +54,21 @@ module Leftovers
50
54
  @path ||= ::File.expand_path("../config/#{name}.yml", __dir__)
51
55
  end
52
56
 
53
- def yaml # rubocop:disable Metrics/MethodLength
57
+ def yaml
58
+ @yaml ||= ::Leftovers::ConfigValidator.validate_and_process!(parse_yaml, path)
59
+ end
60
+
61
+ def parse_yaml
54
62
  # :nocov:
55
- @yaml ||= if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6')
56
- Psych.safe_load(content, symbolize_names: true, filename: path) || {}
63
+ if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6')
64
+ Psych.safe_load(content, filename: path) || {}
57
65
  else
58
- symbolize_names!(Psych.safe_load(content, [], [], false, path)) || {}
66
+ Psych.safe_load(content, [], [], false, path) || {}
59
67
  end
60
68
  # :nocov:
61
69
  rescue ::Psych::SyntaxError => e
62
70
  warn "\e[31mConfig SyntaxError: #{e.message}\e[0m"
63
71
  Leftovers.exit 1
64
72
  end
65
-
66
- # :nocov:
67
- def symbolize_names!(obj) # rubocop:disable Metrics/MethodLength
68
- case obj
69
- when Hash
70
- obj.keys.each do |key| # rubocop:disable Style/HashEachMethods # each_key never finishes.
71
- obj[key.to_sym] = symbolize_names!(obj.delete(key))
72
- end
73
- when Array
74
- obj.map! { |ea| symbolize_names!(ea) }
75
- end
76
- obj
77
- end
78
- # :nocov:
79
73
  end
80
74
  end
@@ -0,0 +1,60 @@
1
+ # frozen-string-literal: true
2
+
3
+ require 'json_schemer'
4
+
5
+ module Leftovers
6
+ module ConfigValidator
7
+ autoload(:ErrorProcessor, "#{__dir__}/config_validator/error_processor")
8
+ autoload(:SCHEMA_HASH, "#{__dir__}/config_validator/schema_hash")
9
+
10
+ def self.default_schema
11
+ @default_schema ||= ::JSONSchemer.schema(::Leftovers::ConfigValidator::SCHEMA_HASH)
12
+ end
13
+
14
+ def self.validate(obj, validator = default_schema)
15
+ validator.validate(obj)
16
+ end
17
+
18
+ def self.validate_and_process!(yaml, path)
19
+ errors = validate(yaml)
20
+ print_validation_errors_and_exit(errors, path) unless errors.first.nil?
21
+ post_process!(yaml)
22
+ end
23
+
24
+ def self.print_validation_errors_and_exit(errors, path)
25
+ ::Leftovers::ConfigValidator::ErrorProcessor.process(errors).each do |message|
26
+ warn "\e[31mConfig SchemaError: (#{path}): #{message}\e[0m"
27
+ end
28
+
29
+ ::Leftovers.exit 1
30
+ end
31
+
32
+ def self.post_process!(obj)
33
+ case obj
34
+ when Hash
35
+ obj.keys.each do |key| # rubocop:disable Style/HashEachMethods # each_key never finishes.
36
+ obj[symbolize_name(key)] = post_process!(obj.delete(key))
37
+ end
38
+ when Array
39
+ obj.map! { |ea| post_process!(ea) }
40
+ end
41
+ obj
42
+ end
43
+
44
+ def self.symbolize_name(name) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
45
+ case name
46
+ when 'matches' then :match
47
+ when 'defines' then :define
48
+ when 'calls' then :call
49
+ when 'name' then :names
50
+ when 'keyword' then :keywords
51
+ when 'argument' then :arguments
52
+ when 'has_argument' then :has_arguments
53
+ when 'path' then :paths
54
+ when 'unless' then :unless_arg
55
+ when 'require' then :requires
56
+ else name.to_sym
57
+ end
58
+ end
59
+ end
60
+ end