From bb808526ae2847f1e9aa6559835da2a10545a273 Mon Sep 17 00:00:00 2001 From: Dmitry Gutov Date: Fri, 14 Dec 2012 10:58:15 +0400 Subject: [PATCH] * lisp/progmodes/ruby-mode.el (ruby-syntax-propertize-function): Extract `ruby-syntax-propertize-expansions'. (ruby-syntax-propertize-expansions): Only change syntax on certain string delimiters, to punctuation. This way the common functions like forward-word and thing-at-point still work. (ruby-match-expression-expansion): Improve readability. (ruby-block-contains-point): New function. (ruby-add-log-current-method): Handle several edge cases. * test/automated/ruby-mode-tests.el Rename one interpolation test; add three more. (ruby-with-temp-buffer): New macro, use it where appropriate. (ruby-add-log-current-method-examples): Use "_" for target point. Add four tests for ruby-add-log-current-method. --- lisp/ChangeLog | 2 + lisp/progmodes/ruby-mode.el | 68 +++++++++++------- test/ChangeLog | 3 + test/automated/ruby-mode-tests.el | 115 ++++++++++++++++++++---------- 4 files changed, 122 insertions(+), 66 deletions(-) diff --git a/lisp/ChangeLog b/lisp/ChangeLog index 2d12a357cbf..8df55eaa108 100644 --- a/lisp/ChangeLog +++ b/lisp/ChangeLog @@ -6,6 +6,8 @@ certain string delimiters, to punctuation. This way the common functions like forward-word and thing-at-point still work. (ruby-match-expression-expansion): Improve readability. + (ruby-block-contains-point): New function. + (ruby-add-log-current-method): Handle several edge cases. 2012-12-13 Juanma Barranquero diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el index 6b9e921be67..8ac2f659058 100644 --- a/lisp/progmodes/ruby-mode.el +++ b/lisp/progmodes/ruby-mode.el @@ -102,6 +102,10 @@ '"\\(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 +388,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 +1061,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 +1105,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 +1120,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) diff --git a/test/ChangeLog b/test/ChangeLog index ccebdda7411..e7e7c755d02 100644 --- a/test/ChangeLog +++ b/test/ChangeLog @@ -2,6 +2,9 @@ * automated/ruby-mode-tests.el Rename one interpolation test; add three more. + (ruby-with-temp-buffer): New macro, use it where appropriate. + (ruby-add-log-current-method-examples): Use "_" for target point. + Add four new tests for ruby-add-log-current-method. 2012-12-11 Glenn Morris diff --git a/test/automated/ruby-mode-tests.el b/test/automated/ruby-mode-tests.el index 6ae23f94f1a..1f0c0ab6f9e 100644 --- a/test/automated/ruby-mode-tests.el +++ b/test/automated/ruby-mode-tests.el @@ -25,9 +25,7 @@ (defun ruby-should-indent (content column) "Assert indentation COLUMN on the last line of CONTENT." - (with-temp-buffer - (insert content) - (ruby-mode) + (ruby-with-temp-buffer content (ruby-indent-line) (should (= (current-indentation) column)))) @@ -35,12 +33,17 @@ "Assert that CONTENT turns into EXPECTED after the buffer is re-indented. The whitespace before and including \"|\" on each line is removed." - (with-temp-buffer - (insert (ruby-test-string content)) - (ruby-mode) + (ruby-with-temp-buffer (ruby-test-string content) (indent-region (point-min) (point-max)) (should (string= (ruby-test-string expected) (buffer-string))))) +(defmacro ruby-with-temp-buffer (contents &rest body) + (declare (indent 1) (debug t)) + `(with-temp-buffer + (insert ,contents) + (ruby-mode) + ,@body)) + (defun ruby-test-string (s &rest args) (apply 'format (replace-regexp-in-string "^[ \t]*|" "" s) args)) @@ -48,9 +51,7 @@ The whitespace before and including \"|\" on each line is removed." "Assert syntax state values at the end of CONTENT. VALUES-PLIST is a list with alternating index and value elements." - (with-temp-buffer - (insert content) - (ruby-mode) + (ruby-with-temp-buffer content (syntax-propertize (point)) (while values-plist (should (eq (nth (car values-plist) @@ -59,9 +60,7 @@ VALUES-PLIST is a list with alternating index and value elements." (setq values-plist (cddr values-plist))))) (defun ruby-assert-face (content pos face) - (with-temp-buffer - (insert content) - (ruby-mode) + (ruby-with-temp-buffer content (font-lock-fontify-buffer) (should (eq face (get-text-property pos 'face))))) @@ -226,17 +225,13 @@ VALUES-PLIST is a list with alternating index and value elements." |")) (ert-deftest ruby-move-to-block-stops-at-indentation () - (with-temp-buffer - (insert "def f\nend") + (ruby-with-temp-buffer "def f\nend" (beginning-of-line) - (ruby-mode) (ruby-move-to-block -1) (should (looking-at "^def")))) (ert-deftest ruby-toggle-block-to-do-end () - (with-temp-buffer - (insert "foo {|b|\n}") - (ruby-mode) + (ruby-with-temp-buffer "foo {|b|\n}" (beginning-of-line) (ruby-toggle-block) (should (string= "foo do |b|\nend" (buffer-string))))) @@ -254,9 +249,7 @@ VALUES-PLIST is a list with alternating index and value elements." (should (string= (cdr pair) (buffer-string)))))))) (ert-deftest ruby-toggle-block-to-multiline () - (with-temp-buffer - (insert "foo {|b| b + 1}") - (ruby-mode) + (ruby-with-temp-buffer "foo {|b| b + 1}" (beginning-of-line) (ruby-toggle-block) (should (string= "foo do |b|\n b + 1\nend" (buffer-string))))) @@ -295,9 +288,8 @@ VALUES-PLIST is a list with alternating index and value elements." (ert-deftest ruby-interpolation-keeps-non-quote-syntax () (let ((s "\"foo#{baz.tee}bar\"")) - (with-temp-buffer - (save-excursion - (insert s)) + (ruby-with-temp-buffer s + (goto-char (point-min)) (ruby-mode) (font-lock-fontify-buffer) (search-forward "tee") @@ -318,21 +310,66 @@ VALUES-PLIST is a list with alternating index and value elements." ("self.foo" . ".foo")))) (dolist (pair pairs) (let ((name (car pair)) - (value (cdr pair))) - (with-temp-buffer - (insert (ruby-test-string - "module M - | class C - | def %s - | end - | end - |end" - name)) - (ruby-mode) - (search-backward "def") - (forward-line) - (should (string= (ruby-add-log-current-method) - (format "M::C%s" value)))))))) + (value (cdr pair))) + (ruby-with-temp-buffer (ruby-test-string + "module M + | class C + | def %s + | _ + | end + | end + |end" + name) + (search-backward "_") + (forward-line) + (should (string= (ruby-add-log-current-method) + (format "M::C%s" value)))))))) + +(ert-deftest ruby-add-log-current-method-outside-of-method () + (ruby-with-temp-buffer (ruby-test-string + "module M + | class C + | def foo + | end + | _ + | end + |end") + (search-backward "_") + (should (string= (ruby-add-log-current-method)"M::C")))) + +(ert-deftest ruby-add-log-current-method-in-singleton-class () + (ruby-with-temp-buffer (ruby-test-string + "class C + | class << self + | def foo + | _ + | end + | end + |end") + (search-backward "_") + (should (string= (ruby-add-log-current-method) "C.foo")))) + +(ert-deftest ruby-add-log-current-method-namespace-shorthand () + (ruby-with-temp-buffer (ruby-test-string + "class C::D + | def foo + | _ + | end + |end") + (search-backward "_") + (should (string= (ruby-add-log-current-method) "C::D#foo")))) + +(ert-deftest ruby-add-log-current-method-after-inner-class () + (ruby-with-temp-buffer (ruby-test-string + "module M + | class C + | class D + | end + | _ + | end + |end") + (search-backward "_") + (should (string= (ruby-add-log-current-method) "M::C")))) (defvar ruby-block-test-example (ruby-test-string -- 2.39.5