]> luflow.net public git repositories - flow-web.git/blob - static/highlight/es/languages/ruby.js
Initial commit.
[flow-web.git] / static / highlight / es / languages / ruby.js
1 /*! `ruby` grammar compiled for Highlight.js 11.11.1 */
2 var hljsGrammar = (function () {
3 'use strict';
4
5 /*
6 Language: Ruby
7 Description: Ruby is a dynamic, open source programming language with a focus on simplicity and productivity.
8 Website: https://www.ruby-lang.org/
9 Author: Anton Kovalyov <anton@kovalyov.net>
10 Contributors: Peter Leonov <gojpeg@yandex.ru>, Vasily Polovnyov <vast@whiteants.net>, Loren Segal <lsegal@soen.ca>, Pascal Hurni <phi@ruby-reactive.org>, Cedric Sohrauer <sohrauer@googlemail.com>
11 Category: common, scripting
12 */
13
14 function ruby(hljs) {
15 const regex = hljs.regex;
16 const RUBY_METHOD_RE = '([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)';
17 // TODO: move concepts like CAMEL_CASE into `modes.js`
18 const CLASS_NAME_RE = regex.either(
19 /\b([A-Z]+[a-z0-9]+)+/,
20 // ends in caps
21 /\b([A-Z]+[a-z0-9]+)+[A-Z]+/,
22 )
23 ;
24 const CLASS_NAME_WITH_NAMESPACE_RE = regex.concat(CLASS_NAME_RE, /(::\w+)*/);
25 // very popular ruby built-ins that one might even assume
26 // are actual keywords (despite that not being the case)
27 const PSEUDO_KWS = [
28 "include",
29 "extend",
30 "prepend",
31 "public",
32 "private",
33 "protected",
34 "raise",
35 "throw"
36 ];
37 const RUBY_KEYWORDS = {
38 "variable.constant": [
39 "__FILE__",
40 "__LINE__",
41 "__ENCODING__"
42 ],
43 "variable.language": [
44 "self",
45 "super",
46 ],
47 keyword: [
48 "alias",
49 "and",
50 "begin",
51 "BEGIN",
52 "break",
53 "case",
54 "class",
55 "defined",
56 "do",
57 "else",
58 "elsif",
59 "end",
60 "END",
61 "ensure",
62 "for",
63 "if",
64 "in",
65 "module",
66 "next",
67 "not",
68 "or",
69 "redo",
70 "require",
71 "rescue",
72 "retry",
73 "return",
74 "then",
75 "undef",
76 "unless",
77 "until",
78 "when",
79 "while",
80 "yield",
81 ...PSEUDO_KWS
82 ],
83 built_in: [
84 "proc",
85 "lambda",
86 "attr_accessor",
87 "attr_reader",
88 "attr_writer",
89 "define_method",
90 "private_constant",
91 "module_function"
92 ],
93 literal: [
94 "true",
95 "false",
96 "nil"
97 ]
98 };
99 const YARDOCTAG = {
100 className: 'doctag',
101 begin: '@[A-Za-z]+'
102 };
103 const IRB_OBJECT = {
104 begin: '#<',
105 end: '>'
106 };
107 const COMMENT_MODES = [
108 hljs.COMMENT(
109 '#',
110 '$',
111 { contains: [ YARDOCTAG ] }
112 ),
113 hljs.COMMENT(
114 '^=begin',
115 '^=end',
116 {
117 contains: [ YARDOCTAG ],
118 relevance: 10
119 }
120 ),
121 hljs.COMMENT('^__END__', hljs.MATCH_NOTHING_RE)
122 ];
123 const SUBST = {
124 className: 'subst',
125 begin: /#\{/,
126 end: /\}/,
127 keywords: RUBY_KEYWORDS
128 };
129 const STRING = {
130 className: 'string',
131 contains: [
132 hljs.BACKSLASH_ESCAPE,
133 SUBST
134 ],
135 variants: [
136 {
137 begin: /'/,
138 end: /'/
139 },
140 {
141 begin: /"/,
142 end: /"/
143 },
144 {
145 begin: /`/,
146 end: /`/
147 },
148 {
149 begin: /%[qQwWx]?\(/,
150 end: /\)/
151 },
152 {
153 begin: /%[qQwWx]?\[/,
154 end: /\]/
155 },
156 {
157 begin: /%[qQwWx]?\{/,
158 end: /\}/
159 },
160 {
161 begin: /%[qQwWx]?</,
162 end: />/
163 },
164 {
165 begin: /%[qQwWx]?\//,
166 end: /\//
167 },
168 {
169 begin: /%[qQwWx]?%/,
170 end: /%/
171 },
172 {
173 begin: /%[qQwWx]?-/,
174 end: /-/
175 },
176 {
177 begin: /%[qQwWx]?\|/,
178 end: /\|/
179 },
180 // in the following expressions, \B in the beginning suppresses recognition of ?-sequences
181 // where ? is the last character of a preceding identifier, as in: `func?4`
182 { begin: /\B\?(\\\d{1,3})/ },
183 { begin: /\B\?(\\x[A-Fa-f0-9]{1,2})/ },
184 { begin: /\B\?(\\u\{?[A-Fa-f0-9]{1,6}\}?)/ },
185 { begin: /\B\?(\\M-\\C-|\\M-\\c|\\c\\M-|\\M-|\\C-\\M-)[\x20-\x7e]/ },
186 { begin: /\B\?\\(c|C-)[\x20-\x7e]/ },
187 { begin: /\B\?\\?\S/ },
188 // heredocs
189 {
190 // this guard makes sure that we have an entire heredoc and not a false
191 // positive (auto-detect, etc.)
192 begin: regex.concat(
193 /<<[-~]?'?/,
194 regex.lookahead(/(\w+)(?=\W)[^\n]*\n(?:[^\n]*\n)*?\s*\1\b/)
195 ),
196 contains: [
197 hljs.END_SAME_AS_BEGIN({
198 begin: /(\w+)/,
199 end: /(\w+)/,
200 contains: [
201 hljs.BACKSLASH_ESCAPE,
202 SUBST
203 ]
204 })
205 ]
206 }
207 ]
208 };
209
210 // Ruby syntax is underdocumented, but this grammar seems to be accurate
211 // as of version 2.7.2 (confirmed with (irb and `Ripper.sexp(...)`)
212 // https://docs.ruby-lang.org/en/2.7.0/doc/syntax/literals_rdoc.html#label-Numbers
213 const decimal = '[1-9](_?[0-9])*|0';
214 const digits = '[0-9](_?[0-9])*';
215 const NUMBER = {
216 className: 'number',
217 relevance: 0,
218 variants: [
219 // decimal integer/float, optionally exponential or rational, optionally imaginary
220 { begin: `\\b(${decimal})(\\.(${digits}))?([eE][+-]?(${digits})|r)?i?\\b` },
221
222 // explicit decimal/binary/octal/hexadecimal integer,
223 // optionally rational and/or imaginary
224 { begin: "\\b0[dD][0-9](_?[0-9])*r?i?\\b" },
225 { begin: "\\b0[bB][0-1](_?[0-1])*r?i?\\b" },
226 { begin: "\\b0[oO][0-7](_?[0-7])*r?i?\\b" },
227 { begin: "\\b0[xX][0-9a-fA-F](_?[0-9a-fA-F])*r?i?\\b" },
228
229 // 0-prefixed implicit octal integer, optionally rational and/or imaginary
230 { begin: "\\b0(_?[0-7])+r?i?\\b" }
231 ]
232 };
233
234 const PARAMS = {
235 variants: [
236 {
237 match: /\(\)/,
238 },
239 {
240 className: 'params',
241 begin: /\(/,
242 end: /(?=\))/,
243 excludeBegin: true,
244 endsParent: true,
245 keywords: RUBY_KEYWORDS,
246 }
247 ]
248 };
249
250 const INCLUDE_EXTEND = {
251 match: [
252 /(include|extend)\s+/,
253 CLASS_NAME_WITH_NAMESPACE_RE
254 ],
255 scope: {
256 2: "title.class"
257 },
258 keywords: RUBY_KEYWORDS
259 };
260
261 const CLASS_DEFINITION = {
262 variants: [
263 {
264 match: [
265 /class\s+/,
266 CLASS_NAME_WITH_NAMESPACE_RE,
267 /\s+<\s+/,
268 CLASS_NAME_WITH_NAMESPACE_RE
269 ]
270 },
271 {
272 match: [
273 /\b(class|module)\s+/,
274 CLASS_NAME_WITH_NAMESPACE_RE
275 ]
276 }
277 ],
278 scope: {
279 2: "title.class",
280 4: "title.class.inherited"
281 },
282 keywords: RUBY_KEYWORDS
283 };
284
285 const UPPER_CASE_CONSTANT = {
286 relevance: 0,
287 match: /\b[A-Z][A-Z_0-9]+\b/,
288 className: "variable.constant"
289 };
290
291 const METHOD_DEFINITION = {
292 match: [
293 /def/, /\s+/,
294 RUBY_METHOD_RE
295 ],
296 scope: {
297 1: "keyword",
298 3: "title.function"
299 },
300 contains: [
301 PARAMS
302 ]
303 };
304
305 const OBJECT_CREATION = {
306 relevance: 0,
307 match: [
308 CLASS_NAME_WITH_NAMESPACE_RE,
309 /\.new[. (]/
310 ],
311 scope: {
312 1: "title.class"
313 }
314 };
315
316 // CamelCase
317 const CLASS_REFERENCE = {
318 relevance: 0,
319 match: CLASS_NAME_RE,
320 scope: "title.class"
321 };
322
323 const RUBY_DEFAULT_CONTAINS = [
324 STRING,
325 CLASS_DEFINITION,
326 INCLUDE_EXTEND,
327 OBJECT_CREATION,
328 UPPER_CASE_CONSTANT,
329 CLASS_REFERENCE,
330 METHOD_DEFINITION,
331 {
332 // swallow namespace qualifiers before symbols
333 begin: hljs.IDENT_RE + '::' },
334 {
335 className: 'symbol',
336 begin: hljs.UNDERSCORE_IDENT_RE + '(!|\\?)?:',
337 relevance: 0
338 },
339 {
340 className: 'symbol',
341 begin: ':(?!\\s)',
342 contains: [
343 STRING,
344 { begin: RUBY_METHOD_RE }
345 ],
346 relevance: 0
347 },
348 NUMBER,
349 {
350 // negative-look forward attempts to prevent false matches like:
351 // @ident@ or $ident$ that might indicate this is not ruby at all
352 className: "variable",
353 begin: '(\\$\\W)|((\\$|@@?)(\\w+))(?=[^@$?])' + `(?![A-Za-z])(?![@$?'])`
354 },
355 {
356 className: 'params',
357 begin: /\|(?!=)/,
358 end: /\|/,
359 excludeBegin: true,
360 excludeEnd: true,
361 relevance: 0, // this could be a lot of things (in other languages) other than params
362 keywords: RUBY_KEYWORDS
363 },
364 { // regexp container
365 begin: '(' + hljs.RE_STARTERS_RE + '|unless)\\s*',
366 keywords: 'unless',
367 contains: [
368 {
369 className: 'regexp',
370 contains: [
371 hljs.BACKSLASH_ESCAPE,
372 SUBST
373 ],
374 illegal: /\n/,
375 variants: [
376 {
377 begin: '/',
378 end: '/[a-z]*'
379 },
380 {
381 begin: /%r\{/,
382 end: /\}[a-z]*/
383 },
384 {
385 begin: '%r\\(',
386 end: '\\)[a-z]*'
387 },
388 {
389 begin: '%r!',
390 end: '![a-z]*'
391 },
392 {
393 begin: '%r\\[',
394 end: '\\][a-z]*'
395 }
396 ]
397 }
398 ].concat(IRB_OBJECT, COMMENT_MODES),
399 relevance: 0
400 }
401 ].concat(IRB_OBJECT, COMMENT_MODES);
402
403 SUBST.contains = RUBY_DEFAULT_CONTAINS;
404 PARAMS.contains = RUBY_DEFAULT_CONTAINS;
405
406 // >>
407 // ?>
408 const SIMPLE_PROMPT = "[>?]>";
409 // irb(main):001:0>
410 const DEFAULT_PROMPT = "[\\w#]+\\(\\w+\\):\\d+:\\d+[>*]";
411 const RVM_PROMPT = "(\\w+-)?\\d+\\.\\d+\\.\\d+(p\\d+)?[^\\d][^>]+>";
412
413 const IRB_DEFAULT = [
414 {
415 begin: /^\s*=>/,
416 starts: {
417 end: '$',
418 contains: RUBY_DEFAULT_CONTAINS
419 }
420 },
421 {
422 className: 'meta.prompt',
423 begin: '^(' + SIMPLE_PROMPT + "|" + DEFAULT_PROMPT + '|' + RVM_PROMPT + ')(?=[ ])',
424 starts: {
425 end: '$',
426 keywords: RUBY_KEYWORDS,
427 contains: RUBY_DEFAULT_CONTAINS
428 }
429 }
430 ];
431
432 COMMENT_MODES.unshift(IRB_OBJECT);
433
434 return {
435 name: 'Ruby',
436 aliases: [
437 'rb',
438 'gemspec',
439 'podspec',
440 'thor',
441 'irb'
442 ],
443 keywords: RUBY_KEYWORDS,
444 illegal: /\/\*/,
445 contains: [ hljs.SHEBANG({ binary: "ruby" }) ]
446 .concat(IRB_DEFAULT)
447 .concat(COMMENT_MODES)
448 .concat(RUBY_DEFAULT_CONTAINS)
449 };
450 }
451
452 return ruby;
453
454 })();
455 ;
456 export default hljsGrammar;