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

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

116 statements  

1""" 

2 pygments.lexers.ruby 

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

4 

5 Lexers for Ruby and related languages. 

6 

7 :copyright: Copyright 2006-present 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 # advance past the consumed lines so they are not 

88 # re-lexed (and thus duplicated) once ctx.end is reset 

89 if lines: 

90 ctx.pos = lines[-1].end() 

91 ctx.end = len(ctx.text) 

92 del heredocstack[:] 

93 

94 def gen_rubystrings_rules(): 

95 def intp_regex_callback(self, match, ctx): 

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

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

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

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

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

101 ctx.pos = match.end() 

102 

103 def intp_string_callback(self, match, ctx): 

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

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

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

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

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

109 ctx.pos = match.end() 

110 

111 states = {} 

112 states['strings'] = [ 

113 # easy ones 

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

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

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

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

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

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

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

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

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

123 ] 

124 

125 # quoted string and symbol 

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

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

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

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

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

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

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

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

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

135 ] 

136 

137 # braced quoted strings 

138 for lbrace, rbrace, bracecc, name in \ 

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

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

141 ('\\(', '\\)', '()', 'pa'), \ 

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

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

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

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

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

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

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

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

150 ] 

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

152 name+'-intp-string')) 

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

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

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

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

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

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

159 ] 

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

161 name+'-string')) 

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

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

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

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

166 include('string-intp'), 

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

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

169 ] 

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

171 name+'-regex')) 

172 

173 # these must come after %<brace>! 

174 states['strings'] += [ 

175 # %r regex 

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

177 intp_regex_callback), 

178 # regular fancy strings with qsw 

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

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

181 intp_string_callback), 

182 # special forms of fancy strings after operators or 

183 # in method calls with braces 

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

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

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

187 # second time for line startings... 

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

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

190 # all regular fancy strings without qsw 

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

192 intp_string_callback), 

193 ] 

194 

195 return states 

196 

197 tokens = { 

198 'root': [ 

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

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

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

202 # keywords 

203 (words(( 

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

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

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

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

208 Keyword), 

209 # start of function, class and module names 

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

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

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

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

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

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

216 # special methods 

217 (words(( 

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

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

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

221 suffix=r'\b'), 

222 Keyword.Pseudo), 

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

224 (words(( 

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

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

227 'private_method_defined', 'protected_method_defined', 

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

229 Name.Builtin), 

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

231 (words(( 

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

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

234 'catch', 'chomp', 'chop', 'class_eval', 'class_variables', 

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

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

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

238 'hash', 'id', 'included_modules', 'inspect', 'instance_eval', 

239 'instance_method', 'instance_methods', 

240 'instance_variable_get', 'instance_variable_set', 'instance_variables', 

241 'lambda', 'load', 'local_variables', 'loop', 

242 'method', 'method_missing', 'methods', 'module_eval', 'name', 

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

244 'private_instance_methods', 

245 'private_methods', 'proc', 'protected_instance_methods', 

246 'protected_methods', 'public_class_method', 

247 'public_instance_methods', 'public_methods', 

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

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

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

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

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

253 Name.Builtin), 

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

255 # normal heredocs 

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

257 heredoc_callback), 

258 # empty string heredocs 

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

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

261 # multiline regex (after keywords or assignments) 

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

286 # multiline regex (in method calls or subscripts) 

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

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

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

290 'multiline-regex'), 

291 # lex numbers and ignore following regular expressions which 

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

293 # better ideas?) 

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

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

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

297 # stupid example: 

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

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

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

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

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

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

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

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

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

307 # Names 

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

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

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

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

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

313 (r'::', Operator), 

314 include('strings'), 

315 # chars 

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

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

318 r'(?!\w)', 

319 String.Char), 

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

321 # this is needed because ruby attributes can look 

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

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

324 bygroups(Operator, Name.Operator)), 

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

326 bygroups(Operator, Name)), 

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

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

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

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

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

332 (r'\s+', Whitespace) 

333 ], 

334 'funcname': [ 

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

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

337 r'(' 

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

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

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

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

342 r')', 

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

344 default('#pop') 

345 ], 

346 'classname': [ 

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

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

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

350 default('#pop') 

351 ], 

352 'defexpr': [ 

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

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

355 include('root') 

356 ], 

357 'in-intp': [ 

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

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

360 include('root'), 

361 ], 

362 'string-intp': [ 

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

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

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

366 ], 

367 'string-intp-escaped': [ 

368 include('string-intp'), 

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

370 String.Escape) 

371 ], 

372 'interpolated-regex': [ 

373 include('string-intp'), 

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

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

376 ], 

377 'interpolated-string': [ 

378 include('string-intp'), 

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

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

381 ], 

382 'multiline-regex': [ 

383 include('string-intp'), 

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

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

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

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

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

389 ], 

390 'end-part': [ 

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

392 ] 

393 } 

394 tokens.update(gen_rubystrings_rules()) 

395 

396 def analyse_text(text): 

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

398 

399 

400class RubyConsoleLexer(Lexer): 

401 """ 

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

403 """ 

404 name = 'Ruby irb session' 

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

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

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

408 version_added = '' 

409 _example = 'rbcon/console' 

410 

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

412 r'|>> |\?> ') 

413 

414 def get_tokens_unprocessed(self, text): 

415 rblexer = RubyLexer(**self.options) 

416 

417 curcode = '' 

418 insertions = [] 

419 for match in line_re.finditer(text): 

420 line = match.group() 

421 m = self._prompt_re.match(line) 

422 if m is not None: 

423 end = m.end() 

424 insertions.append((len(curcode), 

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

426 curcode += line[end:] 

427 else: 

428 if curcode: 

429 yield from do_insertions( 

430 insertions, rblexer.get_tokens_unprocessed(curcode)) 

431 curcode = '' 

432 insertions = [] 

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

434 if curcode: 

435 yield from do_insertions( 

436 insertions, rblexer.get_tokens_unprocessed(curcode)) 

437 

438 

439class FancyLexer(RegexLexer): 

440 """ 

441 Pygments Lexer For Fancy. 

442 

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

444 class-based, concurrent general-purpose programming language 

445 running on Rubinius, the Ruby VM. 

446 """ 

447 name = 'Fancy' 

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

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

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

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

452 version_added = '1.5' 

453 

454 tokens = { 

455 # copied from PerlLexer: 

456 'balanced-regex': [ 

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

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

467 ], 

468 'root': [ 

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

470 

471 # balanced delimiters (copied from PerlLexer): 

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

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

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

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

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

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

478 

479 # Comments 

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

481 # Symbols 

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

483 # Multi-line DoubleQuotedString 

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

485 # DoubleQuotedString 

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

487 # keywords 

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

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

490 # constants 

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

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

493 # names 

494 (words(( 

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

496 'Number', 'Enumerable', 'FancyEnumerable', 'Block', 'TrueClass', 

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

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

499 Name.Builtin), 

500 # functions 

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

502 # operators, must be below functions 

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

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

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

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

507 ('@@?', Operator), 

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

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

510 # see comment in RubyLexer 

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

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

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

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

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

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

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

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

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

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

521 ] 

522 }