defmastership 1.0.17 → 1.0.18

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 (63) hide show
  1. checksums.yaml +4 -4
  2. data/.gitlab-ci.yml +22 -10
  3. data/Gemfile +51 -1
  4. data/Rakefile +16 -61
  5. data/bin/defmastership +9 -6
  6. data/config/mutant.yml +23 -3
  7. data/defmastership.gemspec +0 -10
  8. data/features/definition_checksum.feature +31 -1
  9. data/features/export.feature +43 -1
  10. data/features/rename_included_files.feature +28 -0
  11. data/lib/defmastership/batch_modifier.rb +17 -12
  12. data/lib/defmastership/change_ref_modifier.rb +88 -6
  13. data/lib/defmastership/comment_filter.rb +1 -1
  14. data/lib/defmastership/constants.rb +5 -4
  15. data/lib/defmastership/csv_formatter.rb +16 -12
  16. data/lib/defmastership/csv_formatter_body.rb +18 -15
  17. data/lib/defmastership/csv_formatter_header.rb +1 -1
  18. data/lib/defmastership/definition.rb +58 -19
  19. data/lib/defmastership/document.rb +109 -74
  20. data/lib/defmastership/matching_line.rb +17 -0
  21. data/lib/defmastership/modifier.rb +42 -0
  22. data/lib/defmastership/modifier_factory.rb +12 -0
  23. data/lib/defmastership/parsing_state.rb +15 -9
  24. data/lib/defmastership/rename_included_files_modifier.rb +172 -5
  25. data/lib/defmastership/set_join_hack.rb +11 -0
  26. data/lib/defmastership/update_def_checksum_modifier.rb +8 -13
  27. data/lib/defmastership/update_def_modifier.rb +49 -0
  28. data/lib/defmastership/update_def_version_modifier.rb +56 -15
  29. data/lib/defmastership/version.rb +1 -1
  30. data/lib/defmastership.rb +1 -6
  31. data/spec/spec_helper.rb +3 -1
  32. data/spec/unit/def_mastership/batch_modifier_spec.rb +38 -36
  33. data/spec/unit/def_mastership/change_ref_modifier_spec.rb +196 -51
  34. data/spec/unit/def_mastership/csv_formatter_body_spec.rb +60 -31
  35. data/spec/unit/def_mastership/csv_formatter_header_spec.rb +1 -1
  36. data/spec/unit/def_mastership/csv_formatter_spec.rb +79 -87
  37. data/spec/unit/def_mastership/definition_parser_spec.rb +1 -1
  38. data/spec/unit/def_mastership/definition_spec.rb +16 -6
  39. data/spec/unit/def_mastership/document_spec.rb +81 -38
  40. data/spec/unit/def_mastership/matching_line_spec.rb +37 -0
  41. data/spec/unit/def_mastership/modifier_factory_spec.rb +37 -0
  42. data/spec/unit/def_mastership/modifier_spec.rb +83 -0
  43. data/spec/unit/def_mastership/parsing_state_spec.rb +1 -1
  44. data/spec/unit/def_mastership/rename_included_files_modifier_spec.rb +219 -47
  45. data/spec/unit/def_mastership/string_spec.rb +1 -1
  46. data/spec/unit/def_mastership/update_def_checksum_modifier_spec.rb +82 -50
  47. data/spec/unit/def_mastership/update_def_modifier_spec.rb +119 -0
  48. data/spec/unit/def_mastership/update_def_version_modifier_spec.rb +135 -56
  49. data/tasks/console.rake +8 -0
  50. data/tasks/package.task +9 -0
  51. data/tasks/smelling_code.rake +38 -0
  52. data/tasks/test.rake +45 -0
  53. metadata +16 -153
  54. data/lib/defmastership/change_ref_line_modifier.rb +0 -85
  55. data/lib/defmastership/line_modifier_base.rb +0 -29
  56. data/lib/defmastership/modifier_base.rb +0 -36
  57. data/lib/defmastership/rename_included_files_line_modifier.rb +0 -126
  58. data/lib/defmastership/update_def_checksum_line_modifier.rb +0 -38
  59. data/lib/defmastership/update_def_version_line_modifier.rb +0 -58
  60. data/spec/unit/def_mastership/change_ref_line_modifier_spec.rb +0 -250
  61. data/spec/unit/def_mastership/rename_included_files_line_modifier_spec.rb +0 -207
  62. data/spec/unit/def_mastership/update_def_checksum_line_modifier_spec.rb +0 -82
  63. data/spec/unit/def_mastership/update_def_version_line_modifier_spec.rb +0 -131
@@ -8,7 +8,7 @@ require('defmastership/csv_formatter_header')
8
8
  module DefMastership
9
9
  # to export a CSV file
10
10
  class CSVFormatter
11
- def initialize(doc, sep = ',')
11
+ def initialize(doc, sep)
12
12
  @doc = doc
13
13
  @sep = sep
14
14
  end
@@ -17,12 +17,16 @@ module DefMastership
17
17
  column_list = build_column_list
18
18
  CSV.open(output_file, 'w:ISO-8859-1', col_sep: @sep) do |csv|
19
19
  csv << header(column_list)
20
- @doc.definitions.each { |definition| csv << body(definition, column_list) }
20
+ export_definitions_in(csv, column_list)
21
21
  end
22
22
  end
23
23
 
24
24
  private
25
25
 
26
+ def export_definitions_in(csv, column_list)
27
+ @doc.definitions.each { |definition| csv << body(definition, column_list) }
28
+ end
29
+
26
30
  def header(column_list)
27
31
  header_formatter = CSVFormatterHeader.new(@doc)
28
32
  header_line = column_list.map { |part| header_formatter.public_send(part) }
@@ -30,20 +34,20 @@ module DefMastership
30
34
  end
31
35
 
32
36
  def body(definition, column_list)
33
- body_formatter = CSVFormatterBody.new(@doc)
34
- body_line = column_list.map { |part| body_formatter.public_send(part, definition) }
37
+ body_formatter = CSVFormatterBody.new(@doc, definition)
38
+ body_line = column_list.map { |part| body_formatter.public_send(part) }
35
39
  body_line.flatten
36
40
  end
37
41
 
38
42
  def build_column_list
39
- column_list = [:fixed]
40
- column_list += [:wrong_explicit_checksum] if @doc.wrong_explicit_checksum?
41
- column_list += [:explicit_version] if @doc.explicit_version?
42
- column_list += [:labels] unless @doc.labels.empty?
43
- column_list += [:eref] unless @doc.eref.empty?
44
- column_list += [:iref] if @doc.iref
45
- column_list += [:attributes] unless @doc.attributes.empty?
46
- column_list
43
+ [
44
+ [:wrong_explicit_checksum, @doc.wrong_explicit_checksum?],
45
+ [:explicit_version, @doc.explicit_version?],
46
+ [:labels, !@doc.labels.empty?],
47
+ [:eref, !@doc.eref.empty?],
48
+ [:iref, @doc.iref],
49
+ [:attributes, !@doc.attributes.empty?]
50
+ ].reduce([:fixed]) { |acc, elem| acc + (elem.fetch(1) ? [elem.first] : []) }
47
51
  end
48
52
  end
49
53
  end
@@ -3,41 +3,44 @@
3
3
 
4
4
  require('csv')
5
5
 
6
+ require('defmastership/set_join_hack')
7
+
6
8
  module DefMastership
7
9
  # format lines per definition
8
10
  class CSVFormatterBody
9
- def initialize(doc)
11
+ def initialize(doc, definition)
10
12
  @doc = doc
13
+ @definition = definition
11
14
  end
12
15
 
13
- def fixed(definition)
14
- [definition.type, definition.reference, definition.value, definition.sha256]
16
+ def fixed
17
+ [@definition.type, @definition.reference, @definition.value, @definition.sha256_short]
15
18
  end
16
19
 
17
- def wrong_explicit_checksum(definition)
18
- wrong_explicit_checksum = definition.wrong_explicit_checksum
20
+ def wrong_explicit_checksum
21
+ wrong_explicit_checksum = @definition.wrong_explicit_checksum
19
22
  wrong_explicit_checksum ? [wrong_explicit_checksum] : ['']
20
23
  end
21
24
 
22
- def explicit_version(definition)
23
- explicit_version = definition.explicit_version
25
+ def explicit_version
26
+ explicit_version = @definition.explicit_version
24
27
  explicit_version ? [explicit_version] : ['']
25
28
  end
26
29
 
27
- def labels(definition)
28
- [definition.labels.to_a.join("\n")]
30
+ def labels
31
+ [@definition.labels.join("\n")]
29
32
  end
30
33
 
31
- def eref(definition)
32
- @doc.eref.map { |key, _| definition.eref[key].join("\n") }
34
+ def eref
35
+ @doc.eref.map { |key,| @definition.eref.fetch(key, []).join("\n") }
33
36
  end
34
37
 
35
- def iref(definition)
36
- [definition.iref.join("\n")]
38
+ def iref
39
+ [@definition.iref.join("\n")]
37
40
  end
38
41
 
39
- def attributes(definition)
40
- @doc.attributes.map { |key, _| definition.attributes[key] }
42
+ def attributes
43
+ @doc.attributes.map { |key,| @definition.attributes.fetch(key, '') }
41
44
  end
42
45
  end
43
46
  end
@@ -27,7 +27,7 @@ module DefMastership
27
27
  end
28
28
 
29
29
  def eref
30
- @doc.eref.map { |_, ref| ref[:prefix] }
30
+ @doc.eref.map { |_, ref| ref.fetch(:prefix) }
31
31
  end
32
32
 
33
33
  def iref
@@ -3,51 +3,90 @@
3
3
 
4
4
  require 'digest'
5
5
 
6
+ # Contains the content of a DefMastership definition
6
7
  module DefMastership
8
+ BUILD_FROM_MATCH = {
9
+ type: ->(match) { match[:type] },
10
+ reference: ->(match) { match[:reference] },
11
+ lines: ->(_) { [] },
12
+ labels: lambda do |match|
13
+ labels = Set.new
14
+ labels.merge(match[:labels].split(/\s*,\s*/).to_set) if match[:labels]
15
+ labels
16
+ end,
17
+ eref: ->(_) { Hash.new([]) },
18
+ iref: ->(_) { [] },
19
+ attributes: ->(_) { {} },
20
+ explicit_checksum: ->(match) { match[:explicit_checksum] },
21
+ explicit_version: ->(match) { match[:explicit_version] }
22
+ }.freeze
23
+
24
+ private_constant :BUILD_FROM_MATCH
25
+
26
+ # Class to host data of Definition class
27
+ DefinitionData = Struct.new(
28
+ :type,
29
+ :reference,
30
+ :lines,
31
+ :labels,
32
+ :eref,
33
+ :iref,
34
+ :attributes,
35
+ :explicit_checksum,
36
+ :explicit_version
37
+ )
38
+
39
+ private_constant :DefinitionData
40
+
7
41
  # DefMastership definition: contains all data of a definition
8
42
  class Definition
9
- attr_reader :type, :reference, :lines, :labels, :eref, :iref, :attributes, :explicit_version
43
+ extend Forwardable
44
+ def_delegators :@data,
45
+ :type,
46
+ :reference,
47
+ :lines,
48
+ :labels,
49
+ :eref,
50
+ :iref,
51
+ :attributes,
52
+ :explicit_checksum,
53
+ :explicit_version
10
54
 
11
55
  def initialize(match)
12
- @type = match[:type]
13
- @reference = match[:reference]
14
- @lines = []
15
- @labels = Set.new
16
- @labels.merge(match[:labels].split(/\s*,\s*/).to_set) if match[:labels]
17
- @eref = Hash.new([])
18
- @iref = []
19
- @attributes = {}
20
- @explicit_checksum = match[:explicit_checksum]
21
- @explicit_version = match[:explicit_version]
56
+ @data = DefinitionData.new(
57
+ *BUILD_FROM_MATCH.transform_values { |lamb| lamb.call(match) }
58
+ .fetch_values(*DefinitionData.members)
59
+ )
22
60
  end
23
61
 
24
62
  def <<(new_line)
25
- @lines << new_line
63
+ lines << new_line
26
64
  self
27
65
  end
28
66
 
29
67
  def value
30
- @lines.join("\n")
68
+ lines.join("\n")
31
69
  end
32
70
 
33
- def sha256
34
- "~#{Digest::SHA2.new(256).hexdigest(value).chars.last(8).join}"
71
+ def sha256_short
72
+ "~#{Digest::SHA2.hexdigest(value).chars.last(8).join}"
35
73
  end
36
74
 
37
75
  def wrong_explicit_checksum
38
- @explicit_checksum if @explicit_checksum != sha256
76
+ explicit_checksum unless explicit_checksum.eql?(sha256_short)
39
77
  end
40
78
 
41
79
  def add_eref(refname, extrefs)
42
- @eref[refname] = extrefs.strip.split(/\s*,\s*/)
80
+ eref[refname] = extrefs.strip.split(/\s*,\s*/)
43
81
  end
44
82
 
45
83
  def add_iref(ref)
46
- @iref << ref
84
+ iref << ref
47
85
  end
48
86
 
49
87
  def set_attribute(key, value)
50
- @attributes[key] = value
88
+ attributes[key] = value
51
89
  end
52
90
  end
91
+ public_constant :Definition
53
92
  end
@@ -2,21 +2,87 @@
2
2
  # frozen_string_literal: true
3
3
 
4
4
  require('asciidoctor')
5
+ require('defmastership/matching_line')
5
6
 
7
+ # Contains the content of a DefMastership document: mainly definitions
6
8
  module DefMastership
7
- # Contains the content of a DefMastership document: mainly definitions
9
+ # Class to host data of Document class
10
+ DocumentData = Struct.new(
11
+ :definitions,
12
+ :labels,
13
+ :eref,
14
+ :iref,
15
+ :attributes,
16
+ :variables
17
+ )
18
+
19
+ private_constant :DocumentData
20
+
21
+ PARSER_ACTIONS = {
22
+ add_new_definition: lambda { |matching_line|
23
+ definition = Definition.new(matching_line.match)
24
+ labels.merge(definition.labels)
25
+ definitions << definition
26
+ matching_line.line
27
+ },
28
+ add_line: lambda { |matching_line|
29
+ line = matching_line.line
30
+ definitions.last << line
31
+ line
32
+ },
33
+ new_eref_setup: lambda { |matching_line|
34
+ refname = matching_line[:refname].to_sym
35
+ eref[refname] ||= {}
36
+ eref[refname][matching_line[:symb].to_sym] = matching_line[:value]
37
+ matching_line.line
38
+ },
39
+ new_eref_def: lambda { |matching_line|
40
+ definitions.last.add_eref(matching_line[:refname].to_sym, matching_line[:extrefs])
41
+ matching_line.line
42
+ },
43
+ new_iref_def: lambda { |matching_line|
44
+ self.iref = true
45
+ line = matching_line.line
46
+ line.scan(DMRegexp::IREF_DEF) do |_|
47
+ definitions.last.add_iref(Regexp.last_match[:intref])
48
+ end
49
+ line
50
+ },
51
+ new_attribute_conf: lambda { |matching_line|
52
+ attributes[matching_line[:attr].to_sym] = matching_line[:prefix]
53
+ matching_line.line
54
+ },
55
+ new_attribute_value: lambda { |matching_line|
56
+ definitions.last.set_attribute(matching_line[:attr].to_sym, matching_line[:value])
57
+ matching_line.line
58
+ },
59
+ new_variable_def: lambda { |matching_line|
60
+ variables[matching_line[:varname].to_sym] = matching_line[:value]
61
+ matching_line.line
62
+ },
63
+ new_variable_use: lambda { |matching_line|
64
+ line = matching_line.line
65
+ line.scan(DMRegexp::VARIABLE_USE) do |_|
66
+ varname = Regexp.last_match[:varname]
67
+ value = variables[varname.to_sym]
68
+
69
+ next unless value
70
+
71
+ line = line.gsub("{#{varname}}", value)
72
+ end
73
+ line
74
+ }
75
+ }.freeze
76
+
77
+ private_constant :PARSER_ACTIONS
8
78
 
9
79
  # Reflects document structure from a definition point of view
10
80
  class Document
11
- attr_reader :definitions, :labels, :eref, :iref, :attributes, :variables
81
+ extend Forwardable
82
+ def_delegators :@data, :definitions, :labels, :eref, :iref, :attributes, :variables
12
83
 
13
84
  def initialize
14
- @definitions = []
15
- @labels = Set.new
16
- @eref = {}
17
- @iref = false
18
- @attributes = {}
19
- @variables = {}
85
+ @data = DocumentData.new([], Set.new, {}, false, {}, {})
20
86
  @parsing_state = ParsingState.new
21
87
  @definition_parser = DefinitionParser.new(self)
22
88
  end
@@ -26,7 +92,7 @@ module DefMastership
26
92
  if @parsing_state.enabled?(line)
27
93
  apply_filters(line)
28
94
  else
29
- generate_event(:new_line, nil, line)
95
+ generate_event(:new_line, MatchingLine.new(nil, line))
30
96
  end
31
97
  end
32
98
  end
@@ -36,96 +102,65 @@ module DefMastership
36
102
  end
37
103
 
38
104
  def wrong_explicit_checksum?
39
- @definitions.reduce(false) do |res, definition|
40
- res || !definition.wrong_explicit_checksum.nil?
105
+ definitions.reduce(false) do |res, definition|
106
+ res || !!definition.wrong_explicit_checksum
41
107
  end
42
108
  end
43
109
 
44
110
  def explicit_version?
45
- @definitions.reduce(false) do |res, definition|
46
- res || !definition.explicit_version.nil?
111
+ definitions.reduce(false) do |res, definition|
112
+ res || !!definition.explicit_version
47
113
  end
48
114
  end
49
115
 
50
- def add_new_definition(match, line)
51
- definition = Definition.new(match)
52
- @labels.merge(definition.labels)
53
- @definitions << definition
54
- line
55
- end
56
-
57
- def ref_to_def(ref)
58
- @definitions.find { |definition| definition.reference == ref }
59
- end
116
+ def method_missing(method_name, *args)
117
+ action = PARSER_ACTIONS[method_name]
118
+ return instance_exec(*args, &action) if action
60
119
 
61
- def add_line(_match, line)
62
- @definitions.last << line
63
- line
120
+ super
64
121
  end
65
122
 
66
- def new_eref_setup(match, line)
67
- @eref[match[:refname].to_sym] ||= {}
68
- @eref[match[:refname].to_sym][match[:symb].to_sym] = match[:value]
69
- line
123
+ # This method smells of :reek:UtilityFunction
124
+ def respond_to_missing?(method_name, *_args)
125
+ PARSER_ACTIONS.key?(method_name)
70
126
  end
71
127
 
72
- def new_eref_def(match, line)
73
- @definitions.last.add_eref(match[:refname].to_sym, match[:extrefs])
74
- line
75
- end
76
-
77
- def new_iref_def(_match, line)
78
- @iref = true
79
- line.scan(DMRegexp::IREF_DEF) do |_|
80
- @definitions.last.add_iref(Regexp.last_match[:intref])
81
- end
82
- line
128
+ def ref_to_def(ref)
129
+ definitions.find { |definition| definition.reference == ref }
83
130
  end
84
131
 
85
- def new_attribute_conf(match, line)
86
- @attributes[match[:attr].to_sym] = match[:prefix]
87
- line
132
+ def iref=(value)
133
+ @data.iref = value
88
134
  end
89
135
 
90
- def new_attribute_value(match, line)
91
- @definitions.last.set_attribute(match[:attr].to_sym, match[:value])
92
- line
93
- end
136
+ private
94
137
 
95
- def new_variable_def(match, line)
96
- @variables[match[:varname].to_sym] = match[:value]
97
- line
138
+ def apply_filters(line)
139
+ Helper.reduce_filters_until_consumed(line) do |event, match, updated_line|
140
+ generate_event(event, MatchingLine.new(match, updated_line))
141
+ end
98
142
  end
99
143
 
100
- def new_variable_use(_match, line)
101
- line.scan(DMRegexp::VARIABLE_USE) do |_|
102
- varname = Regexp.last_match[:varname]
103
- next if @variables[varname.to_sym].nil?
104
-
105
- line = line.gsub("{#{varname}}", @variables[varname.to_sym])
144
+ def generate_event(event, matching_line)
145
+ if PARSER_ACTIONS.key?(event)
146
+ public_send(event, matching_line)
147
+ else
148
+ @definition_parser.public_send(event, matching_line)
106
149
  end
107
- line
108
150
  end
109
151
 
110
- private
111
-
112
- def apply_filters(line)
113
- FILTERS.each do |filter|
114
- next unless line.match(filter.regexp)
152
+ # Helper functions
153
+ module Helper
154
+ def self.reduce_filters_until_consumed(line)
155
+ FILTERS.reduce(line) do |res, filter|
156
+ next res unless line.match(filter.regexp)
115
157
 
116
- line = generate_event(filter.event, Regexp.last_match, line)
158
+ res = yield(filter.event, Regexp.last_match, res)
159
+ break if filter.consumed_line
117
160
 
118
- break if filter.consumed_line
119
- end
120
- end
121
-
122
- def generate_event(event, match, line)
123
- if respond_to?(event)
124
- line = public_send(event, match, line)
125
- else
126
- @definition_parser.public_send(event, match, line)
161
+ res
162
+ end
127
163
  end
128
- line
129
164
  end
130
165
  end
131
166
  end
@@ -0,0 +1,17 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # a composite class
6
+ MatchingLine =
7
+ Struct.new(:match, :line) do
8
+ def [](key)
9
+ value = match[key]
10
+ return value if value
11
+
12
+ super
13
+ end
14
+ end
15
+
16
+ public_constant :MatchingLine
17
+ end
@@ -0,0 +1,42 @@
1
+ # Copyright (c) 2020 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # define methods for line modifiers
6
+ module Modifier
7
+ attr_reader :config, :changes
8
+
9
+ def setup_modifier_module(config)
10
+ @config = self.class.default_config.merge(config)
11
+ @changes = []
12
+ end
13
+
14
+ def method_missing(method_name, *args)
15
+ config_method_name = config[method_name]
16
+ return config_method_name if config_method_name
17
+
18
+ super
19
+ end
20
+
21
+ def respond_to_missing?(method_name, *args)
22
+ config.key?(method_name) || super
23
+ end
24
+
25
+ def apply_to_all(texts, method)
26
+ texts.transform_values do |text|
27
+ apply_to_one(text, method)
28
+ end
29
+ end
30
+
31
+ def apply_to_one(text, method)
32
+ text.lines.map { |line| public_send(method, line) }
33
+ .join
34
+ end
35
+
36
+ def do_modifications(adoc_sources)
37
+ self.class.replacement_methods.reduce(adoc_sources) do |texts, method|
38
+ apply_to_all(texts, method)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,12 @@
1
+ # Copyright (c) 2023 Jerome Arbez-Gindre
2
+ # frozen_string_literal: true
3
+
4
+ module DefMastership
5
+ # build midifers from a piece of configuration
6
+ module ModifierFactory
7
+ def self.from_config(config)
8
+ class_name = "#{config.fetch(:type).split('_').map(&:capitalize).join}Modifier"
9
+ DefMastership.const_get(class_name).new(config.fetch(:config))
10
+ end
11
+ end
12
+ end
@@ -4,22 +4,28 @@
4
4
  module DefMastership
5
5
  # Allow to know if we need to parse the line or simply ignore it
6
6
  class ParsingState
7
+ # mutant:disable (for mutant, aatribute initialization is useless)
7
8
  def initialize
8
9
  @last_disabling_line = nil
9
10
  end
10
11
 
11
12
  def enabled?(line)
12
- return false if line.match(DMRegexp::SINGLE_LINE_COMMENT)
13
+ return false if line.match?(DMRegexp::SINGLE_LINE_COMMENT)
13
14
 
14
- line = line.dup.chomp
15
- if ['....', '----', '////'].include?(line)
16
- if @last_disabling_line == line
17
- @last_disabling_line = nil
18
- elsif @last_disabling_line.nil?
19
- @last_disabling_line = line
20
- end
15
+ line = line.chomp
16
+ possibly_invert_last_disabling_line(line) if ['....', '----', '////'].include?(line)
17
+
18
+ !@last_disabling_line
19
+ end
20
+
21
+ private
22
+
23
+ def possibly_invert_last_disabling_line(line)
24
+ if @last_disabling_line == line
25
+ @last_disabling_line = nil
26
+ elsif !@last_disabling_line
27
+ @last_disabling_line = line
21
28
  end
22
- @last_disabling_line.nil?
23
29
  end
24
30
  end
25
31
  end