leftovers 0.7.0 → 0.10.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (227) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +39 -0
  3. data/README.md +8 -7
  4. data/docs/Configuration.md +187 -93
  5. data/docs/Custom-Precompilers.md +44 -0
  6. data/leftovers.gemspec +2 -1
  7. data/lib/config/actioncable.yml +36 -0
  8. data/lib/config/actionmailbox.yml +28 -0
  9. data/lib/config/actionmailer.yml +87 -11
  10. data/lib/config/actionpack.yml +130 -32
  11. data/lib/config/actiontext.yml +56 -0
  12. data/lib/config/actionview.yml +194 -44
  13. data/lib/config/activejob.yml +15 -8
  14. data/lib/config/activemodel.yml +175 -18
  15. data/lib/config/activerecord.yml +422 -89
  16. data/lib/config/activestorage.yml +26 -0
  17. data/lib/config/activesupport.yml +167 -24
  18. data/lib/config/haml.yml +4 -2
  19. data/lib/config/leftovers.yml +48 -0
  20. data/lib/config/rails.yml +7 -3
  21. data/lib/config/railties.yml +7 -0
  22. data/lib/config/ruby.yml +439 -95
  23. data/lib/config/slim.yml +4 -2
  24. data/lib/config/test-unit.yml +8 -0
  25. data/lib/leftovers/ast/array_node.rb +12 -0
  26. data/lib/leftovers/ast/block_node.rb +12 -0
  27. data/lib/leftovers/ast/builder.rb +24 -5
  28. data/lib/leftovers/ast/casgn_node.rb +20 -0
  29. data/lib/leftovers/ast/const_node.rb +15 -0
  30. data/lib/leftovers/ast/def_node.rb +15 -0
  31. data/lib/leftovers/ast/defs_node.rb +15 -0
  32. data/lib/leftovers/ast/false_node.rb +24 -0
  33. data/lib/leftovers/ast/has_arguments.rb +31 -0
  34. data/lib/leftovers/ast/hash_node.rb +17 -0
  35. data/lib/leftovers/ast/module_node.rb +16 -0
  36. data/lib/leftovers/ast/nil_node.rb +23 -0
  37. data/lib/leftovers/ast/node.rb +33 -90
  38. data/lib/leftovers/ast/numeric_node.rb +22 -0
  39. data/lib/leftovers/ast/send_node.rb +25 -0
  40. data/lib/leftovers/ast/str_node.rb +24 -0
  41. data/lib/leftovers/ast/sym_node.rb +25 -0
  42. data/lib/leftovers/ast/true_node.rb +24 -0
  43. data/lib/leftovers/ast/var_node.rb +14 -0
  44. data/lib/leftovers/ast/vasgn_node.rb +20 -0
  45. data/lib/leftovers/ast.rb +18 -0
  46. data/lib/leftovers/cli.rb +12 -1
  47. data/lib/leftovers/collector.rb +2 -1
  48. data/lib/leftovers/comparable_instance.rb +18 -0
  49. data/lib/leftovers/config.rb +2 -18
  50. data/lib/leftovers/config_loader/argument_position_schema.rb +5 -3
  51. data/lib/leftovers/config_loader/array_schema.rb +53 -0
  52. data/lib/leftovers/config_loader/attribute.rb +36 -10
  53. data/lib/leftovers/config_loader/built_in_precompiler_schema.rb +13 -0
  54. data/lib/leftovers/config_loader/document_schema.rb +33 -5
  55. data/lib/leftovers/config_loader/dynamic_schema.rb +1 -0
  56. data/lib/leftovers/config_loader/has_argument_schema.rb +2 -2
  57. data/lib/leftovers/config_loader/has_receiver_schema.rb +15 -0
  58. data/lib/leftovers/config_loader/has_value_schema.rb +7 -3
  59. data/lib/leftovers/config_loader/inherit_schema_attributes.rb +22 -0
  60. data/lib/leftovers/config_loader/keep_test_only_schema.rb +2 -2
  61. data/lib/leftovers/config_loader/keyword_argument_schema.rb +13 -0
  62. data/lib/leftovers/config_loader/object_schema.rb +33 -105
  63. data/lib/leftovers/config_loader/precompile_schema.rb +12 -0
  64. data/lib/leftovers/config_loader/precompiler_schema.rb +11 -0
  65. data/lib/leftovers/config_loader/privacy_processor_schema.rb +0 -2
  66. data/lib/leftovers/config_loader/regexp_schema.rb +27 -0
  67. data/lib/leftovers/config_loader/require_schema.rb +3 -3
  68. data/lib/leftovers/config_loader/rule_pattern_schema.rb +3 -1
  69. data/lib/leftovers/config_loader/scalar_value_schema.rb +8 -0
  70. data/lib/leftovers/config_loader/schema.rb +12 -0
  71. data/lib/leftovers/config_loader/string_enum_schema.rb +1 -1
  72. data/lib/leftovers/config_loader/string_pattern_schema.rb +3 -3
  73. data/lib/leftovers/config_loader/string_value_processor_schema.rb +2 -2
  74. data/lib/leftovers/config_loader/transform_schema.rb +10 -6
  75. data/lib/leftovers/config_loader/value_matcher_condition_schema.rb +13 -0
  76. data/lib/leftovers/config_loader/value_matcher_schema.rb +6 -3
  77. data/lib/leftovers/config_loader/value_or_array_schema.rb +2 -32
  78. data/lib/leftovers/config_loader/value_or_object_schema.rb +40 -0
  79. data/lib/leftovers/config_loader/value_processor_schema.rb +4 -4
  80. data/lib/leftovers/config_loader.rb +15 -3
  81. data/lib/leftovers/definition_collection.rb +37 -0
  82. data/lib/leftovers/definition_node.rb +8 -14
  83. data/lib/leftovers/definition_node_set.rb +10 -2
  84. data/lib/leftovers/file.rb +8 -54
  85. data/lib/leftovers/file_collector/comments_processor.rb +57 -0
  86. data/lib/leftovers/file_collector/node_processor.rb +131 -0
  87. data/lib/leftovers/file_collector.rb +56 -223
  88. data/lib/leftovers/file_list.rb +3 -2
  89. data/lib/leftovers/matcher_builders/and.rb +26 -9
  90. data/lib/leftovers/matcher_builders/and_not.rb +7 -5
  91. data/lib/leftovers/matcher_builders/name.rb +18 -17
  92. data/lib/leftovers/matcher_builders/node.rb +60 -34
  93. data/lib/leftovers/matcher_builders/node_has_argument.rb +48 -52
  94. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +16 -11
  95. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +29 -15
  96. data/lib/leftovers/matcher_builders/node_has_receiver.rb +12 -3
  97. data/lib/leftovers/matcher_builders/node_pair_key.rb +16 -0
  98. data/lib/leftovers/matcher_builders/node_type.rb +10 -10
  99. data/lib/leftovers/matcher_builders/node_value.rb +46 -25
  100. data/lib/leftovers/matcher_builders/or.rb +64 -49
  101. data/lib/leftovers/matcher_builders/path.rb +3 -1
  102. data/lib/leftovers/matcher_builders/string_pattern.rb +1 -1
  103. data/lib/leftovers/matcher_builders.rb +1 -1
  104. data/lib/leftovers/matchers/all.rb +4 -0
  105. data/lib/leftovers/matchers/and.rb +4 -0
  106. data/lib/leftovers/matchers/any.rb +2 -0
  107. data/lib/leftovers/matchers/node_has_any_keyword_argument.rb +7 -4
  108. data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +5 -4
  109. data/lib/leftovers/matchers/node_has_any_receiver.rb +13 -0
  110. data/lib/leftovers/matchers/node_has_positional_argument.rb +5 -1
  111. data/lib/leftovers/matchers/node_has_positional_argument_with_value.rb +6 -1
  112. data/lib/leftovers/matchers/node_has_receiver.rb +4 -0
  113. data/lib/leftovers/matchers/node_is_proc.rb +13 -0
  114. data/lib/leftovers/matchers/node_name.rb +9 -3
  115. data/lib/leftovers/matchers/node_pair_key.rb +23 -0
  116. data/lib/leftovers/matchers/node_pair_value.rb +7 -3
  117. data/lib/leftovers/matchers/node_path.rb +7 -3
  118. data/lib/leftovers/matchers/node_privacy.rb +7 -3
  119. data/lib/leftovers/matchers/node_scalar_value.rb +6 -1
  120. data/lib/leftovers/matchers/node_type.rb +7 -3
  121. data/lib/leftovers/matchers/not.rb +2 -0
  122. data/lib/leftovers/matchers/or.rb +2 -0
  123. data/lib/leftovers/matchers/path.rb +21 -0
  124. data/lib/leftovers/matchers.rb +4 -1
  125. data/lib/leftovers/merged_config.rb +28 -47
  126. data/lib/leftovers/parser.rb +7 -4
  127. data/lib/leftovers/precompilers/erb.rb +22 -0
  128. data/lib/leftovers/precompilers/haml.rb +15 -0
  129. data/lib/leftovers/precompilers/json.rb +27 -0
  130. data/lib/leftovers/precompilers/precompiler.rb +28 -0
  131. data/lib/leftovers/precompilers/slim.rb +15 -0
  132. data/lib/leftovers/precompilers/yaml.rb +75 -0
  133. data/lib/leftovers/precompilers.rb +50 -0
  134. data/lib/leftovers/processor_builders/action.rb +69 -42
  135. data/lib/leftovers/processor_builders/add_prefix.rb +18 -10
  136. data/lib/leftovers/processor_builders/add_suffix.rb +18 -10
  137. data/lib/leftovers/processor_builders/argument.rb +28 -14
  138. data/lib/leftovers/processor_builders/dynamic.rb +37 -31
  139. data/lib/leftovers/processor_builders/each.rb +83 -11
  140. data/lib/leftovers/processor_builders/itself.rb +2 -2
  141. data/lib/leftovers/processor_builders/keyword.rb +9 -9
  142. data/lib/leftovers/processor_builders/keyword_argument.rb +4 -2
  143. data/lib/leftovers/processor_builders/receiver.rb +13 -0
  144. data/lib/leftovers/processor_builders/transform.rb +55 -44
  145. data/lib/leftovers/processor_builders/transform_chain.rb +16 -8
  146. data/lib/leftovers/processor_builders/transform_set.rb +16 -32
  147. data/lib/leftovers/processor_builders/value.rb +4 -4
  148. data/lib/leftovers/processor_builders.rb +1 -3
  149. data/lib/leftovers/processors/add_call.rb +14 -0
  150. data/lib/leftovers/processors/add_definition_node.rb +16 -0
  151. data/lib/leftovers/processors/add_dynamic_prefix.rb +29 -0
  152. data/lib/leftovers/processors/add_dynamic_suffix.rb +29 -0
  153. data/lib/leftovers/{value_processors → processors}/add_prefix.rb +7 -3
  154. data/lib/leftovers/{value_processors → processors}/add_suffix.rb +7 -3
  155. data/lib/leftovers/processors/append_sym.rb +13 -0
  156. data/lib/leftovers/{value_processors → processors}/camelize.rb +7 -3
  157. data/lib/leftovers/{value_processors → processors}/capitalize.rb +7 -3
  158. data/lib/leftovers/{value_processors → processors}/deconstantize.rb +7 -3
  159. data/lib/leftovers/{value_processors → processors}/delete_after.rb +9 -5
  160. data/lib/leftovers/processors/delete_after_last.rb +26 -0
  161. data/lib/leftovers/processors/delete_before.rb +27 -0
  162. data/lib/leftovers/processors/delete_before_last.rb +27 -0
  163. data/lib/leftovers/{value_processors → processors}/delete_prefix.rb +7 -3
  164. data/lib/leftovers/{value_processors → processors}/delete_suffix.rb +7 -3
  165. data/lib/leftovers/{value_processors → processors}/demodulize.rb +7 -3
  166. data/lib/leftovers/{value_processors → processors}/downcase.rb +7 -3
  167. data/lib/leftovers/processors/each.rb +25 -0
  168. data/lib/leftovers/processors/each_for_definition_set.rb +33 -0
  169. data/lib/leftovers/processors/each_keyword.rb +29 -0
  170. data/lib/leftovers/processors/each_keyword_argument.rb +29 -0
  171. data/lib/leftovers/processors/each_positional_argument.rb +27 -0
  172. data/lib/leftovers/processors/each_positional_argument_from.rb +30 -0
  173. data/lib/leftovers/processors/eval.rb +16 -0
  174. data/lib/leftovers/processors/itself.rb +21 -0
  175. data/lib/leftovers/{value_processors → processors}/keyword_argument.rb +9 -11
  176. data/lib/leftovers/processors/match_current_node.rb +26 -0
  177. data/lib/leftovers/processors/match_matched_node.rb +26 -0
  178. data/lib/leftovers/{value_processors → processors}/parameterize.rb +7 -3
  179. data/lib/leftovers/{value_processors → processors}/placeholder.rb +5 -4
  180. data/lib/leftovers/{value_processors → processors}/pluralize.rb +7 -3
  181. data/lib/leftovers/{value_processors → processors}/positional_argument.rb +8 -6
  182. data/lib/leftovers/processors/receiver.rb +24 -0
  183. data/lib/leftovers/{value_processors → processors}/replace_value.rb +7 -3
  184. data/lib/leftovers/processors/set_default_privacy.rb +21 -0
  185. data/lib/leftovers/processors/set_privacy.rb +23 -0
  186. data/lib/leftovers/{value_processors → processors}/singularize.rb +7 -3
  187. data/lib/leftovers/{value_processors → processors}/split.rb +8 -4
  188. data/lib/leftovers/{value_processors → processors}/swapcase.rb +7 -3
  189. data/lib/leftovers/{value_processors → processors}/titleize.rb +7 -3
  190. data/lib/leftovers/{value_processors → processors}/underscore.rb +7 -3
  191. data/lib/leftovers/{value_processors → processors}/upcase.rb +7 -3
  192. data/lib/leftovers/processors.rb +49 -0
  193. data/lib/leftovers/rake_task.rb +1 -1
  194. data/lib/leftovers/version.rb +1 -1
  195. data/lib/leftovers.rb +34 -8
  196. metadata +116 -58
  197. data/lib/leftovers/dynamic_processors/call.rb +0 -22
  198. data/lib/leftovers/dynamic_processors/call_definition.rb +0 -34
  199. data/lib/leftovers/dynamic_processors/definition.rb +0 -27
  200. data/lib/leftovers/dynamic_processors/each.rb +0 -19
  201. data/lib/leftovers/dynamic_processors/null.rb +0 -9
  202. data/lib/leftovers/dynamic_processors/set_default_privacy.rb +0 -18
  203. data/lib/leftovers/dynamic_processors/set_privacy.rb +0 -23
  204. data/lib/leftovers/dynamic_processors.rb +0 -13
  205. data/lib/leftovers/erb.rb +0 -20
  206. data/lib/leftovers/haml.rb +0 -21
  207. data/lib/leftovers/json.rb +0 -28
  208. data/lib/leftovers/matcher_builders/node_pair_name.rb +0 -18
  209. data/lib/leftovers/matchers/predicate.rb +0 -19
  210. data/lib/leftovers/processor_builders/each_action.rb +0 -51
  211. data/lib/leftovers/processor_builders/each_dynamic.rb +0 -54
  212. data/lib/leftovers/processor_builders/each_for_definition_set.rb +0 -36
  213. data/lib/leftovers/slim.rb +0 -21
  214. data/lib/leftovers/value_processors/add_dynamic_prefix.rb +0 -31
  215. data/lib/leftovers/value_processors/add_dynamic_suffix.rb +0 -31
  216. data/lib/leftovers/value_processors/delete_before.rb +0 -22
  217. data/lib/leftovers/value_processors/each.rb +0 -21
  218. data/lib/leftovers/value_processors/each_for_definition_set.rb +0 -26
  219. data/lib/leftovers/value_processors/each_keyword.rb +0 -27
  220. data/lib/leftovers/value_processors/each_keyword_argument.rb +0 -27
  221. data/lib/leftovers/value_processors/each_positional_argument.rb +0 -24
  222. data/lib/leftovers/value_processors/itself.rb +0 -17
  223. data/lib/leftovers/value_processors/keyword.rb +0 -32
  224. data/lib/leftovers/value_processors/return_definition_node.rb +0 -14
  225. data/lib/leftovers/value_processors/return_sym.rb +0 -14
  226. data/lib/leftovers/value_processors.rb +0 -40
  227. data/lib/leftovers/yaml.rb +0 -73
@@ -0,0 +1,53 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class ArraySchema < Schema
6
+ class << self
7
+ def [](value_schema)
8
+ new(value_schema)
9
+ end
10
+ end
11
+
12
+ attr_reader :value_schema
13
+
14
+ def initialize(value_schema)
15
+ @value_schema = value_schema
16
+
17
+ super()
18
+ end
19
+
20
+ def validate(node)
21
+ validate_array(node) && validate_length(node) && validate_values(node)
22
+ end
23
+
24
+ def to_ruby(node)
25
+ node.children.map do |value|
26
+ value_schema.to_ruby(value)
27
+ end
28
+ end
29
+
30
+ private
31
+
32
+ def validate_array(node)
33
+ self.class.error(node, 'be an array') unless node.array?
34
+
35
+ node.valid?
36
+ end
37
+
38
+ def validate_length(node)
39
+ self.class.error(node, 'not be empty') if node.children.empty?
40
+
41
+ node.valid?
42
+ end
43
+
44
+ def validate_values(node)
45
+ node.children.each do |value|
46
+ value_schema.validate(value)
47
+ end
48
+
49
+ node.children.all?(&:valid?)
50
+ end
51
+ end
52
+ end
53
+ end
@@ -3,27 +3,53 @@
3
3
  module Leftovers
4
4
  class ConfigLoader
5
5
  class Attribute
6
- def initialize(name, value_schema, aliases: nil, require_group: nil)
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)
7
14
  @name = name
8
- @value_schema = value_schema
15
+ @schema = schema
9
16
  @aliases = aliases
10
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
11
29
  end
12
30
 
13
31
  def attributes
14
- { @name => @value_schema }
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)]
15
43
  end
16
44
 
17
- def aliases
18
- ::Leftovers.each_or_self(@aliases).map do |aka|
19
- [aka, @name]
20
- end.to_h
45
+ def validate_value(value)
46
+ @schema.validate(value)
21
47
  end
22
48
 
23
- def require_groups
24
- return {} unless @require_group
49
+ private
25
50
 
26
- { @require_group => [@name, *::Leftovers.each_or_self(@aliases)] }
51
+ def key_to_ruby
52
+ name == :unless ? :unless_arg : name
27
53
  end
28
54
  end
29
55
  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
@@ -6,16 +6,44 @@ module Leftovers
6
6
  attribute :include_paths, ValueOrArraySchema[StringSchema], aliases: :include_path
7
7
  attribute :exclude_paths, ValueOrArraySchema[StringSchema], aliases: :exclude_path
8
8
  attribute :test_paths, ValueOrArraySchema[StringSchema], aliases: :test_path
9
- attribute :haml_paths, ValueOrArraySchema[StringSchema], aliases: :haml_path
10
- attribute :slim_paths, ValueOrArraySchema[StringSchema], aliases: :slim_path
11
- attribute :yaml_paths, ValueOrArraySchema[StringSchema], aliases: :yaml_path
12
- attribute :json_paths, ValueOrArraySchema[StringSchema], aliases: :json_path
13
- attribute :erb_paths, ValueOrArraySchema[StringSchema], aliases: :erb_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]
14
15
  attribute :requires, ValueOrArraySchema[RequireSchema], aliases: :require
15
16
  attribute :gems, ValueOrArraySchema[StringSchema], aliases: :gem
16
17
  attribute :keep, ValueOrArraySchema[KeepTestOnlySchema]
17
18
  attribute :test_only, ValueOrArraySchema[KeepTestOnlySchema]
18
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').to_sym }
31
+ yaml = { 'precompile' => [value.transform_keys(&:to_s).transform_values(&:to_s)] }
32
+ .to_yaml.delete_prefix("---\n")
33
+
34
+ Leftovers.warn(<<~MESSAGE)
35
+ \e[33m`#{key}:` is deprecated\e[0m
36
+ Replace with:
37
+ \e[32m#{yaml}\e[0m
38
+ MESSAGE
39
+
40
+ write_hash[:precompile] = Leftovers.each_or_self(write_hash[:precompile]).to_a
41
+ write_hash[:precompile] << value
42
+ write_hash.delete(key)
43
+ end
44
+
45
+ write_hash
46
+ end
19
47
  end
20
48
  end
21
49
  end
@@ -12,6 +12,7 @@ module Leftovers
12
12
  attribute :set_privacy, ValueOrArraySchema[PrivacyProcessorSchema],
13
13
  require_group: :processor
14
14
  attribute :set_default_privacy, PrivacySchema, require_group: :processor
15
+ attribute :eval, ValueOrArraySchema[ValueProcessorSchema], require_group: :processor
15
16
  end
16
17
  end
17
18
  end
@@ -2,12 +2,12 @@
2
2
 
3
3
  module Leftovers
4
4
  class ConfigLoader
5
- class HasArgumentSchema < ObjectSchema
5
+ class HasArgumentSchema < ValueOrObjectSchema
6
6
  attribute :at, ValueOrArraySchema[ArgumentPositionSchema], require_group: :matcher
7
7
  attribute :has_value, ValueOrArraySchema[HasValueSchema], require_group: :matcher
8
8
  attribute :unless, ValueOrArraySchema[HasArgumentSchema], require_group: :matcher
9
9
 
10
- self.or_schema = ScalarArgumentSchema
10
+ self.or_value_schema = ScalarArgumentSchema
11
11
  end
12
12
  end
13
13
  end
@@ -0,0 +1,15 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class HasReceiverSchema < ValueOrObjectSchema
6
+ inherit_attributes_from HasValueSchema, except: :unless
7
+
8
+ attribute :literal, ValueOrArraySchema[ScalarValueSchema],
9
+ require_group: :matcher
10
+ attribute :unless, ValueOrArraySchema[HasReceiverSchema], require_group: :matcher
11
+
12
+ self.or_value_schema = ScalarValueSchema
13
+ end
14
+ end
15
+ end
@@ -2,17 +2,21 @@
2
2
 
3
3
  module Leftovers
4
4
  class ConfigLoader
5
- class HasValueSchema < ObjectSchema
5
+ class HasValueSchema < ValueOrObjectSchema
6
+ attribute :names, ValueOrArraySchema[StringPatternSchema], aliases: :name,
7
+ require_group: :matcher
6
8
  inherit_attributes_from StringPatternSchema, except: :unless
9
+ attribute :has_arguments, ValueOrArraySchema[HasArgumentSchema], aliases: :has_argument,
10
+ require_group: :matcher
7
11
 
8
12
  attribute :at, ValueOrArraySchema[ArgumentPositionSchema], require_group: :matcher
9
13
  attribute :has_value, ValueOrArraySchema[HasValueSchema], require_group: :matcher
10
14
 
11
- attribute :has_receiver, ValueOrArraySchema[HasValueSchema], require_group: :matcher
15
+ attribute :has_receiver, ValueOrArraySchema[HasReceiverSchema], require_group: :matcher
12
16
  attribute :type, ValueOrArraySchema[ValueTypeSchema], require_group: :matcher
13
17
  attribute :unless, ValueOrArraySchema[HasValueSchema], require_group: :matcher
14
18
 
15
- self.or_schema = ScalarValueSchema
19
+ self.or_value_schema = ScalarValueSchema
16
20
  end
17
21
  end
18
22
  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
@@ -2,12 +2,12 @@
2
2
 
3
3
  module Leftovers
4
4
  class ConfigLoader
5
- class KeepTestOnlySchema < ObjectSchema
5
+ class KeepTestOnlySchema < ValueOrObjectSchema
6
6
  inherit_attributes_from StringPatternSchema, except: :unless
7
7
  inherit_attributes_from RulePatternSchema, except: :unless
8
8
  attribute :unless, ValueOrArraySchema[KeepTestOnlySchema], require_group: :matcher
9
9
 
10
- self.or_schema = StringSchema
10
+ self.or_value_schema = StringSchema
11
11
  end
12
12
  end
13
13
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class KeywordArgumentSchema < ValueOrObjectSchema
6
+ inherit_attributes_from StringPatternSchema, except: :unless
7
+ attribute :type, ValueOrArraySchema[ValueTypeSchema], require_group: :matcher
8
+ attribute :unless, ValueOrArraySchema[KeywordArgumentSchema], require_group: :matcher
9
+
10
+ self.or_value_schema = StringSchema
11
+ end
12
+ end
13
+ end
@@ -2,93 +2,49 @@
2
2
 
3
3
  module Leftovers
4
4
  class ConfigLoader
5
- class ObjectSchema < Schema # rubocop:disable Metrics/ClassLength
5
+ class ObjectSchema < Schema
6
6
  class << self
7
7
  def inherit_attributes_from(schema, require_group: true, except: nil)
8
- attributes_and_schemas_to_inherit_from << schema
9
-
10
- inherit_except[schema] = Leftovers.each_or_self(except)
11
-
12
- return if require_group
13
-
14
- skip_require_group << schema
8
+ attributes_and_schemas_to_inherit_from << InheritSchemaAttributes.new(
9
+ schema, require_group: require_group, except: except
10
+ )
15
11
  end
16
12
 
17
13
  def attributes
18
- nonexcluded_attributes = attributes_and_schemas_to_inherit_from.map do |attr_or_schema|
19
- attr_or_schema.attributes.dup.tap do |attributes_copy|
20
- inherit_except[attr_or_schema]&.each { |e| attributes_copy.delete(e) }
21
- end
22
- end
23
-
24
- nonexcluded_attributes.reduce { |a, e| a.merge(e) { raise 'Duplicate attributes' } }
14
+ attributes_and_schemas_to_inherit_from.flat_map(&:attributes)
25
15
  end
26
16
 
27
- def aliases
28
- attributes_and_schemas_to_inherit_from.map(&:aliases)
29
- .reduce { |a, e| a.merge(e) { raise 'Duplicate aliases' } }
17
+ def attribute(name, value_schema, aliases: nil, require_group: nil, suggest: true)
18
+ attributes_and_schemas_to_inherit_from << Attribute.new(
19
+ name, value_schema,
20
+ aliases: aliases, require_group: require_group, suggest: suggest
21
+ )
30
22
  end
31
23
 
32
24
  def require_groups
33
- (attributes_and_schemas_to_inherit_from - skip_require_group)
34
- .map(&:require_groups).each_with_object({}) do |require_groups, hash|
35
- require_groups.each do |group, keys|
36
- hash[group] ||= []
37
- hash[group] += keys
38
- end
39
- end
40
- end
41
-
42
- attr_accessor :or_schema
43
-
44
- def attribute(name, value_schema, aliases: nil, require_group: nil)
45
- attributes_and_schemas_to_inherit_from << Attribute.new(
46
- name,
47
- value_schema,
48
- aliases: aliases,
49
- require_group: require_group
50
- )
25
+ attributes.group_by(&:require_group).tap { |rg| rg.delete(nil) }.values
51
26
  end
52
27
 
53
28
  def validate(node)
54
29
  if node.hash?
55
30
  validate_attributes(node)
56
- elsif or_schema
57
- validate_or_schema(node)
58
31
  else
59
- validate_is_hash(node)
32
+ error(node, 'be a hash')
33
+
34
+ node.valid?
60
35
  end
61
36
  end
62
37
 
63
38
  def to_ruby(node)
64
- if node.hash?
65
- node.pairs.map { |(key, value)| pair_to_ruby(key, value) }.to_h
66
- else
67
- or_schema.to_ruby(node)
68
- end
39
+ node.pairs.map { |(key, value)| attribute_for_key(key).to_ruby(value) }.to_h
69
40
  end
70
41
 
71
42
  private
72
43
 
73
- def inherit_except
74
- @inherit_except ||= {}
75
- end
76
-
77
- def skip_require_group
78
- @skip_require_group ||= []
79
- end
80
-
81
44
  def attributes_and_schemas_to_inherit_from
82
45
  @attributes_and_schemas_to_inherit_from ||= []
83
46
  end
84
47
 
85
- def pair_to_ruby(key, value)
86
- key_sym = key.to_sym
87
- key_sym = aliases[key_sym] || key_sym
88
- key_sym = :unless_arg if key_sym == :unless
89
- [key_sym, schema_for_attribute(key).to_ruby(value)]
90
- end
91
-
92
48
  def validate_attributes(node)
93
49
  validate_attribute_keys(node) && validate_required_keys(node)
94
50
  validate_alias_uniqueness_of_keys(node)
@@ -97,20 +53,8 @@ module Leftovers
97
53
  node.children.all?(&:valid?)
98
54
  end
99
55
 
100
- def validate_or_schema(node)
101
- or_schema.validate(node)
102
- return true if node.valid?
103
-
104
- if node.string? && valid_keys.include?(node.to_sym)
105
- node.error = "#{node.name_}#{node.to_sym} must be a hash key"
106
- else
107
- node.error += " or a hash with any of #{attributes.keys.join(', ')}"
108
- end
109
- end
110
-
111
- def validate_is_hash(node)
112
- error(node, 'be a hash')
113
- node.valid?
56
+ def attribute_for_key(node)
57
+ attributes.find { |attr| attr.name?(node) }
114
58
  end
115
59
 
116
60
  def validate_attribute_keys(node)
@@ -118,52 +62,45 @@ module Leftovers
118
62
  node.keys.all?(&:valid?)
119
63
  end
120
64
 
121
- def valid_keys
122
- attributes.keys + aliases.keys
123
- end
124
-
125
65
  def validate_alias_uniqueness_of_keys(node)
126
66
  node.keys.select(&:valid?)
127
- .group_by { |key| aliases[key.to_sym] || key.to_sym }
128
- .each_value do |keys|
129
- next unless keys.length > 1
67
+ .group_by { |key| attribute_for_key(key) }
68
+ .each_value { |keys| error_message_for_non_unique_keys(node, keys) if keys.length > 1 }
130
69
 
131
- error_message_for_non_unique_keys(node, keys)
132
- end
70
+ node.valid?
133
71
  end
134
72
 
135
73
  def error_message_for_non_unique_keys(node, keys)
136
- keys.each do |key|
137
- key.error = "#{node.name_}must only use one of #{keys.uniq.join(' or ')}"
138
- end
74
+ keys.each { |k| k.error = "#{node.name_}must only use one of #{keys.uniq.join(' or ')}" }
139
75
  end
140
76
 
141
77
  def validate_recognized_key(key, node)
142
- return true if valid_keys.include?(key.to_sym)
78
+ return true if attribute_for_key(key)
143
79
 
144
80
  suggestions = suggestions_for_unrecognized_key(key, node)
145
81
  did_you_mean = "\nDid you mean: #{suggestions.join(', ')}" unless suggestions.empty?
146
- for_name = " for #{node.name}" if node.name
147
-
148
- key.error = "unrecognized key #{key}#{for_name}#{did_you_mean}"
82
+ key.error = "unrecognized key #{key}#{" for #{node.name}" if node.name}#{did_you_mean}"
149
83
 
150
84
  false
151
85
  end
152
86
 
153
87
  def suggester
154
- @suggester ||= Suggester.new(attributes.keys)
88
+ @suggester ||= Suggester.new(suggestions)
155
89
  end
156
90
 
157
91
  def suggestions_for_unrecognized_key(key, node)
158
- existing_keys = node.keys.flat_map { |k| [k.to_sym, aliases[k.to_sym]] }.compact
159
- suggester.suggest(key.to_ruby) - existing_keys
92
+ suggester.suggest(key.to_ruby) - node.keys.map { |k| attribute_for_key(k)&.name }.compact
93
+ end
94
+
95
+ def suggestions(attributes = self.attributes)
96
+ attributes.select(&:suggest?).map(&:name)
160
97
  end
161
98
 
162
99
  def validate_required_keys(node)
163
- missing_groups = require_groups.map do |_name, group|
164
- next if node.keys.any? { |key| group.include?(key.to_sym) }
100
+ missing_groups = require_groups.map do |group|
101
+ next if node.keys.any? { |key| group.any? { |attr| attr.name?(key) } }
165
102
 
166
- "include at least one of #{(attributes.keys & group).join(', ')}"
103
+ "include at least one of #{suggestions(group).join(', ')}"
167
104
  end.compact
168
105
 
169
106
  error(node, missing_groups.join(' and ')) unless missing_groups.empty?
@@ -171,17 +108,8 @@ module Leftovers
171
108
  node.valid?
172
109
  end
173
110
 
174
- def schema_for_attribute(key)
175
- key_sym = key.to_sym
176
- attributes[key_sym] || attributes.fetch(aliases[key_sym])
177
- end
178
-
179
111
  def validate_valid_attribute_values(node)
180
- node.pairs.each do |(key, value)|
181
- next unless key.valid?
182
-
183
- schema_for_attribute(key).validate(value)
184
- end
112
+ node.pairs.each { |(k, v)| attribute_for_key(k).validate_value(v) if k.valid? }
185
113
  end
186
114
  end
187
115
  end
@@ -0,0 +1,12 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class PrecompileSchema < ObjectSchema
6
+ attribute :paths, ValueOrArraySchema[StringSchema],
7
+ aliases: %i{path include_paths include_path}, require_group: :paths
8
+
9
+ attribute :format, PrecompilerSchema, require_group: :precompiler
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,11 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class PrecompilerSchema < ValueOrObjectSchema
6
+ attribute :custom, StringSchema, require_group: :custom
7
+
8
+ self.or_value_schema = BuiltInPrecompilerSchema
9
+ end
10
+ end
11
+ end
@@ -5,8 +5,6 @@ module Leftovers
5
5
  class PrivacyProcessorSchema < ObjectSchema
6
6
  inherit_attributes_from ValueProcessorSchema
7
7
  attribute :to, PrivacySchema, require_group: :privacy_setting
8
-
9
- self.or_schema = nil
10
8
  end
11
9
  end
12
10
  end
@@ -0,0 +1,27 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class RegexpSchema < StringSchema
6
+ class << self
7
+ def validate(node)
8
+ validate_string(node) && validate_regexp(node)
9
+ end
10
+
11
+ def validate_string(node)
12
+ error(node, 'be a string with a valid ruby regexp') unless node.string?
13
+
14
+ node.valid?
15
+ end
16
+
17
+ def validate_regexp(node)
18
+ /#{node.to_ruby}/
19
+ rescue RegexpError, ArgumentError => e
20
+ error(node, "be a string with a valid ruby regexp (#{e.message})")
21
+ else
22
+ true
23
+ end
24
+ end
25
+ end
26
+ end
27
+ end
@@ -2,10 +2,10 @@
2
2
 
3
3
  module Leftovers
4
4
  class ConfigLoader
5
- class RequireSchema < ObjectSchema
6
- attribute :quiet, StringSchema, aliases: :name, require_group: :quiet
5
+ class RequireSchema < ValueOrObjectSchema
6
+ attribute :quiet, StringSchema, require_group: :quiet
7
7
 
8
- self.or_schema = StringSchema
8
+ self.or_value_schema = StringSchema
9
9
  end
10
10
  end
11
11
  end
@@ -9,10 +9,12 @@ module Leftovers
9
9
  attribute :document, TrueSchema, require_group: :matcher
10
10
  attribute :has_arguments, ValueOrArraySchema[HasArgumentSchema], aliases: :has_argument,
11
11
  require_group: :matcher
12
- attribute :has_receiver, ValueOrArraySchema[HasValueSchema], require_group: :matcher
12
+ attribute :has_receiver, ValueOrArraySchema[HasReceiverSchema], require_group: :matcher
13
13
  attribute :type, ValueOrArraySchema[ValueTypeSchema], require_group: :matcher
14
14
  attribute :privacy, ValueOrArraySchema[PrivacySchema], require_group: :matcher
15
15
  attribute :unless, ValueOrArraySchema[RulePatternSchema], require_group: :matcher
16
+ attribute :all, ArraySchema[RulePatternSchema], require_group: :matcher
17
+ attribute :any, ArraySchema[RulePatternSchema], require_group: :matcher
16
18
  end
17
19
  end
18
20
  end
@@ -8,6 +8,14 @@ module Leftovers
8
8
  error(node, 'be any scalar value') unless node.scalar?
9
9
  super
10
10
  end
11
+
12
+ def to_ruby(node)
13
+ if node.to_ruby.nil?
14
+ :_leftovers_nil_value
15
+ else
16
+ node.to_ruby
17
+ end
18
+ end
11
19
  end
12
20
  end
13
21
  end
@@ -6,6 +6,8 @@ module Leftovers
6
6
  class << self
7
7
  def error(node, requirement)
8
8
  node.error = "#{node.name_}must #{requirement}"
9
+
10
+ false
9
11
  end
10
12
 
11
13
  def validate(node)
@@ -15,6 +17,16 @@ module Leftovers
15
17
  def to_ruby(node)
16
18
  node.to_ruby
17
19
  end
20
+
21
+ def ===(other) # leftovers:test_only
22
+ # :nocov:
23
+ if other.is_a?(Module)
24
+ self >= other
25
+ else
26
+ other.is_a?(self)
27
+ end
28
+ # :nocov:
29
+ end
18
30
  end
19
31
  end
20
32
  end
@@ -28,7 +28,7 @@ module Leftovers
28
28
  end
29
29
 
30
30
  def to_ruby(node)
31
- aliases[node.to_sym]&.to_s || node.to_ruby
31
+ aliases[node.to_sym] || node.to_sym
32
32
  end
33
33
 
34
34
  def validate(node)