leftovers 0.6.0 → 0.9.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (235) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +51 -3
  3. data/README.md +8 -7
  4. data/docs/Configuration.md +241 -105
  5. data/docs/Custom-Precompilers.md +44 -0
  6. data/leftovers.gemspec +3 -2
  7. data/lib/config/actioncable.yml +36 -4
  8. data/lib/config/actionmailbox.yml +28 -0
  9. data/lib/config/actionmailer.yml +92 -16
  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 +397 -86
  16. data/lib/config/activestorage.yml +26 -0
  17. data/lib/config/activesupport.yml +168 -25
  18. data/lib/config/haml.yml +4 -2
  19. data/lib/config/leftovers.yml +48 -0
  20. data/lib/config/rails.yml +8 -4
  21. data/lib/config/railties.yml +18 -0
  22. data/lib/config/ruby.yml +473 -57
  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 +39 -91
  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 +3 -42
  50. data/lib/leftovers/config_loader/argument_position_schema.rb +13 -0
  51. data/lib/leftovers/config_loader/argumentless_transform_schema.rb +21 -0
  52. data/lib/leftovers/config_loader/array_schema.rb +53 -0
  53. data/lib/leftovers/config_loader/attribute.rb +56 -0
  54. data/lib/leftovers/config_loader/built_in_precompiler_schema.rb +13 -0
  55. data/lib/leftovers/config_loader/document_schema.rb +49 -0
  56. data/lib/leftovers/config_loader/dynamic_schema.rb +18 -0
  57. data/lib/leftovers/config_loader/has_argument_schema.rb +13 -0
  58. data/lib/leftovers/config_loader/has_value_schema.rb +22 -0
  59. data/lib/leftovers/config_loader/inherit_schema_attributes.rb +22 -0
  60. data/lib/leftovers/config_loader/keep_test_only_schema.rb +13 -0
  61. data/lib/leftovers/config_loader/keyword_argument_schema.rb +13 -0
  62. data/lib/leftovers/config_loader/node.rb +106 -0
  63. data/lib/leftovers/config_loader/object_schema.rb +117 -0
  64. data/lib/leftovers/config_loader/precompile_schema.rb +12 -0
  65. data/lib/leftovers/config_loader/precompiler_schema.rb +11 -0
  66. data/lib/leftovers/config_loader/privacy_processor_schema.rb +10 -0
  67. data/lib/leftovers/config_loader/privacy_schema.rb +15 -0
  68. data/lib/leftovers/config_loader/regexp_schema.rb +27 -0
  69. data/lib/leftovers/config_loader/require_schema.rb +11 -0
  70. data/lib/leftovers/config_loader/rule_pattern_schema.rb +20 -0
  71. data/lib/leftovers/config_loader/scalar_argument_schema.rb +14 -0
  72. data/lib/leftovers/config_loader/scalar_value_schema.rb +22 -0
  73. data/lib/leftovers/config_loader/schema.rb +33 -0
  74. data/lib/leftovers/config_loader/string_enum_schema.rb +62 -0
  75. data/lib/leftovers/config_loader/string_pattern_schema.rb +14 -0
  76. data/lib/leftovers/config_loader/string_schema.rb +14 -0
  77. data/lib/leftovers/config_loader/string_value_processor_schema.rb +11 -0
  78. data/lib/leftovers/config_loader/suggester.rb +22 -0
  79. data/lib/leftovers/config_loader/transform_schema.rb +32 -0
  80. data/lib/leftovers/config_loader/true_schema.rb +18 -0
  81. data/lib/leftovers/config_loader/value_matcher_condition_schema.rb +13 -0
  82. data/lib/leftovers/config_loader/value_matcher_schema.rb +21 -0
  83. data/lib/leftovers/config_loader/value_or_array_schema.rb +34 -0
  84. data/lib/leftovers/config_loader/value_or_object_schema.rb +40 -0
  85. data/lib/leftovers/config_loader/value_processor_schema.rb +14 -0
  86. data/lib/leftovers/config_loader/value_type_schema.rb +17 -0
  87. data/lib/leftovers/config_loader.rb +93 -0
  88. data/lib/leftovers/definition_collection.rb +37 -0
  89. data/lib/leftovers/definition_node.rb +6 -17
  90. data/lib/leftovers/definition_node_set.rb +19 -0
  91. data/lib/leftovers/definition_to_add.rb +31 -0
  92. data/lib/leftovers/file.rb +13 -55
  93. data/lib/leftovers/file_collector/comments_processor.rb +57 -0
  94. data/lib/leftovers/file_collector/node_processor.rb +131 -0
  95. data/lib/leftovers/file_collector.rb +62 -202
  96. data/lib/leftovers/file_list.rb +3 -2
  97. data/lib/leftovers/matcher_builders/and.rb +26 -9
  98. data/lib/leftovers/matcher_builders/and_not.rb +7 -5
  99. data/lib/leftovers/matcher_builders/name.rb +18 -17
  100. data/lib/leftovers/matcher_builders/node.rb +60 -30
  101. data/lib/leftovers/matcher_builders/node_has_argument.rb +48 -52
  102. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +16 -11
  103. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +29 -15
  104. data/lib/leftovers/matcher_builders/node_pair_key.rb +16 -0
  105. data/lib/leftovers/matcher_builders/node_privacy.rb +13 -0
  106. data/lib/leftovers/matcher_builders/node_type.rb +11 -11
  107. data/lib/leftovers/matcher_builders/node_value.rb +44 -25
  108. data/lib/leftovers/matcher_builders/or.rb +64 -49
  109. data/lib/leftovers/matcher_builders/path.rb +3 -1
  110. data/lib/leftovers/matcher_builders/string_pattern.rb +14 -5
  111. data/lib/leftovers/matcher_builders.rb +2 -1
  112. data/lib/leftovers/matchers/all.rb +4 -0
  113. data/lib/leftovers/matchers/and.rb +4 -0
  114. data/lib/leftovers/matchers/any.rb +2 -0
  115. data/lib/leftovers/matchers/node_has_any_keyword_argument.rb +7 -4
  116. data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +5 -4
  117. data/lib/leftovers/matchers/node_has_positional_argument.rb +5 -1
  118. data/lib/leftovers/matchers/node_has_positional_argument_with_value.rb +6 -1
  119. data/lib/leftovers/matchers/node_has_receiver.rb +4 -0
  120. data/lib/leftovers/matchers/node_is_proc.rb +13 -0
  121. data/lib/leftovers/matchers/node_name.rb +9 -3
  122. data/lib/leftovers/matchers/node_pair_key.rb +23 -0
  123. data/lib/leftovers/matchers/node_pair_value.rb +7 -3
  124. data/lib/leftovers/matchers/node_path.rb +7 -3
  125. data/lib/leftovers/matchers/node_privacy.rb +23 -0
  126. data/lib/leftovers/matchers/node_scalar_value.rb +6 -1
  127. data/lib/leftovers/matchers/node_type.rb +7 -3
  128. data/lib/leftovers/matchers/not.rb +2 -0
  129. data/lib/leftovers/matchers/or.rb +2 -0
  130. data/lib/leftovers/matchers/path.rb +21 -0
  131. data/lib/leftovers/matchers.rb +4 -1
  132. data/lib/leftovers/merged_config.rb +40 -75
  133. data/lib/leftovers/parser.rb +7 -4
  134. data/lib/leftovers/precompilers/erb.rb +22 -0
  135. data/lib/leftovers/precompilers/haml.rb +15 -0
  136. data/lib/leftovers/precompilers/json.rb +27 -0
  137. data/lib/leftovers/precompilers/precompiler.rb +28 -0
  138. data/lib/leftovers/precompilers/slim.rb +15 -0
  139. data/lib/leftovers/precompilers/yaml.rb +75 -0
  140. data/lib/leftovers/precompilers.rb +50 -0
  141. data/lib/leftovers/processor_builders/action.rb +69 -42
  142. data/lib/leftovers/processor_builders/add_prefix.rb +18 -10
  143. data/lib/leftovers/processor_builders/add_suffix.rb +18 -10
  144. data/lib/leftovers/processor_builders/argument.rb +28 -14
  145. data/lib/leftovers/processor_builders/dynamic.rb +57 -17
  146. data/lib/leftovers/processor_builders/each.rb +83 -11
  147. data/lib/leftovers/processor_builders/itself.rb +2 -2
  148. data/lib/leftovers/processor_builders/keyword.rb +9 -9
  149. data/lib/leftovers/processor_builders/keyword_argument.rb +4 -2
  150. data/lib/leftovers/processor_builders/receiver.rb +13 -0
  151. data/lib/leftovers/processor_builders/transform.rb +55 -44
  152. data/lib/leftovers/processor_builders/transform_chain.rb +16 -8
  153. data/lib/leftovers/processor_builders/transform_set.rb +16 -32
  154. data/lib/leftovers/processor_builders/value.rb +4 -4
  155. data/lib/leftovers/processor_builders.rb +1 -3
  156. data/lib/leftovers/processors/add_call.rb +14 -0
  157. data/lib/leftovers/processors/add_definition_node.rb +16 -0
  158. data/lib/leftovers/processors/add_dynamic_prefix.rb +29 -0
  159. data/lib/leftovers/processors/add_dynamic_suffix.rb +29 -0
  160. data/lib/leftovers/{value_processors → processors}/add_prefix.rb +7 -3
  161. data/lib/leftovers/{value_processors → processors}/add_suffix.rb +7 -3
  162. data/lib/leftovers/processors/append_sym.rb +13 -0
  163. data/lib/leftovers/{value_processors → processors}/camelize.rb +7 -3
  164. data/lib/leftovers/{value_processors → processors}/capitalize.rb +7 -3
  165. data/lib/leftovers/{value_processors → processors}/deconstantize.rb +7 -3
  166. data/lib/leftovers/{value_processors → processors}/delete_after.rb +9 -5
  167. data/lib/leftovers/processors/delete_after_last.rb +26 -0
  168. data/lib/leftovers/processors/delete_before.rb +27 -0
  169. data/lib/leftovers/processors/delete_before_last.rb +27 -0
  170. data/lib/leftovers/{value_processors → processors}/delete_prefix.rb +7 -3
  171. data/lib/leftovers/{value_processors → processors}/delete_suffix.rb +7 -3
  172. data/lib/leftovers/{value_processors → processors}/demodulize.rb +7 -3
  173. data/lib/leftovers/{value_processors → processors}/downcase.rb +7 -3
  174. data/lib/leftovers/processors/each.rb +25 -0
  175. data/lib/leftovers/processors/each_for_definition_set.rb +33 -0
  176. data/lib/leftovers/processors/each_keyword.rb +29 -0
  177. data/lib/leftovers/processors/each_keyword_argument.rb +29 -0
  178. data/lib/leftovers/processors/each_positional_argument.rb +27 -0
  179. data/lib/leftovers/processors/each_positional_argument_from.rb +30 -0
  180. data/lib/leftovers/processors/eval.rb +16 -0
  181. data/lib/leftovers/processors/itself.rb +21 -0
  182. data/lib/leftovers/{value_processors → processors}/keyword_argument.rb +9 -11
  183. data/lib/leftovers/processors/match_current_node.rb +26 -0
  184. data/lib/leftovers/processors/match_matched_node.rb +26 -0
  185. data/lib/leftovers/{value_processors → processors}/parameterize.rb +7 -3
  186. data/lib/leftovers/{value_processors → processors}/placeholder.rb +5 -4
  187. data/lib/leftovers/{value_processors → processors}/pluralize.rb +7 -3
  188. data/lib/leftovers/{value_processors → processors}/positional_argument.rb +8 -6
  189. data/lib/leftovers/processors/receiver.rb +24 -0
  190. data/lib/leftovers/{value_processors → processors}/replace_value.rb +7 -3
  191. data/lib/leftovers/processors/set_default_privacy.rb +21 -0
  192. data/lib/leftovers/processors/set_privacy.rb +23 -0
  193. data/lib/leftovers/{value_processors → processors}/singularize.rb +7 -3
  194. data/lib/leftovers/{value_processors → processors}/split.rb +8 -4
  195. data/lib/leftovers/{value_processors → processors}/swapcase.rb +7 -3
  196. data/lib/leftovers/{value_processors → processors}/titleize.rb +7 -3
  197. data/lib/leftovers/{value_processors → processors}/underscore.rb +7 -3
  198. data/lib/leftovers/{value_processors → processors}/upcase.rb +7 -3
  199. data/lib/leftovers/processors.rb +49 -0
  200. data/lib/leftovers/rake_task.rb +1 -1
  201. data/lib/leftovers/version.rb +1 -1
  202. data/lib/leftovers.rb +55 -20
  203. metadata +159 -72
  204. data/lib/leftovers/config_validator/error_processor.rb +0 -196
  205. data/lib/leftovers/config_validator/schema_hash.rb +0 -551
  206. data/lib/leftovers/config_validator.rb +0 -61
  207. data/lib/leftovers/dynamic_processors/call.rb +0 -21
  208. data/lib/leftovers/dynamic_processors/call_definition.rb +0 -27
  209. data/lib/leftovers/dynamic_processors/definition.rb +0 -22
  210. data/lib/leftovers/dynamic_processors/each.rb +0 -19
  211. data/lib/leftovers/dynamic_processors/null.rb +0 -9
  212. data/lib/leftovers/dynamic_processors.rb +0 -11
  213. data/lib/leftovers/erb.rb +0 -20
  214. data/lib/leftovers/haml.rb +0 -21
  215. data/lib/leftovers/json.rb +0 -28
  216. data/lib/leftovers/matcher_builders/node_pair_name.rb +0 -18
  217. data/lib/leftovers/matchers/predicate.rb +0 -19
  218. data/lib/leftovers/processor_builders/each_action.rb +0 -51
  219. data/lib/leftovers/processor_builders/each_dynamic.rb +0 -54
  220. data/lib/leftovers/processor_builders/each_for_definition_set.rb +0 -36
  221. data/lib/leftovers/slim.rb +0 -21
  222. data/lib/leftovers/value_processors/add_dynamic_prefix.rb +0 -31
  223. data/lib/leftovers/value_processors/add_dynamic_suffix.rb +0 -31
  224. data/lib/leftovers/value_processors/delete_before.rb +0 -22
  225. data/lib/leftovers/value_processors/each.rb +0 -21
  226. data/lib/leftovers/value_processors/each_for_definition_set.rb +0 -29
  227. data/lib/leftovers/value_processors/each_keyword.rb +0 -27
  228. data/lib/leftovers/value_processors/each_keyword_argument.rb +0 -27
  229. data/lib/leftovers/value_processors/each_positional_argument.rb +0 -24
  230. data/lib/leftovers/value_processors/itself.rb +0 -17
  231. data/lib/leftovers/value_processors/keyword.rb +0 -32
  232. data/lib/leftovers/value_processors/return_definition.rb +0 -22
  233. data/lib/leftovers/value_processors/return_string.rb +0 -14
  234. data/lib/leftovers/value_processors.rb +0 -40
  235. data/lib/leftovers/yaml.rb +0 -73
@@ -3,41 +3,71 @@
3
3
  module Leftovers
4
4
  module MatcherBuilders
5
5
  module Node
6
- def self.build(pattern)
7
- ::Leftovers::MatcherBuilders::Or.each_or_self(pattern) do |pat|
8
- case pat
9
- when ::String
10
- ::Leftovers::MatcherBuilders::NodeName.build(pat)
11
- when ::Hash
12
- build_from_hash(**pat)
13
- # :nocov:
14
- else raise
15
- # :nocov:
6
+ class << self
7
+ def build(patterns)
8
+ ::Leftovers::MatcherBuilders::Or.each_or_self(patterns) do |pattern|
9
+ case pattern
10
+ when ::String then ::Leftovers::MatcherBuilders::NodeName.build(pattern)
11
+ when ::Hash then build_from_hash(**pattern)
12
+ # :nocov:
13
+ else raise Leftovers::UnexpectedCase, "Unhandled value #{pattern.inspect}"
14
+ # :nocov:
15
+ end
16
16
  end
17
17
  end
18
- end
19
18
 
20
- def self.build_from_hash( # rubocop:disable Metrics/ParameterLists, Metrics/MethodLength
21
- names: nil, match: nil, has_prefix: nil, has_suffix: nil,
22
- document: false,
23
- paths: nil,
24
- has_arguments: nil,
25
- has_receiver: nil,
26
- unless_arg: nil
27
- )
28
- ::Leftovers::MatcherBuilders::And.build([
29
- ::Leftovers::MatcherBuilders::NodeName.build([
30
- names,
31
- { match: match, has_prefix: has_prefix, has_suffix: has_suffix }.compact
32
- ]),
33
- ::Leftovers::MatcherBuilders::Document.build(document),
34
- ::Leftovers::MatcherBuilders::NodePath.build(paths),
35
- ::Leftovers::MatcherBuilders::NodeHasArgument.build(has_arguments),
36
- ::Leftovers::MatcherBuilders::NodeHasReceiver.build(has_receiver),
19
+ def build_from_hash( # rubocop:disable Metrics/ParameterLists
20
+ names: nil, match: nil, has_prefix: nil, has_suffix: nil,
21
+ document: false,
22
+ paths: nil,
23
+ has_arguments: nil,
24
+ has_receiver: nil,
25
+ type: nil,
26
+ privacy: nil,
27
+ unless_arg: nil, all: nil, any: nil
28
+ )
29
+ ::Leftovers::MatcherBuilders::And.build([
30
+ build_node_name_matcher(names, match, has_prefix, has_suffix),
31
+ ::Leftovers::MatcherBuilders::Document.build(document),
32
+ ::Leftovers::MatcherBuilders::NodePath.build(paths),
33
+ ::Leftovers::MatcherBuilders::NodeHasArgument.build(has_arguments),
34
+ ::Leftovers::MatcherBuilders::NodeHasReceiver.build(has_receiver),
35
+ ::Leftovers::MatcherBuilders::NodePrivacy.build(privacy),
36
+ ::Leftovers::MatcherBuilders::NodeType.build(type),
37
+ build_unless_matcher(unless_arg), build_all_matcher(all), build_any_matcher(any)
38
+ ])
39
+ end
40
+
41
+ private
42
+
43
+ def build_node_name_matcher(names, match, has_prefix, has_suffix)
44
+ ::Leftovers::MatcherBuilders::Or.build([
45
+ ::Leftovers::MatcherBuilders::NodeName.build(names),
46
+ ::Leftovers::MatcherBuilders::NodeName.build(
47
+ match: match, has_prefix: has_prefix, has_suffix: has_suffix
48
+ )
49
+ ])
50
+ end
51
+
52
+ def build_unless_matcher(unless_arg)
53
+ return unless unless_arg
54
+
37
55
  ::Leftovers::MatcherBuilders::Unless.build(
38
- (::Leftovers::MatcherBuilders::Node.build(unless_arg) if unless_arg)
56
+ ::Leftovers::MatcherBuilders::Node.build(unless_arg)
39
57
  )
40
- ])
58
+ end
59
+
60
+ def build_all_matcher(all)
61
+ return unless all
62
+
63
+ ::Leftovers::MatcherBuilders::And.build(
64
+ all.map { |pattern| ::Leftovers::MatcherBuilders::Node.build(pattern) }
65
+ )
66
+ end
67
+
68
+ def build_any_matcher(any)
69
+ ::Leftovers::MatcherBuilders::Node.build(any)
70
+ end
41
71
  end
42
72
  end
43
73
  end
@@ -3,71 +3,67 @@
3
3
  module Leftovers
4
4
  module MatcherBuilders
5
5
  module NodeHasArgument
6
- def self.build(patterns) # rubocop:disable Metrics/MethodLength
7
- ::Leftovers::MatcherBuilders::Or.each_or_self(patterns) do |pat|
8
- case pat
9
- when ::String
10
- ::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(pat, nil)
11
- when ::Integer
12
- ::Leftovers::MatcherBuilders::NodeHasPositionalArgument.build(pat, nil)
13
- when ::Hash
14
- build_from_hash(**pat)
15
- # :nocov:
16
- else
17
- raise
6
+ class << self
7
+ def build(patterns)
8
+ ::Leftovers::MatcherBuilders::Or.each_or_self(patterns) do |pat|
9
+ case pat
10
+ when ::String
11
+ ::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(pat, nil)
12
+ when ::Integer
13
+ ::Leftovers::MatcherBuilders::NodeHasPositionalArgument.build(pat, nil)
14
+ when ::Hash then build_from_hash(**pat)
18
15
  # :nocov:
16
+ else raise Leftovers::UnexpectedCase, "Unhandled value #{pat.inspect}"
17
+ # :nocov:
18
+ end
19
19
  end
20
20
  end
21
- end
22
21
 
23
- def self.separate_argument_types(at) # rubocop:disable Metrics/MethodLength
24
- keys = []
25
- positions = []
22
+ private
26
23
 
27
- ::Leftovers.each_or_self(at) do |k|
28
- case k
29
- when '*', ::Integer
30
- positions << k
31
- when ::String, ::Hash
32
- keys << k
33
- # :nocov:
34
- else raise
35
- # :nocov:
36
- end
37
- end
24
+ def build_from_hash(at: nil, has_value: nil, unless_arg: nil)
25
+ value_matcher = ::Leftovers::MatcherBuilders::NodeValue.build(has_value)
38
26
 
39
- keys = nil if keys.empty?
40
- positions = nil if positions.empty?
27
+ ::Leftovers::MatcherBuilders::AndNot.build(
28
+ build_argument_matcher(value_matcher, **separate_argument_types(at)),
29
+ ::Leftovers::MatcherBuilders::NodeHasArgument.build(unless_arg)
30
+ )
31
+ end
41
32
 
42
- [keys, positions]
43
- end
33
+ def separate_argument_types(at)
34
+ groups = ::Leftovers.each_or_self(at).group_by do |index|
35
+ case index
36
+ when '*', ::Integer then :positions
37
+ when ::String, ::Hash then :keys
38
+ # :nocov:
39
+ else raise Leftovers::UnexpectedCase, "Unhandled value #{index.inspect}"
40
+ # :nocov:
41
+ end
42
+ end
44
43
 
45
- def self.build_from_hash( # rubocop:disable Metrics/MethodLength
46
- at: nil,
47
- has_value: nil,
48
- unless_arg: nil
49
- )
50
- keys, positions = separate_argument_types(at)
44
+ groups.transform_values { |v| Leftovers.unwrap_array(v) }
45
+ end
51
46
 
52
- value_matcher = ::Leftovers::MatcherBuilders::NodeValue.build(has_value)
53
- matcher = if (keys && positions) || (!keys && !positions)
54
- ::Leftovers::MatcherBuilders::Or.build([
55
- ::Leftovers::MatcherBuilders::NodeHasPositionalArgument.build(positions, value_matcher),
56
- ::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(keys, value_matcher)
57
- ])
58
- elsif keys
47
+ def build_has_keyword_argument(keys, value_matcher)
59
48
  ::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(keys, value_matcher)
60
- elsif positions
49
+ end
50
+
51
+ def build_has_positional_argument(positions, value_matcher)
61
52
  ::Leftovers::MatcherBuilders::NodeHasPositionalArgument.build(positions, value_matcher)
62
- # :nocov:
63
- else
64
- raise
65
- # :nocov:
66
53
  end
67
54
 
68
- ::Leftovers::MatcherBuilders::AndNot.build(
69
- matcher, ::Leftovers::MatcherBuilders::NodeHasArgument.build(unless_arg)
70
- )
55
+ def build_argument_matcher(value_matcher, keys: nil, positions: nil)
56
+ if keys && !positions
57
+ build_has_keyword_argument(keys, value_matcher)
58
+ elsif positions && !keys
59
+ build_has_positional_argument(positions, value_matcher)
60
+ else
61
+ ::Leftovers::MatcherBuilders::Or.build([
62
+ build_has_positional_argument(positions, value_matcher),
63
+ build_has_keyword_argument(keys, value_matcher)
64
+ ])
65
+ end
66
+ end
71
67
  end
72
68
  end
73
69
  end
@@ -4,22 +4,27 @@ module Leftovers
4
4
  module MatcherBuilders
5
5
  module NodeHasKeywordArgument
6
6
  class << self
7
- def build(keywords, value_matcher) # rubocop:disable Metrics/MethodLength
7
+ def build(keywords, value_matcher)
8
8
  value_matcher = ::Leftovers::MatcherBuilders::NodePairValue.build(value_matcher)
9
- keyword_matcher = if ::Leftovers.each_or_self(keywords).include?('**')
10
- ::Leftovers::Matchers::NodeType.new(:pair)
11
- else
12
- ::Leftovers::MatcherBuilders::NodePairName.build(keywords)
13
- end
9
+ keyword_matcher = build_keyword_matcher(keywords)
10
+ pair_matcher = ::Leftovers::MatcherBuilders::And.build([keyword_matcher, value_matcher])
14
11
 
15
- pair_matcher = ::Leftovers::MatcherBuilders::And.build([
16
- keyword_matcher, value_matcher
17
- ])
18
-
19
- return nil unless pair_matcher
12
+ return unless pair_matcher
20
13
 
21
14
  ::Leftovers::Matchers::NodeHasAnyKeywordArgument.new(pair_matcher)
22
15
  end
16
+
17
+ private
18
+
19
+ def build_keyword_matcher(keywords)
20
+ if ::Leftovers.each_or_self(keywords).include?('**')
21
+ ::Leftovers::Matchers::NodeType.new(:pair)
22
+ else
23
+ ::Leftovers::MatcherBuilders::NodePairKey.build(
24
+ ::Leftovers::MatcherBuilders::Node.build(keywords)
25
+ )
26
+ end
27
+ end
23
28
  end
24
29
  end
25
30
  end
@@ -4,22 +4,36 @@ module Leftovers
4
4
  module MatcherBuilders
5
5
  module NodeHasPositionalArgument
6
6
  class << self
7
- def build(positions, value_matcher) # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity, Metrics/MethodLength
8
- if positions && value_matcher
9
- ::Leftovers::MatcherBuilders::Or.each_or_self(positions) do |pos|
10
- if pos == '*'
11
- ::Leftovers::Matchers::NodeHasAnyPositionalArgumentWithValue.new(value_matcher)
12
- else
13
- ::Leftovers::Matchers::NodeHasPositionalArgumentWithValue.new(pos, value_matcher)
14
- end
15
- end
16
- elsif positions
17
- pos = 0 if ::Leftovers.each_or_self(positions).include?('*')
18
- pos ||= ::Leftovers.each_or_self(positions).min
19
-
20
- ::Leftovers::Matchers::NodeHasPositionalArgument.new(pos)
7
+ def build(positions, value_matcher)
8
+ if positions && !all_positions?(positions) && value_matcher
9
+ build_has_positional_value_matcher(positions, value_matcher)
10
+ elsif positions && !value_matcher
11
+ build_has_position_matcher(positions)
21
12
  elsif value_matcher
22
- ::Leftovers::Matchers::NodeHasAnyPositionalArgumentWithValue.new(value_matcher)
13
+ build_has_any_positional_value_matcher(value_matcher)
14
+ end
15
+ end
16
+
17
+ private
18
+
19
+ def all_positions?(positions)
20
+ ::Leftovers.each_or_self(positions).include?('*')
21
+ end
22
+
23
+ def build_has_position_matcher(positions)
24
+ position = 0 if all_positions?(positions)
25
+ position ||= ::Leftovers.each_or_self(positions).min
26
+
27
+ ::Leftovers::Matchers::NodeHasPositionalArgument.new(position)
28
+ end
29
+
30
+ def build_has_any_positional_value_matcher(value_matcher)
31
+ ::Leftovers::Matchers::NodeHasAnyPositionalArgumentWithValue.new(value_matcher)
32
+ end
33
+
34
+ def build_has_positional_value_matcher(positions, value_matcher)
35
+ ::Leftovers::MatcherBuilders::Or.each_or_self(positions) do |position|
36
+ ::Leftovers::Matchers::NodeHasPositionalArgumentWithValue.new(position, value_matcher)
23
37
  end
24
38
  end
25
39
  end
@@ -0,0 +1,16 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module NodePairKey
6
+ def self.build(key_matcher)
7
+ return unless key_matcher
8
+
9
+ ::Leftovers::MatcherBuilders::And.build([
10
+ ::Leftovers::Matchers::NodeType.new(:pair),
11
+ ::Leftovers::Matchers::NodePairKey.new(key_matcher)
12
+ ])
13
+ end
14
+ end
15
+ end
16
+ end
@@ -0,0 +1,13 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module MatcherBuilders
5
+ module NodePrivacy
6
+ def self.build(privacy_settings)
7
+ ::Leftovers::MatcherBuilders::Or.each_or_self(privacy_settings) do |privacy|
8
+ ::Leftovers::Matchers::NodePrivacy.new(privacy)
9
+ end
10
+ end
11
+ end
12
+ end
13
+ end
@@ -8,18 +8,18 @@ module Leftovers
8
8
  def self.build(types_pattern) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity
9
9
  ::Leftovers::MatcherBuilders::Or.each_or_self(types_pattern) do |type|
10
10
  case type
11
- when 'Symbol' then ::Leftovers::Matchers::NodeType.new(:sym)
12
- when 'String' then ::Leftovers::Matchers::NodeType.new(:str)
13
- when 'Integer' then ::Leftovers::Matchers::NodeType.new(:int)
14
- when 'Float' then ::Leftovers::Matchers::NodeType.new(:float)
15
- when 'Array' then ::Leftovers::Matchers::NodeType.new(:array)
16
- when 'Hash' then ::Leftovers::Matchers::NodeType.new(:hash)
17
-
18
- when 'Proc' then ::Leftovers::Matchers::Predicate.new(:proc?)
19
- # when 'Method' then ::Leftovers::Matchers::NodeType.new(Set[:send, :csend, :def])
20
- # when 'Constant' then ::Leftovers::Matchers::NodeType.new(Set[:const, :class, :module])
11
+ when :Symbol then ::Leftovers::Matchers::NodeType.new(:sym)
12
+ when :String then ::Leftovers::Matchers::NodeType.new(:str)
13
+ when :Integer then ::Leftovers::Matchers::NodeType.new(:int)
14
+ when :Float then ::Leftovers::Matchers::NodeType.new(:float)
15
+ when :Array then ::Leftovers::Matchers::NodeType.new(:array)
16
+ when :Hash then ::Leftovers::Matchers::NodeType.new(:hash)
17
+ when :Proc then ::Leftovers::Matchers::NodeIsProc
18
+ when :Method then ::Leftovers::Matchers::NodeType.new(Set[:send, :csend, :def, :defs])
19
+ when :Constant
20
+ ::Leftovers::Matchers::NodeType.new(Set[:const, :class, :module, :casgn])
21
21
  # :nocov:
22
- else raise
22
+ else raise Leftovers::UnexpectedCase, "Unhandled value #{type.inspect}"
23
23
  # :nocov:
24
24
  end
25
25
  end
@@ -4,17 +4,17 @@ module Leftovers
4
4
  module MatcherBuilders
5
5
  module NodeValue
6
6
  class << self
7
- def build(pattern) # rubocop:disable Metrics/MethodLength
8
- ::Leftovers::MatcherBuilders::Or.each_or_self(pattern) do |pat|
9
- case pat
10
- when ::Integer, true, false, nil
11
- ::Leftovers::Matchers::NodeScalarValue.new(pat)
12
- when ::String
13
- ::Leftovers::MatcherBuilders::NodeName.build(pat)
14
- when ::Hash
15
- build_from_hash(**pat)
7
+ def build(patterns)
8
+ ::Leftovers::MatcherBuilders::Or.each_or_self(patterns) do |pattern|
9
+ case pattern
10
+ when ::Integer, ::Float, true, false
11
+ # matching scalar on nil will fall afoul of compact and each_or_self etc.
12
+ ::Leftovers::Matchers::NodeScalarValue.new(pattern)
13
+ when :_leftovers_nil_value then ::Leftovers::Matchers::NodeType.new(:nil)
14
+ when ::String then ::Leftovers::MatcherBuilders::NodeName.build(pattern)
15
+ when ::Hash then build_from_hash(**pattern)
16
16
  # :nocov:
17
- else raise
17
+ else raise Leftovers::UnexpectedCase, "Unhandled value #{pattern.inspect}"
18
18
  # :nocov:
19
19
  end
20
20
  end
@@ -22,27 +22,46 @@ module Leftovers
22
22
 
23
23
  private
24
24
 
25
- def build_from_hash( # rubocop:disable Metrics/MethodLength, Metrics/ParameterLists
26
- at: nil, has_value: nil,
27
- match: nil, has_prefix: nil, has_suffix: nil,
25
+ def build_node_name_matcher(names, match, has_prefix, has_suffix)
26
+ ::Leftovers::MatcherBuilders::Or.build([
27
+ ::Leftovers::MatcherBuilders::NodeName.build(names),
28
+ ::Leftovers::MatcherBuilders::NodeName.build(
29
+ match: match, has_prefix: has_prefix, has_suffix: has_suffix
30
+ )
31
+ ])
32
+ end
33
+
34
+ def build_node_has_argument_matcher(has_arguments, at, has_value)
35
+ ::Leftovers::MatcherBuilders::Or.build([
36
+ ::Leftovers::MatcherBuilders::NodeHasArgument.build(has_arguments),
37
+ ::Leftovers::MatcherBuilders::NodeHasArgument.build(
38
+ at: at, has_value: has_value
39
+ )
40
+ ])
41
+ end
42
+
43
+ def build_unless(unless_arg)
44
+ return unless unless_arg
45
+
46
+ ::Leftovers::MatcherBuilders::Unless.build(
47
+ ::Leftovers::MatcherBuilders::NodeValue.build(unless_arg)
48
+ )
49
+ end
50
+
51
+ def build_from_hash( # rubocop:disable Metrics/ParameterLists
52
+ has_arguments: nil, at: nil, has_value: nil,
53
+ names: nil, match: nil, has_prefix: nil, has_suffix: nil,
28
54
  type: nil,
29
55
  has_receiver: nil,
30
56
  unless_arg: nil
31
57
  )
32
- matcher = ::Leftovers::MatcherBuilders::And.build([
33
- ::Leftovers::MatcherBuilders::NodeHasArgument.build(
34
- at: at, has_value: has_value
35
- ),
36
- ::Leftovers::MatcherBuilders::NodeName.build(
37
- match: match, has_prefix: has_prefix, has_suffix: has_suffix
38
- ),
58
+ ::Leftovers::MatcherBuilders::And.build([
59
+ build_node_has_argument_matcher(has_arguments, at, has_value),
60
+ build_node_name_matcher(names, match, has_prefix, has_suffix),
39
61
  ::Leftovers::MatcherBuilders::NodeType.build(type),
40
- ::Leftovers::MatcherBuilders::NodeHasReceiver.build(has_receiver)
62
+ ::Leftovers::MatcherBuilders::NodeHasReceiver.build(has_receiver),
63
+ build_unless(unless_arg)
41
64
  ])
42
-
43
- ::Leftovers::MatcherBuilders::AndNot.build(
44
- matcher, ::Leftovers::MatcherBuilders::NodeValue.build(unless_arg)
45
- )
46
65
  end
47
66
  end
48
67
  end
@@ -5,68 +5,83 @@ require 'set'
5
5
  module Leftovers
6
6
  module MatcherBuilders
7
7
  module Or
8
- def self.each_or_self(value, &block)
9
- case value
10
- when nil then nil
11
- when Array then build(value.map(&block))
12
- else build([yield(value)])
8
+ class << self
9
+ def each_or_self(value, &block)
10
+ case value
11
+ when nil then nil
12
+ when Array then build(value.map(&block))
13
+ else build([yield(value)])
14
+ end
13
15
  end
14
- end
15
16
 
16
- def self.build(matchers)
17
- matchers = compact(matchers)
18
- case matchers.length
19
- # :nocov:
20
- when 0 then nil
21
- # :nocov:
22
- when 1 then matchers.first
23
- when 2 then ::Leftovers::Matchers::Or.new(matchers.first, matchers[1])
24
- else ::Leftovers::Matchers::Any.new(matchers.dup)
17
+ def build(matchers)
18
+ matchers = compact(matchers)
19
+ case matchers.length
20
+ # :nocov:
21
+ when 0 then nil
22
+ # :nocov:
23
+ when 1 then matchers.first
24
+ when 2 then ::Leftovers::Matchers::Or.new(matchers.first, matchers[1])
25
+ else ::Leftovers::Matchers::Any.new(matchers.dup)
26
+ end
25
27
  end
26
- end
27
28
 
28
- def self.flatten(value) # rubocop:disable Metrics/MethodLength
29
- case value
30
- when ::Leftovers::Matchers::Or
31
- [*flatten(value.lhs), *flatten(value.rhs)]
32
- when ::Leftovers::Matchers::Any
33
- flatten(value.matchers)
34
- when Array
35
- ret = value.map { |v| flatten(v) }
36
- ret.flatten!(1)
37
- ret
38
- else
39
- value
29
+ private
30
+
31
+ def flatten(value)
32
+ case value
33
+ when ::Leftovers::Matchers::Or
34
+ [*flatten(value.lhs), *flatten(value.rhs)]
35
+ when ::Leftovers::Matchers::Any
36
+ flatten(value.matchers)
37
+ when Array, Set
38
+ value.flat_map { |v| flatten(v) }
39
+ else
40
+ [value]
41
+ end
40
42
  end
41
- end
42
43
 
43
- def self.compact(matchers) # rubocop:disable Metrics/MethodLength, Metrics/CyclomaticComplexity, Metrics/AbcSize,
44
- return matchers if matchers.length <= 1
44
+ def group_by_compactable(matchers)
45
+ groups = matchers.group_by do |matcher|
46
+ case matcher
47
+ when ::Integer, ::Symbol, true, false then :set
48
+ when ::Regexp then :regexp
49
+ when nil then :nil
50
+ else matcher.class.to_s.to_sym
51
+ end
52
+ end
45
53
 
46
- set = Set.new
47
- regexps = []
48
- uncompactable = []
54
+ groups.transform_values { |v| Leftovers.unwrap_array(v) }
55
+ end
49
56
 
50
- matchers = flatten(matchers)
57
+ def mergeable?(matcher)
58
+ matcher.respond_to?(:matcher)
59
+ end
51
60
 
52
- matchers.each do |matcher|
53
- case matcher
54
- when nil then nil
55
- when ::Integer, ::Symbol then set << matcher
56
- # when ::Set then set.merge(matcher) # may not be necessary
57
- when ::Regexp then regexps << matcher
58
- else uncompactable << matcher
59
- end
61
+ def build_grouped_for_matcher(matchers)
62
+ return matchers unless matchers.is_a?(Array)
63
+ return matchers unless mergeable?(matchers.first)
64
+
65
+ matchers.first.class.new(build(matchers.map(&:matcher)))
60
66
  end
61
67
 
62
- set = set.first if set.length <= 1
63
- regexps = if regexps.length <= 1
64
- regexps.first
65
- else
66
- Regexp.union(regexps)
68
+ def build_grouped(set: nil, regexp: nil, nil: nil, **matcher_classes) # rubocop:disable Lint/UnusedMethodArgument i want to throw away nils
69
+ set = set.to_set.compare_by_identity if set.is_a?(Array)
70
+ regexp = Regexp.union(regexp) if regexp.is_a?(Array)
71
+ matcher_classes = matcher_classes.each_value.flat_map do |matchers|
72
+ build_grouped_for_matcher(matchers)
73
+ end
74
+
75
+ [set, regexp].compact.concat(matcher_classes).uniq
67
76
  end
68
77
 
69
- [set, regexps].compact.concat(uncompactable)
78
+ def compact(matchers)
79
+ matchers = flatten(matchers)
80
+
81
+ return matchers if matchers.length <= 1
82
+
83
+ build_grouped(**group_by_compactable(matchers))
84
+ end
70
85
  end
71
86
  end
72
87
  end
@@ -8,7 +8,9 @@ module Leftovers
8
8
  def self.build(path_pattern)
9
9
  return if path_pattern.nil? || path_pattern.empty?
10
10
 
11
- ::FastIgnore.new(include_rules: path_pattern, gitignore: false, root: Leftovers.pwd)
11
+ ::Leftovers::Matchers::Path.new(
12
+ ::FastIgnore.new(include_rules: path_pattern, gitignore: false, root: Leftovers.pwd)
13
+ )
12
14
  end
13
15
  end
14
16
  end
@@ -3,15 +3,24 @@
3
3
  module Leftovers
4
4
  module MatcherBuilders
5
5
  module StringPattern
6
- def self.build(match: nil, has_prefix: nil, has_suffix: nil)
7
- if match
6
+ def self.build(match: nil, has_prefix: nil, has_suffix: nil) # rubocop:disable Metrics
7
+ has_prefix = ::Regexp.escape(has_prefix) if has_prefix
8
+ has_suffix = ::Regexp.escape(has_suffix) if has_suffix
9
+
10
+ if match && has_prefix && has_suffix
11
+ /\A(?=#{match}\z)(?=#{has_prefix}).*#{has_suffix}\z/
12
+ elsif match && has_prefix
13
+ /\A(?=#{match}\z)#{has_prefix}/
14
+ elsif match && has_suffix
15
+ /\A(?=#{match}\z).*#{has_suffix}\z/
16
+ elsif match
8
17
  /\A#{match}\z/
9
18
  elsif has_prefix && has_suffix
10
- /\A#{::Regexp.escape(has_prefix)}.*#{::Regexp.escape(has_suffix)}\z/
19
+ /\A(?=#{has_prefix}).*#{has_suffix}\z/
11
20
  elsif has_prefix
12
- /\A#{::Regexp.escape(has_prefix)}/
21
+ /\A#{has_prefix}/
13
22
  elsif has_suffix
14
- /#{::Regexp.escape(has_suffix)}\z/
23
+ /#{has_suffix}\z/
15
24
  end
16
25
  end
17
26
  end
@@ -12,9 +12,10 @@ module Leftovers
12
12
  autoload(:NodeHasPositionalArgument, "#{__dir__}/matcher_builders/node_has_positional_argument")
13
13
  autoload(:NodeHasReceiver, "#{__dir__}/matcher_builders/node_has_receiver")
14
14
  autoload(:NodeName, "#{__dir__}/matcher_builders/node_name")
15
- autoload(:NodePairName, "#{__dir__}/matcher_builders/node_pair_name")
15
+ autoload(:NodePairKey, "#{__dir__}/matcher_builders/node_pair_key")
16
16
  autoload(:NodePairValue, "#{__dir__}/matcher_builders/node_pair_value")
17
17
  autoload(:NodePath, "#{__dir__}/matcher_builders/node_path")
18
+ autoload(:NodePrivacy, "#{__dir__}/matcher_builders/node_privacy")
18
19
  autoload(:NodeType, "#{__dir__}/matcher_builders/node_type")
19
20
  autoload(:NodeValue, "#{__dir__}/matcher_builders/node_value")
20
21
  autoload(:Or, "#{__dir__}/matcher_builders/or")