From 2d37800819505ffb778183d72597a56a82fdfc1d Mon Sep 17 00:00:00 2001 From: Golmote Date: Thu, 3 Sep 2015 22:16:03 +0200 Subject: [PATCH] Ruby: Add % notations for strings and regexps. Fix #590 --- components/prism-ruby.js | 126 ++++++++--- components/prism-ruby.min.js | 2 +- tests/languages/ruby/regex_feature.test | 32 ++- tests/languages/ruby/string_feature.test | 261 ++++++++++++++++++++++- 4 files changed, 381 insertions(+), 40 deletions(-) diff --git a/components/prism-ruby.js b/components/prism-ruby.js index e8e220b504..10e8b5002d 100644 --- a/components/prism-ruby.js +++ b/components/prism-ruby.js @@ -4,37 +4,107 @@ * Adds the following new token classes: * constant, builtin, variable, symbol, regex */ -Prism.languages.ruby = Prism.languages.extend('clike', { - 'comment': /#(?!\{[^\r\n]*?\}).*/, - 'keyword': /\b(alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/ -}); +(function(Prism) { + Prism.languages.ruby = Prism.languages.extend('clike', { + 'comment': /#(?!\{[^\r\n]*?\}).*/, + 'keyword': /\b(alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/ + }); -Prism.languages.insertBefore('ruby', 'keyword', { - 'regex': { - pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/, - lookbehind: true - }, - 'variable': /[@$]+[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/, - 'symbol': /:[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/ -}); + var interpolation = { + pattern: /#\{[^}]+\}/, + inside: { + 'delimiter': { + pattern: /^#\{|\}$/, + alias: 'tag' + }, + rest: Prism.util.clone(Prism.languages.ruby) + } + }; + + Prism.languages.insertBefore('ruby', 'keyword', { + 'regex': [ + { + pattern: /%r([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1[gim]{0,3}/, + inside: { + 'interpolation': interpolation + } + }, + { + pattern: /%r\((?:[^()\\]|\\[\s\S])*\)[gim]{0,3}/, + inside: { + 'interpolation': interpolation + } + }, + { + // Here we need to specifically allow interpolation + pattern: /%r\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}[gim]{0,3}/, + inside: { + 'interpolation': interpolation + } + }, + { + pattern: /%r\[(?:[^\[\]\\]|\\[\s\S])*\][gim]{0,3}/, + inside: { + 'interpolation': interpolation + } + }, + { + pattern: /%r<(?:[^<>\\]|\\[\s\S])*>[gim]{0,3}/, + inside: { + 'interpolation': interpolation + } + }, + { + pattern: /(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/, + lookbehind: true + } + ], + 'variable': /[@$]+[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/, + 'symbol': /:[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/ + }); -Prism.languages.insertBefore('ruby', 'number', { - 'builtin': /\b(Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|File|Fixnum|Fload|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/, - 'constant': /\b[A-Z][a-zA-Z_0-9]*(?:[?!]|\b)/ -}); + Prism.languages.insertBefore('ruby', 'number', { + 'builtin': /\b(Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|File|Fixnum|Fload|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/, + 'constant': /\b[A-Z][a-zA-Z_0-9]*(?:[?!]|\b)/ + }); -Prism.languages.ruby.string = { - pattern: /("|')(#\{[^}]+\}|\\(?:\r?\n|\r)|\\?.)*?\1/, - inside: { - 'interpolation': { - pattern: /#\{[^}]+\}/, + Prism.languages.ruby.string = [ + { + pattern: /%[qQiIwWxs]?([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1/, + inside: { + 'interpolation': interpolation + } + }, + { + pattern: /%[qQiIwWxs]?\((?:[^()\\]|\\[\s\S])*\)/, + inside: { + 'interpolation': interpolation + } + }, + { + // Here we need to specifically allow interpolation + pattern: /%[qQiIwWxs]?\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/, + inside: { + 'interpolation': interpolation + } + }, + { + pattern: /%[qQiIwWxs]?\[(?:[^\[\]\\]|\\[\s\S])*\]/, + inside: { + 'interpolation': interpolation + } + }, + { + pattern: /%[qQiIwWxs]?<(?:[^<>\\]|\\[\s\S])*>/, + inside: { + 'interpolation': interpolation + } + }, + { + pattern: /("|')(#\{[^}]+\}|\\(?:\r?\n|\r)|\\?.)*?\1/, inside: { - 'delimiter': { - pattern: /^#\{|\}$/, - alias: 'tag' - }, - rest: Prism.util.clone(Prism.languages.ruby) + 'interpolation': interpolation } } - } -}; + ]; +}(Prism)); \ No newline at end of file diff --git a/components/prism-ruby.min.js b/components/prism-ruby.min.js index 675a76c3d6..637187c854 100644 --- a/components/prism-ruby.min.js +++ b/components/prism-ruby.min.js @@ -1 +1 @@ -Prism.languages.ruby=Prism.languages.extend("clike",{comment:/#(?!\{[^\r\n]*?\}).*/,keyword:/\b(alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/}),Prism.languages.insertBefore("ruby","keyword",{regex:{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0},variable:/[@$]+[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/,symbol:/:[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/}),Prism.languages.insertBefore("ruby","number",{builtin:/\b(Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|File|Fixnum|Fload|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,constant:/\b[A-Z][a-zA-Z_0-9]*(?:[?!]|\b)/}),Prism.languages.ruby.string={pattern:/("|')(#\{[^}]+\}|\\(?:\r?\n|\r)|\\?.)*?\1/,inside:{interpolation:{pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"tag"},rest:Prism.util.clone(Prism.languages.ruby)}}}}; \ No newline at end of file +!function(e){e.languages.ruby=e.languages.extend("clike",{comment:/#(?!\{[^\r\n]*?\}).*/,keyword:/\b(alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|false|for|if|in|module|new|next|nil|not|or|raise|redo|require|rescue|retry|return|self|super|then|throw|true|undef|unless|until|when|while|yield)\b/});var n={pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"tag"},rest:e.util.clone(e.languages.ruby)}};e.languages.insertBefore("ruby","keyword",{regex:[{pattern:/%r([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1[gim]{0,3}/,inside:{interpolation:n}},{pattern:/%r\((?:[^()\\]|\\[\s\S])*\)[gim]{0,3}/,inside:{interpolation:n}},{pattern:/%r\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}[gim]{0,3}/,inside:{interpolation:n}},{pattern:/%r\[(?:[^\[\]\\]|\\[\s\S])*\][gim]{0,3}/,inside:{interpolation:n}},{pattern:/%r<(?:[^<>\\]|\\[\s\S])*>[gim]{0,3}/,inside:{interpolation:n}},{pattern:/(^|[^/])\/(?!\/)(\[.+?]|\\.|[^/\r\n])+\/[gim]{0,3}(?=\s*($|[\r\n,.;})]))/,lookbehind:!0}],variable:/[@$]+[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/,symbol:/:[a-zA-Z_][a-zA-Z_0-9]*(?:[?!]|\b)/}),e.languages.insertBefore("ruby","number",{builtin:/\b(Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|File|Fixnum|Fload|Hash|Integer|IO|MatchData|Method|Module|NilClass|Numeric|Object|Proc|Range|Regexp|String|Struct|TMS|Symbol|ThreadGroup|Thread|Time|TrueClass)\b/,constant:/\b[A-Z][a-zA-Z_0-9]*(?:[?!]|\b)/}),e.languages.ruby.string=[{pattern:/%[qQiIwWxs]?([^a-zA-Z0-9\s\{\(\[<])(?:[^\\]|\\[\s\S])*?\1/,inside:{interpolation:n}},{pattern:/%[qQiIwWxs]?\((?:[^()\\]|\\[\s\S])*\)/,inside:{interpolation:n}},{pattern:/%[qQiIwWxs]?\{(?:[^#{}\\]|#(?:\{[^}]+\})?|\\[\s\S])*\}/,inside:{interpolation:n}},{pattern:/%[qQiIwWxs]?\[(?:[^\[\]\\]|\\[\s\S])*\]/,inside:{interpolation:n}},{pattern:/%[qQiIwWxs]?<(?:[^<>\\]|\\[\s\S])*>/,inside:{interpolation:n}},{pattern:/("|')(#\{[^}]+\}|\\(?:\r?\n|\r)|\\?.)*?\1/,inside:{interpolation:n}}]}(Prism); \ No newline at end of file diff --git a/tests/languages/ruby/regex_feature.test b/tests/languages/ruby/regex_feature.test index da20fe2930..0dee02d34d 100644 --- a/tests/languages/ruby/regex_feature.test +++ b/tests/languages/ruby/regex_feature.test @@ -1,13 +1,43 @@ /[foo]\/bar/gim /[bar]/, /./i; +%r!foo?bar#{39+3}! +%r(foo?bar#{39+3}) +%r{foo?bar#{39+3}} +%r[foo?bar#{39+3}] +%r ---------------------------------------------------- [ ["regex", "/[foo]\\/bar/gim"], ["regex", "/[bar]/"], ["punctuation", ","], - ["regex", "/./i"], ["punctuation", ";"] + ["regex", "/./i"], ["punctuation", ";"], + ["regex", ["%r!foo?bar", ["interpolation", [ + ["delimiter", "#{"], + ["number", "39"], ["operator", "+"], ["number", "3"], + ["delimiter", "}"] + ]], "!"]], + ["regex", ["%r(foo?bar", ["interpolation", [ + ["delimiter", "#{"], + ["number", "39"], ["operator", "+"], ["number", "3"], + ["delimiter", "}"] + ]], ")"]], + ["regex", ["%r{foo?bar", ["interpolation", [ + ["delimiter", "#{"], + ["number", "39"], ["operator", "+"], ["number", "3"], + ["delimiter", "}"] + ]], "}"]], + ["regex", ["%r[foo?bar", ["interpolation", [ + ["delimiter", "#{"], + ["number", "39"], ["operator", "+"], ["number", "3"], + ["delimiter", "}"] + ]], "]"]], + ["regex", ["%r"]] ] ---------------------------------------------------- diff --git a/tests/languages/ruby/string_feature.test b/tests/languages/ruby/string_feature.test index 889ab14e91..810a844798 100644 --- a/tests/languages/ruby/string_feature.test +++ b/tests/languages/ruby/string_feature.test @@ -7,9 +7,34 @@ bar' "foo\ bar" -'foo #{42} bar' "foo #{ 42 } bar" +%!foo #{ 42 }! +%(foo #{ 42 }) +%{foo #{ 42 }} +%[foo #{ 42 }] +% +%Q!foo #{ 42 }! +%Q(foo #{ 42 }) +%Q{foo #{ 42 }} +%Q[foo #{ 42 }] +%Q +%I!foo #{ 42 }! +%I(foo #{ 42 }) +%I{foo #{ 42 }} +%I[foo #{ 42 }] +%I +%W!foo #{ 42 }! +%W(foo #{ 42 }) +%W{foo #{ 42 }} +%W[foo #{ 42 }] +%W +%x!foo #{ 42 }! +%x(foo #{ 42 }) +%x{foo #{ 42 }} +%x[foo #{ 42 }] +%x + ---------------------------------------------------- [ @@ -19,15 +44,6 @@ bar" ["string", ["\"foo\""]], ["string", ["'foo\\\r\nbar'"]], ["string", ["\"foo\\\r\nbar\""]], - ["string", [ - "'foo ", - ["interpolation", [ - ["delimiter", "#{"], - ["number", "42"], - ["delimiter", "}"] - ]], - " bar'" - ]], ["string", [ "\"foo ", ["interpolation", [ @@ -36,6 +52,231 @@ bar" ["delimiter", "}"] ]], " bar\"" + ]], + ["string", [ + "%!foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "!" + ]], + ["string", [ + "%(foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + ")" + ]], + ["string", [ + "%{foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "}" + ]], + ["string", [ + "%[foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "]" + ]], + ["string", [ + "%" + ]], + ["string", [ + "%Q!foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "!" + ]], + ["string", [ + "%Q(foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + ")" + ]], + ["string", [ + "%Q{foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "}" + ]], + ["string", [ + "%Q[foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "]" + ]], + ["string", [ + "%Q" + ]], + ["string", [ + "%I!foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "!" + ]], + ["string", [ + "%I(foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + ")" + ]], + ["string", [ + "%I{foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "}" + ]], + ["string", [ + "%I[foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "]" + ]], + ["string", [ + "%I" + ]], + ["string", [ + "%W!foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "!" + ]], + ["string", [ + "%W(foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + ")" + ]], + ["string", [ + "%W{foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "}" + ]], + ["string", [ + "%W[foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "]" + ]], + ["string", [ + "%W" + ]], + ["string", [ + "%x!foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "!" + ]], + ["string", [ + "%x(foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + ")" + ]], + ["string", [ + "%x{foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "}" + ]], + ["string", [ + "%x[foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + "]" + ]], + ["string", [ + "%x" ]] ]