This is a multi-part message in MIME format.
--------------050607010203070700060801
Content-Type: text/plain; charset=ISO-8859-1; format=flowed
Content-Transfer-Encoding: 7bit

At the moment, ruby-mode.el uses font-lock-keywords as opposed to 
font-lock-syntactic-keywords to highlight here-doc strings. This means 
that Emacs doesn't actually recognize them as strings, so unbalanced 
quotes paint the whole buffer in font-lock-string-face. In addition, it 
improperly highlights strings that look like nested heredocs, like the 
following:

<<FOO
<<BAR
BAR
FOO

The attached patch uses font-lock-syntactic-keywords instead, so that 
heredocs actually register as strings, so stray quotation marks don't 
wreak havoc.

- Nathan


--------------050607010203070700060801
Content-Type: text/x-diff;
 nameere-doc.patch"
Content-Transfer-Encoding: 7bit
Content-Disposition: inline;
 filenameere-doc.patch"

Index: ruby-mode.el
--- ruby-mode.el	(revision 198)
+++ ruby-mode.el	(working copy)
@@ -48,16 +48,26 @@
 (defconst ruby-block-end-re "\\<end\\>")
 
 (defconst ruby-here-doc-beg-re
-  "<<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)")
+  "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)")
 
+(defconst ruby-here-doc-end-re
+  "^\\([ \t]+\\)?\\(.*\\)\\(.\\)$")
+
 (defun ruby-here-doc-end-match ()
   (concat "^"
-	  (if (match-string 1) "[ \t]*" nil)
+	  (if (match-string 2) "[ \t]*" nil)
 	  (regexp-quote
-	   (or (match-string 3)
-	       (match-string 4)
-	       (match-string 5)))))
+	   (or (match-string 4)
+	       (match-string 5)
+	       (match-string 6)))))
 
+(defun ruby-here-doc-beg-match ()
+  (let ((contents (regexp-quote (concat (match-string 2) (match-string 3)))))
+    (concat "<<"
+            (if (match-string 1)
+                (concat "\\(?:-\\|\\([\"']\\)" (match-string 1) contents "\\1\\)")
+              (concat "-?\\([\"']\\|\\)" contents "\\1")))))
+
 (defconst ruby-delimiter
   (concat "[?$/%(){}#\"'`.:]\\|<<\\|\\[\\|\\]\\|\\<\\("
 	  ruby-block-beg-re
@@ -1007,7 +1017,7 @@
       (setq font-lock-variable-name-face font-lock-type-face))
 
   (setq ruby-font-lock-syntactic-keywords
-	'(
+	`(
 	  ;; #{ }, #$hoge, #@foo are not comments
 	  ("\\(#\\)[{$@]" 1 (1 . nil))
 	  ;; the last $', $", $` in the respective string is not variable
@@ -1023,8 +1033,29 @@
 	   (4 (7 . ?/))
 	   (6 (7 . ?/)))
 	  ("^\\()begin\\(\\s \\|$\\)" 1 (7 . nil))
-	  ("^\\()end\\(\\s \\|$\\)" 1 (7 . nil))))
+	  ("^\\()end\\(\\s \\|$\\)" 1 (7 . nil))
+          ("^\\()end\\(\\s \\|$\\)" 1 (7 . nil))
+ 	  (,ruby-here-doc-beg-re 1 (ruby-here-doc-beg-syntax))
+ 	  (,ruby-here-doc-end-re 3 (ruby-here-doc-end-syntax))))
 
+  (defun ruby-in-here-doc-p ()
+    (save-excursion
+      (let ((old-point (point)))
+        (and (re-search-backward ruby-here-doc-beg-re nil t)
+             (not (re-search-forward (ruby-here-doc-end-match) old-point t))))))
+
+  (defun ruby-here-doc-beg-syntax ()
+    (save-excursion
+      (goto-char (match-beginning 0))
+      (unless (ruby-in-here-doc-p) (string-to-syntax "|"))))
+
+  (defun ruby-here-doc-end-syntax ()
+    (save-excursion
+      (goto-char (match-beginning 0))
+      (if (and (re-search-backward (ruby-here-doc-beg-match) nil t)
+               (not (ruby-in-here-doc-p)))
+          (string-to-syntax "|"))))
+
   (if (featurep 'xemacs)
       (put 'ruby-mode 'font-lock-defaults
 	   '((ruby-font-lock-keywords)
@@ -1064,34 +1095,6 @@
       (modify-syntax-entry ?_ "w" tbl)
       tbl))
 
-  (defun ruby-font-lock-here-docs (limit)
-    (if (re-search-forward ruby-here-doc-beg-re limit t)
-	(let (beg)
-	  (beginning-of-line)
-          (forward-line)
-	  (setq beg (point))
-	  (if (re-search-forward (ruby-here-doc-end-match) nil t)
-	      (progn
-		(set-match-data (list beg (point)))
-		t)))))
-
-  (defun ruby-font-lock-maybe-here-docs (limit)
-    (let (beg)
-      (save-excursion
-	(if (re-search-backward ruby-here-doc-beg-re nil t)
-	    (progn
-	      (beginning-of-line)
-              (forward-line)
-	      (setq beg (point)))))
-      (if (and beg
-	       (let ((end-match (ruby-here-doc-end-match)))
-                 (and (not (re-search-backward end-match beg t))
-		      (re-search-forward end-match nil t))))
-	  (progn
-	    (set-match-data (list beg (point)))
-	    t)
-          nil)))
-
   (defvar ruby-font-lock-keywords
     (list
      ;; functions
@@ -1154,13 +1157,6 @@
        0 font-lock-comment-face t)
      '(ruby-font-lock-maybe-docs
        0 font-lock-comment-face t)
-     ;; "here" document
-     '(ruby-font-lock-here-docs
-       0 font-lock-string-face t)
-     '(ruby-font-lock-maybe-here-docs
-       0 font-lock-string-face t)
-     `(,ruby-here-doc-beg-re
-       0 font-lock-string-face t)
      ;; general delimited string
      '("\\(^\\|[[ \t\n<+(,\)\\(%[xrqQwW]?\\([^<[{(a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\3\\)\\)"
        (2 font-lock-string-face))

--------------050607010203070700060801--