summaryrefslogtreecommitdiff
path: root/lisp/progmodes/ruby-mode.el
diff options
context:
space:
mode:
Diffstat (limited to 'lisp/progmodes/ruby-mode.el')
-rw-r--r--lisp/progmodes/ruby-mode.el189
1 files changed, 108 insertions, 81 deletions
diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index bc9979ae997..69acc7a3944 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -39,6 +39,8 @@
;;; Code:
+(eval-when-compile (require 'cl-lib))
+
(defgroup ruby nil
"Major mode for editing Ruby code."
:prefix "ruby-"
@@ -106,7 +108,7 @@
"Regexp to match the beginning of a heredoc.")
(defconst ruby-expression-expansion-re
- "\\(?:[^\\]\\|\\=\\)\\(\\\\\\\\\\)*\\(#\\({[^}\n\\\\]*\\(\\\\.[^}\n\\\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\|\\$[^a-zA-Z \n]\\)\\)"))
+ "\\(?:[^\\]\\|\\=\\)\\(\\\\\\\\\\)*\\(#\\({[^}\n\\]*\\(\\\\.[^}\n\\]*\\)*}\\|\\(\\$\\|@\\|@@\\)\\(\\w\\|_\\)+\\|\\$[^a-zA-Z \n]\\)\\)"))
(defun ruby-here-doc-end-match ()
"Return a regexp to find the end of a heredoc.
@@ -153,6 +155,7 @@ This should only be called after matching against `ruby-here-doc-beg-re'."
(define-key map (kbd "M-C-n") 'ruby-end-of-block)
(define-key map (kbd "C-c {") 'ruby-toggle-block)
(define-key map (kbd "C-c '") 'ruby-toggle-string-quotes)
+ (define-key map (kbd "C-c C-f") 'ruby-find-library-file)
map)
"Keymap used in Ruby mode.")
@@ -215,19 +218,16 @@ This should only be called after matching against `ruby-here-doc-beg-re'."
(defcustom ruby-indent-tabs-mode nil
"Indentation can insert tabs in Ruby mode if this is non-nil."
:type 'boolean
- :group 'ruby
:safe 'booleanp)
(defcustom ruby-indent-level 2
"Indentation of Ruby statements."
:type 'integer
- :group 'ruby
:safe 'integerp)
(defcustom ruby-comment-column (default-value 'comment-column)
"Indentation column of comments."
:type 'integer
- :group 'ruby
:safe 'integerp)
(defconst ruby-alignable-keywords '(if while unless until begin case for def)
@@ -255,8 +255,7 @@ the statement:
qux
end
-Only has effect when `ruby-use-smie' is t.
-"
+Only has effect when `ruby-use-smie' is t."
:type `(choice
(const :tag "None" nil)
(const :tag "All" t)
@@ -264,7 +263,6 @@ Only has effect when `ruby-use-smie' is t.
(choice ,@(mapcar
(lambda (kw) (list 'const kw))
ruby-alignable-keywords))))
- :group 'ruby
:safe 'listp
:version "24.4")
@@ -276,7 +274,6 @@ of its parent.
Only has effect when `ruby-use-smie' is t."
:type 'boolean
- :group 'ruby
:safe 'booleanp
:version "24.4")
@@ -285,7 +282,6 @@ Only has effect when `ruby-use-smie' is t."
Also ignores spaces after parenthesis when `space'.
Only has effect when `ruby-use-smie' is nil."
:type 'boolean
- :group 'ruby
:safe 'booleanp)
;; FIXME Woefully under documented. What is the point of the last t?.
@@ -300,14 +296,12 @@ Only has effect when `ruby-use-smie' is nil."
(cons character (choice (const nil)
(const t)))
(const t) ; why?
- )))
- :group 'ruby)
+ ))))
(defcustom ruby-deep-indent-paren-style 'space
"Default deep indent style.
Only has effect when `ruby-use-smie' is nil."
- :type '(choice (const t) (const nil) (const space))
- :group 'ruby)
+ :type '(choice (const t) (const nil) (const space)))
(defcustom ruby-encoding-map
'((us-ascii . nil) ;; Do not put coding: us-ascii
@@ -317,8 +311,7 @@ Only has effect when `ruby-use-smie' is nil."
"Alist to map encoding name from Emacs to Ruby.
Associating an encoding name with nil means it needs not be
explicitly declared in magic comment."
- :type '(repeat (cons (symbol :tag "From") (symbol :tag "To")))
- :group 'ruby)
+ :type '(repeat (cons (symbol :tag "From") (symbol :tag "To"))))
(defcustom ruby-insert-encoding-magic-comment t
"Insert a magic Ruby encoding comment upon save if this is non-nil.
@@ -335,14 +328,12 @@ even if it's not required."
(const :tag "Emacs Style" emacs)
(const :tag "Ruby Style" ruby)
(const :tag "Custom Style" custom))
- :group 'ruby
:version "24.4")
(defcustom ruby-custom-encoding-magic-comment-template "# encoding: %s"
"A custom encoding comment template.
It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
:type 'string
- :group 'ruby
:version "24.4")
(defcustom ruby-use-encoding-map t
@@ -527,6 +518,9 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
((ruby-smie--opening-pipe-p) "opening-|")
((ruby-smie--closing-pipe-p) "closing-|")
(t tok)))
+ ((string-match "\\`[^|]+|\\'" tok)
+ (forward-char -1)
+ (substring tok 0 -1))
((and (equal tok "") (looking-at "\\\\\n"))
(goto-char (match-end 0)) (ruby-smie--forward-token))
((equal tok "do")
@@ -569,6 +563,7 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
((ruby-smie--opening-pipe-p) "opening-|")
((ruby-smie--closing-pipe-p) "closing-|")
(t tok)))
+ ((string-match-p "\\`[^|]+|\\'" tok) "closing-|")
((string-match-p "\\`|[*&]\\'" tok)
(forward-char 1)
(substring tok 1))
@@ -596,12 +591,12 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
(defun ruby-smie-rules (kind token)
(pcase (cons kind token)
- (`(:elem . basic) ruby-indent-level)
+ ('(:elem . basic) ruby-indent-level)
;; "foo" "bar" is the concatenation of the two strings, so the second
;; should be aligned with the first.
- (`(:elem . args) (if (looking-at "\\s\"") 0))
+ ('(:elem . args) (if (looking-at "\\s\"") 0))
;; (`(:after . ",") (smie-rule-separator kind))
- (`(:before . ";")
+ ('(:before . ";")
(cond
((smie-rule-parent-p "def" "begin" "do" "class" "module" "for"
"while" "until" "unless"
@@ -611,7 +606,7 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
;; For (invalid) code between switch and case.
;; (if (smie-parent-p "switch") 4)
))
- (`(:before . ,(or `"(" `"[" `"{"))
+ (`(:before . ,(or "(" "[" "{"))
(cond
((and (equal token "{")
(not (smie-rule-prev-p "(" "{" "[" "," "=>" "=" "return" ";"))
@@ -638,7 +633,7 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
(forward-char -1))
(smie-indent-virtual))
(t (smie-rule-parent))))))
- (`(:after . ,(or `"(" "[" "{"))
+ (`(:after . ,(or "(" "[" "{"))
;; FIXME: Shouldn't this be the default behavior of
;; `smie-indent-after-keyword'?
(save-excursion
@@ -648,20 +643,20 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
;; because we want to reject hanging tokens at bol, too.
(unless (or (eolp) (forward-comment 1))
(cons 'column (current-column)))))
- (`(:before . " @ ")
+ ('(:before . " @ ")
(save-excursion
(skip-chars-forward " \t")
(cons 'column (current-column))))
- (`(:before . "do") (ruby-smie--indent-to-stmt))
- (`(:before . ".")
+ ('(:before . "do") (ruby-smie--indent-to-stmt))
+ ('(:before . ".")
(if (smie-rule-sibling-p)
(and ruby-align-chained-calls 0)
(smie-backward-sexp ".")
(cons 'column (+ (current-column)
ruby-indent-level))))
- (`(:before . ,(or `"else" `"then" `"elsif" `"rescue" `"ensure"))
+ (`(:before . ,(or "else" "then" "elsif" "rescue" "ensure"))
(smie-rule-parent))
- (`(:before . "when")
+ ('(:before . "when")
;; Align to the previous `when', but look up the virtual
;; indentation of `case'.
(if (smie-rule-sibling-p) 0 (smie-rule-parent)))
@@ -678,7 +673,7 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
(if (ruby-smie--indent-to-stmt-p token)
(ruby-smie--indent-to-stmt)
(cons 'column (current-column)))))
- (`(:before . "iuwu-mod")
+ ('(:before . "iuwu-mod")
(smie-rule-parent ruby-indent-level))
))
@@ -740,7 +735,7 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
(back-to-indentation)
(narrow-to-region (point) end)
(smie-forward-sexp))
- (while (and (setq state (apply 'ruby-parse-partial end state))
+ (while (and (setq state (apply #'ruby-parse-partial end state))
(>= (nth 2 state) 0) (< (point) end))))))
(defun ruby-mode-variables ()
@@ -750,7 +745,7 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
(smie-setup ruby-smie-grammar #'ruby-smie-rules
:forward-token #'ruby-smie--forward-token
:backward-token #'ruby-smie--backward-token)
- (setq-local indent-line-function 'ruby-indent-line))
+ (setq-local indent-line-function #'ruby-indent-line))
(setq-local comment-start "# ")
(setq-local comment-end "")
(setq-local comment-column ruby-comment-column)
@@ -766,9 +761,9 @@ It is used when `ruby-encoding-magic-comment-style' is set to `custom'."
The style of the comment is controlled by `ruby-encoding-magic-comment-style'."
(let ((encoding-magic-comment-template
(pcase ruby-encoding-magic-comment-style
- (`ruby "# coding: %s")
- (`emacs "# -*- coding: %s -*-")
- (`custom
+ ('ruby "# coding: %s")
+ ('emacs "# -*- coding: %s -*-")
+ ('custom
ruby-custom-encoding-magic-comment-template))))
(insert
(format encoding-magic-comment-template encoding)
@@ -935,9 +930,9 @@ Can be one of `heredoc', `modifier', `expr-qstr', `expr-re'."
(goto-char (match-end 0))
(not (looking-at "\\s_")))
((eq option 'expr-qstr)
- (looking-at "[a-zA-Z][a-zA-z0-9_]* +%[^ \t]"))
+ (looking-at "[a-zA-Z][a-zA-Z0-9_]* +%[^ \t]"))
((eq option 'expr-re)
- (looking-at "[a-zA-Z][a-zA-z0-9_]* +/[^ \t]"))
+ (looking-at "[a-zA-Z][a-zA-Z0-9_]* +/[^ \t]"))
(t nil)))))))))
(defun ruby-forward-string (term &optional end no-error expand)
@@ -985,6 +980,7 @@ delimiter."
((eq c ?\( ) ruby-deep-arglist)))
(defun ruby-parse-partial (&optional end in-string nest depth pcol indent)
+ ;; FIXME: Document why we can't just use parse-partial-sexp.
"TODO: document throughout function body."
(or depth (setq depth 0))
(or indent (setq indent 0))
@@ -1052,7 +1048,7 @@ delimiter."
((looking-at "\\?") ;skip ?char
(cond
((and (ruby-expr-beg)
- (looking-at "?\\(\\\\C-\\|\\\\M-\\)*\\\\?."))
+ (looking-at "\\?\\(\\\\C-\\|\\\\M-\\)*\\\\?."))
(goto-char (match-end 0)))
(t
(goto-char pnt))))
@@ -1159,7 +1155,7 @@ delimiter."
(state (list in-string nest depth pcol indent)))
;; parse the rest of the line
(while (and (> line-end-position (point))
- (setq state (apply 'ruby-parse-partial
+ (setq state (apply #'ruby-parse-partial
line-end-position state))))
(setq in-string (car state)
nest (nth 1 state)
@@ -1196,7 +1192,7 @@ delimiter."
(save-restriction
(narrow-to-region (point) end)
(while (and (> end (point))
- (setq state (apply 'ruby-parse-partial end state))))))
+ (setq state (apply #'ruby-parse-partial end state))))))
(list (nth 0 state) ; in-string
(car (nth 1 state)) ; nest
(nth 2 state) ; depth
@@ -1495,7 +1491,7 @@ With ARG, do it many times. Negative ARG means move backward."
(cond ((looking-at "\\?\\(\\\\[CM]-\\)*\\\\?\\S ")
(goto-char (match-end 0)))
((progn
- (skip-chars-forward ",.:;|&^~=!?\\+\\-\\*")
+ (skip-chars-forward "-,.:;|&^~=!?+*")
(looking-at "\\s("))
(goto-char (scan-sexps (point) 1)))
((and (looking-at (concat "\\<\\(" ruby-block-beg-re
@@ -1538,20 +1534,20 @@ With ARG, do it many times. Negative ARG means move forward."
(let ((i (or arg 1)))
(condition-case nil
(while (> i 0)
- (skip-chars-backward " \t\n,.:;|&^~=!?\\+\\-\\*")
+ (skip-chars-backward "- \t\n,.:;|&^~=!?+*")
(forward-char -1)
(cond ((looking-at "\\s)")
(goto-char (scan-sexps (1+ (point)) -1))
(pcase (char-before)
- (`?% (forward-char -1))
- ((or `?q `?Q `?w `?W `?r `?x)
+ (?% (forward-char -1))
+ ((or ?q ?Q ?w ?W ?r ?x)
(if (eq (char-before (1- (point))) ?%)
(forward-char -2))))
nil)
((looking-at "\\s\"\\|\\\\\\S_")
(let ((c (char-to-string (char-before (match-end 0)))))
(while (and (search-backward c)
- (eq (logand (skip-chars-backward "\\") 1)
+ (eq (logand (skip-chars-backward "\\\\") 1)
1))))
nil)
((looking-at "\\s.\\|\\s\\")
@@ -1561,13 +1557,13 @@ With ARG, do it many times. Negative ARG means move forward."
(forward-char 1)
(while (progn (forward-word-strictly -1)
(pcase (char-before)
- (`?_ t)
- (`?. (forward-char -1) t)
- ((or `?$ `?@)
+ (?_ t)
+ (?. (forward-char -1) t)
+ ((or ?$ ?@)
(forward-char -1)
(and (eq (char-before) (char-after))
(forward-char -1)))
- (`?:
+ (?:
(forward-char -1)
(eq (char-before) :)))))
(if (looking-at ruby-block-end-re)
@@ -1619,7 +1615,7 @@ See `add-log-current-defun-function'."
(concat "^[ \t]*" re "[ \t]+"
"\\("
;; \\. and :: for class methods
- "\\([A-Za-z_]" ruby-symbol-re "*\\|\\.\\|::" "\\)"
+ "\\([A-Za-z_]" ruby-symbol-re "*[?!]?\\|\\.\\|::" "\\)"
"+\\)")))
(definition-re (funcall make-definition-re ruby-defun-beg-re))
(module-re (funcall make-definition-re "\\(class\\|module\\)")))
@@ -1694,7 +1690,8 @@ See `add-log-current-defun-function'."
(when (eq (char-before) ?\})
(delete-char -1)
(when (save-excursion
- (skip-chars-backward " \t")
+ (let ((n (skip-chars-backward " \t")))
+ (if (< n 0) (delete-char (- n))))
(not (bolp)))
(insert "\n"))
(insert "end")
@@ -1799,14 +1796,36 @@ If the result is do-end block, it will always be multiline."
(buffer-substring-no-properties (1+ min) (1- max))))
(setq content
(if (equal string-quote "'")
- (replace-regexp-in-string "\\\\\"" "\"" (replace-regexp-in-string "\\(\\`\\|[^\\\\]\\)'" "\\1\\\\'" content))
- (replace-regexp-in-string "\\\\'" "'" (replace-regexp-in-string "\\(\\`\\|[^\\\\]\\)\"" "\\1\\\\\"" content))))
+ (replace-regexp-in-string "\\\\\"" "\"" (replace-regexp-in-string "\\(\\`\\|[^\\]\\)'" "\\1\\\\'" content))
+ (replace-regexp-in-string "\\\\'" "'" (replace-regexp-in-string "\\(\\`\\|[^\\]\\)\"" "\\1\\\\\"" content))))
(let ((orig-point (point)))
(delete-region min max)
(insert
(format "%s%s%s" string-quote content string-quote))
(goto-char orig-point)))))
+(defun ruby-find-library-file (&optional feature-name)
+ "Visit a library file denoted by FEATURE-NAME.
+FEATURE-NAME is a relative file name, file extension is optional.
+This commands delegates to 'gem which', which searches both
+installed gems and the standard library. When called
+interactively, defaults to the feature name in the 'require'
+statement around point."
+ (interactive)
+ (unless feature-name
+ (let ((init (save-excursion
+ (forward-line 0)
+ (when (looking-at "require [\"']\\(.*\\)[\"']")
+ (match-string 1)))))
+ (setq feature-name (read-string "Feature name: " init))))
+ (let ((out
+ (substring
+ (shell-command-to-string (concat "gem which " feature-name))
+ 0 -1)))
+ (if (string-match-p "\\`ERROR" out)
+ (user-error "%s" out)
+ (find-file out))))
+
(eval-and-compile
(defconst ruby-percent-literal-beg-re
"\\(%\\)[qQrswWxIi]?\\([[:punct:]]\\)"
@@ -1839,7 +1858,7 @@ It will be properly highlighted even when the call omits parens.")
"Syntactic keywords for Ruby mode. See `syntax-propertize-function'."
(let (case-fold-search)
(goto-char start)
- (remove-text-properties start end '(ruby-expansion-match-data))
+ (remove-text-properties start end '(ruby-expansion-match-data nil))
(ruby-syntax-propertize-heredoc end)
(ruby-syntax-enclosing-percent-literal end)
(funcall
@@ -1872,7 +1891,7 @@ It will be properly highlighted even when the call omits parens.")
("^[ \t]*def +\\(`\\)" (1 "_"))
;; Ternary operator colon followed by opening paren or bracket
;; (semi-important for indentation).
- ("\\(:\\)\\(?:[\({]\\|\\[[^]]\\)"
+ ("\\(:\\)\\(?:[({]\\|\\[[^]]\\)"
(1 (string-to-syntax ".")))
;; Regular expressions. Start with matching unescaped slash.
("\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\(/\\)"
@@ -2033,13 +2052,6 @@ It will be properly highlighted even when the call omits parens.")
context)))
t)))
-(defvar ruby-font-lock-syntax-table
- (let ((tbl (make-syntax-table ruby-mode-syntax-table)))
- (modify-syntax-entry ?_ "w" tbl)
- tbl)
- "The syntax table to use for fontifying Ruby mode buffers.
-See `font-lock-syntax-table'.")
-
(defconst ruby-font-lock-keyword-beg-re "\\(?:^\\|[^.@$:]\\|\\.\\.\\)")
(defconst ruby-font-lock-keywords
@@ -2190,7 +2202,7 @@ See `font-lock-syntax-table'.")
font-lock-constant-face)
nil t))
;; Special globals.
- (,(concat "\\$\\(?:[:\"!@;,/\\._><\\$?~=*&`'+0-9]\\|-[0adFiIlpvw]\\|"
+ (,(concat "\\$\\(?:[:\"!@;,/._><\\$?~=*&`'+0-9]\\|-[0adFiIlpvw]\\|"
(regexp-opt '("LOAD_PATH" "LOADED_FEATURES" "PROGRAM_NAME"
"ERROR_INFO" "ERROR_POSITION"
"FS" "FIELD_SEPARATOR"
@@ -2218,7 +2230,8 @@ See `font-lock-syntax-table'.")
;; Conversion methods on Kernel.
(,(concat ruby-font-lock-keyword-beg-re
(regexp-opt '("Array" "Complex" "Float" "Hash"
- "Integer" "Rational" "String") 'symbols))
+ "Integer" "Rational" "String")
+ 'symbols))
(1 font-lock-builtin-face))
;; Expression expansion.
(ruby-match-expression-expansion
@@ -2299,7 +2312,7 @@ See `font-lock-syntax-table'.")
:command command
:sentinel
(lambda (proc _event)
- (when (eq 'exit (process-status proc))
+ (when (and (eq 'exit (process-status proc)) (buffer-live-p source))
(unwind-protect
(if (with-current-buffer source (eq proc ruby--flymake-proc))
(with-current-buffer (process-buffer proc)
@@ -2311,36 +2324,44 @@ See `font-lock-syntax-table'.")
(process-send-eof ruby--flymake-proc))))
(defcustom ruby-flymake-use-rubocop-if-available t
- "Non-nil to use the Rubocop Flymake backend.
-Only takes effect if Rubocop is installed."
+ "Non-nil to use the RuboCop Flymake backend.
+Only takes effect if RuboCop is installed.
+
+If there is no Rubocop config file, Rubocop will be passed a flag
+'--lint' to only show syntax errors and important problems."
:version "26.1"
:type 'boolean
- :group 'ruby
:safe 'booleanp)
(defcustom ruby-rubocop-config ".rubocop.yml"
"Configuration file for `ruby-flymake-rubocop'."
:version "26.1"
:type 'string
- :group 'ruby
:safe 'stringp)
(defun ruby-flymake-rubocop (report-fn &rest _args)
- "Rubocop backend for Flymake."
+ "RuboCop backend for Flymake."
(unless (executable-find "rubocop")
(error "Cannot find the rubocop executable"))
(let ((command (list "rubocop" "--stdin" buffer-file-name "--format" "emacs"
"--cache" "false" ; Work around a bug in old version.
"--display-cop-names"))
+ (default-directory default-directory)
config-dir)
(when buffer-file-name
(setq config-dir (locate-dominating-file buffer-file-name
ruby-rubocop-config))
- (when config-dir
+ (if (not config-dir)
+ (setq command (append command '("--lint")))
(setq command (append command (list "--config"
(expand-file-name ruby-rubocop-config
- config-dir)))))
+ config-dir))))
+ (when (ruby-flymake-rubocop--use-bundler-p config-dir)
+ (setq command (append '("bundle" "exec") command))
+ ;; In case of a project with multiple nested subprojects,
+ ;; each one with a Gemfile.
+ (setq default-directory config-dir)))
(ruby-flymake--helper
"rubocop-flymake"
@@ -2352,7 +2373,7 @@ Only takes effect if Rubocop is installed."
(when (eq (process-exit-status proc) 127)
;; Not sure what to do in this case. Maybe ideally we'd
;; switch back to ruby-flymake-simple.
- (flymake-log :warning "Rubocop returned status 127: %s"
+ (flymake-log :warning "RuboCop returned status 127: %s"
(buffer-string)))
(goto-char (point-min))
(cl-loop
@@ -2378,6 +2399,13 @@ Only takes effect if Rubocop is installed."
into diags
finally (funcall report-fn diags)))))))
+(defun ruby-flymake-rubocop--use-bundler-p (dir)
+ (let ((file (expand-file-name "Gemfile" dir)))
+ (and (file-exists-p file)
+ (with-temp-buffer
+ (insert-file-contents file)
+ (re-search-forward "^ *gem ['\"]rubocop['\"]" nil t)))))
+
(defun ruby-flymake-auto (report-fn &rest args)
(apply
(if (and ruby-flymake-use-rubocop-if-available
@@ -2392,18 +2420,17 @@ Only takes effect if Rubocop is installed."
"Major mode for editing Ruby code."
(ruby-mode-variables)
- (setq-local imenu-create-index-function 'ruby-imenu-create-index)
- (setq-local add-log-current-defun-function 'ruby-add-log-current-method)
- (setq-local beginning-of-defun-function 'ruby-beginning-of-defun)
- (setq-local end-of-defun-function 'ruby-end-of-defun)
+ (setq-local imenu-create-index-function #'ruby-imenu-create-index)
+ (setq-local add-log-current-defun-function #'ruby-add-log-current-method)
+ (setq-local beginning-of-defun-function #'ruby-beginning-of-defun)
+ (setq-local end-of-defun-function #'ruby-end-of-defun)
- (add-hook 'after-save-hook 'ruby-mode-set-encoding nil 'local)
- (add-hook 'electric-indent-functions 'ruby--electric-indent-p nil 'local)
- (add-hook 'flymake-diagnostic-functions 'ruby-flymake-auto nil 'local)
+ (add-hook 'after-save-hook #'ruby-mode-set-encoding nil 'local)
+ (add-hook 'electric-indent-functions #'ruby--electric-indent-p nil 'local)
+ (add-hook 'flymake-diagnostic-functions #'ruby-flymake-auto nil 'local)
- (setq-local font-lock-defaults '((ruby-font-lock-keywords) nil nil))
- (setq-local font-lock-keywords ruby-font-lock-keywords)
- (setq-local font-lock-syntax-table ruby-font-lock-syntax-table)
+ (setq-local font-lock-defaults '((ruby-font-lock-keywords) nil nil
+ ((?_ . "w"))))
(setq-local syntax-propertize-function #'ruby-syntax-propertize))