Last 25 of December while we were all celebrating with our families the Ruby core team released our Christmas gift.
The release 3.2.0 of Ruby is faster and brought some amazing tools for us.
WebAssembly support
Ruby 3.2.0 added initial support for WebAssembly through WASI, this allows running CRuby in a web browser, for example through TryRuby Playground but it also allows running CRuby securely in different platforms, like running the exact same binary version of ruby in a x86 and arm64 environments.
It isn’t complete yet, the WebAssembly support for Fiber, exception and GC isn’t complete, but is implements a VFS on top of web assembly, what allows the packaging of an entire ruby app into a single .wasm file.
Production Ready YJIT
YJIT is faster and uses less memory than before! it now supports both x86-64 and arm64/aarch64 CPUs on Linux, MacOS, BSD and other UNIX platforms.
To compile ruby with YJIT support you’ll need Rust 1.58.0+ so make sure you install it before running ./configure (or before asking rvm or a similar tool to install it for you)
Wanna know more about YJIT? check this amazing presentation
Regexp matching way faster
Sometimes depending on the Regexp we are using in our ruby code, it is possible to use our notebooks to fry some eggs 😛
But this will change and you’ll need to use the correct pan for that in the future…
The improved regexp matching can keep the regexp time mostly linear in almost all tests done by the Ruby Core team check the graph bellow.
Regexp.timeout can be used for the cases where these improvements fail, for example in complex cases where you use lots of back-references or look-around
Regexp.timeout = 1.0
/^a*b?a*()\1$/ =~ "a" * 50000 + "x"
#=> Regexp::TimeoutError is raised in one second
You can also make one specific Regexp ignore the timeout if needed
Regexp.timeout = 1.0
# This regexp has no timeout
long_time_re = Regexp.new('^a*b?a*()\1$', timeout: Float::INFINITY)
long_time_re =~ "a" * 50000 + "x" # never interrupted
there are other improvements like better syntax error reporting.
A few language improvements like allowing the usage of rest and keyword rest arguments as method parameters
def foo(*)
bar(*)
end
def baz(**)
quux(**)
end
There is a new Data class to represent immutable objects similar to the Struct class today.
Measure = Data.define(:amount, :unit)
distance = Measure.new(100, 'km') #=> #<data Measure amount=100, unit="km">
weight = Measure.new(amount: 50, unit: 'kg') #=> #<data Measure amount=50, unit="kg">
weight.with(amount: 40) #=> #<data Measure amount=40, unit="kg">
weight.amount #=> 50
weight.amount = 40 #=> NoMethodError: undefined method `amount='
Struct now also support keyword arguments
Post = Struct.new(:id, :name)
Post.new(1, "hello") #=> #<struct Post id=1, name="hello">
# From Ruby 3.2, the following code also works without keyword_init: true.
Post.new(id: 1, name: "hello") #=> #<struct Post id=1, name="hello">
You can read the full release notes in this link.