Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.11/site-packages/pygments/lexers/ruby.py: 46%

Shortcuts on this page

r m x   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

114 statements  

1""" 

2 pygments.lexers.ruby 

3 ~~~~~~~~~~~~~~~~~~~~ 

4 

5 Lexers for Ruby and related languages. 

6 

7 :copyright: Copyright 2006-2025 by the Pygments team, see AUTHORS. 

8 :license: BSD, see LICENSE for details. 

9""" 

10 

11import re 

12 

13from pygments.lexer import Lexer, RegexLexer, ExtendedRegexLexer, include, \ 

14 bygroups, default, LexerContext, do_insertions, words, line_re 

15from pygments.token import Text, Comment, Operator, Keyword, Name, String, \ 

16 Number, Punctuation, Error, Generic, Whitespace 

17from pygments.util import shebang_matches 

18 

19__all__ = ['RubyLexer', 'RubyConsoleLexer', 'FancyLexer'] 

20 

21 

22RUBY_OPERATORS = ( 

23 '*', '**', '-', '+', '-@', '+@', '/', '%', '&', '|', '^', '`', '~', 

24 '[]', '[]=', '<<', '>>', '<', '<>', '<=>', '>', '>=', '==', '===' 

25) 

26 

27 

28class RubyLexer(ExtendedRegexLexer): 

29 """ 

30 For Ruby source code. 

31 """ 

32 

33 name = 'Ruby' 

34 url = 'http://www.ruby-lang.org' 

35 aliases = ['ruby', 'rb', 'duby'] 

36 filenames = ['*.rb', '*.rbw', 'Rakefile', '*.rake', '*.gemspec', 

37 '*.rbx', '*.duby', 'Gemfile', 'Vagrantfile'] 

38 mimetypes = ['text/x-ruby', 'application/x-ruby'] 

39 version_added = '' 

40 

41 flags = re.DOTALL | re.MULTILINE 

42 

43 def heredoc_callback(self, match, ctx): 

44 # okay, this is the hardest part of parsing Ruby... 

45 # match: 1 = <<[-~]?, 2 = quote? 3 = name 4 = quote? 5 = rest of line 

46 

47 start = match.start(1) 

48 yield start, Operator, match.group(1) # <<[-~]? 

49 yield match.start(2), String.Heredoc, match.group(2) # quote ", ', ` 

50 yield match.start(3), String.Delimiter, match.group(3) # heredoc name 

51 yield match.start(4), String.Heredoc, match.group(4) # quote again 

52 

53 heredocstack = ctx.__dict__.setdefault('heredocstack', []) 

54 outermost = not bool(heredocstack) 

55 heredocstack.append((match.group(1) in ('<<-', '<<~'), match.group(3))) 

56 

57 ctx.pos = match.start(5) 

58 ctx.end = match.end(5) 

59 # this may find other heredocs, so limit the recursion depth 

60 if len(heredocstack) < 100: 

61 yield from self.get_tokens_unprocessed(context=ctx) 

62 else: 

63 yield ctx.pos, String.Heredoc, match.group(5) 

64 ctx.pos = match.end() 

65 

66 if outermost: 

67 # this is the outer heredoc again, now we can process them all 

68 for tolerant, hdname in heredocstack: 

69 lines = [] 

70 for match in line_re.finditer(ctx.text, ctx.pos): 

71 if tolerant: 

72 check = match.group().strip() 

73 else: 

74 check = match.group().rstrip() 

75 if check == hdname: 

76 for amatch in lines: 

77 yield amatch.start(), String.Heredoc, amatch.group() 

78 yield match.start(), String.Delimiter, match.group() 

79 ctx.pos = match.end() 

80 break 

81 else: 

82 lines.append(match) 

83 else: 

84 # end of heredoc not found -- error! 

85 for amatch in lines: 

86 yield amatch.start(), Error, amatch.group() 

87 ctx.end = len(ctx.text) 

88 del heredocstack[:] 

89 

90 def gen_rubystrings_rules(): 

91 def intp_regex_callback(self, match, ctx): 

92 yield match.start(1), String.Regex, match.group(1) # begin 

93 nctx = LexerContext(match.group(3), 0, ['interpolated-regex']) 

94 for i, t, v in self.get_tokens_unprocessed(context=nctx): 

95 yield match.start(3)+i, t, v 

96 yield match.start(4), String.Regex, match.group(4) # end[mixounse]* 

97 ctx.pos = match.end() 

98 

99 def intp_string_callback(self, match, ctx): 

100 yield match.start(1), String.Other, match.group(1) 

101 nctx = LexerContext(match.group(3), 0, ['interpolated-string']) 

102 for i, t, v in self.get_tokens_unprocessed(context=nctx): 

103 yield match.start(3)+i, t, v 

104 yield match.start(4), String.Other, match.group(4) # end 

105 ctx.pos = match.end() 

106 

107 states = {} 

108 states['strings'] = [ 

109 # easy ones 

110 (r'\:@{0,2}[a-zA-Z_]\w*[!?]?', String.Symbol), 

111 (words(RUBY_OPERATORS, prefix=r'\:@{0,2}'), String.Symbol), 

112 (r":'(\\\\|\\[^\\]|[^'\\])*'", String.Symbol), 

113 (r':"', String.Symbol, 'simple-sym'), 

114 (r'([a-zA-Z_]\w*)(:)(?!:)', 

115 bygroups(String.Symbol, Punctuation)), # Since Ruby 1.9 

116 (r'"', String.Double, 'simple-string-double'), 

117 (r"'", String.Single, 'simple-string-single'), 

118 (r'(?<!\.)`', String.Backtick, 'simple-backtick'), 

119 ] 

120 

121 # quoted string and symbol 

122 for name, ttype, end in ('string-double', String.Double, '"'), \ 

123 ('string-single', String.Single, "'"),\ 

124 ('sym', String.Symbol, '"'), \ 

125 ('backtick', String.Backtick, '`'): 

126 states['simple-'+name] = [ 

127 include('string-intp-escaped'), 

128 (rf'[^\\{end}#]+', ttype), 

129 (r'[\\#]', ttype), 

130 (end, ttype, '#pop'), 

131 ] 

132 

133 # braced quoted strings 

134 for lbrace, rbrace, bracecc, name in \ 

135 ('\\{', '\\}', '{}', 'cb'), \ 

136 ('\\[', '\\]', '\\[\\]', 'sb'), \ 

137 ('\\(', '\\)', '()', 'pa'), \ 

138 ('<', '>', '<>', 'ab'): 

139 states[name+'-intp-string'] = [ 

140 (r'\\[\\' + bracecc + ']', String.Other), 

141 (lbrace, String.Other, '#push'), 

142 (rbrace, String.Other, '#pop'), 

143 include('string-intp-escaped'), 

144 (r'[\\#' + bracecc + ']', String.Other), 

145 (r'[^\\#' + bracecc + ']+', String.Other), 

146 ] 

147 states['strings'].append((r'%[QWx]?' + lbrace, String.Other, 

148 name+'-intp-string')) 

149 states[name+'-string'] = [ 

150 (r'\\[\\' + bracecc + ']', String.Other), 

151 (lbrace, String.Other, '#push'), 

152 (rbrace, String.Other, '#pop'), 

153 (r'[\\#' + bracecc + ']', String.Other), 

154 (r'[^\\#' + bracecc + ']+', String.Other), 

155 ] 

156 states['strings'].append((r'%[qsw]' + lbrace, String.Other, 

157 name+'-string')) 

158 states[name+'-regex'] = [ 

159 (r'\\[\\' + bracecc + ']', String.Regex), 

160 (lbrace, String.Regex, '#push'), 

161 (rbrace + '[mixounse]*', String.Regex, '#pop'), 

162 include('string-intp'), 

163 (r'[\\#' + bracecc + ']', String.Regex), 

164 (r'[^\\#' + bracecc + ']+', String.Regex), 

165 ] 

166 states['strings'].append((r'%r' + lbrace, String.Regex, 

167 name+'-regex')) 

168 

169 # these must come after %<brace>! 

170 states['strings'] += [ 

171 # %r regex 

172 (r'(%r([\W_]))((?:\\\2|(?!\2).)*)(\2[mixounse]*)', 

173 intp_regex_callback), 

174 # regular fancy strings with qsw 

175 (r'%[qsw]([\W_])((?:\\\1|(?!\1).)*)\1', String.Other), 

176 (r'(%[QWx]([\W_]))((?:\\\2|(?!\2).)*)(\2)', 

177 intp_string_callback), 

178 # special forms of fancy strings after operators or 

179 # in method calls with braces 

180 (r'(?<=[-+/*%=<>&!^|~,(])(\s*)(%([\t ])(?:(?:\\\3|(?!\3).)*)\3)', 

181 bygroups(Whitespace, String.Other, None)), 

182 # and because of fixed width lookbehinds the whole thing a 

183 # second time for line startings... 

184 (r'^(\s*)(%([\t ])(?:(?:\\\3|(?!\3).)*)\3)', 

185 bygroups(Whitespace, String.Other, None)), 

186 # all regular fancy strings without qsw 

187 (r'(%([^a-zA-Z0-9\s]))((?:\\\2|(?!\2).)*)(\2)', 

188 intp_string_callback), 

189 ] 

190 

191 return states 

192 

193 tokens = { 

194 'root': [ 

195 (r'\A#!.+?$', Comment.Hashbang), 

196 (r'#.*?$', Comment.Single), 

197 (r'=begin\s.*?\n=end.*?$', Comment.Multiline), 

198 # keywords 

199 (words(( 

200 'BEGIN', 'END', 'alias', 'begin', 'break', 'case', 'defined?', 

201 'do', 'else', 'elsif', 'end', 'ensure', 'for', 'if', 'in', 'next', 'redo', 

202 'rescue', 'raise', 'retry', 'return', 'super', 'then', 'undef', 

203 'unless', 'until', 'when', 'while', 'yield'), suffix=r'\b'), 

204 Keyword), 

205 # start of function, class and module names 

206 (r'(module)(\s+)([a-zA-Z_]\w*' 

207 r'(?:::[a-zA-Z_]\w*)*)', 

208 bygroups(Keyword, Whitespace, Name.Namespace)), 

209 (r'(def)(\s+)', bygroups(Keyword, Whitespace), 'funcname'), 

210 (r'def(?=[*%&^`~+-/\[<>=])', Keyword, 'funcname'), 

211 (r'(class)(\s+)', bygroups(Keyword, Whitespace), 'classname'), 

212 # special methods 

213 (words(( 

214 'initialize', 'new', 'loop', 'include', 'extend', 'raise', 'attr_reader', 

215 'attr_writer', 'attr_accessor', 'attr', 'catch', 'throw', 'private', 

216 'module_function', 'public', 'protected', 'true', 'false', 'nil'), 

217 suffix=r'\b'), 

218 Keyword.Pseudo), 

219 (r'(not|and|or)\b', Operator.Word), 

220 (words(( 

221 'autoload', 'block_given', 'const_defined', 'eql', 'equal', 'frozen', 'include', 

222 'instance_of', 'is_a', 'iterator', 'kind_of', 'method_defined', 'nil', 

223 'private_method_defined', 'protected_method_defined', 

224 'public_method_defined', 'respond_to', 'tainted'), suffix=r'\?'), 

225 Name.Builtin), 

226 (r'(chomp|chop|exit|gsub|sub)!', Name.Builtin), 

227 (words(( 

228 'Array', 'Float', 'Integer', 'String', '__id__', '__send__', 'abort', 

229 'ancestors', 'at_exit', 'autoload', 'binding', 'callcc', 'caller', 

230 'catch', 'chomp', 'chop', 'class_eval', 'class_variables', 

231 'clone', 'const_defined?', 'const_get', 'const_missing', 'const_set', 

232 'constants', 'display', 'dup', 'eval', 'exec', 'exit', 'extend', 'fail', 'fork', 

233 'format', 'freeze', 'getc', 'gets', 'global_variables', 'gsub', 

234 'hash', 'id', 'included_modules', 'inspect', 'instance_eval', 

235 'instance_method', 'instance_methods', 

236 'instance_variable_get', 'instance_variable_set', 'instance_variables', 

237 'lambda', 'load', 'local_variables', 'loop', 

238 'method', 'method_missing', 'methods', 'module_eval', 'name', 

239 'object_id', 'open', 'p', 'print', 'printf', 'private_class_method', 

240 'private_instance_methods', 

241 'private_methods', 'proc', 'protected_instance_methods', 

242 'protected_methods', 'public_class_method', 

243 'public_instance_methods', 'public_methods', 

244 'putc', 'puts', 'raise', 'rand', 'readline', 'readlines', 'require', 

245 'scan', 'select', 'self', 'send', 'set_trace_func', 'singleton_methods', 'sleep', 

246 'split', 'sprintf', 'srand', 'sub', 'syscall', 'system', 'taint', 

247 'test', 'throw', 'to_a', 'to_s', 'trace_var', 'trap', 'untaint', 

248 'untrace_var', 'warn'), prefix=r'(?<!\.)', suffix=r'\b'), 

249 Name.Builtin), 

250 (r'__(FILE|LINE)__\b', Name.Builtin.Pseudo), 

251 # normal heredocs 

252 (r'(?<!\w)(<<[-~]?)(["`\']?)([a-zA-Z_]\w*)(\2)(.*?\n)', 

253 heredoc_callback), 

254 # empty string heredocs 

255 (r'(<<[-~]?)("|\')()(\2)(.*?\n)', heredoc_callback), 

256 (r'__END__', Comment.Preproc, 'end-part'), 

257 # multiline regex (after keywords or assignments) 

258 (r'(?:^|(?<=[=<>~!:])|' 

259 r'(?<=(?:\s|;)when\s)|' 

260 r'(?<=(?:\s|;)or\s)|' 

261 r'(?<=(?:\s|;)and\s)|' 

262 r'(?<=\.index\s)|' 

263 r'(?<=\.scan\s)|' 

264 r'(?<=\.sub\s)|' 

265 r'(?<=\.sub!\s)|' 

266 r'(?<=\.gsub\s)|' 

267 r'(?<=\.gsub!\s)|' 

268 r'(?<=\.match\s)|' 

269 r'(?<=(?:\s|;)if\s)|' 

270 r'(?<=(?:\s|;)elsif\s)|' 

271 r'(?<=^when\s)|' 

272 r'(?<=^index\s)|' 

273 r'(?<=^scan\s)|' 

274 r'(?<=^sub\s)|' 

275 r'(?<=^gsub\s)|' 

276 r'(?<=^sub!\s)|' 

277 r'(?<=^gsub!\s)|' 

278 r'(?<=^match\s)|' 

279 r'(?<=^if\s)|' 

280 r'(?<=^elsif\s)' 

281 r')(\s*)(/)', bygroups(Text, String.Regex), 'multiline-regex'), 

282 # multiline regex (in method calls or subscripts) 

283 (r'(?<=\(|,|\[)/', String.Regex, 'multiline-regex'), 

284 # multiline regex (this time the funny no whitespace rule) 

285 (r'(\s+)(/)(?![\s=])', bygroups(Whitespace, String.Regex), 

286 'multiline-regex'), 

287 # lex numbers and ignore following regular expressions which 

288 # are division operators in fact (grrrr. i hate that. any 

289 # better ideas?) 

290 # since pygments 0.7 we also eat a "?" operator after numbers 

291 # so that the char operator does not work. Chars are not allowed 

292 # there so that you can use the ternary operator. 

293 # stupid example: 

294 # x>=0?n[x]:"" 

295 (r'(0_?[0-7]+(?:_[0-7]+)*)(\s*)([/?])?', 

296 bygroups(Number.Oct, Whitespace, Operator)), 

297 (r'(0x[0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*)(\s*)([/?])?', 

298 bygroups(Number.Hex, Whitespace, Operator)), 

299 (r'(0b[01]+(?:_[01]+)*)(\s*)([/?])?', 

300 bygroups(Number.Bin, Whitespace, Operator)), 

301 (r'([\d]+(?:_\d+)*)(\s*)([/?])?', 

302 bygroups(Number.Integer, Whitespace, Operator)), 

303 # Names 

304 (r'@@[a-zA-Z_]\w*', Name.Variable.Class), 

305 (r'@[a-zA-Z_]\w*', Name.Variable.Instance), 

306 (r'\$\w+', Name.Variable.Global), 

307 (r'\$[!@&`\'+~=/\\,;.<>_*$?:"^-]', Name.Variable.Global), 

308 (r'\$-[0adFiIlpvw]', Name.Variable.Global), 

309 (r'::', Operator), 

310 include('strings'), 

311 # chars 

312 (r'\?(\\[MC]-)*' # modifiers 

313 r'(\\([\\abefnrstv#"\']|x[a-fA-F0-9]{1,2}|[0-7]{1,3})|\S)' 

314 r'(?!\w)', 

315 String.Char), 

316 (r'[A-Z]\w+', Name.Constant), 

317 # this is needed because ruby attributes can look 

318 # like keywords (class) or like this: ` ?!? 

319 (words(RUBY_OPERATORS, prefix=r'(\.|::)'), 

320 bygroups(Operator, Name.Operator)), 

321 (r'(\.|::)([a-zA-Z_]\w*[!?]?|[*%&^`~+\-/\[<>=])', 

322 bygroups(Operator, Name)), 

323 (r'[a-zA-Z_]\w*[!?]?', Name), 

324 (r'(\[|\]|\*\*|<<?|>>?|>=|<=|<=>|=~|={3}|' 

325 r'!~|&&?|\|\||\.{1,3})', Operator), 

326 (r'[-+/*%=<>&!^|~]=?', Operator), 

327 (r'[(){};,/?:\\]', Punctuation), 

328 (r'\s+', Whitespace) 

329 ], 

330 'funcname': [ 

331 (r'\(', Punctuation, 'defexpr'), 

332 (r'(?:([a-zA-Z_]\w*)(\.))?' # optional scope name, like "self." 

333 r'(' 

334 r'[a-zA-Z\u0080-\uffff][a-zA-Z0-9_\u0080-\uffff]*[!?=]?' # method name 

335 r'|!=|!~|=~|\*\*?|[-+!~]@?|[/%&|^]|<=>|<[<=]?|>[>=]?|===?' # or operator override 

336 r'|\[\]=?' # or element reference/assignment override 

337 r'|`' # or the undocumented backtick override 

338 r')', 

339 bygroups(Name.Class, Operator, Name.Function), '#pop'), 

340 default('#pop') 

341 ], 

342 'classname': [ 

343 (r'\(', Punctuation, 'defexpr'), 

344 (r'<<', Operator, '#pop'), 

345 (r'[A-Z_]\w*', Name.Class, '#pop'), 

346 default('#pop') 

347 ], 

348 'defexpr': [ 

349 (r'(\))(\.|::)?', bygroups(Punctuation, Operator), '#pop'), 

350 (r'\(', Operator, '#push'), 

351 include('root') 

352 ], 

353 'in-intp': [ 

354 (r'\{', String.Interpol, '#push'), 

355 (r'\}', String.Interpol, '#pop'), 

356 include('root'), 

357 ], 

358 'string-intp': [ 

359 (r'#\{', String.Interpol, 'in-intp'), 

360 (r'#@@?[a-zA-Z_]\w*', String.Interpol), 

361 (r'#\$[a-zA-Z_]\w*', String.Interpol) 

362 ], 

363 'string-intp-escaped': [ 

364 include('string-intp'), 

365 (r'\\([\\abefnrstv#"\']|x[a-fA-F0-9]{1,2}|[0-7]{1,3})', 

366 String.Escape) 

367 ], 

368 'interpolated-regex': [ 

369 include('string-intp'), 

370 (r'[\\#]', String.Regex), 

371 (r'[^\\#]+', String.Regex), 

372 ], 

373 'interpolated-string': [ 

374 include('string-intp'), 

375 (r'[\\#]', String.Other), 

376 (r'[^\\#]+', String.Other), 

377 ], 

378 'multiline-regex': [ 

379 include('string-intp'), 

380 (r'\\\\', String.Regex), 

381 (r'\\/', String.Regex), 

382 (r'[\\#]', String.Regex), 

383 (r'[^\\/#]+', String.Regex), 

384 (r'/[mixounse]*', String.Regex, '#pop'), 

385 ], 

386 'end-part': [ 

387 (r'.+', Comment.Preproc, '#pop') 

388 ] 

389 } 

390 tokens.update(gen_rubystrings_rules()) 

391 

392 def analyse_text(text): 

393 return shebang_matches(text, r'ruby(1\.\d)?') 

394 

395 

396class RubyConsoleLexer(Lexer): 

397 """ 

398 For Ruby interactive console (**irb**) output. 

399 """ 

400 name = 'Ruby irb session' 

401 aliases = ['rbcon', 'irb'] 

402 mimetypes = ['text/x-ruby-shellsession'] 

403 url = 'https://www.ruby-lang.org' 

404 version_added = '' 

405 _example = 'rbcon/console' 

406 

407 _prompt_re = re.compile(r'irb\([a-zA-Z_]\w*\):\d{3}:\d+[>*"\'] ' 

408 r'|>> |\?> ') 

409 

410 def get_tokens_unprocessed(self, text): 

411 rblexer = RubyLexer(**self.options) 

412 

413 curcode = '' 

414 insertions = [] 

415 for match in line_re.finditer(text): 

416 line = match.group() 

417 m = self._prompt_re.match(line) 

418 if m is not None: 

419 end = m.end() 

420 insertions.append((len(curcode), 

421 [(0, Generic.Prompt, line[:end])])) 

422 curcode += line[end:] 

423 else: 

424 if curcode: 

425 yield from do_insertions( 

426 insertions, rblexer.get_tokens_unprocessed(curcode)) 

427 curcode = '' 

428 insertions = [] 

429 yield match.start(), Generic.Output, line 

430 if curcode: 

431 yield from do_insertions( 

432 insertions, rblexer.get_tokens_unprocessed(curcode)) 

433 

434 

435class FancyLexer(RegexLexer): 

436 """ 

437 Pygments Lexer For Fancy. 

438 

439 Fancy is a self-hosted, pure object-oriented, dynamic, 

440 class-based, concurrent general-purpose programming language 

441 running on Rubinius, the Ruby VM. 

442 """ 

443 name = 'Fancy' 

444 url = 'https://github.com/bakkdoor/fancy' 

445 filenames = ['*.fy', '*.fancypack'] 

446 aliases = ['fancy', 'fy'] 

447 mimetypes = ['text/x-fancysrc'] 

448 version_added = '1.5' 

449 

450 tokens = { 

451 # copied from PerlLexer: 

452 'balanced-regex': [ 

453 (r'/(\\\\|\\[^\\]|[^/\\])*/[egimosx]*', String.Regex, '#pop'), 

454 (r'!(\\\\|\\[^\\]|[^!\\])*![egimosx]*', String.Regex, '#pop'), 

455 (r'\\(\\\\|[^\\])*\\[egimosx]*', String.Regex, '#pop'), 

456 (r'\{(\\\\|\\[^\\]|[^}\\])*\}[egimosx]*', String.Regex, '#pop'), 

457 (r'<(\\\\|\\[^\\]|[^>\\])*>[egimosx]*', String.Regex, '#pop'), 

458 (r'\[(\\\\|\\[^\\]|[^\]\\])*\][egimosx]*', String.Regex, '#pop'), 

459 (r'\((\\\\|\\[^\\]|[^)\\])*\)[egimosx]*', String.Regex, '#pop'), 

460 (r'@(\\\\|\\[^\\]|[^@\\])*@[egimosx]*', String.Regex, '#pop'), 

461 (r'%(\\\\|\\[^\\]|[^%\\])*%[egimosx]*', String.Regex, '#pop'), 

462 (r'\$(\\\\|\\[^\\]|[^$\\])*\$[egimosx]*', String.Regex, '#pop'), 

463 ], 

464 'root': [ 

465 (r'\s+', Whitespace), 

466 

467 # balanced delimiters (copied from PerlLexer): 

468 (r's\{(\\\\|\\[^\\]|[^}\\])*\}\s*', String.Regex, 'balanced-regex'), 

469 (r's<(\\\\|\\[^\\]|[^>\\])*>\s*', String.Regex, 'balanced-regex'), 

470 (r's\[(\\\\|\\[^\\]|[^\]\\])*\]\s*', String.Regex, 'balanced-regex'), 

471 (r's\((\\\\|\\[^\\]|[^)\\])*\)\s*', String.Regex, 'balanced-regex'), 

472 (r'm?/(\\\\|\\[^\\]|[^///\n])*/[gcimosx]*', String.Regex), 

473 (r'm(?=[/!\\{<\[(@%$])', String.Regex, 'balanced-regex'), 

474 

475 # Comments 

476 (r'#(.*?)\n', Comment.Single), 

477 # Symbols 

478 (r'\'([^\'\s\[\](){}]+|\[\])', String.Symbol), 

479 # Multi-line DoubleQuotedString 

480 (r'"""(\\\\|\\[^\\]|[^\\])*?"""', String), 

481 # DoubleQuotedString 

482 (r'"(\\\\|\\[^\\]|[^"\\])*"', String), 

483 # keywords 

484 (r'(def|class|try|catch|finally|retry|return|return_local|match|' 

485 r'case|->|=>)\b', Keyword), 

486 # constants 

487 (r'(self|super|nil|false|true)\b', Name.Constant), 

488 (r'[(){};,/?|:\\]', Punctuation), 

489 # names 

490 (words(( 

491 'Object', 'Array', 'Hash', 'Directory', 'File', 'Class', 'String', 

492 'Number', 'Enumerable', 'FancyEnumerable', 'Block', 'TrueClass', 

493 'NilClass', 'FalseClass', 'Tuple', 'Symbol', 'Stack', 'Set', 

494 'FancySpec', 'Method', 'Package', 'Range'), suffix=r'\b'), 

495 Name.Builtin), 

496 # functions 

497 (r'[a-zA-Z](\w|[-+?!=*/^><%])*:', Name.Function), 

498 # operators, must be below functions 

499 (r'[-+*/~,<>=&!?%^\[\].$]+', Operator), 

500 (r'[A-Z]\w*', Name.Constant), 

501 (r'@[a-zA-Z_]\w*', Name.Variable.Instance), 

502 (r'@@[a-zA-Z_]\w*', Name.Variable.Class), 

503 ('@@?', Operator), 

504 (r'[a-zA-Z_]\w*', Name), 

505 # numbers - / checks are necessary to avoid mismarking regexes, 

506 # see comment in RubyLexer 

507 (r'(0[oO]?[0-7]+(?:_[0-7]+)*)(\s*)([/?])?', 

508 bygroups(Number.Oct, Whitespace, Operator)), 

509 (r'(0[xX][0-9A-Fa-f]+(?:_[0-9A-Fa-f]+)*)(\s*)([/?])?', 

510 bygroups(Number.Hex, Whitespace, Operator)), 

511 (r'(0[bB][01]+(?:_[01]+)*)(\s*)([/?])?', 

512 bygroups(Number.Bin, Whitespace, Operator)), 

513 (r'([\d]+(?:_\d+)*)(\s*)([/?])?', 

514 bygroups(Number.Integer, Whitespace, Operator)), 

515 (r'\d+([eE][+-]?[0-9]+)|\d+\.\d+([eE][+-]?[0-9]+)?', Number.Float), 

516 (r'\d+', Number.Integer) 

517 ] 

518 }