Supporting Ruby 1.9's Hash Syntax in Ruby 1.8

Supporting Ruby 1.9's hash syntax in Ruby 1.8

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.

Allowing for Ruby 1.9's hash syntax?

Even in Ruby < 1.9, you could use symbols for keys. For example:

# Ruby 1.8.7
settings = { :host => "localhost" }
puts settings[:host] #outputs localhost
settings.keys[0].class # => Symbol

Ruby 1.9 changes the way that you create hashes. It takes the key and converts it to a symbol for you, while eliminating the need for a hash rocket.

# Ruby 1.9.2
settings = { host: "localhost" }
settings[:host] # => "localhost"
settings.keys[0].class # => Symbol

In both cases, if I try to access settings[:name] with settings["name"], I'm going to get nil. All Ruby 1.9 does is allow for a new way of creating hashes. To answer your question, you cannot, as far as I know, use the new {key: value} syntax if you want backwards compatibility with Ruby 1.8.

Does Ruby 1.8.7 head support 1.9-style hash literals?

Check the version number: this patch was applied to Ruby 1.8.8, not 1.8.7. Which ruby-core agreed just 4 days ago will never be released. As of last week, 1.8 is officially dead.

1.8.8 was the mythical transitional version that would correctly parse but not execute Ruby 1.9 syntax, so that you could write stuff like

if RUBY_VERSION > '1.8'
->x { x }
else
lambda {|x| x }
end

However, it turned out that everybody who wanted to migrate to Ruby 1.9 was already doing so, and the people that didn't want to migrate would not have been swayed by 1.8.8, so it simply didn't make sense to divert any more resources to it.

What does Ruby have that Python doesn't, and vice versa?

You can have code in the class definition in both Ruby and Python. However, in Ruby you have a reference to the class (self). In Python you don't have a reference to the class, as the class isn't defined yet.

An example:

class Kaka
puts self
end

self in this case is the class, and this code would print out "Kaka". There is no way to print out the class name or in other ways access the class from the class definition body in Python.

accessing instance methods inside a ruby/Rails class but outside an instance method

Unfortunately, it looks like you will have to go the longer way of setting up save callbacks for your comments. I browsed through the gem and it doesn't look like passing a proc for calling later is supported yet (see here).

By the way:

Besides the fact that you are calling the class method and not the instance method, self.comments.count is evaluated when the class is loaded, right there when you call:

 value :redis_comment_count, :default => self.comments.count

# This becomes:
# value :redis_comment_count, :default => 1 # Example

and not every time that the redis-objects gem uses value_options[:default].

This value will keep getting re-evaluated if your class keeps getting reloaded, as in the case of the default setup for the development environment. However, in the production environment where we usually have cache_classes enabled, this value will be evaluated only whenever the Rails application boots up and loads your models.

Passing a proc would work if this were supported.

Regex with named capture groups getting all matches in Ruby

Named captures are suitable only for one matching result.

Ruby's analogue of findall is String#scan. You can either use scan result as an array, or pass a block to it:

irb> s = "123--abc,123--abc,123--abc"
=> "123--abc,123--abc,123--abc"

irb> s.scan(/(\d*)--([a-z]*)/)
=> [["123", "abc"], ["123", "abc"], ["123", "abc"]]

irb> s.scan(/(\d*)--([a-z]*)/) do |number, chars|
irb* p [number,chars]
irb> end
["123", "abc"]
["123", "abc"]
["123", "abc"]
=> "123--abc,123--abc,123--abc"

What does Ruby have that Python doesn't, and vice versa?

You can have code in the class definition in both Ruby and Python. However, in Ruby you have a reference to the class (self). In Python you don't have a reference to the class, as the class isn't defined yet.

An example:

class Kaka
puts self
end

self in this case is the class, and this code would print out "Kaka". There is no way to print out the class name or in other ways access the class from the class definition body in Python.



Related Topics



Leave a reply



Submit