From 20b77bffa41bc35864523e421ed9571bbc9a2e6d Mon Sep 17 00:00:00 2001 From: Samuel Cochran Date: Fri, 14 May 2021 21:04:43 +0800 Subject: [PATCH] Ruby: Added heredoc literals (#2885) Adds support for heredoc-style string literals in the Ruby syntax. https://ruby-doc.org/core-2.7.0/doc/syntax/literals_rdoc.html#label-Here+Documents+-28heredocs-29 This isn't perfect, but it's a good start. --- components/prism-ruby.js | 29 ++++++++ components/prism-ruby.min.js | 2 +- examples/prism-ruby.html | 5 +- tests/languages/ruby/string_feature.test | 90 +++++++++++++++++++++++- 4 files changed, 123 insertions(+), 3 deletions(-) diff --git a/components/prism-ruby.js b/components/prism-ruby.js index 9e220142d7..6c7342b68e 100644 --- a/components/prism-ruby.js +++ b/components/prism-ruby.js @@ -102,6 +102,35 @@ inside: { 'interpolation': interpolation } + }, + { + pattern: /<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i, + alias: 'heredoc-string', + greedy: true, + inside: { + 'delimiter': { + pattern: /^<<[-~]?[a-z_]\w*|[a-z_]\w*$/i, + alias: 'symbol', + inside: { + 'punctuation': /^<<[-~]?/ + } + }, + 'interpolation': interpolation + } + }, + { + pattern: /<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i, + alias: 'heredoc-string', + greedy: true, + inside: { + 'delimiter': { + pattern: /^<<[-~]?'[a-z_]\w*'|[a-z_]\w*$/i, + alias: 'symbol', + inside: { + 'punctuation': /^<<[-~]?'|'$/, + } + } + } } ]; diff --git a/components/prism-ruby.min.js b/components/prism-ruby.min.js index fb967df66d..4a0ecd4459 100644 --- a/components/prism-ruby.min.js +++ b/components/prism-ruby.min.js @@ -1 +1 @@ -!function(e){e.languages.ruby=e.languages.extend("clike",{comment:[/#.*/,{pattern:/^=begin\s[\s\S]*?^=end/m,greedy:!0}],"class-name":{pattern:/(\b(?:class)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|protected|private|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/});var n={pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"tag"},rest:e.languages.ruby}};delete e.languages.ruby.function,e.languages.insertBefore("ruby","keyword",{regex:[{pattern:RegExp("%r(?:"+["([^a-zA-Z0-9\\s{(\\[<])(?:(?!\\1)[^\\\\]|\\\\[^])*\\1","\\((?:[^()\\\\]|\\\\[^])*\\)","\\{(?:[^#{}\\\\]|#(?:\\{[^}]+\\})?|\\\\[^])*\\}","\\[(?:[^\\[\\]\\\\]|\\\\[^])*\\]","<(?:[^<>\\\\]|\\\\[^])*>"].join("|")+")[egimnosux]{0,6}"),greedy:!0,inside:{interpolation:n}},{pattern:/(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,lookbehind:!0,greedy:!0,inside:{interpolation:n}}],variable:/[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,symbol:{pattern:/(^|[^:]):[a-zA-Z_]\w*(?:[?!]|\b)/,lookbehind:!0},"method-definition":{pattern:/(\bdef\s+)[\w.]+/,lookbehind:!0,inside:{function:/\w+$/,rest:e.languages.ruby}}}),e.languages.insertBefore("ruby","number",{builtin:/\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|Fixnum|Float|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]\w*(?:[?!]|\b)/}),e.languages.ruby.string=[{pattern:RegExp("%[qQiIwWxs]?(?:"+["([^a-zA-Z0-9\\s{(\\[<])(?:(?!\\1)[^\\\\]|\\\\[^])*\\1","\\((?:[^()\\\\]|\\\\[^])*\\)","\\{(?:[^#{}\\\\]|#(?:\\{[^}]+\\})?|\\\\[^])*\\}","\\[(?:[^\\[\\]\\\\]|\\\\[^])*\\]","<(?:[^<>\\\\]|\\\\[^])*>"].join("|")+")"),greedy:!0,inside:{interpolation:n}},{pattern:/("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/,greedy:!0,inside:{interpolation:n}}],e.languages.rb=e.languages.ruby}(Prism); \ No newline at end of file +!function(e){e.languages.ruby=e.languages.extend("clike",{comment:[/#.*/,{pattern:/^=begin\s[\s\S]*?^=end/m,greedy:!0}],"class-name":{pattern:/(\b(?:class)\s+|\bcatch\s+\()[\w.\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\]/}},keyword:/\b(?:alias|and|BEGIN|begin|break|case|class|def|define_method|defined|do|each|else|elsif|END|end|ensure|extend|for|if|in|include|module|new|next|nil|not|or|prepend|protected|private|public|raise|redo|require|rescue|retry|return|self|super|then|throw|undef|unless|until|when|while|yield)\b/});var n={pattern:/#\{[^}]+\}/,inside:{delimiter:{pattern:/^#\{|\}$/,alias:"tag"},rest:e.languages.ruby}};delete e.languages.ruby.function,e.languages.insertBefore("ruby","keyword",{regex:[{pattern:RegExp("%r(?:"+["([^a-zA-Z0-9\\s{(\\[<])(?:(?!\\1)[^\\\\]|\\\\[^])*\\1","\\((?:[^()\\\\]|\\\\[^])*\\)","\\{(?:[^#{}\\\\]|#(?:\\{[^}]+\\})?|\\\\[^])*\\}","\\[(?:[^\\[\\]\\\\]|\\\\[^])*\\]","<(?:[^<>\\\\]|\\\\[^])*>"].join("|")+")[egimnosux]{0,6}"),greedy:!0,inside:{interpolation:n}},{pattern:/(^|[^/])\/(?!\/)(?:\[[^\r\n\]]+\]|\\.|[^[/\\\r\n])+\/[egimnosux]{0,6}(?=\s*(?:$|[\r\n,.;})#]))/,lookbehind:!0,greedy:!0,inside:{interpolation:n}}],variable:/[@$]+[a-zA-Z_]\w*(?:[?!]|\b)/,symbol:{pattern:/(^|[^:]):[a-zA-Z_]\w*(?:[?!]|\b)/,lookbehind:!0},"method-definition":{pattern:/(\bdef\s+)[\w.]+/,lookbehind:!0,inside:{function:/\w+$/,rest:e.languages.ruby}}}),e.languages.insertBefore("ruby","number",{builtin:/\b(?:Array|Bignum|Binding|Class|Continuation|Dir|Exception|FalseClass|File|Stat|Fixnum|Float|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]\w*(?:[?!]|\b)/}),e.languages.ruby.string=[{pattern:RegExp("%[qQiIwWxs]?(?:"+["([^a-zA-Z0-9\\s{(\\[<])(?:(?!\\1)[^\\\\]|\\\\[^])*\\1","\\((?:[^()\\\\]|\\\\[^])*\\)","\\{(?:[^#{}\\\\]|#(?:\\{[^}]+\\})?|\\\\[^])*\\}","\\[(?:[^\\[\\]\\\\]|\\\\[^])*\\]","<(?:[^<>\\\\]|\\\\[^])*>"].join("|")+")"),greedy:!0,inside:{interpolation:n}},{pattern:/("|')(?:#\{[^}]+\}|#(?!\{)|\\(?:\r\n|[\s\S])|(?!\1)[^\\#\r\n])*\1/,greedy:!0,inside:{interpolation:n}},{pattern:/<<[-~]?([a-z_]\w*)[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?[a-z_]\w*|[a-z_]\w*$/i,alias:"symbol",inside:{punctuation:/^<<[-~]?/}},interpolation:n}},{pattern:/<<[-~]?'([a-z_]\w*)'[\r\n](?:.*[\r\n])*?[\t ]*\1/i,alias:"heredoc-string",greedy:!0,inside:{delimiter:{pattern:/^<<[-~]?'[a-z_]\w*'|[a-z_]\w*$/i,alias:"symbol",inside:{punctuation:/^<<[-~]?'|'$/}}}}],e.languages.rb=e.languages.ruby}(Prism); \ No newline at end of file diff --git a/examples/prism-ruby.html b/examples/prism-ruby.html index 4f1e3906f7..58d43cd1ea 100644 --- a/examples/prism-ruby.html +++ b/examples/prism-ruby.html @@ -7,7 +7,10 @@

Comments

Strings

"foo \"bar\" baz"
-'foo \'bar\' baz'
+'foo \'bar\' baz' +<<STRING + here's some #{string} contents +STRING

Regular expressions

/foo?[ ]*bar/
diff --git a/tests/languages/ruby/string_feature.test b/tests/languages/ruby/string_feature.test index 2703abee39..f8a6473725 100644 --- a/tests/languages/ruby/string_feature.test +++ b/tests/languages/ruby/string_feature.test @@ -36,6 +36,25 @@ bar" %x[foo #{ 42 }] %x +<" + ]], + ["string", [ + ["delimiter", [ + ["punctuation", "<<"], + "STRING" + ]], + "\r\n foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + " bar\r\n", + ["delimiter", ["STRING"]] + ]], + ["string", [ + ["delimiter", [ + ["punctuation", "<<-"], + "STRING" + ]], + "\r\n foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + " bar\r\n ", + ["delimiter", ["STRING"]] + ]], + ["string", [ + ["delimiter", [ + ["punctuation", "<<~"], + "STRING" + ]], + "\r\n foo ", + ["interpolation", [ + ["delimiter", "#{"], + ["number", "42"], + ["delimiter", "}"] + ]], + " bar\r\n ", + ["delimiter", ["STRING"]] + ]], + ["string", [ + ["delimiter", [ + ["punctuation", "<<'"], + "STRING", + ["punctuation", "'"] + ]], + "\r\n foo #{42} bar\r\n", + ["delimiter", ["STRING"]] + ]], + ["string", [ + ["delimiter", [ + ["punctuation", "<<-'"], + "STRING", + ["punctuation", "'"] + ]], + "\r\n foo #{42} bar\r\n ", + ["delimiter", ["STRING"]] + ]], + ["string", [ + ["delimiter", [ + ["punctuation", "<<~'"], + "STRING", + ["punctuation", "'"] + ]], + "\r\n foo #{42} bar\r\n ", + ["delimiter", ["STRING"]] ]] ] ---------------------------------------------------- -Checks for strings and string interpolation. \ No newline at end of file +Checks for strings and string interpolation.