Merge from emacs-24; up to 2012-12-06T01:39:03Z!monnier@iro.umontreal.ca
[bpt/emacs.git] / lisp / progmodes / ruby-mode.el
index 6b9e921..a42a66d 100644 (file)
@@ -1,13 +1,13 @@
 ;;; ruby-mode.el --- Major mode for editing Ruby files
 
-;; Copyright (C) 1994-201 Free Software Foundation, Inc.
+;; Copyright (C) 1994-2013 Free Software Foundation, Inc.
 
 ;; Authors: Yukihiro Matsumoto
 ;;     Nobuyoshi Nakada
 ;; URL: http://www.emacswiki.org/cgi-bin/wiki/RubyMode
 ;; Created: Fri Feb  4 14:49:13 JST 1994
 ;; Keywords: languages ruby
-;; Version: 1.0
+;; Version: 1.2
 
 ;; This file is part of GNU Emacs.
 
@@ -64,8 +64,9 @@
   "Regexp to match keywords that nest without blocks.")
 
 (defconst ruby-indent-beg-re
-  (concat "^\\s *" (regexp-opt '("class" "module" "def" "if" "unless" "case"
-                                 "while" "until" "for" "begin")) "\\_>")
+  (concat "^\\(\\s *" (regexp-opt '("class" "module" "def")) "\\|"
+          (regexp-opt '("if" "unless" "case" "while" "until" "for" "begin"))
+          "\\)\\_>")
   "Regexp to match where the indentation gets deeper.")
 
 (defconst ruby-modifier-beg-keywords
   '"\\(def\\|class\\|module\\)"
   "Regexp to match the beginning of a defun, in the general sense.")
 
+(defconst ruby-singleton-class-re
+  "class\\s *<<"
+  "Regexp to match the beginning of a singleton class context.")
+
 (eval-and-compile
   (defconst ruby-here-doc-beg-re
   "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)"
@@ -384,7 +389,7 @@ and `\\' when preceded by `?'."
     (when pos (goto-char pos))
     (forward-word -1)
     (and (or (bolp) (not (eq (char-before (point)) ?_)))
-         (looking-at "class\\s *<<"))))
+         (looking-at ruby-singleton-class-re))))
 
 (defun ruby-expr-beg (&optional option)
   "Check if point is possibly at the beginning of an expression.
@@ -1057,35 +1062,32 @@ For example:
 See `add-log-current-defun-function'."
   (condition-case nil
       (save-excursion
-        (let (mname mlist (indent 0))
+        (let ((indent 0) mname mlist
+              (start (point))
+              (definition-re
+                (concat "^[ \t]*" ruby-defun-beg-re "[ \t]+"
+                        "\\("
+                        ;; \\. and :: for class methods
+                        "\\([A-Za-z_]" ruby-symbol-re "*\\|\\.\\|::" "\\)"
+                        "+\\)")))
           ;; Get the current method definition (or class/module).
-          (if (re-search-backward
-               (concat "^[ \t]*" ruby-defun-beg-re "[ \t]+"
-                       "\\("
-                       ;; \\. and :: for class methods
-                       "\\([A-Za-z_]" ruby-symbol-re "*\\|\\.\\|::" "\\)"
-                       "+\\)")
-               nil t)
-              (progn
-                (setq mname (match-string 2))
-                (unless (string-equal "def" (match-string 1))
-                  (setq mlist (list mname) mname nil))
-                (goto-char (match-beginning 1))
-                (setq indent (current-column))
-                (beginning-of-line)))
+          (when (re-search-backward definition-re nil t)
+            (goto-char (match-beginning 1))
+            (when (ruby-block-contains-point start)
+              ;; We're inside the method, class or module.
+              (setq mname (match-string 2))
+              (unless (string-equal "def" (match-string 1))
+                (setq mlist (list mname) mname nil)))
+            (setq indent (current-column))
+            (beginning-of-line))
           ;; Walk up the class/module nesting.
           (while (and (> indent 0)
-                      (re-search-backward
-                       (concat
-                        "^[ \t]*\\(class\\|module\\)[ \t]+"
-                        "\\([A-Z]" ruby-symbol-re "*\\)")
-                       nil t))
+                      (re-search-backward definition-re nil t))
             (goto-char (match-beginning 1))
-            (if (< (current-column) indent)
-                (progn
-                  (setq mlist (cons (match-string 2) mlist))
-                  (setq indent (current-column))
-                  (beginning-of-line))))
+            (when (ruby-block-contains-point start)
+              (setq mlist (cons (match-string 2) mlist))
+              (setq indent (current-column))
+              (beginning-of-line)))
           ;; Process the method name.
           (when mname
             (let ((mn (split-string mname "\\.\\|::")))
@@ -1104,7 +1106,14 @@ See `add-log-current-defun-function'."
                           (setcdr (last mlist) (butlast mn))
                         (setq mlist (butlast mn))))
                     (setq mname (concat "." (car (last mn)))))
-                (setq mname (concat "#" mname)))))
+                ;; See if the method is in singleton class context.
+                (let ((in-singleton-class
+                       (when (re-search-forward ruby-singleton-class-re start t)
+                         (goto-char (match-beginning 0))
+                         (ruby-block-contains-point start))))
+                  (setq mname (concat
+                               (if in-singleton-class "." "#")
+                               mname))))))
           ;; Generate the string.
           (if (consp mlist)
               (setq mlist (mapconcat (function identity) mlist "::")))
@@ -1112,6 +1121,12 @@ See `add-log-current-defun-function'."
               (if mlist (concat mlist mname) mname)
             mlist)))))
 
+(defun ruby-block-contains-point (pt)
+  (save-excursion
+    (save-match-data
+      (ruby-forward-sexp)
+      (> (point) pt))))
+
 (defun ruby-brace-to-do-end (orig end)
   (let (beg-marker end-marker)
     (goto-char end)
@@ -1326,7 +1341,7 @@ It will be properly highlighted even when the call omits parens."))
         (goto-char start)
         ;; Find all expression expansions and
         ;; - save the match data to a text property, for font-locking later,
-        ;; - set the syntax of all double quotes and backticks to puctuation.
+        ;; - set the syntax of all double quotes and backticks to punctuation.
         (while (re-search-forward ruby-expression-expansion-re end 'move)
           (let ((beg (match-beginning 2))
                 (end (match-end 2)))
@@ -1668,7 +1683,9 @@ The variable `ruby-indent-level' controls the amount of indentation.
 ;;;###autoload
 (add-to-list 'auto-mode-alist (cons (purecopy "\\.rb\\'") 'ruby-mode))
 ;;;###autoload
-(add-to-list 'auto-mode-alist '("Rakefile\\'" . ruby-mode))
+(add-to-list 'auto-mode-alist (cons (purecopy "Rakefile\\'") 'ruby-mode))
+;;;###autoload
+(add-to-list 'auto-mode-alist (cons (purecopy "\\.gemspec\\'") 'ruby-mode))
 
 ;;;###autoload
 (dolist (name (list "ruby" "rbx" "jruby" "ruby1.9" "ruby1.8"))