* 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.
This commit is contained in:
Dmitry Gutov 2012-12-14 10:58:15 +04:00
parent dbb530d988
commit bb808526ae
4 changed files with 122 additions and 66 deletions

View file

@ -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 <lekktu@gmail.com>

View file

@ -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)

View file

@ -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 <rgm@gnu.org>

View file

@ -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