haml_lint 0.40.0 → 0.51.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +4 -4
  2. data/bin/haml-lint +1 -1
  3. data/config/default.yml +9 -27
  4. data/config/forced_rubocop_config.yml +180 -0
  5. data/lib/haml_lint/adapter/haml_4.rb +20 -0
  6. data/lib/haml_lint/adapter/haml_5.rb +11 -0
  7. data/lib/haml_lint/adapter/haml_6.rb +59 -0
  8. data/lib/haml_lint/adapter.rb +2 -0
  9. data/lib/haml_lint/cli.rb +8 -3
  10. data/lib/haml_lint/configuration_loader.rb +49 -13
  11. data/lib/haml_lint/document.rb +89 -8
  12. data/lib/haml_lint/exceptions.rb +6 -0
  13. data/lib/haml_lint/extensions/haml_util_unescape_interpolation_tracking.rb +35 -0
  14. data/lib/haml_lint/file_finder.rb +2 -2
  15. data/lib/haml_lint/lint.rb +10 -1
  16. data/lib/haml_lint/linter/final_newline.rb +4 -3
  17. data/lib/haml_lint/linter/implicit_div.rb +1 -1
  18. data/lib/haml_lint/linter/indentation.rb +3 -3
  19. data/lib/haml_lint/linter/no_placeholders.rb +18 -0
  20. data/lib/haml_lint/linter/repeated_id.rb +2 -1
  21. data/lib/haml_lint/linter/rubocop.rb +353 -59
  22. data/lib/haml_lint/linter/space_before_script.rb +8 -10
  23. data/lib/haml_lint/linter/trailing_empty_lines.rb +22 -0
  24. data/lib/haml_lint/linter/unnecessary_string_output.rb +1 -1
  25. data/lib/haml_lint/linter/view_length.rb +1 -1
  26. data/lib/haml_lint/linter.rb +60 -10
  27. data/lib/haml_lint/linter_registry.rb +3 -5
  28. data/lib/haml_lint/logger.rb +2 -2
  29. data/lib/haml_lint/options.rb +26 -2
  30. data/lib/haml_lint/rake_task.rb +2 -2
  31. data/lib/haml_lint/reporter/hash_reporter.rb +1 -3
  32. data/lib/haml_lint/reporter/offense_count_reporter.rb +1 -1
  33. data/lib/haml_lint/reporter/utils.rb +33 -4
  34. data/lib/haml_lint/ruby_extraction/ad_hoc_chunk.rb +24 -0
  35. data/lib/haml_lint/ruby_extraction/base_chunk.rb +114 -0
  36. data/lib/haml_lint/ruby_extraction/chunk_extractor.rb +672 -0
  37. data/lib/haml_lint/ruby_extraction/coordinator.rb +181 -0
  38. data/lib/haml_lint/ruby_extraction/haml_comment_chunk.rb +34 -0
  39. data/lib/haml_lint/ruby_extraction/implicit_end_chunk.rb +17 -0
  40. data/lib/haml_lint/ruby_extraction/interpolation_chunk.rb +26 -0
  41. data/lib/haml_lint/ruby_extraction/non_ruby_filter_chunk.rb +32 -0
  42. data/lib/haml_lint/ruby_extraction/placeholder_marker_chunk.rb +40 -0
  43. data/lib/haml_lint/ruby_extraction/ruby_filter_chunk.rb +33 -0
  44. data/lib/haml_lint/ruby_extraction/ruby_source.rb +5 -0
  45. data/lib/haml_lint/ruby_extraction/script_chunk.rb +251 -0
  46. data/lib/haml_lint/ruby_extraction/tag_attributes_chunk.rb +63 -0
  47. data/lib/haml_lint/ruby_extraction/tag_script_chunk.rb +30 -0
  48. data/lib/haml_lint/ruby_parser.rb +11 -1
  49. data/lib/haml_lint/runner.rb +35 -3
  50. data/lib/haml_lint/spec/matchers/report_lint.rb +22 -7
  51. data/lib/haml_lint/spec/normalize_indent.rb +2 -2
  52. data/lib/haml_lint/spec/shared_linter_context.rb +9 -1
  53. data/lib/haml_lint/spec/shared_rubocop_autocorrect_context.rb +158 -0
  54. data/lib/haml_lint/spec.rb +1 -0
  55. data/lib/haml_lint/tree/filter_node.rb +10 -0
  56. data/lib/haml_lint/tree/node.rb +13 -4
  57. data/lib/haml_lint/tree/script_node.rb +7 -1
  58. data/lib/haml_lint/tree/silent_script_node.rb +16 -1
  59. data/lib/haml_lint/tree/tag_node.rb +5 -9
  60. data/lib/haml_lint/utils.rb +135 -5
  61. data/lib/haml_lint/version.rb +1 -1
  62. data/lib/haml_lint/version_comparer.rb +25 -0
  63. data/lib/haml_lint.rb +12 -0
  64. metadata +29 -15
  65. data/lib/haml_lint/ruby_extractor.rb +0 -222
@@ -0,0 +1,30 @@
1
+ # frozen_string_literal: true
2
+
3
+ module HamlLint::RubyExtraction
4
+ # Chunk for handling outputting scripts after a tag, such as `%div= spam`
5
+ class TagScriptChunk < BaseChunk
6
+ def transfer_correction_logic(coordinator, to_ruby_lines, haml_lines) # rubocop:disable Metrics/AbcSize
7
+ # TODO: add checks that we have commas at the end of each line except the last one
8
+
9
+ from_ruby_line = @ruby_lines.first
10
+ to_ruby_line = to_ruby_lines.first
11
+
12
+ to_line_indent = to_ruby_line.index(/\S/)
13
+
14
+ from_ruby_line = from_ruby_line.sub(coordinator.script_output_prefix, '').sub(/^\s+/, '')
15
+ to_ruby_line = to_ruby_line.sub(coordinator.script_output_prefix, '').sub(/^\s+/, '')
16
+
17
+ affected_start_index = haml_lines[@haml_line_index].rindex(from_ruby_line)
18
+
19
+ haml_lines[@haml_line_index][affected_start_index..-1] = to_ruby_line
20
+
21
+ indent_delta = affected_start_index - coordinator.script_output_prefix.size - to_line_indent
22
+
23
+ HamlLint::Utils.map_after_first!(to_ruby_lines) do |line|
24
+ HamlLint::Utils.indent(line, indent_delta)
25
+ end
26
+
27
+ haml_lines[(@haml_line_index + 1)..haml_end_line_index] = to_ruby_lines[1..]
28
+ end
29
+ end
30
+ end
@@ -2,7 +2,6 @@
2
2
 
3
3
  require 'rubocop'
4
4
  require 'rubocop/ast/builder'
5
- require 'parser/current'
6
5
 
7
6
  module HamlLint
8
7
  # Parser for the Ruby language.
@@ -14,10 +13,21 @@ module HamlLint
14
13
  class RubyParser
15
14
  # Creates a reusable parser.
16
15
  def initialize
16
+ require_parser
17
17
  @builder = ::RuboCop::AST::Builder.new
18
18
  @parser = ::Parser::CurrentRuby.new(@builder)
19
19
  end
20
20
 
21
+ # Require the current parser version while suppressing the
22
+ # compliancy warning for minor version differences.
23
+ def require_parser
24
+ prev = $VERBOSE
25
+ $VERBOSE = nil
26
+ require 'parser/current'
27
+ ensure
28
+ $VERBOSE = prev
29
+ end
30
+
21
31
  # Parse the given Ruby source into an abstract syntax tree.
22
32
  #
23
33
  # @param source [String] Ruby source code
@@ -24,6 +24,8 @@ module HamlLint
24
24
  @linter_selector = HamlLint::LinterSelector.new(config, options)
25
25
  @fail_fast = options.fetch(:fail_fast, false)
26
26
  @cache = {}
27
+ @autocorrect = options[:autocorrect]
28
+ @autocorrect_only = options[:autocorrect_only]
27
29
 
28
30
  report(options)
29
31
  end
@@ -88,9 +90,39 @@ module HamlLint
88
90
  e.line, e.to_s, :error)]
89
91
  end
90
92
 
91
- linter_selector.linters_for_file(file).map do |linter|
92
- linter.run(document)
93
- end.flatten
93
+ linters = linter_selector.linters_for_file(file)
94
+ lint_arrays = []
95
+
96
+ if @autocorrect
97
+ lint_arrays << autocorrect_document(document, linters)
98
+ end
99
+
100
+ unless @autocorrect_only
101
+ lint_arrays << linters.map do |linter|
102
+ linter.run(document)
103
+ end
104
+ end
105
+ lint_arrays.flatten
106
+ end
107
+
108
+ # Out of the provided linters, runs those that support autocorrect
109
+ # against the specified document.
110
+ # Updates the document and returns the lints that were corrected.
111
+ #
112
+ # @param document [HamlLint::Document]
113
+ # @param linter_selector [HamlLint::LinterSelector]
114
+ # @return [Array<HamlLint::Lint>]
115
+ def autocorrect_document(document, linters)
116
+ lint_arrays = []
117
+
118
+ autocorrecting_linters = linters.select(&:supports_autocorrect?)
119
+ lint_arrays << autocorrecting_linters.map do |linter|
120
+ linter.run(document, autocorrect: @autocorrect)
121
+ end
122
+
123
+ document.write_to_disk!
124
+
125
+ lint_arrays
94
126
  end
95
127
 
96
128
  # Returns the list of files that should be linted given the specified
@@ -10,9 +10,11 @@ module HamlLint
10
10
  expected_line = options[:line]
11
11
  expected_message = options[:message]
12
12
  expected_severity = options[:severity]
13
+ expected_corrected = options[:corrected]
13
14
 
14
15
  match do |linter|
15
- has_lints?(linter, expected_line, count, expected_message, expected_severity)
16
+ has_lints?(linter, expected_line, count, expected_message, expected_severity,
17
+ expected_corrected)
16
18
  end
17
19
 
18
20
  failure_message do |linter|
@@ -63,13 +65,15 @@ module HamlLint
63
65
  (expected_severity ? " with severity '#{expected_severity}'" : '')
64
66
  end
65
67
 
66
- def has_lints?(linter, expected_line, count, expected_message, expected_severity)
68
+ def has_lints?(linter, expected_line, count, expected_message, expected_severity, # rubocop:disable Metrics/ParameterLists
69
+ expected_corrected)
67
70
  if expected_line
68
71
  has_expected_line_lints?(linter,
69
72
  expected_line,
70
73
  count,
71
74
  expected_message,
72
- expected_severity)
75
+ expected_severity,
76
+ expected_corrected)
73
77
  elsif count
74
78
  linter.lints.count == count
75
79
  elsif expected_message
@@ -79,17 +83,20 @@ module HamlLint
79
83
  end
80
84
  end
81
85
 
82
- def has_expected_line_lints?(linter,
86
+ def has_expected_line_lints?(linter, # rubocop:disable Metrics/ParameterLists
83
87
  expected_line,
84
88
  count,
85
89
  expected_message,
86
- expected_severity)
90
+ expected_severity,
91
+ expected_corrected)
87
92
  if count
88
93
  multiple_lints_match_line?(linter, expected_line, count)
89
94
  elsif expected_message
90
95
  lint_on_line_matches_message?(linter, expected_line, expected_message)
91
96
  elsif expected_severity
92
97
  lint_on_line_matches_severity?(linter, expected_line, expected_severity)
98
+ elsif !expected_corrected.nil?
99
+ lint_on_line_matches_corrected?(linter, expected_line, expected_corrected)
93
100
  else
94
101
  lint_lines(linter).include?(expected_line)
95
102
  end
@@ -101,9 +108,10 @@ module HamlLint
101
108
  end
102
109
 
103
110
  def lint_on_line_matches_message?(linter, expected_line, expected_message)
111
+ # Using === to support regex to match anywhere in the string
104
112
  linter
105
113
  .lints
106
- .any? { |lint| lint.line == expected_line && lint.message == expected_message }
114
+ .any? { |lint| lint.line == expected_line && expected_message === lint.message } # rubocop:disable Style/CaseEquality
107
115
  end
108
116
 
109
117
  def lint_on_line_matches_severity?(linter, expected_line, expected_severity)
@@ -112,8 +120,15 @@ module HamlLint
112
120
  .any? { |lint| lint.line == expected_line && lint.severity == expected_severity }
113
121
  end
114
122
 
123
+ def lint_on_line_matches_corrected?(linter, expected_line, expected_corrected)
124
+ linter
125
+ .lints
126
+ .any? { |lint| lint.line == expected_line && lint.corrected == expected_corrected }
127
+ end
128
+
115
129
  def lint_messages_match?(linter, expected_message)
116
- lint_messages(linter).all? { |message| message == expected_message }
130
+ # Using === to support regex to match anywhere in the string
131
+ lint_messages(linter).all? { |message| expected_message === message } # rubocop:disable Style/CaseEquality
117
132
  end
118
133
 
119
134
  def lint_lines(linter)
@@ -6,8 +6,8 @@ module HamlLint
6
6
  # for writing code without having the leading indentation count.
7
7
  module IndentNormalizer
8
8
  def normalize_indent(code)
9
- leading_indent = code[/^(\s*)/, 1]
10
- code.lstrip.gsub(/\n#{leading_indent}/, "\n")
9
+ leading_indent = code[/([ \t]*)/, 1]
10
+ code.gsub(/^#{leading_indent}/, '')
11
11
  end
12
12
  end
13
13
  end
@@ -14,13 +14,21 @@ module HamlLint
14
14
  }
15
15
  end
16
16
 
17
+ let(:autocorrect) { nil }
18
+
17
19
  let(:config) { options[:config].for_linter(described_class) }
18
20
 
19
21
  let(:document) { HamlLint::Document.new(normalize_indent(haml), options) }
20
22
 
23
+ # :run_or_raise, :run, or nil to not auto-call something
24
+ let(:run_method_to_use) { :run_or_raise }
25
+
21
26
  subject { described_class.new(config) }
22
27
 
23
- before { subject.run(document) }
28
+ before do
29
+ next unless run_method_to_use
30
+ subject.send(run_method_to_use, document, autocorrect: autocorrect)
31
+ end
24
32
  end
25
33
  end
26
34
  end
@@ -0,0 +1,158 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Makes writing tests for linters a lot DRYer by taking any currently `haml`
4
+ # variable defined via `let` and normalizing it and running the linter against
5
+ # it, allowing specs to simply specify whether a lint was reported.
6
+
7
+ module HamlLint
8
+ module Spec
9
+ module SharedRubocopAutocorrectContext
10
+ RSpec.shared_context 'rubocop_autocorrect' do
11
+ # Setting ENV['STUB_RUBOCOP'] to 1 or true makes rubocop tests faster by not involving rubocop.
12
+ # It is sometimes automatically activated for tests which need a different Rubocop version
13
+ stub_rubocop_env_result = %w[1 true].include?(ENV['STUB_RUBOCOP'])
14
+
15
+ let(:stub_rubocop?) do |example|
16
+ # Tries to match `{% rubocop_version <= '1.2' %}`, extracting the operator and the "number"
17
+ rubocop_version_regex = /\{%\s*rubocop_version\s*([^\w\s]+?)\s*['"]?(\d+(\.\d+)*)['"]?\s*%\}/
18
+ requirements = example.metadata[:full_description].scan(rubocop_version_regex)
19
+
20
+ # This can be used by the requirements in eval
21
+ rubocop_version = HamlLint::VersionComparer.for_rubocop
22
+
23
+ accepted = requirements.all? do |(operator, version)|
24
+ rubocop_version.send(operator, version)
25
+ end
26
+
27
+ next true unless accepted
28
+
29
+ # Doing this last so that exceptions in the requirements always fail
30
+ next true if stub_rubocop_env_result
31
+
32
+ false
33
+ end
34
+
35
+ let(:supported_haml?) do |example|
36
+ # Tries to match `{% haml_version >= '5' %}`, extracting the operator and the "number"
37
+ haml_version_regex = /\{%\s*haml_version\s*([^\w\s]+?)\s*['"]?(\d+(\.\d+)*)['"]?\s*%\}/
38
+ requirements = example.metadata[:full_description].scan(haml_version_regex)
39
+
40
+ # This can be used by the requirements in eval
41
+ haml_version = HamlLint::VersionComparer.for_haml
42
+
43
+ requirements.all? do |(operator, version)|
44
+ haml_version.send(operator, version)
45
+ end
46
+ end
47
+
48
+ before do
49
+ if stub_rubocop?
50
+ skip if end_ruby.include?('SKIP')
51
+ subject.stub(:process_ruby_source).and_return(end_ruby)
52
+ end
53
+ subject.stub(:transfer_corrections?).and_return(true)
54
+ end
55
+
56
+ include_context 'linter'
57
+ # The goal is not to test rubocop the gem, so no need to test the details using both
58
+ # :safe and :all
59
+ let(:autocorrect) { :all }
60
+
61
+ # We want want to do error handling ourself
62
+ let(:run_method_to_use) { nil }
63
+
64
+ let(:steps_parts) do
65
+ parts = steps_string.split(/^[ \t]*---[ \t]*\n/, -1)
66
+ raise "Expected 4 steps, got: #{parts.size}" if parts.size != 4
67
+ parts
68
+ end
69
+
70
+ let(:start_haml) { steps_parts[0] }
71
+
72
+ let(:start_ruby) do
73
+ lines = steps_parts[1].split("\n", -1)
74
+ current_matching_line = 1
75
+ @source_map = {}
76
+ lines.each.with_index do |line, i|
77
+ next unless line =~ /\S/
78
+ mo = line.match(/^(.*?)\$?\s*\$\$(\d+)$/)
79
+ if mo
80
+ lines[i] = mo[1]
81
+ current_matching_line = Integer(mo[2])
82
+ end
83
+ @source_map[i + 1] = current_matching_line
84
+ end
85
+ lines.join("\n")
86
+ end
87
+
88
+ let(:source_map) do
89
+ start_ruby
90
+ @source_map
91
+ end
92
+
93
+ let(:end_ruby) { steps_parts[2] }
94
+
95
+ let(:end_haml) { steps_parts[3] }
96
+
97
+ # Used by the 'linter' context
98
+ let(:haml) { start_haml }
99
+
100
+ # steps_string is string of multiple lines describing the steps that
101
+ # the code will take:
102
+ # 1) input haml
103
+ # 2) extracted ruby
104
+ # 3) the corrected ruby
105
+ # 4) the corrected haml
106
+ # Each steps is delimited by a line with ---
107
+ def follows_steps # rubocop:disable Metrics
108
+ skip unless supported_haml?
109
+
110
+ begin
111
+ subject.run_or_raise(document, autocorrect: autocorrect)
112
+ rescue StandardError => e
113
+ exception_while_running = e
114
+ end
115
+
116
+ syntax_lints = subject.lints.select { |lint| lint.message =~ %r{Lint/Syntax} }
117
+
118
+ if start_ruby.strip != 'SKIP' && subject.last_extracted_source
119
+ matcher = eq(start_ruby)
120
+ subject.last_extracted_source.source.should(
121
+ matcher,
122
+ -> { "Extracted Ruby is different from expected. #{matcher.failure_message}\n#{format_lints}" }
123
+ )
124
+ end
125
+
126
+ syntax_lints.should(be_empty, "Generated Ruby has Syntax Lints:\n#{format_lints(syntax_lints)}")
127
+
128
+ if end_ruby.strip != 'SKIP' && subject.last_new_ruby_source
129
+ matcher = eq(end_ruby)
130
+ subject.last_new_ruby_source.should(
131
+ matcher,
132
+ -> { "Ruby generated by RuboCop is different from expected. #{matcher.failure_message}\n#{format_lints}" }
133
+ )
134
+ end
135
+
136
+ raise exception_while_running if exception_while_running
137
+
138
+ matcher = eq(end_haml)
139
+ document.source.should(
140
+ matcher,
141
+ -> { "Final HAML is different from expected. #{matcher.failure_message}\n#{format_lints}" }
142
+ )
143
+
144
+ if subject.last_extracted_source && start_ruby.strip != 'SKIP'
145
+ subject.last_extracted_source.source_map.should == source_map
146
+ end
147
+
148
+ haml_different = start_haml != end_haml
149
+ document.source_was_changed.should == haml_different
150
+ end
151
+
152
+ def format_lints(lints = subject.lints)
153
+ lints.map { |lint| "#{lint.line}:#{lint.message}" }.join("\n")
154
+ end
155
+ end
156
+ end
157
+ end
158
+ end
@@ -2,4 +2,5 @@
2
2
 
3
3
  require 'haml_lint/spec/normalize_indent'
4
4
  require 'haml_lint/spec/shared_linter_context'
5
+ require 'haml_lint/spec/shared_rubocop_autocorrect_context'
5
6
  require 'haml_lint/spec/matchers/report_lint'
@@ -7,5 +7,15 @@ module HamlLint::Tree
7
7
  def filter_type
8
8
  @value[:name]
9
9
  end
10
+
11
+ def text
12
+ # Seems HAML strips the starting blank lines... without them, line numbers become offset,
13
+ # breaking the source_map and auto-correct
14
+
15
+ nb_blank_lines = 0
16
+ nb_blank_lines += 1 while @document.source_lines[line + nb_blank_lines]&.empty?
17
+
18
+ "#{"\n" * nb_blank_lines}#{super}"
19
+ end
10
20
  end
11
21
  end
@@ -104,8 +104,13 @@ module HamlLint::Tree
104
104
  def line_numbers
105
105
  return (line..line) unless @value && text
106
106
 
107
- end_line = line + lines.count
108
- end_line = nontrivial_end_line if line == end_line && children.empty?
107
+ end_line = if !lines.empty?
108
+ line + lines.count - 1
109
+ elsif children.empty?
110
+ nontrivial_end_line
111
+ else
112
+ line
113
+ end
109
114
 
110
115
  (line..end_line)
111
116
  end
@@ -155,6 +160,10 @@ module HamlLint::Tree
155
160
  @value[:text].to_s
156
161
  end
157
162
 
163
+ def keyword
164
+ @value[:keyword]
165
+ end
166
+
158
167
  private
159
168
 
160
169
  # Discovers the end line of the node when there are no lines.
@@ -164,7 +173,7 @@ module HamlLint::Tree
164
173
  if successor
165
174
  successor.line_numbers.begin - 1
166
175
  else
167
- @document.source_lines.count
176
+ @document.last_non_empty_line
168
177
  end
169
178
  end
170
179
 
@@ -212,7 +221,7 @@ module HamlLint::Tree
212
221
  # @param node [HamlLint::Tree::Node]
213
222
  # @return [Array<HamlLint::Tree::Node>]
214
223
  def subsequents(node)
215
- siblings[(position(node) + 1)..-1]
224
+ siblings[(position(node) + 1)..]
216
225
  end
217
226
 
218
227
  private
@@ -9,7 +9,13 @@ module HamlLint::Tree
9
9
  #
10
10
  # @return [ParsedRuby] syntax tree in the form returned by Parser gem
11
11
  def parsed_script
12
- HamlLint::ParsedRuby.new(HamlLint::RubyParser.new.parse(script))
12
+ statement =
13
+ if children.empty?
14
+ script
15
+ else
16
+ "#{script}#{@value[:keyword] == 'case' ? ';when 0;end' : ';end'}"
17
+ end
18
+ HamlLint::ParsedRuby.new(HamlLint::RubyParser.new.parse(statement))
13
19
  end
14
20
 
15
21
  # Returns the source for the script following the `-` marker.
@@ -8,7 +8,22 @@ module HamlLint::Tree
8
8
  #
9
9
  # @return [ParsedRuby] syntax tree in the form returned by Parser gem
10
10
  def parsed_script
11
- HamlLint::ParsedRuby.new(HamlLint::RubyParser.new.parse(script))
11
+ statement =
12
+ case keyword = @value[:keyword]
13
+ when 'else', 'elsif'
14
+ 'if 0;' + script + ';end'
15
+ when 'when'
16
+ 'case;' + script + ';end'
17
+ when 'rescue', 'ensure'
18
+ 'begin;' + script + ';end'
19
+ else
20
+ if children.empty?
21
+ script
22
+ else
23
+ "#{script}#{keyword == 'case' ? ';when 0;end' : ';end'}"
24
+ end
25
+ end
26
+ HamlLint::ParsedRuby.new(HamlLint::RubyParser.new.parse(statement))
12
27
  end
13
28
 
14
29
  # Returns the source for the script following the `-` marker.
@@ -2,7 +2,7 @@
2
2
 
3
3
  module HamlLint::Tree
4
4
  # Represents a tag node in a HAML document.
5
- class TagNode < Node # rubocop:disable Metrics/ClassLength
5
+ class TagNode < Node
6
6
  # Computed set of attribute hashes code.
7
7
  #
8
8
  # This is a combination of all dynamically calculated attributes from the
@@ -49,9 +49,7 @@ module HamlLint::Tree
49
49
  # dot removed
50
50
  def static_classes
51
51
  @static_classes ||=
52
- begin
53
- static_attributes_source.scan(/\.([-:\w]+)/)
54
- end
52
+ static_attributes_source.scan(/\.([-:\w]+)/)
55
53
  end
56
54
 
57
55
  # List of ids statically defined for this tag.
@@ -63,9 +61,7 @@ module HamlLint::Tree
63
61
  # removed
64
62
  def static_ids
65
63
  @static_ids ||=
66
- begin
67
- static_attributes_source.scan(/#([-:\w]+)/)
68
- end
64
+ static_attributes_source.scan(/#([-:\w]+)/)
69
65
  end
70
66
 
71
67
  # Static element attributes defined after the tag name.
@@ -101,7 +97,7 @@ module HamlLint::Tree
101
97
  @attributes_source ||=
102
98
  begin
103
99
  _explicit_tag, static_attrs, rest =
104
- source_code.scan(/\A\s*(%[-:\w]+)?([-:\w\.\#]*)(.*)/m)[0]
100
+ source_code.scan(/\A\s*(%[-:\w]+)?([-:\w.\#]*)(.*)/m)[0]
105
101
 
106
102
  attr_types = {
107
103
  '{' => [:hash, %w[{ }]],
@@ -220,7 +216,7 @@ module HamlLint::Tree
220
216
  #
221
217
  # @return [true,false]
222
218
  def remove_outer_whitespace?
223
- !!@value[:nuke_outer_whitespace] # rubocop:disable Style/DoubleNegation
219
+ !!@value[:nuke_outer_whitespace]
224
220
  end
225
221
 
226
222
  # Returns the script source that will be evaluated to produce this tag's