leftovers 0.6.0 → 0.7.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +21 -3
  3. data/docs/Configuration.md +82 -18
  4. data/leftovers.gemspec +1 -1
  5. data/lib/config/actionmailer.yml +11 -11
  6. data/lib/config/activesupport.yml +1 -1
  7. data/lib/config/rails.yml +1 -1
  8. data/lib/config/railties.yml +11 -0
  9. data/lib/config/ruby.yml +72 -0
  10. data/lib/leftovers/ast/node.rb +16 -11
  11. data/lib/leftovers/config.rb +1 -24
  12. data/lib/leftovers/config_loader/argument_position_schema.rb +11 -0
  13. data/lib/leftovers/config_loader/argumentless_transform_schema.rb +21 -0
  14. data/lib/leftovers/config_loader/attribute.rb +30 -0
  15. data/lib/leftovers/config_loader/document_schema.rb +21 -0
  16. data/lib/leftovers/config_loader/dynamic_schema.rb +17 -0
  17. data/lib/leftovers/config_loader/has_argument_schema.rb +13 -0
  18. data/lib/leftovers/config_loader/has_value_schema.rb +18 -0
  19. data/lib/leftovers/config_loader/keep_test_only_schema.rb +13 -0
  20. data/lib/leftovers/config_loader/node.rb +106 -0
  21. data/lib/leftovers/config_loader/object_schema.rb +189 -0
  22. data/lib/leftovers/config_loader/privacy_processor_schema.rb +12 -0
  23. data/lib/leftovers/config_loader/privacy_schema.rb +15 -0
  24. data/lib/leftovers/config_loader/require_schema.rb +11 -0
  25. data/lib/leftovers/config_loader/rule_pattern_schema.rb +18 -0
  26. data/lib/leftovers/config_loader/scalar_argument_schema.rb +14 -0
  27. data/lib/leftovers/config_loader/scalar_value_schema.rb +14 -0
  28. data/lib/leftovers/config_loader/schema.rb +21 -0
  29. data/lib/leftovers/config_loader/string_enum_schema.rb +62 -0
  30. data/lib/leftovers/config_loader/string_pattern_schema.rb +14 -0
  31. data/lib/leftovers/config_loader/string_schema.rb +14 -0
  32. data/lib/leftovers/config_loader/string_value_processor_schema.rb +11 -0
  33. data/lib/leftovers/config_loader/suggester.rb +22 -0
  34. data/lib/leftovers/config_loader/transform_schema.rb +28 -0
  35. data/lib/leftovers/config_loader/true_schema.rb +18 -0
  36. data/lib/leftovers/config_loader/value_matcher_schema.rb +18 -0
  37. data/lib/leftovers/config_loader/value_or_array_schema.rb +64 -0
  38. data/lib/leftovers/config_loader/value_processor_schema.rb +14 -0
  39. data/lib/leftovers/config_loader/value_type_schema.rb +17 -0
  40. data/lib/leftovers/config_loader.rb +82 -0
  41. data/lib/leftovers/definition_node.rb +6 -17
  42. data/lib/leftovers/definition_node_set.rb +11 -0
  43. data/lib/leftovers/definition_to_add.rb +31 -0
  44. data/lib/leftovers/dynamic_processors/call.rb +4 -3
  45. data/lib/leftovers/dynamic_processors/call_definition.rb +14 -7
  46. data/lib/leftovers/dynamic_processors/definition.rb +8 -3
  47. data/lib/leftovers/dynamic_processors/set_default_privacy.rb +18 -0
  48. data/lib/leftovers/dynamic_processors/set_privacy.rb +23 -0
  49. data/lib/leftovers/dynamic_processors.rb +2 -0
  50. data/lib/leftovers/file.rb +5 -1
  51. data/lib/leftovers/file_collector.rb +44 -17
  52. data/lib/leftovers/matcher_builders/node.rb +4 -0
  53. data/lib/leftovers/matcher_builders/node_privacy.rb +13 -0
  54. data/lib/leftovers/matcher_builders/node_type.rb +4 -4
  55. data/lib/leftovers/matcher_builders/node_value.rb +1 -1
  56. data/lib/leftovers/matcher_builders/string_pattern.rb +14 -5
  57. data/lib/leftovers/matcher_builders.rb +1 -0
  58. data/lib/leftovers/matchers/node_privacy.rb +19 -0
  59. data/lib/leftovers/matchers.rb +1 -0
  60. data/lib/leftovers/merged_config.rb +18 -34
  61. data/lib/leftovers/processor_builders/add_prefix.rb +1 -1
  62. data/lib/leftovers/processor_builders/add_suffix.rb +1 -1
  63. data/lib/leftovers/processor_builders/dynamic.rb +50 -16
  64. data/lib/leftovers/processor_builders/transform.rb +2 -2
  65. data/lib/leftovers/processor_builders/transform_set.rb +8 -8
  66. data/lib/leftovers/value_processors/each_for_definition_set.rb +2 -5
  67. data/lib/leftovers/value_processors/each_positional_argument.rb +1 -1
  68. data/lib/leftovers/value_processors/return_definition_node.rb +14 -0
  69. data/lib/leftovers/value_processors/{return_string.rb → return_sym.rb} +1 -1
  70. data/lib/leftovers/value_processors.rb +2 -2
  71. data/lib/leftovers/version.rb +1 -1
  72. data/lib/leftovers.rb +23 -14
  73. metadata +54 -22
  74. data/lib/config/actioncable.yml +0 -4
  75. data/lib/leftovers/config_validator/error_processor.rb +0 -196
  76. data/lib/leftovers/config_validator/schema_hash.rb +0 -551
  77. data/lib/leftovers/config_validator.rb +0 -61
  78. data/lib/leftovers/value_processors/return_definition.rb +0 -22
@@ -0,0 +1,17 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class ConfigLoader
5
+ class ValueTypeSchema < StringEnumSchema
6
+ value :String
7
+ value :Symbol
8
+ value :Integer
9
+ value :Float
10
+ value :Array
11
+ value :Hash
12
+ value :Proc
13
+ value :Method
14
+ value :Constant
15
+ end
16
+ end
17
+ end
@@ -0,0 +1,82 @@
1
+ # frozen-string-literal: true
2
+
3
+ require 'yaml'
4
+ require 'leftovers'
5
+
6
+ module Leftovers
7
+ class ConfigLoader
8
+ autoload(:ArgumentPositionSchema, "#{__dir__}/config_loader/argument_position_schema")
9
+ autoload(:ArgumentlessTransformSchema, "#{__dir__}/config_loader/argumentless_transform_schema")
10
+ autoload(:Attribute, "#{__dir__}/config_loader/attribute")
11
+ autoload(:DocumentSchema, "#{__dir__}/config_loader/document_schema")
12
+ autoload(:DynamicSchema, "#{__dir__}/config_loader/dynamic_schema")
13
+ autoload(:HasArgumentSchema, "#{__dir__}/config_loader/has_argument_schema")
14
+ autoload(:HasValueSchema, "#{__dir__}/config_loader/has_value_schema")
15
+ autoload(:KeepTestOnlySchema, "#{__dir__}/config_loader/keep_test_only_schema")
16
+ autoload(:Node, "#{__dir__}/config_loader/node")
17
+ autoload(:ObjectSchema, "#{__dir__}/config_loader/object_schema")
18
+ autoload(:PrivacyProcessorSchema, "#{__dir__}/config_loader/privacy_processor_schema")
19
+ autoload(:PrivacySchema, "#{__dir__}/config_loader/privacy_schema")
20
+ autoload(:RequireSchema, "#{__dir__}/config_loader/require_schema")
21
+ autoload(:RulePatternSchema, "#{__dir__}/config_loader/rule_pattern_schema")
22
+ autoload(:ScalarArgumentSchema, "#{__dir__}/config_loader/scalar_argument_schema")
23
+ autoload(:ScalarValueSchema, "#{__dir__}/config_loader/scalar_value_schema")
24
+ autoload(:Schema, "#{__dir__}/config_loader/schema")
25
+ autoload(:Suggester, "#{__dir__}/config_loader/suggester")
26
+ autoload(:StringEnumSchema, "#{__dir__}/config_loader/string_enum_schema")
27
+ autoload(:StringPatternSchema, "#{__dir__}/config_loader/string_pattern_schema")
28
+ autoload(:StringSchema, "#{__dir__}/config_loader/string_schema")
29
+ autoload(:StringValueProcessorSchema, "#{__dir__}/config_loader/string_value_processor_schema")
30
+ autoload(:TransformSchema, "#{__dir__}/config_loader/transform_schema")
31
+ autoload(:TrueSchema, "#{__dir__}/config_loader/true_schema")
32
+ autoload(:ValueMatcherSchema, "#{__dir__}/config_loader/value_matcher_schema")
33
+ autoload(:ValueOrArraySchema, "#{__dir__}/config_loader/value_or_array_schema")
34
+ autoload(:ValueProcessorSchema, "#{__dir__}/config_loader/value_processor_schema")
35
+ autoload(:ValueTypeSchema, "#{__dir__}/config_loader/value_type_schema")
36
+
37
+ def self.load(name, path: nil, content: nil)
38
+ new(name, path: path, content: content).load
39
+ end
40
+
41
+ attr_reader :name
42
+
43
+ def initialize(name, path: nil, content: nil)
44
+ @name = name
45
+ @path = path
46
+ @content = content
47
+ end
48
+
49
+ def load
50
+ document = ::Leftovers::ConfigLoader::Node.new(parse, file)
51
+ DocumentSchema.validate(document)
52
+
53
+ all_errors = document.all_errors
54
+ return DocumentSchema.to_ruby(document) if all_errors.empty?
55
+
56
+ Leftovers.error(all_errors.join("\n"))
57
+ end
58
+
59
+ private
60
+
61
+ def path
62
+ @path ||= ::File.expand_path("../config/#{name}.yml", __dir__)
63
+ end
64
+
65
+ def file
66
+ @file ||= ::Leftovers::File.new(path)
67
+ end
68
+
69
+ def content
70
+ @content ||= file.exist? ? file.read : ''
71
+ end
72
+
73
+ def parse
74
+ parsed = Psych.parse(content)
75
+ parsed ||= Psych.parse('{}')
76
+ parsed.children.first
77
+ rescue ::Psych::SyntaxError => e
78
+ message = [e.problem, e.context].compact.join(' ')
79
+ Leftovers.error "Config SyntaxError: #{file.relative_path}:#{e.line}:#{e.column} #{message}"
80
+ end
81
+ end
82
+ end
@@ -1,19 +1,15 @@
1
1
  # frozen-string-literal: true
2
2
 
3
- # To give to matchers before creating a Definition
4
-
5
3
  module Leftovers
6
4
  class DefinitionNode
7
- attr_reader :path, :name
5
+ attr_reader :name, :loc, :node
8
6
 
9
- def initialize(name, path)
7
+ def initialize(node, name:, location: node.loc.expression)
8
+ @node = node
10
9
  @name = name
11
- @path = path
12
-
13
- freeze
10
+ @loc = location
14
11
  end
15
12
 
16
- # these are the methods checked by things in lib/leftovers/matchers
17
13
  def kwargs
18
14
  nil
19
15
  end
@@ -22,15 +18,8 @@ module Leftovers
22
18
  nil
23
19
  end
24
20
 
25
- # these two i'm not sure are possible with the current config flags
26
- # :nocov:
27
- def scalar?
28
- false
29
- end
30
-
31
- def type
32
- :leftovers_definition
21
+ def path
22
+ node.path
33
23
  end
34
- # :nocov:
35
24
  end
36
25
  end
@@ -0,0 +1,11 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ class DefinitionNodeSet
5
+ attr_reader :definitions
6
+
7
+ def initialize(definitions)
8
+ @definitions = definitions
9
+ end
10
+ end
11
+ end
@@ -0,0 +1,31 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ class DefinitionToAdd
5
+ attr_reader :node, :name, :location
6
+
7
+ def initialize(node, name: node.name, location: node.loc.name)
8
+ @node = node
9
+ @name = name
10
+ @location = location
11
+ end
12
+
13
+ def privacy=(value)
14
+ @node.privacy = value
15
+ end
16
+
17
+ def keep?(file_collector)
18
+ @keep ||= file_collector.keep_line?(location.line) || ::Leftovers.config.keep === node
19
+ end
20
+
21
+ def test?(file_collector)
22
+ file_collector.test_line?(location.line) || ::Leftovers.config.test_only === node
23
+ end
24
+
25
+ def to_definition(file_collector)
26
+ return if keep?(file_collector)
27
+
28
+ Leftovers::Definition.new(name, location: location, test: test?(file_collector))
29
+ end
30
+ end
31
+ end
@@ -11,10 +11,11 @@ module Leftovers
11
11
  def process(node, file)
12
12
  return unless @matcher === node
13
13
 
14
- call = @processor.process(nil, node, node)
15
- return unless call
14
+ calls = @processor.process(nil, node, node)
16
15
 
17
- file.calls << call
16
+ ::Leftovers.each_or_self(calls) do |call|
17
+ file.calls << call
18
+ end
18
19
  end
19
20
  end
20
21
  end
@@ -9,18 +9,25 @@ module Leftovers
9
9
  @definition_processor = definition_processor
10
10
  end
11
11
 
12
- def process(node, file)
12
+ def process(node, file) # rubocop:disable Metrics/MethodLength
13
13
  return unless @matcher === node
14
14
 
15
- call = @call_processor.process(nil, node, node)
16
- (file.calls << call) if call
15
+ calls = @call_processor.process(nil, node, node)
17
16
 
18
- return if node.keep_line?
17
+ ::Leftovers.each_or_self(calls) do |call|
18
+ file.calls << call
19
+ end
19
20
 
20
- definition = @definition_processor.process(nil, node, node)
21
- return unless definition
21
+ return if node.keep_line?
22
22
 
23
- file.definitions << definition
23
+ definitions = @definition_processor.process(nil, node, node)
24
+ ::Leftovers.each_or_self(definitions) do |definition|
25
+ if definition.is_a?(DefinitionNodeSet)
26
+ file.add_definition_set(definition)
27
+ else
28
+ file.add_definition(definition, loc: definition.loc)
29
+ end
30
+ end
24
31
  end
25
32
  end
26
33
  end
@@ -12,10 +12,15 @@ module Leftovers
12
12
  return if node.keep_line?
13
13
  return unless @matcher === node
14
14
 
15
- definition = @processor.process(nil, node, node)
16
- return unless definition
15
+ definitions = @processor.process(nil, node, node)
17
16
 
18
- file.definitions << definition
17
+ ::Leftovers.each_or_self(definitions) do |definition|
18
+ if definition.is_a?(DefinitionNodeSet)
19
+ file.add_definition_set(definition)
20
+ else
21
+ file.add_definition(definition, loc: definition.loc)
22
+ end
23
+ end
19
24
  end
20
25
  end
21
26
  end
@@ -0,0 +1,18 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module DynamicProcessors
5
+ class SetDefaultPrivacy
6
+ def initialize(matcher, to)
7
+ @matcher = matcher
8
+ @to = to
9
+ end
10
+
11
+ def process(node, file)
12
+ return unless @matcher === node
13
+
14
+ file.default_method_privacy = @to
15
+ end
16
+ end
17
+ end
18
+ end
@@ -0,0 +1,23 @@
1
+ # frozen-string-literal: true
2
+
3
+ module Leftovers
4
+ module DynamicProcessors
5
+ class SetPrivacy
6
+ def initialize(matcher, processor, to)
7
+ @matcher = matcher
8
+ @processor = processor
9
+ @to = to
10
+ end
11
+
12
+ def process(node, file)
13
+ return unless @matcher === node
14
+
15
+ set_privacy = @processor.process(nil, node, node)
16
+
17
+ ::Leftovers.each_or_self(set_privacy) do |name|
18
+ file.set_privacy(name, @to)
19
+ end
20
+ end
21
+ end
22
+ end
23
+ end
@@ -7,5 +7,7 @@ module Leftovers
7
7
  autoload(:Definition, "#{__dir__}/dynamic_processors/definition")
8
8
  autoload(:Each, "#{__dir__}/dynamic_processors/each")
9
9
  autoload(:Null, "#{__dir__}/dynamic_processors/null")
10
+ autoload(:SetDefaultPrivacy, "#{__dir__}/dynamic_processors/set_default_privacy")
11
+ autoload(:SetPrivacy, "#{__dir__}/dynamic_processors/set_privacy")
10
12
  end
11
13
  end
@@ -5,7 +5,11 @@ require 'pathname'
5
5
  module Leftovers
6
6
  class File < Pathname
7
7
  def relative_path
8
- @relative_path ||= relative_path_from(Leftovers.pwd)
8
+ @relative_path ||= begin
9
+ relative_path_from(Leftovers.pwd)
10
+ rescue ArgumentError
11
+ self
12
+ end
9
13
  end
10
14
 
11
15
  def test?
@@ -5,16 +5,19 @@ require 'parser'
5
5
 
6
6
  module Leftovers
7
7
  class FileCollector < ::Parser::AST::Processor # rubocop:disable Metrics/ClassLength
8
- attr_reader :calls, :definitions
8
+ attr_reader :calls
9
+ attr_accessor :default_method_privacy
9
10
 
10
11
  def initialize(ruby, file) # rubocop:disable Lint/MissingSuper
11
12
  @calls = []
12
- @definitions = []
13
+ @definitions_to_add = {}
13
14
  @allow_lines = Set.new.compare_by_identity
14
15
  @test_lines = Set.new.compare_by_identity
15
16
  @dynamic_lines = {}
16
17
  @ruby = ruby
17
18
  @file = file
19
+ @default_method_privacy = :public
20
+ @definition_sets_to_add = []
18
21
  end
19
22
 
20
23
  def filename
@@ -38,7 +41,6 @@ module Leftovers
38
41
  definitions.flatten!
39
42
  definitions.compact!
40
43
  definitions.uniq!
41
- definitions.reject! { |v| v == :keep }
42
44
  end
43
45
 
44
46
  def collect
@@ -76,6 +78,12 @@ module Leftovers
76
78
 
77
79
  # grab method definitions
78
80
  def on_def(node)
81
+ node.privacy = default_method_privacy
82
+ add_definition(node)
83
+ super
84
+ end
85
+
86
+ def on_defs(node)
79
87
  add_definition(node)
80
88
  super
81
89
  end
@@ -184,24 +192,41 @@ module Leftovers
184
192
  add_call(original_method.children.first)
185
193
  end
186
194
 
187
- private
195
+ def add_definition(node, name: node.name, loc: node.loc.name)
196
+ @definitions_to_add[name] =
197
+ ::Leftovers::DefinitionToAdd.new(node, name: name, location: loc)
198
+ end
188
199
 
189
- def test_line?(loc)
190
- @file.test? ||
191
- @test_lines.include?(loc.line)
200
+ def add_definition_set(definition_node_set)
201
+ @definition_sets_to_add << definition_node_set.definitions.map do |definition_node|
202
+ ::Leftovers::DefinitionToAdd.new(definition_node, location: definition_node.loc)
203
+ end
192
204
  end
193
205
 
194
- def test_node?(node, loc)
195
- test_line?(loc) || ::Leftovers.config.test_only === node
206
+ def set_privacy(name, to)
207
+ @definitions_to_add[name]&.privacy = to
196
208
  end
197
209
 
198
- def add_definition(node, name: node.name, loc: node.loc.name)
199
- return if @allow_lines.include?(loc.line)
200
- return if Leftovers.config.keep === node
210
+ def definitions
211
+ @definitions ||= @definitions_to_add.each_value.map { |d| d.to_definition(self) }.compact +
212
+ @definition_sets_to_add.map do |definition_set|
213
+ next nil if definition_set.any? { |d| d.keep?(self) }
201
214
 
202
- definitions << Leftovers::Definition.new(name, location: loc, test: test_node?(node, loc))
215
+ ::Leftovers::DefinitionSet.new(definition_set.map { |d| d.to_definition(self) })
216
+ end.compact
203
217
  end
204
218
 
219
+ def test_line?(line)
220
+ @file.test? ||
221
+ @test_lines.include?(line)
222
+ end
223
+
224
+ def keep_line?(line)
225
+ @allow_lines.include?(line)
226
+ end
227
+
228
+ private
229
+
205
230
  def add_call(name)
206
231
  calls << name
207
232
  end
@@ -232,11 +257,14 @@ module Leftovers
232
257
 
233
258
  def collect_op_asgn(node)
234
259
  node = node.children.first
235
- # :nocov: # don't need else, it's exhaustive for callers
236
260
  case node.type
237
- # :nocov:
238
261
  when :send then collect_send_op_asgn(node)
239
262
  when :ivasgn, :gvasgn, :cvasgn then collect_var_op_asgn(node)
263
+ when :lvasgn then nil # we don't care about lvasgn
264
+ # :nocov:
265
+ else
266
+ raise "Unrecognized op_asgn node type #{node.type}"
267
+ # :nocov:
240
268
  end
241
269
  end
242
270
 
@@ -256,9 +284,8 @@ module Leftovers
256
284
  )
257
285
  end
258
286
 
259
- def collect_dynamic(node) # rubocop:disable Metrics/AbcSize
287
+ def collect_dynamic(node)
260
288
  node.keep_line = @allow_lines.include?(node.loc.line)
261
- node.test_line = test_line?(node.loc) unless node.keep_line?
262
289
 
263
290
  Leftovers.config.dynamic.process(node, self)
264
291
  rescue StandardError => e
@@ -23,6 +23,8 @@ module Leftovers
23
23
  paths: nil,
24
24
  has_arguments: nil,
25
25
  has_receiver: nil,
26
+ type: nil,
27
+ privacy: nil,
26
28
  unless_arg: nil
27
29
  )
28
30
  ::Leftovers::MatcherBuilders::And.build([
@@ -34,6 +36,8 @@ module Leftovers
34
36
  ::Leftovers::MatcherBuilders::NodePath.build(paths),
35
37
  ::Leftovers::MatcherBuilders::NodeHasArgument.build(has_arguments),
36
38
  ::Leftovers::MatcherBuilders::NodeHasReceiver.build(has_receiver),
39
+ ::Leftovers::MatcherBuilders::NodePrivacy.build(privacy),
40
+ ::Leftovers::MatcherBuilders::NodeType.build(type),
37
41
  ::Leftovers::MatcherBuilders::Unless.build(
38
42
  (::Leftovers::MatcherBuilders::Node.build(unless_arg) if unless_arg)
39
43
  )
@@ -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
@@ -14,12 +14,12 @@ module Leftovers
14
14
  when 'Float' then ::Leftovers::Matchers::NodeType.new(:float)
15
15
  when 'Array' then ::Leftovers::Matchers::NodeType.new(:array)
16
16
  when 'Hash' then ::Leftovers::Matchers::NodeType.new(:hash)
17
-
18
17
  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])
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 "Unknown type #{type}"
23
23
  # :nocov:
24
24
  end
25
25
  end
@@ -7,7 +7,7 @@ module Leftovers
7
7
  def build(pattern) # rubocop:disable Metrics/MethodLength
8
8
  ::Leftovers::MatcherBuilders::Or.each_or_self(pattern) do |pat|
9
9
  case pat
10
- when ::Integer, true, false, nil
10
+ when ::Integer, ::Float, true, false, nil
11
11
  ::Leftovers::Matchers::NodeScalarValue.new(pat)
12
12
  when ::String
13
13
  ::Leftovers::MatcherBuilders::NodeName.build(pat)
@@ -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/CyclomaticComplexity, Metrics/MethodLength, Metrics/PerceivedComplexity
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
@@ -15,6 +15,7 @@ module Leftovers
15
15
  autoload(:NodePairName, "#{__dir__}/matcher_builders/node_pair_name")
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")
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module Matchers
5
+ class NodePrivacy
6
+ def initialize(privacy_matcher)
7
+ @privacy_matcher = privacy_matcher
8
+
9
+ freeze
10
+ end
11
+
12
+ def ===(node)
13
+ @privacy_matcher === node.privacy
14
+ end
15
+
16
+ freeze
17
+ end
18
+ end
19
+ end
@@ -19,6 +19,7 @@ module Leftovers
19
19
  autoload(:NodeName, "#{__dir__}/matchers/node_name")
20
20
  autoload(:NodePairValue, "#{__dir__}/matchers/node_pair_value")
21
21
  autoload(:NodePath, "#{__dir__}/matchers/node_path")
22
+ autoload(:NodePrivacy, "#{__dir__}/matchers/node_privacy")
22
23
  autoload(:NodeScalarValue, "#{__dir__}/matchers/node_scalar_value")
23
24
  autoload(:NodeType, "#{__dir__}/matchers/node_type")
24
25
  autoload(:Not, "#{__dir__}/matchers/not")
@@ -4,7 +4,7 @@ require 'set'
4
4
  require 'fast_ignore'
5
5
 
6
6
  module Leftovers
7
- class MergedConfig # rubocop:disable Metrics/ClassLength
7
+ class MergedConfig
8
8
  def initialize(load_defaults: false)
9
9
  @configs = []
10
10
  @loaded_configs = Set.new
@@ -24,9 +24,7 @@ module Leftovers
24
24
  @configs << config
25
25
  @loaded_configs << config.name
26
26
  config.gems.each { |gem| self << gem }
27
- config.requires.each do |req|
28
- Leftovers.try_require(req, message: "cannot require '#{req}' from #{config.name}.yml")
29
- end
27
+ require_requires(config)
30
28
  end
31
29
 
32
30
  def project_config
@@ -66,51 +64,27 @@ module Leftovers
66
64
  end
67
65
 
68
66
  def test_paths
69
- @test_paths ||= FastIgnore.new(
70
- include_rules: @configs.flat_map(&:test_paths),
71
- gitignore: false,
72
- root: Leftovers.pwd
73
- )
67
+ @test_paths ||= Leftovers::MatcherBuilders::Path.build(@configs.flat_map(&:test_paths))
74
68
  end
75
69
 
76
70
  def haml_paths
77
- @haml_paths ||= FastIgnore.new(
78
- include_rules: @configs.flat_map(&:haml_paths),
79
- gitignore: false,
80
- root: Leftovers.pwd
81
- )
71
+ @haml_paths ||= Leftovers::MatcherBuilders::Path.build(@configs.flat_map(&:haml_paths))
82
72
  end
83
73
 
84
74
  def slim_paths
85
- @slim_paths ||= FastIgnore.new(
86
- include_rules: @configs.flat_map(&:slim_paths),
87
- gitignore: false,
88
- root: Leftovers.pwd
89
- )
75
+ @slim_paths ||= Leftovers::MatcherBuilders::Path.build(@configs.flat_map(&:slim_paths))
90
76
  end
91
77
 
92
78
  def yaml_paths
93
- @yaml_paths ||= FastIgnore.new(
94
- include_rules: @configs.flat_map(&:yaml_paths),
95
- gitignore: false,
96
- root: Leftovers.pwd
97
- )
79
+ @yaml_paths ||= Leftovers::MatcherBuilders::Path.build(@configs.flat_map(&:yaml_paths))
98
80
  end
99
81
 
100
82
  def json_paths
101
- @json_paths ||= FastIgnore.new(
102
- include_rules: @configs.flat_map(&:json_paths),
103
- gitignore: false,
104
- root: Leftovers.pwd
105
- )
83
+ @json_paths ||= Leftovers::MatcherBuilders::Path.build(@configs.flat_map(&:json_paths))
106
84
  end
107
85
 
108
86
  def erb_paths
109
- @erb_paths ||= FastIgnore.new(
110
- include_rules: @configs.flat_map(&:erb_paths),
111
- gitignore: false,
112
- root: Leftovers.pwd
113
- )
87
+ @erb_paths ||= Leftovers::MatcherBuilders::Path.build(@configs.flat_map(&:erb_paths))
114
88
  end
115
89
 
116
90
  def dynamic
@@ -127,6 +101,16 @@ module Leftovers
127
101
 
128
102
  private
129
103
 
104
+ def require_requires(config)
105
+ config.requires.each do |req|
106
+ if req.is_a?(Hash) && req[:quiet]
107
+ Leftovers.try_require(req[:quiet])
108
+ else
109
+ Leftovers.try_require(req, message: "cannot require '#{req}' from #{config.name}.yml")
110
+ end
111
+ end
112
+ end
113
+
130
114
  def load_bundled_gem_config
131
115
  return unless Leftovers.try_require('bundler')
132
116