diff options
| author | Dmitry Gutov | 2012-12-14 10:58:15 +0400 |
|---|---|---|
| committer | Dmitry Gutov | 2012-12-14 10:58:15 +0400 |
| commit | bb808526ae2847f1e9aa6559835da2a10545a273 (patch) | |
| tree | 98fea65f31b2de5192163bea1d25beab29cb5044 | |
| parent | dbb530d9887fd51de9f8e338b325537d9eac0a3a (diff) | |
| download | emacs-bb808526ae2847f1e9aa6559835da2a10545a273.tar.gz emacs-bb808526ae2847f1e9aa6559835da2a10545a273.zip | |
* 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.
| -rw-r--r-- | lisp/ChangeLog | 2 | ||||
| -rw-r--r-- | lisp/progmodes/ruby-mode.el | 68 | ||||
| -rw-r--r-- | test/ChangeLog | 3 | ||||
| -rw-r--r-- | 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 @@ | |||
| 6 | certain string delimiters, to punctuation. This way the common | 6 | certain string delimiters, to punctuation. This way the common |
| 7 | functions like forward-word and thing-at-point still work. | 7 | functions like forward-word and thing-at-point still work. |
| 8 | (ruby-match-expression-expansion): Improve readability. | 8 | (ruby-match-expression-expansion): Improve readability. |
| 9 | (ruby-block-contains-point): New function. | ||
| 10 | (ruby-add-log-current-method): Handle several edge cases. | ||
| 9 | 11 | ||
| 10 | 2012-12-13 Juanma Barranquero <lekktu@gmail.com> | 12 | 2012-12-13 Juanma Barranquero <lekktu@gmail.com> |
| 11 | 13 | ||
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 @@ | |||
| 102 | '"\\(def\\|class\\|module\\)" | 102 | '"\\(def\\|class\\|module\\)" |
| 103 | "Regexp to match the beginning of a defun, in the general sense.") | 103 | "Regexp to match the beginning of a defun, in the general sense.") |
| 104 | 104 | ||
| 105 | (defconst ruby-singleton-class-re | ||
| 106 | "class\\s *<<" | ||
| 107 | "Regexp to match the beginning of a singleton class context.") | ||
| 108 | |||
| 105 | (eval-and-compile | 109 | (eval-and-compile |
| 106 | (defconst ruby-here-doc-beg-re | 110 | (defconst ruby-here-doc-beg-re |
| 107 | "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)" | 111 | "\\(<\\)<\\(-\\)?\\(\\([a-zA-Z0-9_]+\\)\\|[\"]\\([^\"]+\\)[\"]\\|[']\\([^']+\\)[']\\)" |
| @@ -384,7 +388,7 @@ and `\\' when preceded by `?'." | |||
| 384 | (when pos (goto-char pos)) | 388 | (when pos (goto-char pos)) |
| 385 | (forward-word -1) | 389 | (forward-word -1) |
| 386 | (and (or (bolp) (not (eq (char-before (point)) ?_))) | 390 | (and (or (bolp) (not (eq (char-before (point)) ?_))) |
| 387 | (looking-at "class\\s *<<")))) | 391 | (looking-at ruby-singleton-class-re)))) |
| 388 | 392 | ||
| 389 | (defun ruby-expr-beg (&optional option) | 393 | (defun ruby-expr-beg (&optional option) |
| 390 | "Check if point is possibly at the beginning of an expression. | 394 | "Check if point is possibly at the beginning of an expression. |
| @@ -1057,35 +1061,32 @@ For example: | |||
| 1057 | See `add-log-current-defun-function'." | 1061 | See `add-log-current-defun-function'." |
| 1058 | (condition-case nil | 1062 | (condition-case nil |
| 1059 | (save-excursion | 1063 | (save-excursion |
| 1060 | (let (mname mlist (indent 0)) | 1064 | (let ((indent 0) mname mlist |
| 1065 | (start (point)) | ||
| 1066 | (definition-re | ||
| 1067 | (concat "^[ \t]*" ruby-defun-beg-re "[ \t]+" | ||
| 1068 | "\\(" | ||
| 1069 | ;; \\. and :: for class methods | ||
| 1070 | "\\([A-Za-z_]" ruby-symbol-re "*\\|\\.\\|::" "\\)" | ||
| 1071 | "+\\)"))) | ||
| 1061 | ;; Get the current method definition (or class/module). | 1072 | ;; Get the current method definition (or class/module). |
| 1062 | (if (re-search-backward | 1073 | (when (re-search-backward definition-re nil t) |
| 1063 | (concat "^[ \t]*" ruby-defun-beg-re "[ \t]+" | 1074 | (goto-char (match-beginning 1)) |
| 1064 | "\\(" | 1075 | (when (ruby-block-contains-point start) |
| 1065 | ;; \\. and :: for class methods | 1076 | ;; We're inside the method, class or module. |
| 1066 | "\\([A-Za-z_]" ruby-symbol-re "*\\|\\.\\|::" "\\)" | 1077 | (setq mname (match-string 2)) |
| 1067 | "+\\)") | 1078 | (unless (string-equal "def" (match-string 1)) |
| 1068 | nil t) | 1079 | (setq mlist (list mname) mname nil))) |
| 1069 | (progn | 1080 | (setq indent (current-column)) |
| 1070 | (setq mname (match-string 2)) | 1081 | (beginning-of-line)) |
| 1071 | (unless (string-equal "def" (match-string 1)) | ||
| 1072 | (setq mlist (list mname) mname nil)) | ||
| 1073 | (goto-char (match-beginning 1)) | ||
| 1074 | (setq indent (current-column)) | ||
| 1075 | (beginning-of-line))) | ||
| 1076 | ;; Walk up the class/module nesting. | 1082 | ;; Walk up the class/module nesting. |
| 1077 | (while (and (> indent 0) | 1083 | (while (and (> indent 0) |
| 1078 | (re-search-backward | 1084 | (re-search-backward definition-re nil t)) |
| 1079 | (concat | ||
| 1080 | "^[ \t]*\\(class\\|module\\)[ \t]+" | ||
| 1081 | "\\([A-Z]" ruby-symbol-re "*\\)") | ||
| 1082 | nil t)) | ||
| 1083 | (goto-char (match-beginning 1)) | 1085 | (goto-char (match-beginning 1)) |
| 1084 | (if (< (current-column) indent) | 1086 | (when (ruby-block-contains-point start) |
| 1085 | (progn | 1087 | (setq mlist (cons (match-string 2) mlist)) |
| 1086 | (setq mlist (cons (match-string 2) mlist)) | 1088 | (setq indent (current-column)) |
| 1087 | (setq indent (current-column)) | 1089 | (beginning-of-line))) |
| 1088 | (beginning-of-line)))) | ||
| 1089 | ;; Process the method name. | 1090 | ;; Process the method name. |
| 1090 | (when mname | 1091 | (when mname |
| 1091 | (let ((mn (split-string mname "\\.\\|::"))) | 1092 | (let ((mn (split-string mname "\\.\\|::"))) |
| @@ -1104,7 +1105,14 @@ See `add-log-current-defun-function'." | |||
| 1104 | (setcdr (last mlist) (butlast mn)) | 1105 | (setcdr (last mlist) (butlast mn)) |
| 1105 | (setq mlist (butlast mn)))) | 1106 | (setq mlist (butlast mn)))) |
| 1106 | (setq mname (concat "." (car (last mn))))) | 1107 | (setq mname (concat "." (car (last mn))))) |
| 1107 | (setq mname (concat "#" mname))))) | 1108 | ;; See if the method is in singleton class context. |
| 1109 | (let ((in-singleton-class | ||
| 1110 | (when (re-search-forward ruby-singleton-class-re start t) | ||
| 1111 | (goto-char (match-beginning 0)) | ||
| 1112 | (ruby-block-contains-point start)))) | ||
| 1113 | (setq mname (concat | ||
| 1114 | (if in-singleton-class "." "#") | ||
| 1115 | mname)))))) | ||
| 1108 | ;; Generate the string. | 1116 | ;; Generate the string. |
| 1109 | (if (consp mlist) | 1117 | (if (consp mlist) |
| 1110 | (setq mlist (mapconcat (function identity) mlist "::"))) | 1118 | (setq mlist (mapconcat (function identity) mlist "::"))) |
| @@ -1112,6 +1120,12 @@ See `add-log-current-defun-function'." | |||
| 1112 | (if mlist (concat mlist mname) mname) | 1120 | (if mlist (concat mlist mname) mname) |
| 1113 | mlist))))) | 1121 | mlist))))) |
| 1114 | 1122 | ||
| 1123 | (defun ruby-block-contains-point (pt) | ||
| 1124 | (save-excursion | ||
| 1125 | (save-match-data | ||
| 1126 | (ruby-forward-sexp) | ||
| 1127 | (> (point) pt)))) | ||
| 1128 | |||
| 1115 | (defun ruby-brace-to-do-end (orig end) | 1129 | (defun ruby-brace-to-do-end (orig end) |
| 1116 | (let (beg-marker end-marker) | 1130 | (let (beg-marker end-marker) |
| 1117 | (goto-char end) | 1131 | (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 @@ | |||
| 2 | 2 | ||
| 3 | * automated/ruby-mode-tests.el | 3 | * automated/ruby-mode-tests.el |
| 4 | Rename one interpolation test; add three more. | 4 | Rename one interpolation test; add three more. |
| 5 | (ruby-with-temp-buffer): New macro, use it where appropriate. | ||
| 6 | (ruby-add-log-current-method-examples): Use "_" for target point. | ||
| 7 | Add four new tests for ruby-add-log-current-method. | ||
| 5 | 8 | ||
| 6 | 2012-12-11 Glenn Morris <rgm@gnu.org> | 9 | 2012-12-11 Glenn Morris <rgm@gnu.org> |
| 7 | 10 | ||
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 @@ | |||
| 25 | 25 | ||
| 26 | (defun ruby-should-indent (content column) | 26 | (defun ruby-should-indent (content column) |
| 27 | "Assert indentation COLUMN on the last line of CONTENT." | 27 | "Assert indentation COLUMN on the last line of CONTENT." |
| 28 | (with-temp-buffer | 28 | (ruby-with-temp-buffer content |
| 29 | (insert content) | ||
| 30 | (ruby-mode) | ||
| 31 | (ruby-indent-line) | 29 | (ruby-indent-line) |
| 32 | (should (= (current-indentation) column)))) | 30 | (should (= (current-indentation) column)))) |
| 33 | 31 | ||
| @@ -35,12 +33,17 @@ | |||
| 35 | "Assert that CONTENT turns into EXPECTED after the buffer is re-indented. | 33 | "Assert that CONTENT turns into EXPECTED after the buffer is re-indented. |
| 36 | 34 | ||
| 37 | The whitespace before and including \"|\" on each line is removed." | 35 | The whitespace before and including \"|\" on each line is removed." |
| 38 | (with-temp-buffer | 36 | (ruby-with-temp-buffer (ruby-test-string content) |
| 39 | (insert (ruby-test-string content)) | ||
| 40 | (ruby-mode) | ||
| 41 | (indent-region (point-min) (point-max)) | 37 | (indent-region (point-min) (point-max)) |
| 42 | (should (string= (ruby-test-string expected) (buffer-string))))) | 38 | (should (string= (ruby-test-string expected) (buffer-string))))) |
| 43 | 39 | ||
| 40 | (defmacro ruby-with-temp-buffer (contents &rest body) | ||
| 41 | (declare (indent 1) (debug t)) | ||
| 42 | `(with-temp-buffer | ||
| 43 | (insert ,contents) | ||
| 44 | (ruby-mode) | ||
| 45 | ,@body)) | ||
| 46 | |||
| 44 | (defun ruby-test-string (s &rest args) | 47 | (defun ruby-test-string (s &rest args) |
| 45 | (apply 'format (replace-regexp-in-string "^[ \t]*|" "" s) args)) | 48 | (apply 'format (replace-regexp-in-string "^[ \t]*|" "" s) args)) |
| 46 | 49 | ||
| @@ -48,9 +51,7 @@ The whitespace before and including \"|\" on each line is removed." | |||
| 48 | "Assert syntax state values at the end of CONTENT. | 51 | "Assert syntax state values at the end of CONTENT. |
| 49 | 52 | ||
| 50 | VALUES-PLIST is a list with alternating index and value elements." | 53 | VALUES-PLIST is a list with alternating index and value elements." |
| 51 | (with-temp-buffer | 54 | (ruby-with-temp-buffer content |
| 52 | (insert content) | ||
| 53 | (ruby-mode) | ||
| 54 | (syntax-propertize (point)) | 55 | (syntax-propertize (point)) |
| 55 | (while values-plist | 56 | (while values-plist |
| 56 | (should (eq (nth (car values-plist) | 57 | (should (eq (nth (car values-plist) |
| @@ -59,9 +60,7 @@ VALUES-PLIST is a list with alternating index and value elements." | |||
| 59 | (setq values-plist (cddr values-plist))))) | 60 | (setq values-plist (cddr values-plist))))) |
| 60 | 61 | ||
| 61 | (defun ruby-assert-face (content pos face) | 62 | (defun ruby-assert-face (content pos face) |
| 62 | (with-temp-buffer | 63 | (ruby-with-temp-buffer content |
| 63 | (insert content) | ||
| 64 | (ruby-mode) | ||
| 65 | (font-lock-fontify-buffer) | 64 | (font-lock-fontify-buffer) |
| 66 | (should (eq face (get-text-property pos 'face))))) | 65 | (should (eq face (get-text-property pos 'face))))) |
| 67 | 66 | ||
| @@ -226,17 +225,13 @@ VALUES-PLIST is a list with alternating index and value elements." | |||
| 226 | |")) | 225 | |")) |
| 227 | 226 | ||
| 228 | (ert-deftest ruby-move-to-block-stops-at-indentation () | 227 | (ert-deftest ruby-move-to-block-stops-at-indentation () |
| 229 | (with-temp-buffer | 228 | (ruby-with-temp-buffer "def f\nend" |
| 230 | (insert "def f\nend") | ||
| 231 | (beginning-of-line) | 229 | (beginning-of-line) |
| 232 | (ruby-mode) | ||
| 233 | (ruby-move-to-block -1) | 230 | (ruby-move-to-block -1) |
| 234 | (should (looking-at "^def")))) | 231 | (should (looking-at "^def")))) |
| 235 | 232 | ||
| 236 | (ert-deftest ruby-toggle-block-to-do-end () | 233 | (ert-deftest ruby-toggle-block-to-do-end () |
| 237 | (with-temp-buffer | 234 | (ruby-with-temp-buffer "foo {|b|\n}" |
| 238 | (insert "foo {|b|\n}") | ||
| 239 | (ruby-mode) | ||
| 240 | (beginning-of-line) | 235 | (beginning-of-line) |
| 241 | (ruby-toggle-block) | 236 | (ruby-toggle-block) |
| 242 | (should (string= "foo do |b|\nend" (buffer-string))))) | 237 | (should (string= "foo do |b|\nend" (buffer-string))))) |
| @@ -254,9 +249,7 @@ VALUES-PLIST is a list with alternating index and value elements." | |||
| 254 | (should (string= (cdr pair) (buffer-string)))))))) | 249 | (should (string= (cdr pair) (buffer-string)))))))) |
| 255 | 250 | ||
| 256 | (ert-deftest ruby-toggle-block-to-multiline () | 251 | (ert-deftest ruby-toggle-block-to-multiline () |
| 257 | (with-temp-buffer | 252 | (ruby-with-temp-buffer "foo {|b| b + 1}" |
| 258 | (insert "foo {|b| b + 1}") | ||
| 259 | (ruby-mode) | ||
| 260 | (beginning-of-line) | 253 | (beginning-of-line) |
| 261 | (ruby-toggle-block) | 254 | (ruby-toggle-block) |
| 262 | (should (string= "foo do |b|\n b + 1\nend" (buffer-string))))) | 255 | (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." | |||
| 295 | 288 | ||
| 296 | (ert-deftest ruby-interpolation-keeps-non-quote-syntax () | 289 | (ert-deftest ruby-interpolation-keeps-non-quote-syntax () |
| 297 | (let ((s "\"foo#{baz.tee}bar\"")) | 290 | (let ((s "\"foo#{baz.tee}bar\"")) |
| 298 | (with-temp-buffer | 291 | (ruby-with-temp-buffer s |
| 299 | (save-excursion | 292 | (goto-char (point-min)) |
| 300 | (insert s)) | ||
| 301 | (ruby-mode) | 293 | (ruby-mode) |
| 302 | (font-lock-fontify-buffer) | 294 | (font-lock-fontify-buffer) |
| 303 | (search-forward "tee") | 295 | (search-forward "tee") |
| @@ -318,21 +310,66 @@ VALUES-PLIST is a list with alternating index and value elements." | |||
| 318 | ("self.foo" . ".foo")))) | 310 | ("self.foo" . ".foo")))) |
| 319 | (dolist (pair pairs) | 311 | (dolist (pair pairs) |
| 320 | (let ((name (car pair)) | 312 | (let ((name (car pair)) |
| 321 | (value (cdr pair))) | 313 | (value (cdr pair))) |
| 322 | (with-temp-buffer | 314 | (ruby-with-temp-buffer (ruby-test-string |
| 323 | (insert (ruby-test-string | 315 | "module M |
| 324 | "module M | 316 | | class C |
| 325 | | class C | 317 | | def %s |
| 326 | | def %s | 318 | | _ |
| 327 | | end | 319 | | end |
| 328 | | end | 320 | | end |
| 329 | |end" | 321 | |end" |
| 330 | name)) | 322 | name) |
| 331 | (ruby-mode) | 323 | (search-backward "_") |
| 332 | (search-backward "def") | 324 | (forward-line) |
| 333 | (forward-line) | 325 | (should (string= (ruby-add-log-current-method) |
| 334 | (should (string= (ruby-add-log-current-method) | 326 | (format "M::C%s" value)))))))) |
| 335 | (format "M::C%s" value)))))))) | 327 | |
| 328 | (ert-deftest ruby-add-log-current-method-outside-of-method () | ||
| 329 | (ruby-with-temp-buffer (ruby-test-string | ||
| 330 | "module M | ||
| 331 | | class C | ||
| 332 | | def foo | ||
| 333 | | end | ||
| 334 | | _ | ||
| 335 | | end | ||
| 336 | |end") | ||
| 337 | (search-backward "_") | ||
| 338 | (should (string= (ruby-add-log-current-method)"M::C")))) | ||
| 339 | |||
| 340 | (ert-deftest ruby-add-log-current-method-in-singleton-class () | ||
| 341 | (ruby-with-temp-buffer (ruby-test-string | ||
| 342 | "class C | ||
| 343 | | class << self | ||
| 344 | | def foo | ||
| 345 | | _ | ||
| 346 | | end | ||
| 347 | | end | ||
| 348 | |end") | ||
| 349 | (search-backward "_") | ||
| 350 | (should (string= (ruby-add-log-current-method) "C.foo")))) | ||
| 351 | |||
| 352 | (ert-deftest ruby-add-log-current-method-namespace-shorthand () | ||
| 353 | (ruby-with-temp-buffer (ruby-test-string | ||
| 354 | "class C::D | ||
| 355 | | def foo | ||
| 356 | | _ | ||
| 357 | | end | ||
| 358 | |end") | ||
| 359 | (search-backward "_") | ||
| 360 | (should (string= (ruby-add-log-current-method) "C::D#foo")))) | ||
| 361 | |||
| 362 | (ert-deftest ruby-add-log-current-method-after-inner-class () | ||
| 363 | (ruby-with-temp-buffer (ruby-test-string | ||
| 364 | "module M | ||
| 365 | | class C | ||
| 366 | | class D | ||
| 367 | | end | ||
| 368 | | _ | ||
| 369 | | end | ||
| 370 | |end") | ||
| 371 | (search-backward "_") | ||
| 372 | (should (string= (ruby-add-log-current-method) "M::C")))) | ||
| 336 | 373 | ||
| 337 | (defvar ruby-block-test-example | 374 | (defvar ruby-block-test-example |
| 338 | (ruby-test-string | 375 | (ruby-test-string |