Class: ThemeCheck::Offense

Inherits:
Object
  • Object
show all
Includes:
PositionHelper
Defined in:
lib/theme_check/offense.rb

Constant Summary collapse

MAX_SOURCE_EXCERPT_SIZE =
120

Instance Attribute Summary collapse

Instance Method Summary collapse

Methods included from PositionHelper

#bounded, #from_index_to_row_column, #from_row_column_to_index

Constructor Details

#initialize(check:, message: nil, template: nil, node: nil, markup: nil, line_number: nil, node_markup_offset: 0, correction: nil) ⇒ Offense

Returns a new instance of Offense.

Raises:

  • (ArgumentError)


10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
# File 'lib/theme_check/offense.rb', line 10

def initialize(
  check:, # instance of a ThemeCheck::Check
  message: nil, # error message for the offense
  template: nil, # Template
  node: nil, # Node or HtmlNode
  markup: nil, # string
  line_number: nil, # line number of the error (1-indexed)
  # node_markup_offset is the index inside node.markup to start
  # looking for markup :mindblow:.
  # This is so we can accurately highlight node substrings.
  # e.g. if we have the following scenario in which we
  # want to highlight the middle comma
  #   * node.markup == "replace ',',', '"
  #   * markup == ","
  # Then we need some way of telling our Position class to start
  # looking for the second comma. This is done with node_markup_offset.
  # More context can be found in #376.
  node_markup_offset: 0,
  correction: nil # block
)
  @check = check
  @correction = correction

  if message
    @message = message
  elsif defined?(check.class::MESSAGE)
    @message = check.class::MESSAGE
  else
    raise ArgumentError, "message required"
  end

  @node = node
  @template = nil
  if node
    @template = node.template
  elsif template
    @template = template
  end

  @markup = if markup
    markup
  else
    node&.markup
  end

  raise ArgumentError, "Offense markup cannot be an empty string" if @markup.is_a?(String) && @markup.empty?

  @line_number = if line_number
    line_number
  elsif @node
    @node.line_number
  end

  @position = Position.new(
    @markup,
    @template&.source,
    line_number_1_indexed: @line_number,
    node_markup_offset: node_markup_offset,
    node_markup: node&.markup
  )
end

Instance Attribute Details

#checkObject (readonly)

Returns the value of attribute check.



8
9
10
# File 'lib/theme_check/offense.rb', line 8

def check
  @check
end

#correctionObject (readonly)

Returns the value of attribute correction.



8
9
10
# File 'lib/theme_check/offense.rb', line 8

def correction
  @correction
end

#line_numberObject (readonly)

Returns the value of attribute line_number.



8
9
10
# File 'lib/theme_check/offense.rb', line 8

def line_number
  @line_number
end

#markupObject (readonly)

Returns the value of attribute markup.



8
9
10
# File 'lib/theme_check/offense.rb', line 8

def markup
  @markup
end

#messageObject (readonly)

Returns the value of attribute message.



8
9
10
# File 'lib/theme_check/offense.rb', line 8

def message
  @message
end

#nodeObject (readonly)

Returns the value of attribute node.



8
9
10
# File 'lib/theme_check/offense.rb', line 8

def node
  @node
end

#templateObject (readonly)

Returns the value of attribute template.



8
9
10
# File 'lib/theme_check/offense.rb', line 8

def template
  @template
end

Instance Method Details

#==(other) ⇒ Object Also known as: eql?



157
158
159
160
161
162
163
164
# File 'lib/theme_check/offense.rb', line 157

def ==(other)
  other.is_a?(Offense) &&
    code_name == other.code_name &&
    message == other.message &&
    location == other.location &&
    start_index == other.start_index &&
    end_index == other.end_index
end

#check_nameObject



120
121
122
# File 'lib/theme_check/offense.rb', line 120

def check_name
  StringHelpers.demodulize(check.class.name)
end

#code_nameObject



108
109
110
# File 'lib/theme_check/offense.rb', line 108

def code_name
  check.code_name
end

#correctObject



142
143
144
145
146
147
# File 'lib/theme_check/offense.rb', line 142

def correct
  if correctable?
    corrector = Corrector.new(template: template)
    correction.call(corrector)
  end
end

#correctable?Boolean

Returns:

  • (Boolean)


138
139
140
# File 'lib/theme_check/offense.rb', line 138

def correctable?
  !!correction
end

#docObject



124
125
126
# File 'lib/theme_check/offense.rb', line 124

def doc
  check.doc
end

#end_columnObject



104
105
106
# File 'lib/theme_check/offense.rb', line 104

def end_column
  @position.end_column
end

#end_indexObject



96
97
98
# File 'lib/theme_check/offense.rb', line 96

def end_index
  @position.end_index
end

#end_lineObject



100
101
102
# File 'lib/theme_check/offense.rb', line 100

def end_line
  @position.end_row
end

#locationObject



128
129
130
131
# File 'lib/theme_check/offense.rb', line 128

def location
  tokens = [template&.relative_path, line_number].compact
  tokens.join(":") if tokens.any?
end

#location_rangeObject



133
134
135
136
# File 'lib/theme_check/offense.rb', line 133

def location_range
  tokens = [template&.relative_path, start_index, end_index].compact
  tokens.join(":") if tokens.any?
end

#markup_start_in_excerptObject



112
113
114
# File 'lib/theme_check/offense.rb', line 112

def markup_start_in_excerpt
  source_excerpt.index(markup) if markup
end

#severityObject



116
117
118
# File 'lib/theme_check/offense.rb', line 116

def severity
  check.severity
end

#single_file?Boolean

Returns:

  • (Boolean)


153
154
155
# File 'lib/theme_check/offense.rb', line 153

def single_file?
  check.single_file?
end

#source_excerptObject



72
73
74
75
76
77
78
79
80
81
82
# File 'lib/theme_check/offense.rb', line 72

def source_excerpt
  return unless line_number
  @source_excerpt ||= begin
    excerpt = template.source_excerpt(line_number)
    if excerpt.size > MAX_SOURCE_EXCERPT_SIZE
      excerpt[0, MAX_SOURCE_EXCERPT_SIZE - 3] + '...'
    else
      excerpt
    end
  end
end

#start_columnObject



92
93
94
# File 'lib/theme_check/offense.rb', line 92

def start_column
  @position.start_column
end

#start_indexObject



84
85
86
# File 'lib/theme_check/offense.rb', line 84

def start_index
  @position.start_index
end

#start_lineObject



88
89
90
# File 'lib/theme_check/offense.rb', line 88

def start_line
  @position.start_row
end

#to_hObject



183
184
185
186
187
188
189
190
191
192
193
194
# File 'lib/theme_check/offense.rb', line 183

def to_h
  {
    check: check.code_name,
    path: template&.relative_path,
    severity: check.severity_value,
    start_line: start_line,
    start_column: start_column,
    end_line: end_line,
    end_column: end_column,
    message: message,
  }
end

#to_sObject



167
168
169
170
171
172
173
# File 'lib/theme_check/offense.rb', line 167

def to_s
  if template
    "#{message} at #{location}"
  else
    message
  end
end

#to_s_rangeObject



175
176
177
178
179
180
181
# File 'lib/theme_check/offense.rb', line 175

def to_s_range
  if template
    "#{message} at #{location_range}"
  else
    message
  end
end

#whole_theme?Boolean

Returns:

  • (Boolean)


149
150
151
# File 'lib/theme_check/offense.rb', line 149

def whole_theme?
  check.whole_theme?
end