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.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176
diff --git a/components/prism-ruby.js b/components/prism-ruby.js
index 9e22014..6c7342b 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 fb967df..4a0ecd4 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 4f1e390..58d43cd 100644
--- a/examples/prism-ruby.html
+++ b/examples/prism-ruby.html
@@ -7,7 +7,10 @@ comment
<h2>Strings</h2>
<pre><code>"foo \"bar\" baz"
-'foo \'bar\' baz'</code></pre>
+'foo \'bar\' baz'
+<<STRING
+ here's some #{string} contents
+STRING</code></pre>
<h2>Regular expressions</h2>
<pre><code>/foo?[ ]*bar/</code></pre>
diff --git a/tests/languages/ruby/string_feature.test b/tests/languages/ruby/string_feature.test
index 2703abe..f8a6473 100644
--- a/tests/languages/ruby/string_feature.test
+++ b/tests/languages/ruby/string_feature.test
@@ -36,6 +36,25 @@ bar"
%x[foo #{ 42 }]
%x<foo #{ 42 }>
+<<STRING
+ foo #{42} bar
+STRING
+ <<-STRING
+ foo #{42} bar
+ STRING
+ <<~STRING
+ foo #{42} bar
+ STRING
+<<'STRING'
+ foo #{42} bar
+STRING
+ <<-'STRING'
+ foo #{42} bar
+ STRING
+ <<~'STRING'
+ foo #{42} bar
+ STRING
+
----------------------------------------------------
[
@@ -279,9 +298,78 @@ bar"
["delimiter", "}"]
]],
">"
+ ]],
+ ["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.