Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1# -*- coding: utf-8 -*- 

2""" 

3 pygments.lexers.ruby 

4 ~~~~~~~~~~~~~~~~~~~~ 

5 

6 Lexers for Ruby and related languages. 

7 

8 :copyright: Copyright 2006-2021 by the Pygments team, see AUTHORS. 

9 :license: BSD, see LICENSE for details. 

10""" 

11 

12import re 

13 

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

15 bygroups, default, LexerContext, do_insertions, words 

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

17 Number, Punctuation, Error, Generic 

18from pygments.util import shebang_matches 

19 

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

21 

22line_re = re.compile('.*?\n') 

23 

24 

25RUBY_OPERATORS = ( 

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

27 '[]', '[]=', '<<', '>>', '<', '<>', '<=>', '>', '>=', '==', '===' 

28) 

29 

30 

31class RubyLexer(ExtendedRegexLexer): 

32 """ 

33 For `Ruby <http://www.ruby-lang.org>`_ source code. 

34 """ 

35 

36 name = 'Ruby' 

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

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

39 '*.rbx', '*.duby', 'Gemfile'] 

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

41 

42 flags = re.DOTALL | re.MULTILINE 

43 

44 def heredoc_callback(self, match, ctx): 

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

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

47 

48 start = match.start(1) 

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

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

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

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

53 

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

55 outermost = not bool(heredocstack) 

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

57 

58 ctx.pos = match.start(5) 

59 ctx.end = match.end(5) 

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

61 if len(heredocstack) < 100: 

62 yield from self.get_tokens_unprocessed(context=ctx) 

63 else: 

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

65 ctx.pos = match.end() 

66 

67 if outermost: 

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

69 for tolerant, hdname in heredocstack: 

70 lines = [] 

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

72 if tolerant: 

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

74 else: 

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

76 if check == hdname: 

77 for amatch in lines: 

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

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

80 ctx.pos = match.end() 

81 break 

82 else: 

83 lines.append(match) 

84 else: 

85 # end of heredoc not found -- error! 

86 for amatch in lines: 

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

88 ctx.end = len(ctx.text) 

89 del heredocstack[:] 

90 

91 def gen_rubystrings_rules(): 

92 def intp_regex_callback(self, match, ctx): 

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

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

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

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

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

98 ctx.pos = match.end() 

99 

100 def intp_string_callback(self, match, ctx): 

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

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

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

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

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

106 ctx.pos = match.end() 

107 

108 states = {} 

109 states['strings'] = [ 

110 # easy ones 

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

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

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

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

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

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

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

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

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

120 ] 

121 

122 # quoted string and symbol 

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

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

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

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

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

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

129 (r'[^\\%s#]+' % end, ttype), 

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

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

132 ] 

133 

134 # braced quoted strings 

135 for lbrace, rbrace, bracecc, name in \ 

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

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

138 ('\\(', '\\)', '()', 'pa'), \ 

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

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

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

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

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

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

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

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

147 ] 

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

149 name+'-intp-string')) 

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

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

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

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

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

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

156 ] 

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

158 name+'-string')) 

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

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

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

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

163 include('string-intp'), 

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

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

166 ] 

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

168 name+'-regex')) 

169 

170 # these must come after %<brace>! 

171 states['strings'] += [ 

172 # %r regex 

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

174 intp_regex_callback), 

175 # regular fancy strings with qsw 

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

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

178 intp_string_callback), 

179 # special forms of fancy strings after operators or 

180 # in method calls with braces 

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

182 bygroups(Text, String.Other, None)), 

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

184 # second time for line startings... 

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

186 bygroups(Text, String.Other, None)), 

187 # all regular fancy strings without qsw 

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

189 intp_string_callback), 

190 ] 

191 

192 return states 

193 

194 tokens = { 

195 'root': [ 

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

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

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

199 # keywords 

200 (words(( 

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

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

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

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

205 Keyword), 

206 # start of function, class and module names 

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

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

209 bygroups(Keyword, Text, Name.Namespace)), 

210 (r'(def)(\s+)', bygroups(Keyword, Text), 'funcname'), 

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

212 (r'(class)(\s+)', bygroups(Keyword, Text), 'classname'), 

213 # special methods 

214 (words(( 

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

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

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

218 suffix=r'\b'), 

219 Keyword.Pseudo), 

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

221 (words(( 

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

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

224 'private_method_defined', 'protected_method_defined', 

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

226 Name.Builtin), 

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

228 (words(( 

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

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

231 'catch', 'chomp', 'chop', 'class_eval', 'class_variables', 

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

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

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

235 'hash', 'id', 'included_modules', 'inspect', 'instance_eval', 

236 'instance_method', 'instance_methods', 

237 'instance_variable_get', 'instance_variable_set', 'instance_variables', 

238 'lambda', 'load', 'local_variables', 'loop', 

239 'method', 'method_missing', 'methods', 'module_eval', 'name', 

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

241 'private_instance_methods', 

242 'private_methods', 'proc', 'protected_instance_methods', 

243 'protected_methods', 'public_class_method', 

244 'public_instance_methods', 'public_methods', 

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

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

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

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

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

250 Name.Builtin), 

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

252 # normal heredocs 

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

254 heredoc_callback), 

255 # empty string heredocs 

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

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

258 # multiline regex (after keywords or assignments) 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

283 # multiline regex (in method calls or subscripts) 

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

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

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

287 'multiline-regex'), 

288 # lex numbers and ignore following regular expressions which 

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

290 # better ideas?) 

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

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

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

294 # stupid example: 

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

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

297 bygroups(Number.Oct, Text, Operator)), 

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

299 bygroups(Number.Hex, Text, Operator)), 

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

301 bygroups(Number.Bin, Text, Operator)), 

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

303 bygroups(Number.Integer, Text, Operator)), 

304 # Names 

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

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

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

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

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

310 (r'::', Operator), 

311 include('strings'), 

312 # chars 

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

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

315 r'(?!\w)', 

316 String.Char), 

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

318 # this is needed because ruby attributes can look 

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

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

321 bygroups(Operator, Name.Operator)), 

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

323 bygroups(Operator, Name)), 

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

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

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

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

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

329 (r'\s+', Text) 

330 ], 

331 'funcname': [ 

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

333 (r'(?:([a-zA-Z_]\w*)(\.))?' 

334 r'([a-zA-Z_]\w*[!?]?|\*\*?|[-+]@?|' 

335 r'[/%&|^`~]|\[\]=?|<<|>>|<=?>|>=?|===?)', 

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

337 default('#pop') 

338 ], 

339 'classname': [ 

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

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

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

343 default('#pop') 

344 ], 

345 'defexpr': [ 

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

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

348 include('root') 

349 ], 

350 'in-intp': [ 

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

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

353 include('root'), 

354 ], 

355 'string-intp': [ 

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

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

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

359 ], 

360 'string-intp-escaped': [ 

361 include('string-intp'), 

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

363 String.Escape) 

364 ], 

365 'interpolated-regex': [ 

366 include('string-intp'), 

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

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

369 ], 

370 'interpolated-string': [ 

371 include('string-intp'), 

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

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

374 ], 

375 'multiline-regex': [ 

376 include('string-intp'), 

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

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

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

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

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

382 ], 

383 'end-part': [ 

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

385 ] 

386 } 

387 tokens.update(gen_rubystrings_rules()) 

388 

389 def analyse_text(text): 

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

391 

392 

393class RubyConsoleLexer(Lexer): 

394 """ 

395 For Ruby interactive console (**irb**) output like: 

396 

397 .. sourcecode:: rbcon 

398 

399 irb(main):001:0> a = 1 

400 => 1 

401 irb(main):002:0> puts a 

402 1 

403 => nil 

404 """ 

405 name = 'Ruby irb session' 

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

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

408 

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

410 r'|>> |\?> ') 

411 

412 def get_tokens_unprocessed(self, text): 

413 rblexer = RubyLexer(**self.options) 

414 

415 curcode = '' 

416 insertions = [] 

417 for match in line_re.finditer(text): 

418 line = match.group() 

419 m = self._prompt_re.match(line) 

420 if m is not None: 

421 end = m.end() 

422 insertions.append((len(curcode), 

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

424 curcode += line[end:] 

425 else: 

426 if curcode: 

427 yield from do_insertions( 

428 insertions, rblexer.get_tokens_unprocessed(curcode)) 

429 curcode = '' 

430 insertions = [] 

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

432 if curcode: 

433 yield from do_insertions( 

434 insertions, rblexer.get_tokens_unprocessed(curcode)) 

435 

436 

437class FancyLexer(RegexLexer): 

438 """ 

439 Pygments Lexer For `Fancy <http://www.fancy-lang.org/>`_. 

440 

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

442 class-based, concurrent general-purpose programming language 

443 running on Rubinius, the Ruby VM. 

444 

445 .. versionadded:: 1.5 

446 """ 

447 name = 'Fancy' 

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

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

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

451 

452 tokens = { 

453 # copied from PerlLexer: 

454 'balanced-regex': [ 

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 (r'%(\\\\|\\[^\\]|[^%\\])*%[egimosx]*', String.Regex, '#pop'), 

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

465 ], 

466 'root': [ 

467 (r'\s+', Text), 

468 

469 # balanced delimiters (copied from PerlLexer): 

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

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

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

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

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

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

476 

477 # Comments 

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

479 # Symbols 

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

481 # Multi-line DoubleQuotedString 

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

483 # DoubleQuotedString 

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

485 # keywords 

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

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

488 # constants 

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

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

491 # names 

492 (words(( 

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

494 'Number', 'Enumerable', 'FancyEnumerable', 'Block', 'TrueClass', 

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

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

497 Name.Builtin), 

498 # functions 

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

500 # operators, must be below functions 

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

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

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

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

505 ('@@?', Operator), 

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

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

508 # see comment in RubyLexer 

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

510 bygroups(Number.Oct, Text, Operator)), 

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

512 bygroups(Number.Hex, Text, Operator)), 

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

514 bygroups(Number.Bin, Text, Operator)), 

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

516 bygroups(Number.Integer, Text, Operator)), 

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

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

519 ] 

520 }