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
data/lib/config/ruby.yml CHANGED
@@ -14,14 +14,10 @@ test_paths:
14
14
  - /tests/
15
15
  - /test/
16
16
 
17
- erb_paths:
18
- - '*.erb'
19
-
20
- haml_paths:
21
- - '*.haml'
22
-
23
- slim_paths:
24
- - '*.slim'
17
+ precompile:
18
+ - { paths: '*.erb', format: 'erb' }
19
+ - { paths: ['*.yml', '*.yaml'], format: 'yaml' }
20
+ - { paths: '*.json', format: 'json' }
25
21
 
26
22
  keep:
27
23
  - initialize # called by new
@@ -91,3 +87,75 @@ dynamic:
91
87
  - instance_variable_set
92
88
  - class_variable_set
93
89
  defines: 0
90
+
91
+ # Module
92
+ - name: public
93
+ unless:
94
+ has_argument: 0
95
+ set_default_privacy: public
96
+
97
+ - name:
98
+ - public
99
+ - public_class_method
100
+ - public_constant
101
+ has_argument: 0
102
+ set_privacy:
103
+ argument: '*'
104
+ to: public
105
+
106
+ - name:
107
+ - public
108
+ - public_class_method
109
+ has_argument: 0
110
+ unless:
111
+ has_argument: 1
112
+ set_privacy:
113
+ argument: 0
114
+ nested:
115
+ argument: '*'
116
+ to: public
117
+
118
+ - name: protected
119
+ unless:
120
+ has_argument: 0
121
+ set_default_privacy: protected
122
+
123
+ - name: protected
124
+ has_argument: 0
125
+ set_privacy:
126
+ argument: '*'
127
+ to: protected
128
+
129
+ - name: protected
130
+ has_argument: 0
131
+ unless:
132
+ has_argument: 1
133
+ set_privacy:
134
+ argument: 0
135
+ nested:
136
+ argument: '*'
137
+ to: protected
138
+
139
+ - name: private
140
+ unless:
141
+ has_argument: 0
142
+ set_default_privacy: private
143
+
144
+ - name:
145
+ - private
146
+ - private_class_method
147
+ - private_constant
148
+ has_argument: 0
149
+ set_privacy:
150
+ argument: '*'
151
+ to: private
152
+
153
+ - name: private
154
+ has_argument: 0
155
+ unless:
156
+ has_argument: 1
157
+ set_privacy:
158
+ argument: 0
159
+ nested:
160
+ argument: '*'
161
+ to: private
data/lib/config/slim.yml CHANGED
@@ -1,4 +1,6 @@
1
1
  include_paths:
2
2
  - '*.slim'
3
- slim_paths:
4
- - '*.slim'
3
+ requires: 'slim'
4
+ precompile:
5
+ paths: '*.slim'
6
+ format: slim
@@ -25,14 +25,6 @@ module Leftovers
25
25
  @memo[:path] ||= loc.expression.source_buffer.name.to_s
26
26
  end
27
27
 
28
- def test_line?
29
- @memo[:test_line]
30
- end
31
-
32
- def test_line=(value)
33
- @memo[:test_line] = value
34
- end
35
-
36
28
  def keep_line=(value)
37
29
  @memo[:keep_line] = value
38
30
  end
@@ -41,6 +33,14 @@ module Leftovers
41
33
  @memo[:keep_line]
42
34
  end
43
35
 
36
+ def privacy=(value)
37
+ @memo[:privacy] = value
38
+ end
39
+
40
+ def privacy
41
+ @memo[:privacy] || :public
42
+ end
43
+
44
44
  def to_scalar_value
45
45
  case type
46
46
  when :sym, :int, :float, :str
@@ -58,7 +58,8 @@ module Leftovers
58
58
  case type
59
59
  when :sym, :int, :float, :str, :true, :false, :nil
60
60
  true
61
- else false
61
+ else
62
+ false
62
63
  end
63
64
  end
64
65
 
@@ -78,6 +79,10 @@ module Leftovers
78
79
  type == :str || type == :sym
79
80
  end
80
81
 
82
+ def string_or_symbol_or_def?
83
+ type == :str || type == :sym || type == :def || type == :defs
84
+ end
85
+
81
86
  def proc?
82
87
  return unless type == :block
83
88
 
@@ -140,9 +145,9 @@ module Leftovers
140
145
 
141
146
  def name
142
147
  @memo[:name] ||= case type
143
- when :send, :csend, :casgn, :const
148
+ when :send, :csend, :casgn, :const, :defs
144
149
  second
145
- when :def, :ivasgn, :ivar, :gvar, :cvar, :gvasgn, :cvasgn, :sym
150
+ when :def, :ivasgn, :ivar, :gvar, :cvar, :gvasgn, :cvasgn, :sym, :lvar
146
151
  first
147
152
  when :str
148
153
  first.to_sym
data/lib/leftovers/cli.rb CHANGED
@@ -57,6 +57,11 @@ module Leftovers
57
57
  end
58
58
 
59
59
  opts.parse(argv)
60
+ rescue OptionParser::InvalidOption => e
61
+ stderr.puts("\e[31mCLI Error: #{e.message}\e[0m")
62
+ stderr.puts ''
63
+ stderr.puts(opts.help)
64
+ Leftovers.exit 1
60
65
  end
61
66
  end
62
67
  end
@@ -28,7 +28,9 @@ module Leftovers
28
28
 
29
29
  def collect_file_list(list)
30
30
  if Leftovers.parallel?
31
- Parallel.each(list, finish: method(:finish_file), &method(:collect_file))
31
+ Parallel.each(list, finish: method(:finish_file)) do |file|
32
+ collect_file(file)
33
+ end
32
34
  else
33
35
  list.each { |file| finish_file(nil, nil, collect_file(file)) }
34
36
  end
@@ -43,7 +45,8 @@ module Leftovers
43
45
 
44
46
  def print_progress
45
47
  Leftovers.print(
46
- "\e[2Kchecked #{@count} files, collected #{@count_calls} calls, #{@count_definitions} definitions\r" # rubocop:disable Layout/LineLength
48
+ "\e[2Kchecked #{@count} files, " \
49
+ "collected #{@count_calls} calls, #{@count_definitions} definitions\r"
47
50
  )
48
51
  end
49
52
 
@@ -1,13 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- require 'yaml'
4
-
5
3
  module Leftovers
6
4
  class Config
7
- # :nocov:
8
- using ::Leftovers::Backports::SetCaseEq if defined?(::Leftovers::Backports::SetCaseEq)
9
- # :nocov:
10
-
11
5
  attr_reader :name
12
6
 
13
7
  def initialize(name, path: nil, content: nil)
@@ -32,16 +26,8 @@ module Leftovers
32
26
  @test_paths ||= Array(yaml[:test_paths])
33
27
  end
34
28
 
35
- def haml_paths
36
- @haml_paths ||= Array(yaml[:haml_paths])
37
- end
38
-
39
- def slim_paths
40
- @slim_paths ||= Array(yaml[:slim_paths])
41
- end
42
-
43
- def erb_paths
44
- @erb_paths ||= Array(yaml[:erb_paths])
29
+ def precompile
30
+ @precompile ||= Leftovers.each_or_self(yaml[:precompile]).to_a
45
31
  end
46
32
 
47
33
  def dynamic
@@ -62,29 +48,8 @@ module Leftovers
62
48
 
63
49
  private
64
50
 
65
- def content
66
- @content ||= ::File.exist?(path) ? ::File.read(path) : ''
67
- end
68
-
69
- def path
70
- @path ||= ::File.expand_path("../config/#{name}.yml", __dir__)
71
- end
72
-
73
51
  def yaml
74
- @yaml ||= ::Leftovers::ConfigValidator.validate_and_process!(parse_yaml, path)
75
- end
76
-
77
- def parse_yaml
78
- # :nocov:
79
- if Gem::Version.new(RUBY_VERSION) >= Gem::Version.new('2.6')
80
- Psych.safe_load(content, filename: path) || {}
81
- else
82
- Psych.safe_load(content, [], [], false, path) || {}
83
- end
84
- # :nocov:
85
- rescue ::Psych::SyntaxError => e
86
- warn "\e[31mConfig SyntaxError: #{e.message}\e[0m"
87
- Leftovers.exit 1
52
+ @yaml ||= ::Leftovers::ConfigLoader.load(name, path: @path, content: @content)
88
53
  end
89
54
  end
90
55
  end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class ArgumentPositionSchema < ValueOrObjectSchema
6
+ inherit_attributes_from StringPatternSchema
7
+
8
+ self.or_value_schema = ScalarArgumentSchema
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,21 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class ArgumentlessTransformSchema < StringEnumSchema
6
+ value :original
7
+ value :pluralize
8
+ value :singularize
9
+ value :camelize, aliases: :camelcase
10
+ value :underscore
11
+ value :titleize, aliases: :titlecase
12
+ value :demodulize
13
+ value :deconstantize
14
+ value :parameterize
15
+ value :downcase
16
+ value :upcase
17
+ value :capitalize
18
+ value :swapcase
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,56 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class Attribute
6
+ attr_reader(
7
+ :name,
8
+ :aliases, :schema # leftovers:test_only
9
+ )
10
+
11
+ attr_accessor :require_group
12
+
13
+ def initialize(name, schema, aliases: nil, require_group: nil, suggest: true)
14
+ @name = name
15
+ @schema = schema
16
+ @aliases = aliases
17
+ @require_group = require_group
18
+ @suggest = suggest
19
+ end
20
+
21
+ def without_require_group
22
+ new = dup
23
+ new.require_group = nil
24
+ new
25
+ end
26
+
27
+ def suggest?
28
+ @suggest
29
+ end
30
+
31
+ def attributes
32
+ [self]
33
+ end
34
+
35
+ def name?(name)
36
+ name = name.to_sym
37
+
38
+ @name == name || Leftovers.each_or_self(@aliases).include?(name)
39
+ end
40
+
41
+ def to_ruby(value)
42
+ [key_to_ruby, @schema.to_ruby(value)]
43
+ end
44
+
45
+ def validate_value(value)
46
+ @schema.validate(value)
47
+ end
48
+
49
+ private
50
+
51
+ def key_to_ruby
52
+ name == :unless ? :unless_arg : name
53
+ end
54
+ end
55
+ end
56
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class BuiltInPrecompilerSchema < StringEnumSchema
6
+ value :erb
7
+ value :yaml
8
+ value :json
9
+ value :slim
10
+ value :haml
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,48 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class DocumentSchema < ObjectSchema
6
+ attribute :include_paths, ValueOrArraySchema[StringSchema], aliases: :include_path
7
+ attribute :exclude_paths, ValueOrArraySchema[StringSchema], aliases: :exclude_path
8
+ attribute :test_paths, ValueOrArraySchema[StringSchema], aliases: :test_path
9
+ attribute :haml_paths, ValueOrArraySchema[StringSchema], aliases: :haml_path, suggest: false
10
+ attribute :slim_paths, ValueOrArraySchema[StringSchema], aliases: :slim_path, suggest: false
11
+ attribute :yaml_paths, ValueOrArraySchema[StringSchema], aliases: :yaml_path, suggest: false
12
+ attribute :json_paths, ValueOrArraySchema[StringSchema], aliases: :json_path, suggest: false
13
+ attribute :erb_paths, ValueOrArraySchema[StringSchema], aliases: :erb_path, suggest: false
14
+ attribute :precompile, ValueOrArraySchema[PrecompileSchema]
15
+ attribute :requires, ValueOrArraySchema[RequireSchema], aliases: :require
16
+ attribute :gems, ValueOrArraySchema[StringSchema], aliases: :gem
17
+ attribute :keep, ValueOrArraySchema[KeepTestOnlySchema]
18
+ attribute :test_only, ValueOrArraySchema[KeepTestOnlySchema]
19
+ attribute :dynamic, ValueOrArraySchema[DynamicSchema]
20
+
21
+ PRECOMPILERS = %i{haml_paths slim_paths json_paths yaml_paths erb_paths}.freeze
22
+
23
+ def self.to_ruby(node) # rubocop:disable Metrics
24
+ read_hash = super
25
+ write_hash = read_hash.dup
26
+
27
+ read_hash.each do |key, value|
28
+ next unless PRECOMPILERS.include?(key)
29
+
30
+ value = { paths: value, format: key.to_s.delete_suffix('_paths') }
31
+ yaml = { 'precompile' => [value.transform_keys(&:to_s)] }.to_yaml.delete_prefix("---\n")
32
+
33
+ Leftovers.warn(<<~MESSAGE)
34
+ \e[33m`#{key}:` is deprecated\e[0m
35
+ Replace with:
36
+ \e[32m#{yaml}\e[0m
37
+ MESSAGE
38
+
39
+ write_hash[:precompile] = Leftovers.each_or_self(write_hash[:precompile]).to_a
40
+ write_hash[:precompile] << value
41
+ write_hash.delete(key)
42
+ end
43
+
44
+ write_hash
45
+ end
46
+ end
47
+ end
48
+ end
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class DynamicSchema < ObjectSchema
6
+ inherit_attributes_from RulePatternSchema
7
+
8
+ attribute :call, ValueOrArraySchema[ValueProcessorSchema], aliases: :calls,
9
+ require_group: :processor
10
+ attribute :define, ValueOrArraySchema[ValueProcessorSchema], aliases: :defines,
11
+ require_group: :processor
12
+ attribute :set_privacy, ValueOrArraySchema[PrivacyProcessorSchema],
13
+ require_group: :processor
14
+ attribute :set_default_privacy, PrivacySchema, require_group: :processor
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class HasArgumentSchema < ValueOrObjectSchema
6
+ attribute :at, ValueOrArraySchema[ArgumentPositionSchema], require_group: :matcher
7
+ attribute :has_value, ValueOrArraySchema[HasValueSchema], require_group: :matcher
8
+ attribute :unless, ValueOrArraySchema[HasArgumentSchema], require_group: :matcher
9
+
10
+ self.or_value_schema = ScalarArgumentSchema
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class HasValueSchema < ValueOrObjectSchema
6
+ inherit_attributes_from StringPatternSchema, except: :unless
7
+
8
+ attribute :at, ValueOrArraySchema[ArgumentPositionSchema], require_group: :matcher
9
+ attribute :has_value, ValueOrArraySchema[HasValueSchema], require_group: :matcher
10
+
11
+ attribute :has_receiver, ValueOrArraySchema[HasValueSchema], require_group: :matcher
12
+ attribute :type, ValueOrArraySchema[ValueTypeSchema], require_group: :matcher
13
+ attribute :unless, ValueOrArraySchema[HasValueSchema], require_group: :matcher
14
+
15
+ self.or_value_schema = ScalarValueSchema
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,22 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class InheritSchemaAttributes
6
+ def initialize(schema, require_group: true, except: nil)
7
+ @schema = schema
8
+ @use_require_groups = require_group
9
+ @except = Leftovers.each_or_self(except)
10
+ end
11
+
12
+ def attributes
13
+ @schema.attributes.map do |attr|
14
+ next if @except.include?(attr.name)
15
+ next attr.without_require_group unless @use_require_groups
16
+
17
+ attr
18
+ end.compact
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class KeepTestOnlySchema < ValueOrObjectSchema
6
+ inherit_attributes_from StringPatternSchema, except: :unless
7
+ inherit_attributes_from RulePatternSchema, except: :unless
8
+ attribute :unless, ValueOrArraySchema[KeepTestOnlySchema], require_group: :matcher
9
+
10
+ self.or_value_schema = StringSchema
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,106 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class Node
6
+ class_loader = Psych::ClassLoader::Restricted.new([], [])
7
+ ToRuby = Psych::Visitors::ToRuby.new(
8
+ Psych::ScalarScanner.new(class_loader),
9
+ class_loader
10
+ )
11
+
12
+ attr_reader :node, :file, :name
13
+ attr_accessor :error
14
+
15
+ def initialize(node, file, name = nil)
16
+ @node = node
17
+ @file = file
18
+ @name = name
19
+ end
20
+
21
+ def name_
22
+ "#{name} " if name
23
+ end
24
+
25
+ def valid?
26
+ !error
27
+ end
28
+
29
+ def error_message
30
+ "Config SchemaError: #{location} #{@error}" if @error
31
+ end
32
+
33
+ def all_errors
34
+ Array(error_message) + children.flat_map(&:all_errors)
35
+ end
36
+
37
+ def to_s
38
+ to_ruby.to_s
39
+ end
40
+
41
+ def hash?
42
+ node.is_a?(Psych::Nodes::Mapping)
43
+ end
44
+
45
+ def location
46
+ "#{file.relative_path}:#{node.start_line + 1}:#{node.start_column}"
47
+ end
48
+
49
+ def children
50
+ @children ||= if hash?
51
+ prepare_hash_children
52
+ elsif array?
53
+ node.children.map { |value| self.class.new(value, file, "#{name} value") }
54
+ else
55
+ []
56
+ end
57
+ end
58
+
59
+ def keys
60
+ @keys ||= pairs.map(&:first)
61
+ end
62
+
63
+ def pairs
64
+ @pairs ||= children.each_slice(2).to_a
65
+ end
66
+
67
+ def each_key(&block)
68
+ keys.each(&block)
69
+ end
70
+
71
+ def to_ruby
72
+ @to_ruby ||= ToRuby.accept(node)
73
+ end
74
+
75
+ def to_sym
76
+ to_ruby.to_sym if string?
77
+ end
78
+
79
+ def string?
80
+ to_ruby.is_a?(String)
81
+ end
82
+
83
+ def scalar?
84
+ !array? and !hash?
85
+ end
86
+
87
+ def array?
88
+ node.is_a?(Psych::Nodes::Sequence)
89
+ end
90
+
91
+ def integer?
92
+ to_ruby.is_a?(Integer)
93
+ end
94
+
95
+ private
96
+
97
+ def prepare_hash_children
98
+ node.children.each_slice(2).flat_map do |key, value|
99
+ key = self.class.new(key, file, name)
100
+ value = self.class.new(value, file, key.to_ruby)
101
+ [key, value]
102
+ end
103
+ end
104
+ end
105
+ end
106
+ end