leftovers 0.11.0 → 0.11.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (130) hide show
  1. checksums.yaml +4 -4
  2. data/CHANGELOG.md +11 -0
  3. data/README.md +1 -0
  4. data/docs/Configuration.md +7 -0
  5. data/exe/leftovers +3 -1
  6. data/leftovers.gemspec +3 -4
  7. data/lib/config/activesupport.yml +1 -1
  8. data/lib/config/rspec.yml +21 -0
  9. data/lib/leftovers/ast/array_node.rb +2 -2
  10. data/lib/leftovers/ast/block_node.rb +1 -1
  11. data/lib/leftovers/ast/builder.rb +19 -18
  12. data/lib/leftovers/ast/casgn_node.rb +2 -2
  13. data/lib/leftovers/ast/const_node.rb +1 -1
  14. data/lib/leftovers/ast/def_node.rb +1 -1
  15. data/lib/leftovers/ast/defs_node.rb +1 -1
  16. data/lib/leftovers/ast/false_node.rb +1 -1
  17. data/lib/leftovers/ast/hash_node.rb +2 -2
  18. data/lib/leftovers/ast/module_node.rb +1 -1
  19. data/lib/leftovers/ast/nil_node.rb +1 -1
  20. data/lib/leftovers/ast/node.rb +13 -1
  21. data/lib/leftovers/ast/numeric_node.rb +1 -1
  22. data/lib/leftovers/ast/send_node.rb +16 -3
  23. data/lib/leftovers/ast/str_node.rb +1 -1
  24. data/lib/leftovers/ast/sym_node.rb +1 -1
  25. data/lib/leftovers/ast/true_node.rb +1 -1
  26. data/lib/leftovers/ast/var_node.rb +1 -1
  27. data/lib/leftovers/ast/vasgn_node.rb +2 -2
  28. data/lib/leftovers/ast.rb +2 -21
  29. data/lib/leftovers/autoloader.rb +36 -0
  30. data/lib/leftovers/cli.rb +58 -42
  31. data/lib/leftovers/collection.rb +66 -0
  32. data/lib/leftovers/collector.rb +17 -27
  33. data/lib/leftovers/config.rb +17 -5
  34. data/lib/leftovers/config_loader/attribute.rb +2 -2
  35. data/lib/leftovers/config_loader/bool_schema.rb +21 -0
  36. data/lib/leftovers/config_loader/document_schema.rb +2 -2
  37. data/lib/leftovers/config_loader/inherit_schema_attributes.rb +1 -1
  38. data/lib/leftovers/config_loader/node.rb +8 -8
  39. data/lib/leftovers/config_loader/regexp_schema.rb +1 -1
  40. data/lib/leftovers/config_loader/rule_pattern_schema.rb +1 -0
  41. data/lib/leftovers/config_loader/schema.rb +1 -1
  42. data/lib/leftovers/config_loader/string_enum_schema.rb +1 -1
  43. data/lib/leftovers/config_loader/value_or_array_schema.rb +1 -1
  44. data/lib/leftovers/config_loader.rb +8 -48
  45. data/lib/leftovers/definition.rb +4 -4
  46. data/lib/leftovers/definition_collection.rb +3 -3
  47. data/lib/leftovers/definition_node.rb +2 -2
  48. data/lib/leftovers/definition_node_set.rb +1 -1
  49. data/lib/leftovers/definition_set.rb +4 -4
  50. data/lib/leftovers/definition_to_add.rb +2 -2
  51. data/lib/leftovers/error.rb +6 -0
  52. data/lib/leftovers/file.rb +4 -4
  53. data/lib/leftovers/file_collector/comments_processor.rb +23 -18
  54. data/lib/leftovers/file_collector/node_processor.rb +9 -1
  55. data/lib/leftovers/file_collector.rb +15 -17
  56. data/lib/leftovers/file_list.rb +4 -6
  57. data/lib/leftovers/matcher_builders/and.rb +5 -5
  58. data/lib/leftovers/matcher_builders/document.rb +1 -3
  59. data/lib/leftovers/matcher_builders/name.rb +4 -7
  60. data/lib/leftovers/matcher_builders/node.rb +21 -35
  61. data/lib/leftovers/matcher_builders/node_has_argument.rb +17 -29
  62. data/lib/leftovers/matcher_builders/node_has_block.rb +17 -0
  63. data/lib/leftovers/matcher_builders/node_has_keyword_argument.rb +7 -9
  64. data/lib/leftovers/matcher_builders/node_has_positional_argument.rb +10 -10
  65. data/lib/leftovers/matcher_builders/node_has_receiver.rb +6 -8
  66. data/lib/leftovers/matcher_builders/node_name.rb +3 -5
  67. data/lib/leftovers/matcher_builders/node_pair_key.rb +4 -4
  68. data/lib/leftovers/matcher_builders/node_pair_value.rb +4 -4
  69. data/lib/leftovers/matcher_builders/node_path.rb +3 -4
  70. data/lib/leftovers/matcher_builders/node_privacy.rb +3 -3
  71. data/lib/leftovers/matcher_builders/node_type.rb +13 -14
  72. data/lib/leftovers/matcher_builders/node_value.rb +18 -31
  73. data/lib/leftovers/matcher_builders/or.rb +10 -10
  74. data/lib/leftovers/matcher_builders/path.rb +3 -3
  75. data/lib/leftovers/matcher_builders/string_pattern.rb +2 -0
  76. data/lib/leftovers/matcher_builders/unless.rb +1 -3
  77. data/lib/leftovers/matcher_builders.rb +2 -22
  78. data/lib/leftovers/matchers/node_has_block.rb +13 -0
  79. data/lib/leftovers/matchers/node_scalar_value.rb +1 -1
  80. data/lib/leftovers/matchers.rb +2 -27
  81. data/lib/leftovers/merged_config.rb +16 -17
  82. data/lib/leftovers/parser.rb +1 -1
  83. data/lib/leftovers/precompile_error.rb +31 -0
  84. data/lib/leftovers/precompilers/haml.rb +23 -3
  85. data/lib/leftovers/precompilers/json.rb +1 -1
  86. data/lib/leftovers/precompilers/precompiler.rb +3 -3
  87. data/lib/leftovers/precompilers/slim.rb +1 -1
  88. data/lib/leftovers/precompilers/yaml/builder.rb +62 -0
  89. data/lib/leftovers/precompilers/yaml.rb +3 -56
  90. data/lib/leftovers/precompilers.rb +11 -16
  91. data/lib/leftovers/processor_builders/action.rb +15 -19
  92. data/lib/leftovers/processor_builders/add_prefix.rb +4 -6
  93. data/lib/leftovers/processor_builders/add_suffix.rb +4 -6
  94. data/lib/leftovers/processor_builders/argument.rb +10 -15
  95. data/lib/leftovers/processor_builders/dynamic.rb +12 -30
  96. data/lib/leftovers/processor_builders/each.rb +63 -76
  97. data/lib/leftovers/processor_builders/each_for_definition_set.rb +15 -0
  98. data/lib/leftovers/processor_builders/itself.rb +2 -4
  99. data/lib/leftovers/processor_builders/keyword.rb +4 -4
  100. data/lib/leftovers/processor_builders/keyword_argument.rb +4 -4
  101. data/lib/leftovers/processor_builders/receiver.rb +2 -4
  102. data/lib/leftovers/processor_builders/transform.rb +26 -49
  103. data/lib/leftovers/processor_builders/transform_chain.rb +4 -7
  104. data/lib/leftovers/processor_builders/transform_set.rb +6 -7
  105. data/lib/leftovers/processor_builders/value.rb +2 -2
  106. data/lib/leftovers/processor_builders.rb +2 -15
  107. data/lib/leftovers/processors/add_definition_node.rb +2 -2
  108. data/lib/leftovers/processors/camelize.rb +3 -3
  109. data/lib/leftovers/processors/deconstantize.rb +3 -3
  110. data/lib/leftovers/processors/demodulize.rb +3 -3
  111. data/lib/leftovers/processors/each_for_definition_set.rb +2 -2
  112. data/lib/leftovers/processors/eval.rb +1 -1
  113. data/lib/leftovers/processors/parameterize.rb +3 -3
  114. data/lib/leftovers/processors/placeholder.rb +1 -1
  115. data/lib/leftovers/processors/pluralize.rb +3 -3
  116. data/lib/leftovers/processors/set_default_privacy.rb +1 -1
  117. data/lib/leftovers/processors/set_privacy.rb +1 -1
  118. data/lib/leftovers/processors/singularize.rb +3 -3
  119. data/lib/leftovers/processors/titleize.rb +3 -3
  120. data/lib/leftovers/processors/underscore.rb +3 -3
  121. data/lib/leftovers/processors.rb +2 -44
  122. data/lib/leftovers/rake_task.rb +2 -2
  123. data/lib/leftovers/reporter.rb +44 -42
  124. data/lib/leftovers/runner.rb +40 -0
  125. data/lib/leftovers/todo_reporter.rb +96 -94
  126. data/lib/leftovers/unexpected_case.rb +8 -0
  127. data/lib/leftovers/version.rb +1 -1
  128. data/lib/leftovers.rb +17 -110
  129. metadata +13 -17
  130. data/lib/leftovers/matcher_builders/and_not.rb +0 -16
@@ -1,20 +1,19 @@
1
- # frozen-string-literal: true
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Leftovers
4
4
  module MatcherBuilders
5
5
  module NodeValue
6
6
  class << self
7
7
  def build(patterns)
8
- ::Leftovers::MatcherBuilders::Or.each_or_self(patterns) do |pattern|
8
+ Or.each_or_self(patterns) do |pattern|
9
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)
10
+ when ::Integer, ::Float, true, false then Matchers::NodeScalarValue.new(pattern)
11
+ # matching scalar on nil will fall afoul of compact and each_or_self etc.
12
+ when :_leftovers_nil_value then Matchers::NodeType.new(:nil)
13
+ when ::String then NodeName.build(pattern)
15
14
  when ::Hash then build_from_hash(**pattern)
16
15
  # :nocov:
17
- else raise Leftovers::UnexpectedCase, "Unhandled value #{pattern.inspect}"
16
+ else raise UnexpectedCase, "Unhandled value #{pattern.inspect}"
18
17
  # :nocov:
19
18
  end
20
19
  end
@@ -23,31 +22,19 @@ module Leftovers
23
22
  private
24
23
 
25
24
  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
- )
25
+ Or.build([
26
+ NodeName.build(names),
27
+ NodeName.build(match: match, has_prefix: has_prefix, has_suffix: has_suffix)
31
28
  ])
32
29
  end
33
30
 
34
31
  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
- )
32
+ Or.build([
33
+ NodeHasArgument.build(has_arguments),
34
+ NodeHasArgument.build(at: at, has_value: has_value)
40
35
  ])
41
36
  end
42
37
 
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
38
  def build_from_hash( # rubocop:disable Metrics/ParameterLists
52
39
  has_arguments: nil, at: nil, has_value: nil,
53
40
  names: nil, match: nil, has_prefix: nil, has_suffix: nil,
@@ -56,13 +43,13 @@ module Leftovers
56
43
  literal: nil,
57
44
  unless_arg: nil
58
45
  )
59
- ::Leftovers::MatcherBuilders::And.build([
46
+ And.build([
60
47
  build_node_has_argument_matcher(has_arguments, at, has_value),
61
48
  build_node_name_matcher(names, match, has_prefix, has_suffix),
62
- ::Leftovers::MatcherBuilders::NodeType.build(type),
63
- ::Leftovers::MatcherBuilders::NodeHasReceiver.build(has_receiver),
64
- ::Leftovers::MatcherBuilders::NodeValue.build(literal),
65
- build_unless(unless_arg)
49
+ NodeType.build(type),
50
+ NodeHasReceiver.build(has_receiver),
51
+ NodeValue.build(literal),
52
+ Unless.build(build(unless_arg))
66
53
  ])
67
54
  end
68
55
  end
@@ -9,7 +9,7 @@ module Leftovers
9
9
  def each_or_self(value, &block)
10
10
  case value
11
11
  when nil then nil
12
- when Array then build(value.map(&block))
12
+ when ::Array then build(value.map(&block))
13
13
  else build([yield(value)])
14
14
  end
15
15
  end
@@ -21,8 +21,8 @@ module Leftovers
21
21
  when 0 then nil
22
22
  # :nocov:
23
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)
24
+ when 2 then Matchers::Or.new(matchers.first, matchers[1])
25
+ else Matchers::Any.new(matchers.dup)
26
26
  end
27
27
  end
28
28
 
@@ -30,11 +30,11 @@ module Leftovers
30
30
 
31
31
  def flatten(value)
32
32
  case value
33
- when ::Leftovers::Matchers::Or
33
+ when Matchers::Or
34
34
  [*flatten(value.lhs), *flatten(value.rhs)]
35
- when ::Leftovers::Matchers::Any
35
+ when Matchers::Any
36
36
  flatten(value.matchers)
37
- when Array, Set
37
+ when ::Array, ::Set
38
38
  value.flat_map { |v| flatten(v) }
39
39
  else
40
40
  [value]
@@ -51,7 +51,7 @@ module Leftovers
51
51
  end
52
52
  end
53
53
 
54
- groups.transform_values { |v| Leftovers.unwrap_array(v) }
54
+ groups.transform_values { |v| ::Leftovers.unwrap_array(v) }
55
55
  end
56
56
 
57
57
  def mergeable?(matcher)
@@ -59,15 +59,15 @@ module Leftovers
59
59
  end
60
60
 
61
61
  def build_grouped_for_matcher(matchers)
62
- return matchers unless matchers.is_a?(Array)
62
+ return matchers unless matchers.is_a?(::Array)
63
63
  return matchers unless mergeable?(matchers.first)
64
64
 
65
65
  matchers.first.class.new(build(matchers.map(&:matcher)))
66
66
  end
67
67
 
68
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)
69
+ set = set.to_set.compare_by_identity if set.is_a?(::Array)
70
+ regexp = ::Regexp.union(regexp) if regexp.is_a?(::Array)
71
71
  matcher_classes = matcher_classes.each_value.flat_map do |matchers|
72
72
  build_grouped_for_matcher(matchers)
73
73
  end
@@ -1,4 +1,4 @@
1
- # frozen-string-literal: true
1
+ # frozen_string_literal: true
2
2
 
3
3
  require 'fast_ignore'
4
4
 
@@ -8,8 +8,8 @@ module Leftovers
8
8
  def self.build(path_pattern)
9
9
  return if path_pattern.nil? || path_pattern.empty?
10
10
 
11
- ::Leftovers::Matchers::Path.new(
12
- ::FastIgnore.new(include_rules: path_pattern, gitignore: false, root: Leftovers.pwd)
11
+ Matchers::Path.new(
12
+ ::FastIgnore.new(include_rules: path_pattern, gitignore: false, root: ::Leftovers.pwd)
13
13
  )
14
14
  end
15
15
  end
@@ -21,6 +21,8 @@ module Leftovers
21
21
  /\A#{has_prefix}/
22
22
  elsif has_suffix
23
23
  /#{has_suffix}\z/
24
+ else
25
+ nil
24
26
  end
25
27
  end
26
28
  end
@@ -4,9 +4,7 @@ module Leftovers
4
4
  module MatcherBuilders
5
5
  module Unless
6
6
  def self.build(matcher)
7
- return unless matcher
8
-
9
- ::Leftovers::Matchers::Not.new(matcher)
7
+ Matchers::Not.new(matcher) if matcher
10
8
  end
11
9
  end
12
10
  end
@@ -1,27 +1,7 @@
1
- # frozen-string-literal: true
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Leftovers
4
4
  module MatcherBuilders
5
- autoload(:AndNot, "#{__dir__}/matcher_builders/and_not")
6
- autoload(:And, "#{__dir__}/matcher_builders/and")
7
- autoload(:Document, "#{__dir__}/matcher_builders/document")
8
- autoload(:Name, "#{__dir__}/matcher_builders/name")
9
- autoload(:Node, "#{__dir__}/matcher_builders/node")
10
- autoload(:NodeHasArgument, "#{__dir__}/matcher_builders/node_has_argument")
11
- autoload(:NodeHasKeywordArgument, "#{__dir__}/matcher_builders/node_has_keyword_argument")
12
- autoload(:NodeHasPositionalArgument, "#{__dir__}/matcher_builders/node_has_positional_argument")
13
- autoload(:NodeHasReceiver, "#{__dir__}/matcher_builders/node_has_receiver")
14
- autoload(:NodeName, "#{__dir__}/matcher_builders/node_name")
15
- autoload(:NodePairKey, "#{__dir__}/matcher_builders/node_pair_key")
16
- autoload(:NodePairValue, "#{__dir__}/matcher_builders/node_pair_value")
17
- autoload(:NodePath, "#{__dir__}/matcher_builders/node_path")
18
- autoload(:NodePrivacy, "#{__dir__}/matcher_builders/node_privacy")
19
- autoload(:NodeType, "#{__dir__}/matcher_builders/node_type")
20
- autoload(:NodeValue, "#{__dir__}/matcher_builders/node_value")
21
- autoload(:Or, "#{__dir__}/matcher_builders/or")
22
- autoload(:Path, "#{__dir__}/matcher_builders/path")
23
- autoload(:StringPattern, "#{__dir__}/matcher_builders/string_pattern")
24
- autoload(:String, "#{__dir__}/matcher_builders/string")
25
- autoload(:Unless, "#{__dir__}/matcher_builders/unless")
5
+ include Autoloader
26
6
  end
27
7
  end
@@ -0,0 +1,13 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module Matchers
5
+ module NodeHasBlock
6
+ def self.===(node)
7
+ node.block_given?
8
+ end
9
+
10
+ freeze
11
+ end
12
+ end
13
+ end
@@ -1,4 +1,4 @@
1
- # frozen-string-literal: true
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Leftovers
4
4
  module Matchers
@@ -1,32 +1,7 @@
1
- # frozen-string-literal: true
1
+ # frozen_string_literal: true
2
2
 
3
3
  module Leftovers
4
4
  module Matchers
5
- autoload(:All, "#{__dir__}/matchers/all")
6
- autoload(:And, "#{__dir__}/matchers/and")
7
- autoload(:Any, "#{__dir__}/matchers/any")
8
- autoload(:NodeHasAnyKeywordArgument, "#{__dir__}/matchers/node_has_any_keyword_argument")
9
- autoload(
10
- :NodeHasAnyPositionalArgumentWithValue,
11
- "#{__dir__}/matchers/node_has_any_positional_argument_with_value"
12
- )
13
- autoload(:NodeHasAnyReceiver, "#{__dir__}/matchers/node_has_any_receiver")
14
- autoload(
15
- :NodeHasPositionalArgumentWithValue,
16
- "#{__dir__}/matchers/node_has_positional_argument_with_value"
17
- )
18
- autoload(:NodeHasPositionalArgument, "#{__dir__}/matchers/node_has_positional_argument")
19
- autoload(:NodeHasReceiver, "#{__dir__}/matchers/node_has_receiver")
20
- autoload(:NodeIsProc, "#{__dir__}/matchers/node_is_proc")
21
- autoload(:NodeName, "#{__dir__}/matchers/node_name")
22
- autoload(:NodePairKey, "#{__dir__}/matchers/node_pair_key")
23
- autoload(:NodePairValue, "#{__dir__}/matchers/node_pair_value")
24
- autoload(:NodePath, "#{__dir__}/matchers/node_path")
25
- autoload(:NodePrivacy, "#{__dir__}/matchers/node_privacy")
26
- autoload(:NodeScalarValue, "#{__dir__}/matchers/node_scalar_value")
27
- autoload(:NodeType, "#{__dir__}/matchers/node_type")
28
- autoload(:Not, "#{__dir__}/matchers/not")
29
- autoload(:Or, "#{__dir__}/matchers/or")
30
- autoload(:Path, "#{__dir__}/matchers/path")
5
+ include Autoloader
31
6
  end
32
7
  end
@@ -17,7 +17,7 @@ module Leftovers
17
17
 
18
18
  def initialize(load_defaults: false)
19
19
  @configs = []
20
- @loaded_configs = Set.new
20
+ @loaded_configs = ::Set.new
21
21
  return unless load_defaults
22
22
 
23
23
  self << :ruby
@@ -28,7 +28,8 @@ module Leftovers
28
28
  end
29
29
 
30
30
  def <<(config)
31
- config = Leftovers::Config.new(config) unless config.is_a?(Leftovers::Config)
31
+ config = Config[config]
32
+
32
33
  return if @loaded_configs.include?(config.name)
33
34
 
34
35
  unmemoize
@@ -47,55 +48,53 @@ module Leftovers
47
48
  end
48
49
 
49
50
  def test_paths
50
- @test_paths ||= Leftovers::MatcherBuilders::Path.build(@configs.flat_map(&:test_paths))
51
+ @test_paths ||= MatcherBuilders::Path.build(@configs.flat_map(&:test_paths))
51
52
  end
52
53
 
53
54
  def precompilers
54
- @precompilers ||= Leftovers::Precompilers.build(@configs.flat_map(&:precompile))
55
+ @precompilers ||= Precompilers.build(@configs.flat_map(&:precompile))
55
56
  end
56
57
 
57
58
  def dynamic
58
- @dynamic ||= ::Leftovers::ProcessorBuilders::Each.build(@configs.map(&:dynamic))
59
+ @dynamic ||= ProcessorBuilders::Each.build(@configs.map(&:dynamic))
59
60
  end
60
61
 
61
62
  def keep
62
- @keep ||= ::Leftovers::MatcherBuilders::Or.build(@configs.map(&:keep))
63
+ @keep ||= MatcherBuilders::Or.build(@configs.map(&:keep))
63
64
  end
64
65
 
65
66
  def test_only
66
- @test_only ||= ::Leftovers::MatcherBuilders::Or.build(@configs.map(&:test_only))
67
+ @test_only ||= MatcherBuilders::Or.build(@configs.map(&:test_only))
67
68
  end
68
69
 
69
70
  private
70
71
 
71
72
  def project_config
72
- Leftovers::Config.new(:'.leftovers.yml', path: Leftovers.pwd + '.leftovers.yml')
73
+ Config.new(:'.leftovers.yml', path: ::Leftovers.pwd + '.leftovers.yml')
73
74
  end
74
75
 
75
76
  def project_todo
76
- Leftovers::Config.new(:'.leftovers_todo.yml', path: Leftovers.pwd + '.leftovers_todo.yml')
77
+ Config.new(:'.leftovers_todo.yml', path: ::Leftovers.pwd + '.leftovers_todo.yml')
77
78
  end
78
79
 
79
80
  def unmemoize
80
- MEMOIZED_IVARS.each do |ivar|
81
- remove_instance_variable(ivar) if instance_variable_get(ivar)
82
- end
81
+ MEMOIZED_IVARS.each { |ivar| remove_instance_variable(ivar) if instance_variable_get(ivar) }
83
82
  end
84
83
 
85
84
  def require_requires(config)
86
85
  config.requires.each do |req|
87
- if req.is_a?(Hash) && req[:quiet]
88
- Leftovers.try_require(req[:quiet])
86
+ if req.is_a?(::Hash) && req[:quiet]
87
+ ::Leftovers.try_require(req[:quiet])
89
88
  else
90
- Leftovers.try_require(req, message: "cannot require '#{req}' from #{config.name}.yml")
89
+ ::Leftovers.try_require(req, message: "cannot require '#{req}' from #{config.name}.yml")
91
90
  end
92
91
  end
93
92
  end
94
93
 
95
94
  def load_bundled_gem_config
96
- return unless Leftovers.try_require('bundler')
95
+ return unless ::Leftovers.try_require('bundler')
97
96
 
98
- Bundler.locked_gems.specs.each do |spec|
97
+ ::Bundler.locked_gems.specs.each do |spec|
99
98
  self << spec.name
100
99
  end
101
100
  end
@@ -24,7 +24,7 @@ module Leftovers
24
24
  # mostly copied from https://github.com/whitequark/parser/blob/master/lib/parser/base.rb
25
25
  # but with our builder
26
26
  def parser
27
- p = ::Parser::CurrentRuby.new(Leftovers::AST::Builder.new)
27
+ p = ::Parser::CurrentRuby.new(AST::Builder.new)
28
28
  p.diagnostics.all_errors_are_fatal = true
29
29
  p.diagnostics.ignore_warnings = true
30
30
 
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ class PrecompileError < Error
5
+ attr_reader :line, :column
6
+
7
+ def initialize(message, line: nil, column: nil, display_class: nil)
8
+ @line = line
9
+ @column = column
10
+ @display_class = display_class
11
+ super(message)
12
+ end
13
+
14
+ def warn(path:)
15
+ ::Leftovers.warn "#{display_class}: #{path}#{location} #{message}"
16
+ end
17
+
18
+ private
19
+
20
+ def display_class
21
+ @display_class || cause&.class || self.class
22
+ end
23
+
24
+ def location
25
+ return unless line
26
+ return ":#{line}" unless column
27
+
28
+ ":#{line}:#{column}"
29
+ end
30
+ end
31
+ end
@@ -5,10 +5,30 @@ require 'haml'
5
5
  module Leftovers
6
6
  module Precompilers
7
7
  module Haml
8
+ HAML_RUNTIME_ERROR_RE = %r{
9
+ \A
10
+ _buf\s=\s'' # preamble
11
+ [\s;]*
12
+ # https://github.com/haml/haml/blob/main/lib/haml/compiler.rb#L93
13
+ raise\s(?:::)?(?<class>.*)\.new\(%q\[(?<message>.*)\],\s(?<line>\d)+\)
14
+ [\s;]*
15
+ _buf # postamble
16
+ \z
17
+ }x.freeze
18
+
8
19
  def self.precompile(haml)
9
- ::Haml::Engine.new(haml).precompiled
10
- rescue ::Haml::SyntaxError => e
11
- raise Leftovers::PrecompileError.new(e.message, line: e.line)
20
+ out = ::Haml::TempleEngine.new.compile(haml)
21
+
22
+ if (e = out.match(HAML_RUNTIME_ERROR_RE))
23
+ raise PrecompileError.new(e[:message], line: e[:line], display_class: e[:class])
24
+ end
25
+
26
+ out
27
+ # :nocov:
28
+ # this is for haml < 6
29
+ rescue ::Haml::Error => e
30
+ raise PrecompileError.new(e.message, line: e.line)
31
+ # :nocov:
12
32
  end
13
33
  end
14
34
  end
@@ -14,7 +14,7 @@ module Leftovers
14
14
 
15
15
  def to_ruby_argument(value)
16
16
  ruby = value.inspect
17
- return ruby unless value.is_a?(Array)
17
+ return ruby unless value.is_a?(::Array)
18
18
 
19
19
  ruby.delete_prefix!('[')
20
20
  ruby.delete_suffix!(']')
@@ -15,11 +15,11 @@ module Leftovers
15
15
 
16
16
  begin
17
17
  @precompiler.precompile(content)
18
- rescue Leftovers::PrecompileError => e
18
+ rescue PrecompileError => e
19
19
  e.warn(path: file.relative_path)
20
20
  ''
21
- rescue StandardError => e
22
- Leftovers.warn "#{e.class}: #{file.relative_path} #{e.message}"
21
+ rescue ::StandardError => e
22
+ ::Leftovers.warn "#{e.class}: #{file.relative_path} #{e.message}"
23
23
  ''
24
24
  end
25
25
  end
@@ -8,7 +8,7 @@ module Leftovers
8
8
  def self.precompile(file)
9
9
  ::Slim::Engine.new(file: file).call(file)
10
10
  rescue ::Slim::Parser::SyntaxError => e
11
- raise Leftovers::PrecompileError.new(e.error, line: e.lineno, column: e.column)
11
+ raise PrecompileError.new(e.error, line: e.lineno, column: e.column)
12
12
  end
13
13
  end
14
14
  end
@@ -0,0 +1,62 @@
1
+ # frozen_string_literal: true
2
+
3
+ module Leftovers
4
+ module Precompilers
5
+ module YAML
6
+ class Builder < ::Psych::TreeBuilder
7
+ def initialize
8
+ @constants = []
9
+
10
+ super
11
+ end
12
+
13
+ def add_constant_for_tag(tag, value = nil)
14
+ match = %r{\A!ruby/[^:]*(?::(.*))?\z}.match(tag)
15
+ return unless match
16
+
17
+ @constants << (match[1] || value)
18
+ end
19
+
20
+ def start_mapping(_anchor, tag, *rest) # leftovers:keep
21
+ add_constant_for_tag(tag)
22
+ tag = nil
23
+
24
+ super
25
+ end
26
+
27
+ def start_sequence(_anchor, tag, *rest) # leftovers:keep
28
+ add_constant_for_tag(tag)
29
+ tag = nil
30
+
31
+ super
32
+ end
33
+
34
+ def scalar(value, _anchor, tag, *rest) # leftovers:keep
35
+ add_constant_for_tag(tag, value)
36
+ tag = nil
37
+
38
+ super
39
+ end
40
+
41
+ def to_ruby_file
42
+ <<~FILE
43
+ __leftovers_document(#{to_ruby_argument(root.to_ruby.first)})
44
+ #{@constants.join("\n")}
45
+ FILE
46
+ end
47
+
48
+ private
49
+
50
+ def to_ruby_argument(value)
51
+ ruby = value.inspect
52
+ return ruby unless value.is_a?(::Array)
53
+
54
+ ruby.delete_prefix!('[')
55
+ ruby.delete_suffix!(']')
56
+
57
+ ruby
58
+ end
59
+ end
60
+ end
61
+ end
62
+ end
@@ -5,70 +5,17 @@ require 'yaml'
5
5
  module Leftovers
6
6
  module Precompilers
7
7
  module YAML
8
- class Builder < ::Psych::TreeBuilder
9
- def initialize
10
- @constants = []
11
-
12
- super
13
- end
14
-
15
- def add_constant_for_tag(tag, value = nil)
16
- match = %r{\A!ruby/[^:]*(?::(.*))?\z}.match(tag)
17
- return unless match
18
-
19
- @constants << (match[1] || value)
20
- end
21
-
22
- def start_mapping(_anchor, tag, *rest) # leftovers:keep
23
- add_constant_for_tag(tag)
24
- tag = nil
25
-
26
- super
27
- end
28
-
29
- def start_sequence(_anchor, tag, *rest) # leftovers:keep
30
- add_constant_for_tag(tag)
31
- tag = nil
32
-
33
- super
34
- end
35
-
36
- def scalar(value, _anchor, tag, *rest) # leftovers:keep
37
- add_constant_for_tag(tag, value)
38
- tag = nil
39
-
40
- super
41
- end
42
-
43
- def to_ruby_file
44
- <<~FILE
45
- __leftovers_document(#{to_ruby_argument(root.to_ruby.first)})
46
- #{@constants.join("\n")}
47
- FILE
48
- end
49
-
50
- private
51
-
52
- def to_ruby_argument(value)
53
- ruby = value.inspect
54
- return ruby unless value.is_a?(Array)
55
-
56
- ruby.delete_prefix!('[')
57
- ruby.delete_suffix!(']')
58
-
59
- ruby
60
- end
61
- end
8
+ include Autoloader
62
9
 
63
10
  def self.precompile(yaml)
64
- builder = ::Leftovers::Precompilers::YAML::Builder.new
11
+ builder = Builder.new
65
12
  parser = ::Psych::Parser.new(builder)
66
13
  parser.parse(yaml)
67
14
 
68
15
  builder.to_ruby_file
69
16
  rescue ::Psych::SyntaxError => e
70
17
  message = [e.problem, e.context].compact.join(' ')
71
- raise ::Leftovers::PrecompileError.new(message, line: e.line, column: e.column)
18
+ raise PrecompileError.new(message, line: e.line, column: e.column)
72
19
  end
73
20
  end
74
21
  end
@@ -2,19 +2,14 @@
2
2
 
3
3
  module Leftovers
4
4
  module Precompilers
5
- autoload(:ERB, "#{__dir__}/precompilers/erb")
6
- autoload(:Haml, "#{__dir__}/precompilers/haml")
7
- autoload(:JSON, "#{__dir__}/precompilers/json")
8
- autoload(:Precompiler, "#{__dir__}/precompilers/precompiler")
9
- autoload(:Slim, "#{__dir__}/precompilers/slim")
10
- autoload(:YAML, "#{__dir__}/precompilers/yaml")
5
+ include Autoloader
11
6
 
12
7
  class << self
13
8
  def build(precompilers)
14
9
  precompilers.group_by { |p| build_precompiler(p[:format]) }.map do |format, precompiler|
15
10
  Precompiler.new(
16
11
  format,
17
- Leftovers::MatcherBuilders::Path.build(precompiler.flat_map { |p| p[:paths] })
12
+ MatcherBuilders::Path.build(precompiler.flat_map { |p| p[:paths] })
18
13
  )
19
14
  end
20
15
  end
@@ -23,14 +18,14 @@ module Leftovers
23
18
 
24
19
  def build_precompiler(format)
25
20
  case format
26
- when :erb then ::Leftovers::Precompilers::ERB
27
- when :haml then ::Leftovers::Precompilers::Haml
28
- when :json then ::Leftovers::Precompilers::JSON
29
- when :slim then ::Leftovers::Precompilers::Slim
30
- when :yaml then ::Leftovers::Precompilers::YAML
31
- when Hash then constantize_precompiler(format[:custom])
21
+ when :erb then ERB
22
+ when :haml then Haml
23
+ when :json then JSON
24
+ when :slim then Slim
25
+ when :yaml then YAML
26
+ when ::Hash then constantize_precompiler(format[:custom])
32
27
  # :nocov:
33
- else raise Leftovers::UnexpectedCase, "Unhandled value #{format}"
28
+ else raise UnexpectedCase, "Unhandled value #{format}"
34
29
  # :nocov:
35
30
  end
36
31
  end
@@ -38,9 +33,9 @@ module Leftovers
38
33
  def constantize_precompiler(precompiler)
39
34
  precompiler = "::#{precompiler}" unless precompiler.start_with?('::')
40
35
 
41
- Object.const_get(precompiler, false)
36
+ ::Object.const_get(precompiler, false)
42
37
  rescue ::NameError
43
- Leftovers.error <<~MESSAGE
38
+ ::Leftovers.error <<~MESSAGE
44
39
  Tried using #{precompiler}, but it wasn't available.
45
40
  add its path to `requires:` in your .leftovers.yml
46
41
  MESSAGE