5

I'm writing a Ruby gem using the {key: 'value'} syntax for hashes throughout my code. My tests all pass in 1.9.x, but I (understandably) get syntax error, unexpected ':', expecting ')' in 1.8.7.

Is there a best practice for supporting the 1.8.x? Do I need to rewrite the code using our old friend =>, or is there a better strategy?

mu is too short
  • 396,305
  • 64
  • 779
  • 743
JackCA
  • 4,775
  • 4
  • 23
  • 26
  • 1
    Ruby 1.8 is going to fade out soon. You don't need support for it. – sawa Mar 14 '12 at 02:46
  • 3
    Is that a popular opinion? I am certainly looking for input on what other Gem authors are doing. I know there is a big push within the Ruby community to get everyone on the 1.9 train. I personally don't mind leaving 1.8 behind. – JackCA Mar 14 '12 at 02:53

2 Answers2

16

I think you're out of luck, if you want to support 1.8 then you have to use =>. As usual, I will mention that you must use => in certain cases in 1.9:

  1. If the key is not a symbol. Remember that any object (symbols, strings, classes, floats, ...) can be a key in a Ruby Hash.
  2. If you need a symbol that you'd quote: :'this.that'.
  3. If you use MongoDB for pretty much anything you'll be using things like :$set => hash but $set: hash is a syntax error.

Back to our regularly scheduled programming.

Why do I say that you're out of luck? The Hash literal syntaxes (both of them) are hard-wired in the parser and I don't think you're going to have much luck patching the parser from your gem. Ruby 1.8.7's parse.y has this to say:

assoc    : arg_value tASSOC arg_value
             {
                 $$ = list_append(NEW_LIST($1), $3);
             }
         ;

and tASSOC is => so hash literals are hard-wired to use =>. 1.9.3's says this:

assoc    : arg_value tASSOC arg_value
             {
             /*%%%*/
                 $$ = list_append(NEW_LIST($1), $3);
             /*%
                 $$ = dispatch2(assoc_new, $1, $3);
             %*/
             }
         | tLABEL arg_value
             {
             /*%%%*/
                 $$ = list_append(NEW_LIST(NEW_LIT(ID2SYM($1))), $2);
             /*%
                 $$ = dispatch2(assoc_new, $1, $2);
             %*/
             }
         ;

We have the fat-arrow syntax again (arg_value tASSOC arg_value) and the JavaScript style (tLABEL arg_value); AFAIK, tLABEL is also the source of the restrictions on what sorts of symbols (no :$set, no :'this.that', ...) can be used with the JavaScript-style syntax. The current trunk parse.y matches 1.9.3 for Hash literals.

So the Hash literal syntax is hard-wired into the parser and you're stuck with fat arrows if you want to support 1.8.

mu is too short
  • 396,305
  • 64
  • 779
  • 743
  • very nice and thorough answer, mu. It looks like I might have to rewrite the instances where I use JS style syntax. Just wish there was a way to support legacy versions without writing legacy code. This might be the best bet though. – JackCA Mar 14 '12 at 02:56
1

Ruby 1.8.7 does not support the new hash syntax.

If you desperately need hash syntax on the non-YARV c-based implementation of Ruby, there is a totally unsupported 1.8 head branch, so you can do

rvm install ruby-head --branch ruby_1_8 ; rvm ruby-head
ruby -v
ruby 1.8.8dev (2011-05-25) [i386-darwin10.7.0]

but upgrading to 1.9 is the way to go.

Andrew Grimm
  • 70,470
  • 47
  • 186
  • 310
  • I think the intention of JackCA is to provide a gem that a Ruby 1.8 user can use, not that JackCA is using Ruby 1.8. So I don't think this will help. – sawa Mar 14 '12 at 17:50