* lisp/progmodes/ruby-mode.el Use `syntax-propertize-function'

unconditionally.  Remove now unnecessary forward declarations.
Remove XEmacs-specific setup.
(ruby-here-doc-end-re, ruby-here-doc-beg-match)
(ruby-font-lock-syntactic-keywords)
(ruby-comment-beg-syntax, ruby-in-here-doc-p)
(ruby-here-doc-find-end, ruby-here-doc-beg-syntax)
(ruby-here-doc-end-syntax): Remove.
(ruby-mode): Don't check whether `syntax-propertize-rules' is
defined as function.
This commit is contained in:
Dmitry Gutov 2013-11-02 05:10:10 +04:00
parent a3996a2eba
commit 7ffd37219b
2 changed files with 178 additions and 342 deletions

View file

@ -1,3 +1,16 @@
2013-11-02 Dmitry Gutov <dgutov@yandex.ru>
* progmodes/ruby-mode.el Use `syntax-propertize-function'
unconditionally. Remove now unnecessary forward declarations.
Remove XEmacs-specific setup.
(ruby-here-doc-end-re, ruby-here-doc-beg-match)
(ruby-font-lock-syntactic-keywords)
(ruby-comment-beg-syntax, ruby-in-here-doc-p)
(ruby-here-doc-find-end, ruby-here-doc-beg-syntax)
(ruby-here-doc-end-syntax): Remove.
(ruby-mode): Don't check whether `syntax-propertize-rules' is
defined as function.
2013-11-02 Bozhidar Batsov <bozhidar@batsov.com>
* progmodes/ruby-mode.el (ruby-mode-variables, ruby-mode): Use `setq-local'.

View file

@ -1515,349 +1515,182 @@ If the result is do-end block, it will always be multiline."
(ruby-do-end-to-brace beg end)))
(goto-char start))))
(declare-function ruby-syntax-propertize-heredoc "ruby-mode" (limit))
(declare-function ruby-syntax-enclosing-percent-literal "ruby-mode" (limit))
(declare-function ruby-syntax-propertize-percent-literal "ruby-mode" (limit))
;; Unusual code layout confuses the byte-compiler.
(declare-function ruby-syntax-propertize-expansion "ruby-mode" ())
(declare-function ruby-syntax-expansion-allowed-p "ruby-mode" (parse-state))
(declare-function ruby-syntax-propertize-function "ruby-mode" (start end))
(eval-and-compile
(defconst ruby-percent-literal-beg-re
"\\(%\\)[qQrswWxIi]?\\([[:punct:]]\\)"
"Regexp to match the beginning of percent literal.")
(if (eval-when-compile (fboundp #'syntax-propertize-rules))
;; New code that works independently from font-lock.
(progn
(eval-and-compile
(defconst ruby-percent-literal-beg-re
"\\(%\\)[qQrswWxIi]?\\([[:punct:]]\\)"
"Regexp to match the beginning of percent literal.")
(defconst ruby-syntax-methods-before-regexp
'("gsub" "gsub!" "sub" "sub!" "scan" "split" "split!" "index" "match"
"assert_match" "Given" "Then" "When")
"Methods that can take regexp as the first argument.
(defconst ruby-syntax-methods-before-regexp
'("gsub" "gsub!" "sub" "sub!" "scan" "split" "split!" "index" "match"
"assert_match" "Given" "Then" "When")
"Methods that can take regexp as the first argument.
It will be properly highlighted even when the call omits parens.")
(defvar ruby-syntax-before-regexp-re
(concat
;; Special tokens that can't be followed by a division operator.
"\\(^\\|[[=(,~;<>]"
;; Distinguish ternary operator tokens.
;; FIXME: They don't really have to be separated with spaces.
"\\|[?:] "
;; Control flow keywords and operators following bol or whitespace.
"\\|\\(?:^\\|\\s \\)"
(regexp-opt '("if" "elsif" "unless" "while" "until" "when" "and"
"or" "not" "&&" "||"))
;; Method name from the list.
"\\|\\_<"
(regexp-opt ruby-syntax-methods-before-regexp)
"\\)\\s *")
"Regexp to match text that can be followed by a regular expression."))
(defvar ruby-syntax-before-regexp-re
(concat
;; Special tokens that can't be followed by a division operator.
"\\(^\\|[[=(,~;<>]"
;; Distinguish ternary operator tokens.
;; FIXME: They don't really have to be separated with spaces.
"\\|[?:] "
;; Control flow keywords and operators following bol or whitespace.
"\\|\\(?:^\\|\\s \\)"
(regexp-opt '("if" "elsif" "unless" "while" "until" "when" "and"
"or" "not" "&&" "||"))
;; Method name from the list.
"\\|\\_<"
(regexp-opt ruby-syntax-methods-before-regexp)
"\\)\\s *")
"Regexp to match text that can be followed by a regular expression."))
(defun ruby-syntax-propertize-function (start end)
"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))
(ruby-syntax-propertize-heredoc end)
(ruby-syntax-enclosing-percent-literal end)
(funcall
(syntax-propertize-rules
;; $' $" $` .... are variables.
;; ?' ?" ?` are character literals (one-char strings in 1.9+).
("\\([?$]\\)[#\"'`]"
(1 (unless (save-excursion
;; Not within a string.
(nth 3 (syntax-ppss (match-beginning 0))))
(string-to-syntax "\\"))))
;; Regular expressions. Start with matching unescaped slash.
("\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\(/\\)"
(1 (let ((state (save-excursion (syntax-ppss (match-beginning 1)))))
(when (or
;; Beginning of a regexp.
(and (null (nth 8 state))
(save-excursion
(forward-char -1)
(looking-back ruby-syntax-before-regexp-re
(point-at-bol))))
;; End of regexp. We don't match the whole
;; regexp at once because it can have
;; string interpolation inside, or span
;; several lines.
(eq ?/ (nth 3 state)))
(string-to-syntax "\"/")))))
;; Expression expansions in strings. We're handling them
;; here, so that the regexp rule never matches inside them.
(ruby-expression-expansion-re
(0 (ignore (ruby-syntax-propertize-expansion))))
("^=en\\(d\\)\\_>" (1 "!"))
("^\\(=\\)begin\\_>" (1 "!"))
;; Handle here documents.
((concat ruby-here-doc-beg-re ".*\\(\n\\)")
(7 (unless (or (nth 8 (save-excursion
(syntax-ppss (match-beginning 0))))
(ruby-singleton-class-p (match-beginning 0)))
(put-text-property (match-beginning 7) (match-end 7)
'syntax-table (string-to-syntax "\""))
(ruby-syntax-propertize-heredoc end))))
;; Handle percent literals: %w(), %q{}, etc.
((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re)
(1 (prog1 "|" (ruby-syntax-propertize-percent-literal end)))))
(point) end)))
(defun ruby-syntax-propertize-function (start end)
"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))
(ruby-syntax-propertize-heredoc end)
(ruby-syntax-enclosing-percent-literal end)
(funcall
(syntax-propertize-rules
;; $' $" $` .... are variables.
;; ?' ?" ?` are character literals (one-char strings in 1.9+).
("\\([?$]\\)[#\"'`]"
(1 (unless (save-excursion
;; Not within a string.
(nth 3 (syntax-ppss (match-beginning 0))))
(string-to-syntax "\\"))))
;; Regular expressions. Start with matching unescaped slash.
("\\(?:\\=\\|[^\\]\\)\\(?:\\\\\\\\\\)*\\(/\\)"
(1 (let ((state (save-excursion (syntax-ppss (match-beginning 1)))))
(when (or
;; Beginning of a regexp.
(and (null (nth 8 state))
(save-excursion
(forward-char -1)
(looking-back ruby-syntax-before-regexp-re
(point-at-bol))))
;; End of regexp. We don't match the whole
;; regexp at once because it can have
;; string interpolation inside, or span
;; several lines.
(eq ?/ (nth 3 state)))
(string-to-syntax "\"/")))))
;; Expression expansions in strings. We're handling them
;; here, so that the regexp rule never matches inside them.
(ruby-expression-expansion-re
(0 (ignore (ruby-syntax-propertize-expansion))))
("^=en\\(d\\)\\_>" (1 "!"))
("^\\(=\\)begin\\_>" (1 "!"))
;; Handle here documents.
((concat ruby-here-doc-beg-re ".*\\(\n\\)")
(7 (unless (or (nth 8 (save-excursion
(syntax-ppss (match-beginning 0))))
(ruby-singleton-class-p (match-beginning 0)))
(put-text-property (match-beginning 7) (match-end 7)
'syntax-table (string-to-syntax "\""))
(ruby-syntax-propertize-heredoc end))))
;; Handle percent literals: %w(), %q{}, etc.
((concat "\\(?:^\\|[[ \t\n<+(,=]\\)" ruby-percent-literal-beg-re)
(1 (prog1 "|" (ruby-syntax-propertize-percent-literal end)))))
(point) end)))
(defun ruby-syntax-propertize-heredoc (limit)
(let ((ppss (syntax-ppss))
(res '()))
(when (eq ?\n (nth 3 ppss))
(save-excursion
(goto-char (nth 8 ppss))
(beginning-of-line)
(while (re-search-forward ruby-here-doc-beg-re
(line-end-position) t)
(unless (ruby-singleton-class-p (match-beginning 0))
(push (concat (ruby-here-doc-end-match) "\n") res))))
(save-excursion
;; With multiple openers on the same line, we don't know in which
;; part `start' is, so we have to go back to the beginning.
(when (cdr res)
(goto-char (nth 8 ppss))
(setq res (nreverse res)))
(while (and res (re-search-forward (pop res) limit 'move))
(if (null res)
(put-text-property (1- (point)) (point)
'syntax-table (string-to-syntax "\""))))
;; End up at bol following the heredoc openers.
;; Propertize expression expansions from this point forward.
))))
(defun ruby-syntax-enclosing-percent-literal (limit)
(let ((state (syntax-ppss))
(start (point)))
;; When already inside percent literal, re-propertize it.
(when (eq t (nth 3 state))
(goto-char (nth 8 state))
(when (looking-at ruby-percent-literal-beg-re)
(ruby-syntax-propertize-percent-literal limit))
(when (< (point) start) (goto-char start)))))
(defun ruby-syntax-propertize-percent-literal (limit)
(goto-char (match-beginning 2))
;; Not inside a simple string or comment.
(when (eq t (nth 3 (syntax-ppss)))
(let* ((op (char-after))
(ops (char-to-string op))
(cl (or (cdr (aref (syntax-table) op))
(cdr (assoc op '((?< . ?>))))))
parse-sexp-lookup-properties)
(save-excursion
(condition-case nil
(progn
(if cl ; Paired delimiters.
;; Delimiter pairs of the same kind can be nested
;; inside the literal, as long as they are balanced.
;; Create syntax table that ignores other characters.
(with-syntax-table (make-char-table 'syntax-table nil)
(modify-syntax-entry op (concat "(" (char-to-string cl)))
(modify-syntax-entry cl (concat ")" ops))
(modify-syntax-entry ?\\ "\\")
(save-restriction
(narrow-to-region (point) limit)
(forward-list))) ; skip to the paired character
;; Single character delimiter.
(re-search-forward (concat "[^\\]\\(?:\\\\\\\\\\)*"
(regexp-quote ops)) limit nil))
;; Found the closing delimiter.
(put-text-property (1- (point)) (point) 'syntax-table
(string-to-syntax "|")))
;; Unclosed literal, do nothing.
((scan-error search-failed)))))))
(defun ruby-syntax-propertize-expansion ()
;; Save the match data to a text property, for font-locking later.
;; Set the syntax of all double quotes and backticks to punctuation.
(let* ((beg (match-beginning 2))
(end (match-end 2))
(state (and beg (save-excursion (syntax-ppss beg)))))
(when (ruby-syntax-expansion-allowed-p state)
(put-text-property beg (1+ beg) 'ruby-expansion-match-data
(match-data))
(goto-char beg)
(while (re-search-forward "[\"`]" end 'move)
(put-text-property (match-beginning 0) (match-end 0)
'syntax-table (string-to-syntax "."))))))
(defun ruby-syntax-expansion-allowed-p (parse-state)
"Return non-nil if expression expansion is allowed."
(let ((term (nth 3 parse-state)))
(cond
((memq term '(?\" ?` ?\n ?/)))
((eq term t)
(save-match-data
(save-excursion
(goto-char (nth 8 parse-state))
(looking-at "%\\(?:[QWrxI]\\|\\W\\)")))))))
(defun ruby-syntax-propertize-expansions (start end)
(save-excursion
(goto-char start)
(while (re-search-forward ruby-expression-expansion-re end 'move)
(ruby-syntax-propertize-expansion))))
)
;; For Emacsen where syntax-propertize-rules is not (yet) available,
;; fallback on the old font-lock-syntactic-keywords stuff.
(defconst ruby-here-doc-end-re
"^\\([ \t]+\\)?\\(.*\\)\\(\n\\)"
"Regexp to match the end of heredocs.
This will actually match any line with one or more characters.
It's useful in that it divides up the match string so that
`ruby-here-doc-beg-match' can search for the beginning of the heredoc.")
(defun ruby-here-doc-beg-match ()
"Return a regexp to find the beginning of a heredoc.
This should only be called after matching against `ruby-here-doc-end-re'."
(let ((contents (concat
(regexp-quote (concat (match-string 2) (match-string 3)))
(if (string= (match-string 3) "_") "\\B" "\\b"))))
(concat "<<"
(let ((match (match-string 1)))
(if (and match (> (length match) 0))
(concat "\\(?:-\\([\"']?\\)\\|\\([\"']\\)"
(match-string 1) "\\)"
contents "\\(\\1\\|\\2\\)")
(concat "-?\\([\"']\\|\\)" contents "\\1"))))))
(defconst ruby-font-lock-syntactic-keywords
`(
;; the last $', $", $` in the respective string is not variable
;; the last ?', ?", ?` in the respective string is not ascii code
("\\(^\\|[\[ \t\n<+\(,=]\\)\\(['\"`]\\)\\(\\\\.\\|\\2\\|[^'\"`\n\\\\]\\)*?\\\\?[?$]\\(\\2\\)"
(2 (7 . nil))
(4 (7 . nil)))
;; $' $" $` .... are variables
;; ?' ?" ?` are ascii codes
("\\(^\\|[^\\\\]\\)\\(\\\\\\\\\\)*[?$]\\([#\"'`]\\)" 3 (1 . nil))
;; regexps
("\\(^\\|[[=(,~?:;<>]\\|\\(^\\|\\s \\)\\(if\\|elsif\\|unless\\|while\\|until\\|when\\|and\\|or\\|&&\\|||\\)\\|g?sub!?\\|scan\\|split!?\\)\\s *\\(/\\)[^/\n\\\\]*\\(\\\\.[^/\n\\\\]*\\)*\\(/\\)"
(4 (7 . ?/))
(6 (7 . ?/)))
("^=en\\(d\\)\\_>" 1 "!")
;; Percent literal.
("\\(^\\|[[ \t\n<+(,=]\\)\\(%[xrqQwW]?\\([^<[{(a-zA-Z0-9 \n]\\)[^\n\\\\]*\\(\\\\.[^\n\\\\]*\\)*\\(\\3\\)\\)"
(3 "\"")
(5 "\""))
("^\\(=\\)begin\\_>" 1 (ruby-comment-beg-syntax))
;; Currently, the following case is highlighted incorrectly:
;;
;; <<FOO
;; FOO
;; <<BAR
;; <<BAZ
;; BAZ
;; BAR
;;
;; This is because all here-doc beginnings are highlighted before any endings,
;; so although <<BAR is properly marked as a beginning, when we get to <<BAZ
;; it thinks <<BAR is part of a string so it's marked as well.
;;
;; This may be fixable by modifying ruby-in-here-doc-p to use
;; ruby-in-non-here-doc-string-p rather than syntax-ppss-context,
;; but I don't want to try that until we've got unit tests set up
;; to make sure I don't break anything else.
(,(concat ruby-here-doc-beg-re ".*\\(\n\\)")
,(+ 1 (regexp-opt-depth ruby-here-doc-beg-re))
(ruby-here-doc-beg-syntax))
(,ruby-here-doc-end-re 3 (ruby-here-doc-end-syntax)))
"Syntactic keywords for Ruby mode. See `font-lock-syntactic-keywords'.")
(defun ruby-comment-beg-syntax ()
"Return the syntax cell for a the first character of a =begin.
See the definition of `ruby-font-lock-syntactic-keywords'.
This returns a comment-delimiter cell as long as the =begin
isn't in a string or another comment."
(when (not (nth 3 (syntax-ppss)))
(string-to-syntax "!")))
(defun ruby-in-here-doc-p ()
"Return whether or not the point is in a heredoc."
(save-excursion
(let ((old-point (point)) (case-fold-search nil))
(defun ruby-syntax-propertize-heredoc (limit)
(let ((ppss (syntax-ppss))
(res '()))
(when (eq ?\n (nth 3 ppss))
(save-excursion
(goto-char (nth 8 ppss))
(beginning-of-line)
(catch 'found-beg
(while (and (re-search-backward ruby-here-doc-beg-re nil t)
(not (ruby-singleton-class-p)))
(if (not (or (ruby-in-ppss-context-p 'anything)
(ruby-here-doc-find-end old-point)))
(throw 'found-beg t)))))))
(while (re-search-forward ruby-here-doc-beg-re
(line-end-position) t)
(unless (ruby-singleton-class-p (match-beginning 0))
(push (concat (ruby-here-doc-end-match) "\n") res))))
(save-excursion
;; With multiple openers on the same line, we don't know in which
;; part `start' is, so we have to go back to the beginning.
(when (cdr res)
(goto-char (nth 8 ppss))
(setq res (nreverse res)))
(while (and res (re-search-forward (pop res) limit 'move))
(if (null res)
(put-text-property (1- (point)) (point)
'syntax-table (string-to-syntax "\""))))
;; End up at bol following the heredoc openers.
;; Propertize expression expansions from this point forward.
))))
(defun ruby-here-doc-find-end (&optional limit)
"Expects the point to be on a line with one or more heredoc openers.
Returns the buffer position at which all heredocs on the line
are terminated, or nil if they aren't terminated before the
buffer position `limit' or the end of the buffer."
(save-excursion
(beginning-of-line)
(catch 'done
(let ((eol (point-at-eol))
(case-fold-search nil)
;; Fake match data such that (match-end 0) is at eol
(end-match-data (progn (looking-at ".*$") (match-data)))
beg-match-data end-re)
(while (re-search-forward ruby-here-doc-beg-re eol t)
(setq beg-match-data (match-data))
(setq end-re (ruby-here-doc-end-match))
(defun ruby-syntax-enclosing-percent-literal (limit)
(let ((state (syntax-ppss))
(start (point)))
;; When already inside percent literal, re-propertize it.
(when (eq t (nth 3 state))
(goto-char (nth 8 state))
(when (looking-at ruby-percent-literal-beg-re)
(ruby-syntax-propertize-percent-literal limit))
(when (< (point) start) (goto-char start)))))
(set-match-data end-match-data)
(goto-char (match-end 0))
(unless (re-search-forward end-re limit t) (throw 'done nil))
(setq end-match-data (match-data))
(defun ruby-syntax-propertize-percent-literal (limit)
(goto-char (match-beginning 2))
;; Not inside a simple string or comment.
(when (eq t (nth 3 (syntax-ppss)))
(let* ((op (char-after))
(ops (char-to-string op))
(cl (or (cdr (aref (syntax-table) op))
(cdr (assoc op '((?< . ?>))))))
parse-sexp-lookup-properties)
(save-excursion
(condition-case nil
(progn
(if cl ; Paired delimiters.
;; Delimiter pairs of the same kind can be nested
;; inside the literal, as long as they are balanced.
;; Create syntax table that ignores other characters.
(with-syntax-table (make-char-table 'syntax-table nil)
(modify-syntax-entry op (concat "(" (char-to-string cl)))
(modify-syntax-entry cl (concat ")" ops))
(modify-syntax-entry ?\\ "\\")
(save-restriction
(narrow-to-region (point) limit)
(forward-list))) ; skip to the paired character
;; Single character delimiter.
(re-search-forward (concat "[^\\]\\(?:\\\\\\\\\\)*"
(regexp-quote ops)) limit nil))
;; Found the closing delimiter.
(put-text-property (1- (point)) (point) 'syntax-table
(string-to-syntax "|")))
;; Unclosed literal, do nothing.
((scan-error search-failed)))))))
(set-match-data beg-match-data)
(goto-char (match-end 0)))
(set-match-data end-match-data)
(goto-char (match-end 0))
(point)))))
(defun ruby-syntax-propertize-expansion ()
;; Save the match data to a text property, for font-locking later.
;; Set the syntax of all double quotes and backticks to punctuation.
(let* ((beg (match-beginning 2))
(end (match-end 2))
(state (and beg (save-excursion (syntax-ppss beg)))))
(when (ruby-syntax-expansion-allowed-p state)
(put-text-property beg (1+ beg) 'ruby-expansion-match-data
(match-data))
(goto-char beg)
(while (re-search-forward "[\"`]" end 'move)
(put-text-property (match-beginning 0) (match-end 0)
'syntax-table (string-to-syntax "."))))))
(defun ruby-here-doc-beg-syntax ()
"Return the syntax cell for a line that may begin a heredoc.
See the definition of `ruby-font-lock-syntactic-keywords'.
This sets the syntax cell for the newline ending the line
containing the heredoc beginning so that cases where multiple
heredocs are started on one line are handled correctly."
(save-excursion
(goto-char (match-beginning 0))
(unless (or (ruby-in-ppss-context-p 'non-heredoc)
(ruby-in-here-doc-p))
(string-to-syntax "\""))))
(defun ruby-here-doc-end-syntax ()
"Return the syntax cell for a line that may end a heredoc.
See the definition of `ruby-font-lock-syntactic-keywords'."
(let ((pss (syntax-ppss)) (case-fold-search nil))
;; If we aren't in a string, we definitely aren't ending a heredoc,
;; so we can just give up.
;; This means we aren't doing a full-document search
;; every time we enter a character.
(when (ruby-in-ppss-context-p 'heredoc pss)
(defun ruby-syntax-expansion-allowed-p (parse-state)
"Return non-nil if expression expansion is allowed."
(let ((term (nth 3 parse-state)))
(cond
((memq term '(?\" ?` ?\n ?/)))
((eq term t)
(save-match-data
(save-excursion
(goto-char (nth 8 pss)) ; Go to the beginning of heredoc.
(let ((eol (point)))
(beginning-of-line)
(if (and (re-search-forward (ruby-here-doc-beg-match) eol t) ; If there is a heredoc that matches this line...
(not (ruby-in-ppss-context-p 'anything)) ; And that's not inside a heredoc/string/comment...
(progn (goto-char (match-end 0)) ; And it's the last heredoc on its line...
(not (re-search-forward ruby-here-doc-beg-re eol t))))
(string-to-syntax "\"")))))))
(goto-char (nth 8 parse-state))
(looking-at "%\\(?:[QWrxI]\\|\\W\\)")))))))
(unless (functionp 'syntax-ppss)
(defun syntax-ppss (&optional pos)
(parse-partial-sexp (point-min) (or pos (point)))))
)
(defun ruby-syntax-propertize-expansions (start end)
(save-excursion
(goto-char start)
(while (re-search-forward ruby-expression-expansion-re end 'move)
(ruby-syntax-propertize-expansion))))
(defun ruby-in-ppss-context-p (context &optional ppss)
(let ((ppss (or ppss (syntax-ppss (point)))))
@ -1880,14 +1713,6 @@ See the definition of `ruby-font-lock-syntactic-keywords'."
"context name `" (symbol-name context) "' is unknown"))))
t)))
(if (featurep 'xemacs)
(put 'ruby-mode 'font-lock-defaults
'((ruby-font-lock-keywords)
nil nil nil
beginning-of-line
(font-lock-syntactic-keywords
. ruby-font-lock-syntactic-keywords))))
(defvar ruby-font-lock-syntax-table
(let ((tbl (copy-syntax-table ruby-mode-syntax-table)))
(modify-syntax-entry ?_ "w" tbl)
@ -2082,9 +1907,7 @@ The variable `ruby-indent-level' controls the amount of indentation.
(setq-local font-lock-keywords ruby-font-lock-keywords)
(setq-local font-lock-syntax-table ruby-font-lock-syntax-table)
(if (eval-when-compile (fboundp 'syntax-propertize-rules))
(setq-local syntax-propertize-function #'ruby-syntax-propertize-function)
(setq-local font-lock-syntactic-keywords ruby-font-lock-syntactic-keywords)))
(setq-local syntax-propertize-function #'ruby-syntax-propertize-function))
;;; Invoke ruby-mode when appropriate