Subject: Re: bug#24181: 25.1.50; ruby mode: wrong auto indent after "?" string literal

From: Dmitry Gutov <[email-masked]>
Date: Sat, 2 Jan 2021 05:06:48 +0200

Sorry for digging this up, just looking through old issues.

On 11.08.2016 09:41, Ryo Furue wrote:

>>> ?a is a valid Ruby syntax for string literal.  After writing this, I
>>> learned
>>> that "a".ord is equivalent (I think)
>>
>> Yes, in Ruby 1.9 and newer, it's a full equivalent.
> 
> After my last message, I learned that Ruby has abandoned the idea of
> "character type" and instead of elevating ?a to a proper character
> literal, it has made it equivalent to a single-character string "a".
> So, a String is no longer a sequence of individual characters (because
> "character" has no representation in the language).  "a".ord returns
> the character code of this single-character string but "abc".ord
> ignores the "bc" part.  I don't think that's a clean design, but
> perhaps it's the simplest, practical one, in the face of various
> character encodings. . . .

This syntax there is purely for compatibility, I believe.

>  That makes me wonder how Haskell handles
> unicode.  In that language, "String" is an alias for "[Char]"  (list
> of Char's). . . . I digressed.

Types in a statically typed language are a bit of a different beast. 
E.g., you can eliminate a lot of associated overhead during compilation. 
Not so with a dynamically typed langues.

For posterity, a fix for the reported problem should look like the patch 
at the end of this message. I'm not going to commit it, though (or, at 
least, not in its current form) because Ruby makes it non-trivial to 
distinguish between these literals and the ternary operator:

 > abc ?( 1+ 2) : 4
=> 3

 > def dee(arg);
 > dee ?( 1+ 2) : 4
SyntaxError ((irb):27: syntax error, unexpected tINTEGER, expecting end)
dee ?( 1+ 2) : 4

Hopefully, the syntax will just be removed in some near future version 
of Ruby and save us the trouble. But here's the patch. To go in, it 
would have to be accompanied by some extra code looking around to 
determine the context.

diff --git a/lisp/progmodes/ruby-mode.el b/lisp/progmodes/ruby-mode.el
index 3effb6ed66..bd74e71f6a 100644
--- a/lisp/progmodes/ruby-mode.el
+++ b/lisp/progmodes/ruby-mode.el
@@ -1854,9 +1854,9 @@ ruby-syntax-propertize
       (syntax-propertize-rules
        ;; $' $" $` .... are variables.
        ;; ?' ?" ?` are character literals (one-char strings in 1.9+).
-      ("\\([?$]\\)[#\"'`:?]"
+      ("\\([?$]\\)[#\"'`:?[:alnum:]]"
         (1 (if (save-excursion
-                (nth 3 (syntax-ppss (match-beginning 0))))
+                (nth 8 (syntax-ppss (match-beginning 0))))
                ;; Within a string, skip.
                (ignore
                 (goto-char (match-end 1)))