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

109 statements  

« prev     ^ index     » next       coverage.py v7.3.1, created at 2023-09-18 06:13 +0000

1""" 

2 pygments.lexers.ruby 

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

4 

5 Lexers for Ruby and related languages. 

6 

7 :copyright: Copyright 2006-2023 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 

40 flags = re.DOTALL | re.MULTILINE 

41 

42 def heredoc_callback(self, match, ctx): 

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

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

45 

46 start = match.start(1) 

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

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

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

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

51 

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

53 outermost = not bool(heredocstack) 

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

55 

56 ctx.pos = match.start(5) 

57 ctx.end = match.end(5) 

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

59 if len(heredocstack) < 100: 

60 yield from self.get_tokens_unprocessed(context=ctx) 

61 else: 

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

63 ctx.pos = match.end() 

64 

65 if outermost: 

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

67 for tolerant, hdname in heredocstack: 

68 lines = [] 

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

70 if tolerant: 

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

72 else: 

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

74 if check == hdname: 

75 for amatch in lines: 

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

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

78 ctx.pos = match.end() 

79 break 

80 else: 

81 lines.append(match) 

82 else: 

83 # end of heredoc not found -- error! 

84 for amatch in lines: 

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

86 ctx.end = len(ctx.text) 

87 del heredocstack[:] 

88 

89 def gen_rubystrings_rules(): 

90 def intp_regex_callback(self, match, ctx): 

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

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

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

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

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

96 ctx.pos = match.end() 

97 

98 def intp_string_callback(self, match, ctx): 

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

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

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

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

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

104 ctx.pos = match.end() 

105 

106 states = {} 

107 states['strings'] = [ 

108 # easy ones 

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

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

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

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

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

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

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

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

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

118 ] 

119 

120 # quoted string and symbol 

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

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

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

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

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

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

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

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

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

130 ] 

131 

132 # braced quoted strings 

133 for lbrace, rbrace, bracecc, name in \ 

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

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

136 ('\\(', '\\)', '()', 'pa'), \ 

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

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

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

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

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

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

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

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

145 ] 

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

147 name+'-intp-string')) 

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

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

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

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

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

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

154 ] 

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

156 name+'-string')) 

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

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

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

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

161 include('string-intp'), 

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

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

164 ] 

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

166 name+'-regex')) 

167 

168 # these must come after %<brace>! 

169 states['strings'] += [ 

170 # %r regex 

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

172 intp_regex_callback), 

173 # regular fancy strings with qsw 

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

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

176 intp_string_callback), 

177 # special forms of fancy strings after operators or 

178 # in method calls with braces 

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

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

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

182 # second time for line startings... 

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

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

185 # all regular fancy strings without qsw 

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

187 intp_string_callback), 

188 ] 

189 

190 return states 

191 

192 tokens = { 

193 'root': [ 

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

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

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

197 # keywords 

198 (words(( 

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

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

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

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

203 Keyword), 

204 # start of function, class and module names 

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

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

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

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

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

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

211 # special methods 

212 (words(( 

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

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

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

216 suffix=r'\b'), 

217 Keyword.Pseudo), 

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

219 (words(( 

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

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

222 'private_method_defined', 'protected_method_defined', 

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

224 Name.Builtin), 

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

226 (words(( 

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

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

229 'catch', 'chomp', 'chop', 'class_eval', 'class_variables', 

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

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

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

233 'hash', 'id', 'included_modules', 'inspect', 'instance_eval', 

234 'instance_method', 'instance_methods', 

235 'instance_variable_get', 'instance_variable_set', 'instance_variables', 

236 'lambda', 'load', 'local_variables', 'loop', 

237 'method', 'method_missing', 'methods', 'module_eval', 'name', 

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

239 'private_instance_methods', 

240 'private_methods', 'proc', 'protected_instance_methods', 

241 'protected_methods', 'public_class_method', 

242 'public_instance_methods', 'public_methods', 

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

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

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

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

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

248 Name.Builtin), 

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

250 # normal heredocs 

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

252 heredoc_callback), 

253 # empty string heredocs 

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

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

256 # multiline regex (after keywords or assignments) 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

281 # multiline regex (in method calls or subscripts) 

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

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

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

285 'multiline-regex'), 

286 # lex numbers and ignore following regular expressions which 

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

288 # better ideas?) 

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

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

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

292 # stupid example: 

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

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

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

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

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

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

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

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

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

302 # Names 

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

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

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

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

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

308 (r'::', Operator), 

309 include('strings'), 

310 # chars 

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

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

313 r'(?!\w)', 

314 String.Char), 

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

316 # this is needed because ruby attributes can look 

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

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

319 bygroups(Operator, Name.Operator)), 

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

321 bygroups(Operator, Name)), 

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

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

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

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

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

327 (r'\s+', Whitespace) 

328 ], 

329 'funcname': [ 

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

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

332 r'(' 

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

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

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

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

337 r')', 

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

339 default('#pop') 

340 ], 

341 'classname': [ 

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

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

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

345 default('#pop') 

346 ], 

347 'defexpr': [ 

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

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

350 include('root') 

351 ], 

352 'in-intp': [ 

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

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

355 include('root'), 

356 ], 

357 'string-intp': [ 

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

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

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

361 ], 

362 'string-intp-escaped': [ 

363 include('string-intp'), 

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

365 String.Escape) 

366 ], 

367 'interpolated-regex': [ 

368 include('string-intp'), 

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

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

371 ], 

372 'interpolated-string': [ 

373 include('string-intp'), 

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

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

376 ], 

377 'multiline-regex': [ 

378 include('string-intp'), 

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

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

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

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

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

384 ], 

385 'end-part': [ 

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

387 ] 

388 } 

389 tokens.update(gen_rubystrings_rules()) 

390 

391 def analyse_text(text): 

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

393 

394 

395class RubyConsoleLexer(Lexer): 

396 """ 

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

398 """ 

399 name = 'Ruby irb session' 

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

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

402 _example = 'rbcon/console' 

403 

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

405 r'|>> |\?> ') 

406 

407 def get_tokens_unprocessed(self, text): 

408 rblexer = RubyLexer(**self.options) 

409 

410 curcode = '' 

411 insertions = [] 

412 for match in line_re.finditer(text): 

413 line = match.group() 

414 m = self._prompt_re.match(line) 

415 if m is not None: 

416 end = m.end() 

417 insertions.append((len(curcode), 

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

419 curcode += line[end:] 

420 else: 

421 if curcode: 

422 yield from do_insertions( 

423 insertions, rblexer.get_tokens_unprocessed(curcode)) 

424 curcode = '' 

425 insertions = [] 

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

427 if curcode: 

428 yield from do_insertions( 

429 insertions, rblexer.get_tokens_unprocessed(curcode)) 

430 

431 

432class FancyLexer(RegexLexer): 

433 """ 

434 Pygments Lexer For Fancy. 

435 

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

437 class-based, concurrent general-purpose programming language 

438 running on Rubinius, the Ruby VM. 

439 

440 .. versionadded:: 1.5 

441 """ 

442 name = 'Fancy' 

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

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

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

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

447 

448 tokens = { 

449 # copied from PerlLexer: 

450 'balanced-regex': [ 

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

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

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 ], 

462 'root': [ 

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

464 

465 # balanced delimiters (copied from PerlLexer): 

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

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

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

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

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

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

472 

473 # Comments 

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

475 # Symbols 

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

477 # Multi-line DoubleQuotedString 

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

479 # DoubleQuotedString 

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

481 # keywords 

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

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

484 # constants 

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

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

487 # names 

488 (words(( 

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

490 'Number', 'Enumerable', 'FancyEnumerable', 'Block', 'TrueClass', 

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

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

493 Name.Builtin), 

494 # functions 

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

496 # operators, must be below functions 

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

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

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

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

501 ('@@?', Operator), 

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

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

504 # see comment in RubyLexer 

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

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

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

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

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

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

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

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

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

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

515 ] 

516 }