11#
22# linter.py
3- # Linter for SublimeLinter3 , a code checking framework for Sublime Text 3
3+ # Linter for SublimeLinter , a code checking framework for Sublime Text
44#
55# Written by Aparajita Fishman
6- # Copyright (c) 2015-2016 The SublimeLinter Community
6+ # Copyright (c) 2015-2025 The SublimeLinter Community
77# Copyright (c) 2013-2014 Aparajita Fishman
88#
99# License: MIT
@@ -23,56 +23,63 @@ class Ruby(RubyLinter):
2323 }
2424
2525 cmd = 'ruby -wc'
26- regex = (
27- r'^(?P<file>.+?):(?P<line>\d+): (?:(?P<error>.*?error)|(?P<warning>warning))[,:] (?P<message>[^\r\n]+)\r?\n'
28- r'(?:^[^\r\n]+\r?\n^(?P<col>.*?)\^)?'
29- )
30- multiline = True
31- comment_re = r'\s*#'
26+ regex = r"""
27+ (?xm)
28+ ^(?:(?P<exe>.*:\s)?)? # optional "C:/ruby...:" prefix
29+ (?P<filename>.+?):(?P<line>\d+): # file and line
30+ (?:\s?(?:(?P<error>.*?error)s?|(?P<warning>warning))) # "syntax error" or warning
31+ [,:]?\s(?P<message>[^\n]+) # headline message
32+ (?:\n # optional multiline block
33+ (?:
34+ (?:\s*\d+\s*\|[^\n]*\n)* # optional leading context lines
35+ >\s*(?P<culprit_line>\d+)\s*\|[^\n]*\n # culprit line
36+ \s*\|\s(?P<col>.*?)\^\s # caret line with message
37+ (?P<culprit_message>[^\n]*) # rest of caret line (error text)
38+ )?
39+ )?
40+ """
3241 on_stderr = None
3342
3443 def split_match (self , match ):
3544 """
36- Return the components of the match.
37-
38- We override this because unrelated library files can throw errors,
39- and we only want errors from the linted file.
45+ Return the error as matched by the regex.
4046
47+ We override this for a better error message.
4148 """
4249
43- if match :
44- if match . group ( 'file' ) != '-' :
45- match = None
46-
47- match , line , col , error , warning , message , _ = super (). split_match ( match )
48- near = self . search_token ( message )
50+ error = super (). split_match ( match )
51+ if culprit_message := error . get ( "culprit_message" , None ) :
52+ error [ "message" ] = culprit_message
53+ error [ "near" ] = self . search_token ( error . message )
54+ if error . error :
55+ error [ "error" ] = error . error . replace ( " " , "-" )
4956
50- return match , line , col , error , warning , message , near
57+ return error
5158
5259 def search_token (self , message ):
5360 """Search text token to be highlighted."""
5461
5562 # First search for variable name enclosed in quotes
56- m = re .search ("(?<=`).*(?=')" , message )
63+ m = re .search (r "(?<=`).*(?=')" , message )
5764
5865 # Then search for variable name following a dash
5966 if m is None :
60- m = re .search ('(?<= - )\S+' , message )
67+ m = re .search (r '(?<= - )\S+' , message )
6168
6269 # Then search for mismatched indentation
6370 if m is None :
64- m = re .search ("(?<=mismatched indentations at ')end" , message )
71+ m = re .search (r "(?<=mismatched indentations at ')end" , message )
6572
6673 # Then search for equal operator in conditional
6774 if m is None :
68- m = re .search ('(?<=found )=(?= in conditional)' , message )
75+ m = re .search (r '(?<=found )=(?= in conditional)' , message )
6976
7077 # Then search for use of operator in void context
7178 if m is None :
72- m = re .search ('\S+(?= in void context)' , message )
79+ m = re .search (r '\S+(?= in void context)' , message )
7380
7481 # Then search for END in method
7582 if m is None :
76- m = re .search ('END(?= in method)' , message )
83+ m = re .search (r 'END(?= in method)' , message )
7784
7885 return m .group (0 ) if m else None
0 commit comments