leftovers 0.4.3 → 0.5.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +14 -0
- data/docs/Configuration.md +46 -11
- data/lib/config/actioncable.yml +4 -0
- data/lib/config/actionmailer.yml +22 -0
- data/lib/config/actionpack.yml +190 -0
- data/lib/config/actionview.yml +64 -0
- data/lib/config/activejob.yml +29 -0
- data/lib/config/activemodel.yml +74 -0
- data/lib/config/activerecord.yml +179 -0
- data/lib/config/activesupport.yml +98 -0
- data/lib/config/haml.yml +2 -0
- data/lib/config/rails.yml +11 -450
- data/lib/config/ruby.yml +6 -0
- data/lib/leftovers/ast/node.rb +14 -0
- data/lib/leftovers/config.rb +8 -0
- data/lib/leftovers/config_validator/schema_hash.rb +50 -5
- data/lib/leftovers/file.rb +2 -3
- data/lib/leftovers/matcher_builders/node.rb +2 -0
- data/lib/leftovers/matcher_builders/node_has_argument.rb +11 -7
- data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +14 -10
- data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +17 -13
- data/lib/leftovers/matcher_builders/node_has_receiver.rb +15 -0
- data/lib/leftovers/matcher_builders/node_type.rb +7 -6
- data/lib/leftovers/matcher_builders/node_value.rb +42 -0
- data/lib/leftovers/matcher_builders.rb +3 -2
- data/lib/leftovers/matchers/node_has_any_positional_argument_with_value.rb +4 -1
- data/lib/leftovers/matchers/node_has_positional_argument.rb +0 -4
- data/lib/leftovers/matchers/node_has_receiver.rb +20 -0
- data/lib/leftovers/matchers/predicate.rb +19 -0
- data/lib/leftovers/matchers.rb +2 -0
- data/lib/leftovers/merged_config.rb +19 -1
- data/lib/leftovers/todo_reporter.rb +9 -6
- data/lib/leftovers/version.rb +1 -1
- data/lib/leftovers.rb +95 -92
- metadata +14 -3
- data/lib/leftovers/matcher_builders/argument_node_value.rb +0 -21
@@ -26,6 +26,8 @@ module Leftovers
|
|
26
26
|
|
27
27
|
::Leftovers.each_or_self(at) do |k|
|
28
28
|
case k
|
29
|
+
when '*'
|
30
|
+
positions << k
|
29
31
|
when ::String, ::Hash
|
30
32
|
keys << k
|
31
33
|
when ::Integer
|
@@ -35,23 +37,25 @@ module Leftovers
|
|
35
37
|
# :nocov:
|
36
38
|
end
|
37
39
|
end
|
40
|
+
|
38
41
|
keys = nil if keys.empty?
|
39
42
|
positions = nil if positions.empty?
|
40
43
|
|
41
44
|
[keys, positions]
|
42
45
|
end
|
43
46
|
|
44
|
-
def self.build_from_hash(
|
47
|
+
def self.build_from_hash( # rubocop:disable Metrics/MethodLength
|
48
|
+
at: nil,
|
49
|
+
has_value: nil,
|
50
|
+
unless_arg: nil
|
51
|
+
)
|
45
52
|
keys, positions = separate_argument_types(at)
|
46
53
|
|
47
|
-
value_matcher = ::Leftovers::MatcherBuilders::
|
48
|
-
::Leftovers::MatcherBuilders::ArgumentNodeValue.build(has_value),
|
49
|
-
::Leftovers::MatcherBuilders::NodeType.build(has_value_type)
|
50
|
-
])
|
54
|
+
value_matcher = ::Leftovers::MatcherBuilders::NodeValue.build(has_value)
|
51
55
|
matcher = if (keys && positions) || (!keys && !positions)
|
52
56
|
::Leftovers::MatcherBuilders::Or.build([
|
53
|
-
::Leftovers::MatcherBuilders::
|
54
|
-
::Leftovers::MatcherBuilders::
|
57
|
+
::Leftovers::MatcherBuilders::NodeHasPositionalArgument.build(positions, value_matcher),
|
58
|
+
::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(keys, value_matcher)
|
55
59
|
])
|
56
60
|
elsif keys
|
57
61
|
::Leftovers::MatcherBuilders::NodeHasKeywordArgument.build(keys, value_matcher)
|
@@ -3,19 +3,23 @@
|
|
3
3
|
module Leftovers
|
4
4
|
module MatcherBuilders
|
5
5
|
module NodeHasKeywordArgument
|
6
|
-
|
7
|
-
|
8
|
-
|
6
|
+
class << self
|
7
|
+
def build(keywords, value_matcher) # rubocop:disable Metrics/MethodLength
|
8
|
+
value_matcher = ::Leftovers::MatcherBuilders::NodePairValue.build(value_matcher)
|
9
|
+
keyword_matcher = if ::Leftovers.each_or_self(keywords).any? { |x| x == '**' }
|
10
|
+
::Leftovers::Matchers::NodeType.new(:pair)
|
11
|
+
else
|
12
|
+
::Leftovers::MatcherBuilders::NodePairName.build(keywords)
|
13
|
+
end
|
9
14
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
# :nocov:
|
14
|
-
raise unless pair_matcher
|
15
|
+
pair_matcher = ::Leftovers::MatcherBuilders::And.build([
|
16
|
+
keyword_matcher, value_matcher
|
17
|
+
])
|
15
18
|
|
16
|
-
|
19
|
+
return nil unless pair_matcher
|
17
20
|
|
18
|
-
|
21
|
+
::Leftovers::Matchers::NodeHasAnyKeywordArgument.new(pair_matcher)
|
22
|
+
end
|
19
23
|
end
|
20
24
|
end
|
21
25
|
end
|
@@ -3,20 +3,24 @@
|
|
3
3
|
module Leftovers
|
4
4
|
module MatcherBuilders
|
5
5
|
module NodeHasPositionalArgument
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
::Leftovers::
|
10
|
-
|
11
|
-
|
12
|
-
|
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).any? { |x| x == '*' }
|
18
|
+
pos ||= ::Leftovers.each_or_self(positions).min
|
13
19
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
else raise
|
19
|
-
# :nocov:
|
20
|
+
::Leftovers::Matchers::NodeHasPositionalArgument.new(pos)
|
21
|
+
elsif value_matcher
|
22
|
+
::Leftovers::Matchers::NodeHasAnyPositionalArgumentWithValue.new(value_matcher)
|
23
|
+
end
|
20
24
|
end
|
21
25
|
end
|
22
26
|
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Leftovers
|
4
|
+
module MatcherBuilders
|
5
|
+
module NodeHasReceiver
|
6
|
+
class << self
|
7
|
+
def build(pattern)
|
8
|
+
matcher = ::Leftovers::MatcherBuilders::NodeValue.build(pattern)
|
9
|
+
|
10
|
+
::Leftovers::Matchers::NodeHasReceiver.new(matcher) if matcher
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
@@ -5,18 +5,19 @@ require 'set'
|
|
5
5
|
module Leftovers
|
6
6
|
module MatcherBuilders
|
7
7
|
module NodeType
|
8
|
-
def self.build(types_pattern)
|
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
11
|
when 'Symbol' then ::Leftovers::Matchers::NodeType.new(:sym)
|
12
12
|
when 'String' then ::Leftovers::Matchers::NodeType.new(:str)
|
13
13
|
when 'Integer' then ::Leftovers::Matchers::NodeType.new(:int)
|
14
14
|
when 'Float' then ::Leftovers::Matchers::NodeType.new(:float)
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
# when '
|
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])
|
20
21
|
# :nocov:
|
21
22
|
else raise
|
22
23
|
# :nocov:
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# frozen-string-literal: true
|
2
|
+
|
3
|
+
module Leftovers
|
4
|
+
module MatcherBuilders
|
5
|
+
module NodeValue
|
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)
|
16
|
+
# :nocov:
|
17
|
+
else raise
|
18
|
+
# :nocov:
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def build_from_hash(pat) # rubocop:disable Metrics/MethodLength
|
26
|
+
matcher = ::Leftovers::MatcherBuilders::And.build([
|
27
|
+
::Leftovers::MatcherBuilders::NodeHasArgument.build(pat.slice(:at, :has_value)),
|
28
|
+
::Leftovers::MatcherBuilders::NodeName.build(
|
29
|
+
pat.slice(:match, :has_prefix, :has_suffix)
|
30
|
+
),
|
31
|
+
::Leftovers::MatcherBuilders::NodeType.build(pat[:type]),
|
32
|
+
::Leftovers::MatcherBuilders::NodeHasReceiver.build(pat[:has_receiver])
|
33
|
+
])
|
34
|
+
|
35
|
+
::Leftovers::MatcherBuilders::AndNot.build(
|
36
|
+
matcher, ::Leftovers::MatcherBuilders::NodeValue.build(pat[:unless_arg])
|
37
|
+
)
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -4,17 +4,18 @@ module Leftovers
|
|
4
4
|
module MatcherBuilders
|
5
5
|
autoload(:AndNot, "#{__dir__}/matcher_builders/and_not")
|
6
6
|
autoload(:And, "#{__dir__}/matcher_builders/and")
|
7
|
-
autoload(:ArgumentNodeValue, "#{__dir__}/matcher_builders/argument_node_value")
|
8
7
|
autoload(:Name, "#{__dir__}/matcher_builders/name")
|
8
|
+
autoload(:Node, "#{__dir__}/matcher_builders/node")
|
9
9
|
autoload(:NodeHasArgument, "#{__dir__}/matcher_builders/node_has_argument")
|
10
10
|
autoload(:NodeHasKeywordArgument, "#{__dir__}/matcher_builders/node_has_keyword_argument")
|
11
11
|
autoload(:NodeHasPositionalArgument, "#{__dir__}/matcher_builders/node_has_positional_argument")
|
12
|
+
autoload(:NodeHasReceiver, "#{__dir__}/matcher_builders/node_has_receiver")
|
12
13
|
autoload(:NodeName, "#{__dir__}/matcher_builders/node_name")
|
13
14
|
autoload(:NodePairName, "#{__dir__}/matcher_builders/node_pair_name")
|
14
15
|
autoload(:NodePairValue, "#{__dir__}/matcher_builders/node_pair_value")
|
15
16
|
autoload(:NodePath, "#{__dir__}/matcher_builders/node_path")
|
16
17
|
autoload(:NodeType, "#{__dir__}/matcher_builders/node_type")
|
17
|
-
autoload(:
|
18
|
+
autoload(:NodeValue, "#{__dir__}/matcher_builders/node_value")
|
18
19
|
autoload(:Or, "#{__dir__}/matcher_builders/or")
|
19
20
|
autoload(:Path, "#{__dir__}/matcher_builders/path")
|
20
21
|
autoload(:StringPattern, "#{__dir__}/matcher_builders/string_pattern")
|
@@ -0,0 +1,20 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Leftovers
|
4
|
+
module Matchers
|
5
|
+
class NodeHasReceiver
|
6
|
+
def initialize(matcher)
|
7
|
+
@matcher = matcher
|
8
|
+
|
9
|
+
freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
def ===(node)
|
13
|
+
receiver = node.receiver
|
14
|
+
@matcher === receiver if receiver
|
15
|
+
end
|
16
|
+
|
17
|
+
freeze
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,19 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module Leftovers
|
4
|
+
module Matchers
|
5
|
+
class Predicate
|
6
|
+
def initialize(predicate)
|
7
|
+
@predicate = predicate
|
8
|
+
|
9
|
+
freeze
|
10
|
+
end
|
11
|
+
|
12
|
+
def ===(node)
|
13
|
+
node.send(@predicate)
|
14
|
+
end
|
15
|
+
|
16
|
+
freeze
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/leftovers/matchers.rb
CHANGED
@@ -15,6 +15,7 @@ module Leftovers
|
|
15
15
|
"#{__dir__}/matchers/node_has_positional_argument_with_value"
|
16
16
|
)
|
17
17
|
autoload(:NodeHasPositionalArgument, "#{__dir__}/matchers/node_has_positional_argument")
|
18
|
+
autoload(:NodeHasReceiver, "#{__dir__}/matchers/node_has_receiver")
|
18
19
|
autoload(:NodeName, "#{__dir__}/matchers/node_name")
|
19
20
|
autoload(:NodePairValue, "#{__dir__}/matchers/node_pair_value")
|
20
21
|
autoload(:NodePath, "#{__dir__}/matchers/node_path")
|
@@ -22,5 +23,6 @@ module Leftovers
|
|
22
23
|
autoload(:NodeType, "#{__dir__}/matchers/node_type")
|
23
24
|
autoload(:Not, "#{__dir__}/matchers/not")
|
24
25
|
autoload(:Or, "#{__dir__}/matchers/or")
|
26
|
+
autoload(:Predicate, "#{__dir__}/matchers/predicate")
|
25
27
|
end
|
26
28
|
end
|
@@ -37,10 +37,12 @@ module Leftovers
|
|
37
37
|
Leftovers::Config.new(:'.leftovers_todo.yml', path: Leftovers.pwd + '.leftovers_todo.yml')
|
38
38
|
end
|
39
39
|
|
40
|
-
def unmemoize
|
40
|
+
def unmemoize # rubocop:disable Metrics/CyclomaticComplexity
|
41
41
|
remove_instance_variable(:@exclude_paths) if defined?(@exclude_paths)
|
42
42
|
remove_instance_variable(:@include_paths) if defined?(@include_paths)
|
43
43
|
remove_instance_variable(:@test_paths) if defined?(@test_paths)
|
44
|
+
remove_instance_variable(:@haml_paths) if defined?(@haml_paths)
|
45
|
+
remove_instance_variable(:@erb_paths) if defined?(@erb_paths)
|
44
46
|
remove_instance_variable(:@dynamic) if defined?(@dynamic)
|
45
47
|
remove_instance_variable(:@keep) if defined?(@keep)
|
46
48
|
end
|
@@ -61,6 +63,22 @@ module Leftovers
|
|
61
63
|
)
|
62
64
|
end
|
63
65
|
|
66
|
+
def haml_paths
|
67
|
+
@haml_paths ||= FastIgnore.new(
|
68
|
+
include_rules: @configs.flat_map(&:haml_paths),
|
69
|
+
gitignore: false,
|
70
|
+
root: Leftovers.pwd
|
71
|
+
)
|
72
|
+
end
|
73
|
+
|
74
|
+
def erb_paths
|
75
|
+
@erb_paths ||= FastIgnore.new(
|
76
|
+
include_rules: @configs.flat_map(&:erb_paths),
|
77
|
+
gitignore: false,
|
78
|
+
root: Leftovers.pwd
|
79
|
+
)
|
80
|
+
end
|
81
|
+
|
64
82
|
def dynamic
|
65
83
|
@dynamic ||= ::Leftovers::ProcessorBuilders::EachDynamic.build(@configs.map(&:dynamic))
|
66
84
|
end
|
@@ -30,12 +30,9 @@ module Leftovers
|
|
30
30
|
def report_instructions
|
31
31
|
puts <<~MESSAGE
|
32
32
|
generated #{path.basename}.
|
33
|
-
running leftovers again will read this file and
|
34
|
-
not alert you to any unused items mentioned in it.
|
33
|
+
running leftovers again will read this file and not alert you to any unused items mentioned in it.
|
35
34
|
|
36
|
-
commit this file so you/your team can gradually
|
37
|
-
address these items while still having leftovers
|
38
|
-
alert you to any newly unused items.
|
35
|
+
commit this file so you/your team can gradually address these items while still having leftovers alert you to any newly unused items.
|
39
36
|
MESSAGE
|
40
37
|
end
|
41
38
|
|
@@ -108,12 +105,18 @@ module Leftovers
|
|
108
105
|
def generate_list(title, list)
|
109
106
|
<<~YML
|
110
107
|
# #{title}
|
111
|
-
#{list
|
108
|
+
#{print_definition_list(list)}
|
112
109
|
|
113
110
|
YML
|
114
111
|
end
|
115
112
|
|
113
|
+
def print_definition_list(definition_list)
|
114
|
+
definition_list.map { |definition| print_definition(definition) }.join("\n")
|
115
|
+
end
|
116
|
+
|
116
117
|
def print_definition(definition)
|
118
|
+
return print_definition_list(definition.definitions) if definition.is_a?(DefinitionSet)
|
119
|
+
|
117
120
|
" - #{definition.to_s.inspect} # #{definition.location_s} #{definition.source_line.strip}"
|
118
121
|
end
|
119
122
|
|
data/lib/leftovers/version.rb
CHANGED
data/lib/leftovers.rb
CHANGED
@@ -3,8 +3,6 @@
|
|
3
3
|
module Leftovers # rubocop:disable Metrics/ModuleLength
|
4
4
|
class Error < ::StandardError; end
|
5
5
|
|
6
|
-
module_function
|
7
|
-
|
8
6
|
autoload(:AST, "#{__dir__}/leftovers/ast")
|
9
7
|
autoload(:Backports, "#{__dir__}/leftovers/backports")
|
10
8
|
autoload(:CLI, "#{__dir__}/leftovers/cli")
|
@@ -32,124 +30,129 @@ module Leftovers # rubocop:disable Metrics/ModuleLength
|
|
32
30
|
autoload(:VERSION, "#{__dir__}/leftovers/version")
|
33
31
|
|
34
32
|
class << self
|
35
|
-
attr_accessor :parallel, :progress
|
33
|
+
attr_accessor :parallel, :progress
|
34
|
+
attr_writer :reporter
|
36
35
|
alias_method :parallel?, :parallel
|
37
36
|
alias_method :progress?, :progress
|
38
|
-
end
|
39
37
|
|
40
|
-
|
41
|
-
|
42
|
-
|
38
|
+
def stdout
|
39
|
+
@stdout ||= $stdout
|
40
|
+
end
|
43
41
|
|
44
|
-
|
45
|
-
|
46
|
-
|
42
|
+
def stderr
|
43
|
+
@stderr ||= $stderr
|
44
|
+
end
|
47
45
|
|
48
|
-
|
49
|
-
|
50
|
-
|
46
|
+
def config
|
47
|
+
@config ||= Leftovers::MergedConfig.new(load_defaults: true)
|
48
|
+
end
|
51
49
|
|
52
|
-
|
53
|
-
|
54
|
-
|
50
|
+
def collector
|
51
|
+
@collector ||= Leftovers::Collector.new
|
52
|
+
end
|
55
53
|
|
56
|
-
|
57
|
-
|
58
|
-
|
54
|
+
def reporter
|
55
|
+
@reporter ||= Leftovers::Reporter.new
|
56
|
+
end
|
59
57
|
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
58
|
+
def leftovers
|
59
|
+
@leftovers ||= begin
|
60
|
+
collector.collect
|
61
|
+
collector.definitions.reject(&:in_collection?)
|
62
|
+
end
|
64
63
|
end
|
65
|
-
end
|
66
64
|
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
65
|
+
def run(stdout: StringIO.new, stderr: StringIO.new) # rubocop:disable Metrics/MethodLength
|
66
|
+
@stdout = stdout
|
67
|
+
@stderr = stderr
|
68
|
+
return reporter.report_success if leftovers.empty?
|
69
|
+
|
70
|
+
only_test = []
|
71
|
+
none = []
|
72
|
+
leftovers.sort_by(&:location_s).each do |definition|
|
73
|
+
if !definition.test? && definition.in_test_collection?
|
74
|
+
only_test << definition
|
75
|
+
else
|
76
|
+
none << definition
|
77
|
+
end
|
79
78
|
end
|
79
|
+
|
80
|
+
reporter.report(only_test: only_test, none: none)
|
80
81
|
end
|
81
82
|
|
82
|
-
|
83
|
-
|
83
|
+
def reset # rubocop:disable Metrics/PerceivedComplexity, Metrics/CyclomaticComplexity
|
84
|
+
remove_instance_variable(:@config) if defined?(@config)
|
85
|
+
remove_instance_variable(:@collector) if defined?(@collector)
|
86
|
+
remove_instance_variable(:@reporter) if defined?(@reporter)
|
87
|
+
remove_instance_variable(:@leftovers) if defined?(@leftovers)
|
88
|
+
remove_instance_variable(:@try_require_cache) if defined?(@try_require_cache)
|
89
|
+
remove_instance_variable(:@stdout) if defined?(@stdout)
|
90
|
+
remove_instance_variable(:@stderr) if defined?(@stderr)
|
91
|
+
remove_instance_variable(:@parallel) if defined?(@parallel)
|
92
|
+
remove_instance_variable(:@pwd) if defined?(@pwd)
|
93
|
+
end
|
84
94
|
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
remove_instance_variable(:@reporter) if defined?(@reporter)
|
89
|
-
remove_instance_variable(:@leftovers) if defined?(@leftovers)
|
90
|
-
remove_instance_variable(:@try_require) if defined?(@try_require)
|
91
|
-
remove_instance_variable(:@stdout) if defined?(@stdout)
|
92
|
-
remove_instance_variable(:@stderr) if defined?(@stderr)
|
93
|
-
remove_instance_variable(:@parallel) if defined?(@parallel)
|
94
|
-
remove_instance_variable(:@pwd) if defined?(@pwd)
|
95
|
-
end
|
95
|
+
def resolution_instructions_link
|
96
|
+
"https://github.com/robotdana/leftovers/tree/v#{Leftovers::VERSION}/README.md#how_to_resolve"
|
97
|
+
end
|
96
98
|
|
97
|
-
|
98
|
-
|
99
|
-
|
99
|
+
def warn(message)
|
100
|
+
stderr.puts("\e[2K#{message}")
|
101
|
+
end
|
100
102
|
|
101
|
-
|
102
|
-
|
103
|
-
|
103
|
+
def error(message)
|
104
|
+
warn(message)
|
105
|
+
exit 1
|
106
|
+
end
|
104
107
|
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
end
|
108
|
+
def puts(message)
|
109
|
+
stdout.puts("\e[2K#{message}")
|
110
|
+
end
|
109
111
|
|
110
|
-
|
111
|
-
|
112
|
-
|
112
|
+
def print(message)
|
113
|
+
stdout.print(message)
|
114
|
+
end
|
113
115
|
|
114
|
-
|
115
|
-
|
116
|
-
|
116
|
+
def newline
|
117
|
+
stdout.puts('')
|
118
|
+
end
|
117
119
|
|
118
|
-
|
119
|
-
|
120
|
-
|
120
|
+
def pwd
|
121
|
+
@pwd ||= Pathname.new(Dir.pwd + '/')
|
122
|
+
end
|
121
123
|
|
122
|
-
|
123
|
-
|
124
|
-
|
124
|
+
def exit(status = 0)
|
125
|
+
throw :leftovers_exit, status
|
126
|
+
end
|
125
127
|
|
126
|
-
|
127
|
-
|
128
|
-
|
128
|
+
def try_require(requirable, message: nil)
|
129
|
+
warn message if !try_require_cache(requirable) && message
|
130
|
+
try_require_cache(requirable)
|
131
|
+
end
|
129
132
|
|
130
|
-
|
131
|
-
|
133
|
+
def each_or_self(value, &block)
|
134
|
+
return enum_for(__method__, value) unless block
|
132
135
|
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
else
|
137
|
-
require requirable
|
138
|
-
true
|
136
|
+
case value
|
137
|
+
when nil then nil
|
138
|
+
when Array then value.each(&block)
|
139
|
+
else yield(value)
|
139
140
|
end
|
140
|
-
rescue LoadError
|
141
|
-
false
|
142
141
|
end
|
143
142
|
|
144
|
-
|
145
|
-
@try_require[requirable]
|
146
|
-
end
|
143
|
+
private
|
147
144
|
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
145
|
+
def try_require_cache(requirable)
|
146
|
+
@try_require_cache ||= {}
|
147
|
+
|
148
|
+
@try_require_cache.fetch(requirable) do
|
149
|
+
begin
|
150
|
+
require requirable
|
151
|
+
@try_require_cache[requirable] = true
|
152
|
+
rescue LoadError
|
153
|
+
@try_require_cache[requirable] = false
|
154
|
+
end
|
155
|
+
end
|
153
156
|
end
|
154
157
|
end
|
155
158
|
end
|