Skip to content

Commit 8cea942

Browse files
authored
(enh) lots of small Ruby improvements (#3491)
* (enh) lots of small Ruby improvements * do not scope () as params * better camel case regex
1 parent 50d3a1e commit 8cea942

File tree

7 files changed

+148
-56
lines changed

7 files changed

+148
-56
lines changed

CHANGES.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ New Grammars:
1111

1212
Grammars:
1313

14+
- enh(ruby) lots of small Ruby cleanups/improvements [Josh Goebel][]
1415
- enh(objectivec) add `type` and `variable.language` scopes [Josh Goebel][]
1516
- enh(xml) support processing instructions (#3492) [Josh Goebel][]
1617
- enh(ruby ) better support multi-line IRB prompts

src/highlight.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -277,8 +277,8 @@ const HLJS = function(hljs) {
277277
*/
278278
function emitMultiClass(scope, match) {
279279
let i = 1;
280-
// eslint-disable-next-line no-undefined
281-
while (match[i] !== undefined) {
280+
const max = match.length - 1;
281+
while (i <= max) {
282282
if (!scope._emit[i]) { i++; continue; }
283283
const klass = language.classNameAliases[scope[i]] || scope[i];
284284
const text = match[i];

src/languages/ruby.js

Lines changed: 138 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,71 @@ Category: common
1010
export default function(hljs) {
1111
const regex = hljs.regex;
1212
const RUBY_METHOD_RE = '([a-zA-Z_]\\w*[!?=]?|[-+~]@|<<|>>|=~|===?|<=>|[<>]=?|\\*\\*|[-/+%^&*~`|]|\\[\\]=?)';
13+
// TODO: move concepts like CAMEL_CASE into `modes.js`
14+
const CLASS_NAME_RE = regex.either(
15+
/\b([A-Z]+[a-z0-9]+)+/,
16+
// ends in caps
17+
/\b([A-Z]+[a-z0-9]+)+[A-Z]+/,
18+
)
19+
;
20+
const CLASS_NAME_WITH_NAMESPACE_RE = regex.concat(CLASS_NAME_RE, /(::\w+)*/)
1321
const RUBY_KEYWORDS = {
14-
keyword:
15-
'and then defined module in return redo if BEGIN retry end for self when '
16-
+ 'next until do begin unless END rescue else break undef not super class case '
17-
+ 'require yield alias while ensure elsif or include attr_reader attr_writer attr_accessor '
18-
+ '__FILE__',
19-
built_in: 'proc lambda',
20-
literal:
21-
'true false nil'
22+
"variable.constant": [
23+
"__FILE__",
24+
"__LINE__"
25+
],
26+
"variable.language": [
27+
"self",
28+
"super",
29+
],
30+
keyword: [
31+
"alias",
32+
"and",
33+
"attr_accessor",
34+
"attr_reader",
35+
"attr_writer",
36+
"begin",
37+
"BEGIN",
38+
"break",
39+
"case",
40+
"class",
41+
"defined",
42+
"do",
43+
"else",
44+
"elsif",
45+
"end",
46+
"END",
47+
"ensure",
48+
"for",
49+
"if",
50+
"in",
51+
"include",
52+
"module",
53+
"next",
54+
"not",
55+
"or",
56+
"redo",
57+
"require",
58+
"rescue",
59+
"retry",
60+
"return",
61+
"then",
62+
"undef",
63+
"unless",
64+
"until",
65+
"when",
66+
"while",
67+
"yield",
68+
],
69+
built_in: [
70+
"proc",
71+
"lambda"
72+
],
73+
literal: [
74+
"true",
75+
"false",
76+
"nil"
77+
]
2278
};
2379
const YARDOCTAG = {
2480
className: 'doctag',
@@ -42,7 +98,7 @@ export default function(hljs) {
4298
relevance: 10
4399
}
44100
),
45-
hljs.COMMENT('^__END__', '\\n$')
101+
hljs.COMMENT('^__END__', hljs.MATCH_NOTHING_RE)
46102
];
47103
const SUBST = {
48104
className: 'subst',
@@ -156,49 +212,82 @@ export default function(hljs) {
156212
};
157213

158214
const PARAMS = {
159-
className: 'params',
160-
begin: '\\(',
161-
end: '\\)',
162-
endsParent: true,
215+
variants: [
216+
{
217+
match: /\(\)/,
218+
},
219+
{
220+
className: 'params',
221+
begin: /\(/,
222+
end: /(?=\))/,
223+
excludeBegin: true,
224+
endsParent: true,
225+
keywords: RUBY_KEYWORDS,
226+
}
227+
]
228+
};
229+
230+
const CLASS_DEFINITION = {
231+
variants: [
232+
{
233+
match: [
234+
/class\s+/,
235+
CLASS_NAME_WITH_NAMESPACE_RE,
236+
/\s+<\s+/,
237+
CLASS_NAME_WITH_NAMESPACE_RE
238+
]
239+
},
240+
{
241+
match: [
242+
/class\s+/,
243+
CLASS_NAME_WITH_NAMESPACE_RE
244+
]
245+
}
246+
],
247+
scope: {
248+
2: "title.class",
249+
4: "title.class.inherited"
250+
},
163251
keywords: RUBY_KEYWORDS
164252
};
165253

254+
const UPPER_CASE_CONSTANT = {
255+
relevance: 0,
256+
match: /\b[A-Z][A-Z_0-9]+\b/,
257+
className: "variable.constant"
258+
};
259+
260+
const METHOD_DEFINITION = {
261+
match: [
262+
/def/, /\s+/,
263+
RUBY_METHOD_RE
264+
],
265+
scope: {
266+
1: "keyword",
267+
3: "title.function"
268+
},
269+
contains: [
270+
PARAMS
271+
]
272+
};
273+
274+
const OBJECT_CREATION = {
275+
relevance: 0,
276+
match: [
277+
CLASS_NAME_WITH_NAMESPACE_RE,
278+
/\.new[ (]/
279+
],
280+
scope: {
281+
1: "title.class"
282+
}
283+
};
284+
166285
const RUBY_DEFAULT_CONTAINS = [
167286
STRING,
168-
{
169-
className: 'class',
170-
beginKeywords: 'class module',
171-
end: '$|;',
172-
illegal: /=/,
173-
contains: [
174-
hljs.inherit(hljs.TITLE_MODE, { begin: '[A-Za-z_]\\w*(::\\w+)*(\\?|!)?' }),
175-
{
176-
begin: '<\\s*',
177-
contains: [
178-
{
179-
begin: '(' + hljs.IDENT_RE + '::)?' + hljs.IDENT_RE,
180-
// we already get points for <, we don't need poitns
181-
// for the name also
182-
relevance: 0
183-
}
184-
]
185-
}
186-
].concat(COMMENT_MODES)
187-
},
188-
{
189-
className: 'function',
190-
// def method_name(
191-
// def method_name;
192-
// def method_name (end of line)
193-
begin: regex.concat(/def\s+/, regex.lookahead(RUBY_METHOD_RE + "\\s*(\\(|;|$)")),
194-
relevance: 0, // relevance comes from kewords
195-
keywords: "def",
196-
end: '$|;',
197-
contains: [
198-
hljs.inherit(hljs.TITLE_MODE, { begin: RUBY_METHOD_RE }),
199-
PARAMS
200-
].concat(COMMENT_MODES)
201-
},
287+
CLASS_DEFINITION,
288+
OBJECT_CREATION,
289+
UPPER_CASE_CONSTANT,
290+
METHOD_DEFINITION,
202291
{
203292
// swallow namespace qualifiers before symbols
204293
begin: hljs.IDENT_RE + '::' },
@@ -227,6 +316,8 @@ export default function(hljs) {
227316
className: 'params',
228317
begin: /\|/,
229318
end: /\|/,
319+
excludeBegin: true,
320+
excludeEnd: true,
230321
relevance: 0, // this could be a lot of things (in other languages) other than params
231322
keywords: RUBY_KEYWORDS
232323
},

test/markup/erb/default.expect.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
<span class="hljs-comment">&lt;%# this is a comment %&gt;</span><span class="language-xml">
22

3-
&lt;%</span><span class="language-ruby"> <span class="hljs-variable">@posts</span>.each <span class="hljs-keyword">do</span> <span class="hljs-params">|post|</span> </span><span class="language-xml">%&gt;
3+
&lt;%</span><span class="language-ruby"> <span class="hljs-variable">@posts</span>.each <span class="hljs-keyword">do</span> |<span class="hljs-params">post</span>| </span><span class="language-xml">%&gt;
44
<span class="hljs-tag">&lt;<span class="hljs-name">p</span>&gt;</span>&lt;%=</span><span class="language-ruby"> link_to post.title, post </span><span class="language-xml">%&gt;<span class="hljs-tag">&lt;/<span class="hljs-name">p</span>&gt;</span>
55
&lt;%</span><span class="language-ruby"> <span class="hljs-keyword">end</span> </span><span class="language-xml">%&gt;
66

test/markup/haml/default.expect.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
<span class="hljs-comment"> /html comment</span>
66
<span class="hljs-comment"> -# ignore this line</span>
77
<span class="hljs-tag"> %<span class="hljs-selector-tag">ul</span>(<span class="hljs-attr">style</span>=<span class="hljs-string">&#x27;margin: 0&#x27;</span>)</span>
8-
-<span class="language-ruby">items.each <span class="hljs-keyword">do</span> <span class="hljs-params">|i|</span></span>
8+
-<span class="language-ruby">items.each <span class="hljs-keyword">do</span> |<span class="hljs-params">i</span>|</span>
99
<span class="hljs-tag"> %<span class="hljs-selector-tag">i</span></span>= i
1010
=<span class="language-ruby"> variable</span>
1111
=<span class="language-ruby">variable2</span>

test/markup/ruby/heredoc.expect.txt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,15 +13,15 @@ message = <span class="hljs-string">&lt;&lt;-MESSAGE.chomp
1313
This looks good
1414
MESSAGE</span>
1515

16-
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">foo</span><span class="hljs-params">()</span></span>
16+
<span class="hljs-keyword">def</span> <span class="hljs-title function_">foo</span>()
1717
msg = <span class="hljs-string">&lt;&lt;-HTML
1818
&lt;div&gt;
1919
&lt;h4&gt;<span class="hljs-subst">#{bar}</span>&lt;/h4&gt;
2020
&lt;/div&gt;
2121
HTML</span>
2222
<span class="hljs-keyword">end</span>
2323

24-
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">baz</span><span class="hljs-params">()</span></span>
24+
<span class="hljs-keyword">def</span> <span class="hljs-title function_">baz</span>()
2525
msg = <span class="hljs-string">&lt;&lt;~FOO
2626
&lt;div&gt;
2727
&lt;h4&gt;<span class="hljs-subst">#{bar}</span>&lt;/h4&gt;

test/markup/ruby/prompt.expect.txt

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
<span class="hljs-meta prompt_">jruby-1.7.16 :001 &gt;</span> <span class="hljs-string">&quot;RVM-Format&quot;</span>
99

10-
<span class="hljs-meta prompt_">&gt;&gt;</span> obj = OpenStruct.new <span class="hljs-symbol">:integer</span> =&gt; <span class="hljs-number">987</span>, <span class="hljs-symbol">:symbol</span> =&gt; <span class="hljs-symbol">:so_great</span>
10+
<span class="hljs-meta prompt_">&gt;&gt;</span> obj = <span class="hljs-title class_">OpenStruct</span>.new <span class="hljs-symbol">:integer</span> =&gt; <span class="hljs-number">987</span>, <span class="hljs-symbol">:symbol</span> =&gt; <span class="hljs-symbol">:so_great</span>
1111
=&gt; #&lt;OpenStruct integer=987, symbol=:so_great&gt;
1212
<span class="hljs-meta prompt_">&gt;&gt;</span> [obj,obj,obj]
1313
=&gt; [#&lt;OpenStruct integer=987, symbol=:so_great&gt;, #&lt;OpenStruct integer=987, symbol=:so_great&gt;, #&lt;OpenStruct integer=987, symbol=:so_great&gt;]
@@ -22,8 +22,8 @@
2222

2323
<span class="hljs-meta prompt_">irb(main):002:0&gt;</span> test = <span class="hljs-number">1</span>
2424

25-
<span class="hljs-meta prompt_">irb(main):001:1*</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Secret</span></span>
26-
<span class="hljs-meta prompt_">irb(main):002:2*</span> <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">[]</span><span class="hljs-params">(x)</span></span>
25+
<span class="hljs-meta prompt_">irb(main):001:1*</span> <span class="hljs-keyword">class</span> <span class="hljs-title class_">Secret</span>
26+
<span class="hljs-meta prompt_">irb(main):002:2*</span> <span class="hljs-keyword">def</span> <span class="hljs-title function_">[]</span>(<span class="hljs-params">x</span>)
2727
<span class="hljs-meta prompt_">irb(main):003:2*</span> <span class="hljs-string">&quot;TREASURE&quot;</span> <span class="hljs-keyword">if</span> x==<span class="hljs-number">42</span>
2828
<span class="hljs-meta prompt_">irb(main):004:1*</span> <span class="hljs-keyword">end</span>
2929
<span class="hljs-meta prompt_">irb(main):005:0&gt;</span> <span class="hljs-keyword">end</span>

0 commit comments

Comments
 (0)