Wake up guys, Ruby 1.9 is here!
This post has been updated at 09/07/2011.
I'm disappointed how slowly Ruby community adopts the new Ruby 1.9. Oh wait, it's not new at all, it's more than a year old now! There is still significant amount of gems which aren't 1.9-compatible, my collegueues are asking me why we should upgrade to Ruby 1.9 and for Rubinius core team has compatibility with 1.9 so low priority that they didn't accept my patches for 1.9 compatibility even if I asked then 3 times.
I'm disappointed how slowly Ruby community adopts the new Ruby 1.9. Oh wait, it's not new at all, it's more than a year old now! There is still significant amount of gems which aren't 1.9-compatible, my collegueues are asking me why we should upgrade to Ruby 1.9 and for Rubinius core team has compatibility with 1.9 so low priority that they didn't accept my patches for 1.9 compatibility even if I asked then 3 times.
I know, it wasn't that stable at the beginning, but it works fine now, so what's the problem? I don't expect that folks start to upgrade their legacy code just ‘cause they like Ruby 1.9, but when you are starting with a new project, why not in Ruby 1.9? I'm working with Ruby 1.9 since March 2009, so let me show you what I like about it.
So How Can I Install It?
Thanks to RVM, the installation is absolutely easy, just type install it and run rvm install 1.9 && rvm use 1.9 and that's it!
Ruby 1.9 Versions & Implementations
First stable version from the 1.9 branch was Ruby 1.9.1. Some people don't like it much because some scoping issues (as far as I know) and since development version of 1.9.2 is pretty stable, I'd recommend to use this one. I'm using Ruby 1.9.2 since last Christmas.
You can use Ruby 1.9 features in JRuby as well, the only thing you need to use is the --1.9 switch. There is one important gotcha: You will need to pass this switch for installing gems which require Ruby 1.9 or higher, because RubyGems check if RUBY_VERSION match the required Ruby version. So instead of gem install rango you have to use jruby --1.9 -S gem install rango or just use export RUBYOPT="--1.9" and then you can use just gem install rango as you are use to.
JRuby is compatible with 1.9.2, not with 1.9.1. I tried and the support isn't bad, a lot of features is implemented, but not everything is so stable.
Ruby 1.9: The Good Parts
Probably everyone knows at least about the main changes which are YARV, Ruby virtual machine. Thanks to YARV, Ruby 1.9 is much faster not just than Ruby 1.8, but also than most of the alternative Ruby implementation except JRuby.
Another big change happened in threads implementation: as you probably know, Ruby 1.8 use green threads which can't use more processor cores. In Ruby 1.9 the implementation finally changed to native threads and also, as a much more light-weight alternative, fibers were added (very useful thing in my opinion).
The third really big change is support for unicode. Or to be precise, for encodings. String isn't a byte sequence anymore, so "hey"[0] is "h" rather than 104. Unfortunately encodings aren't just a good thing (see the section about these bad parts of Ruby 1.9).
Another very pleasant difference, is a new syntax for hash, instead of using {:key => "value"} you can use just {key: "value"}. Although this might not seems as a good reason for using new Ruby, in fact it is, because it really makes difference in code readability, mainly in libraries which heavily uses options hashes like everything Rake, Rails or Capistrano related.
Encoding
Unlike in most of the other languages, there is no default internal encoding (Japanese guys doesn't like UTF-8), so you need to set it up via magic comment # encoding: utf-8. You also should know that there are 3 types of encoding: encoding of the sources, encoding in which IO is read and encoding to which the data are converted. So you can read file as latin2 and convert it to UTF-8 just setting internal encoding to latin2 and external encoding to UTF-8.
Anyway this is quite complex topic, so I'd recommend you to go through character encodings series by James Edward Gray II.
Arguments Parsing
Since Ruby 1.9 splat argument doesn't have to be the last one before the blok argument, so you can do:
def hello(*foo, bar)
end
Argument parsing for procs & lambdas is finally same as for methods. That's a very good thing, consider following:
lambda { |&block| }
lambda { |*args, params = Hash.new| }
Also all the block arguments are always local variables and you can even create additional variables local for block by:
lambda { |;a, b| }
In my experience, improved argument parsing is one of the best things about Ruby 1.9, I used it many times. For example in my Rake replacement called Nake where you can do task.define(*args, options = Hash.new), so when you call this task from command-line with <the-task-name> /tmp /home --dry-run, then the task get ["/tmp", "/home"] into args and {dry_run: true} into options.
Ruby 1.9.2 adds another awesome method Method#parameters, so you don't have to use ParseTree anymore for action-args:
lambda { |a, b = 2, *args, &block| }.parameters
# => [[:req, :a], [:opt, :b], [:rest, :args], [:block, :block]]
I'm using it in Rango and the implementation is just dead-simple: rango/mixins/action_args.
Useful New Methods & Constants
Kernel#require_relativeHash#default_proc=Kernel#define_singleton_method-
RUBY_ENGINEto distinguish between Ruby processor implementation BasicObject
Changed Methods
"%{title} %{name} %{surname}" % {title: "Mr.", name: "Jakub", surname: "Stastny"}-
#[]can take splatted arguments, hash style arguments and a block. - Negative operators such as
!,!=and!~are now overloadable. It's not anything you should use, but it's a sign of improving official implementation of Ruby. Binding#eval- non-blocking IO
-
Hash#selectreturns a hash -
Hashpreserves order. It enumerates its elements in the order in which the keys are inserted. -
Kernel#callccandContinuationnow becomecontinuationbundled library. -
Method#source_location,UnboundMethod#source_locationandProc#source_location - __callee__
- Elements in
$LOAD_PATHand$LOADED_FEATURESare expanded -
--enable-gems,--disable-gems -
--enable-rubyopt,--disable-rubyopt
... And The Bad Ones
Since I'm not very big fan of RubyGems, I'm not very pleased that this crap found its way into Ruby runtime. I think it would be nice to distribute Ruby with RubyGems, but require RubyGems in runtime by default? That's just mental. Of course I understand the idea behind it, do not confuse newbies, but this approach (should) have other side “don't piss off advanced users” as well. So ruby --disable-gems FTW!
Another thing is the encoding support. Encoding support in general is a good thing, but ... well, the implementation isn't very good. Read the linked page, it's really worthy.
My projects doesn't support 1.8 anymore. I don't have the need. Since I have s.required_ruby_version = ::Gem::Requirement.new("~> 1.9") in my gemspec, you won't be able to install my projects under 1.8 at all. If you download it from GitHub, it will fail with syntax error because I'm using new hash syntax etc. I believe it's an argument to not use my projects for a lot of people, on the other side some people switched to 1.9 because of them, so I believe it's worthy.
And you! Yeah I'm talking with you, the guy sitting at the computer and reading this ... whatever you want to call it – what are you going to do about that? Are your gems compatible with 1.9?
