Greg Navis Profile picture
Jan 5, 2023 18 tweets 5 min read Read on X
🆕 Ruby 3.2 is out, so let's start 2023 by exploring what's new.

Many of the changes warrant separate deep-dives, but we can describe them briefly to raise awareness.

Let's roll!
1/16 New hook method! 🎉

Whenever a new constant is added to a module, .const_added is called with that constant's name as a symbol.

Example use case: automatic registration of classes inside a module with some third-party API
2/16 New core class: Data

Data is like Struct for immutable value objects. Changing its attributes is only possible by creating a new instance with the updated values.

I think immutability is a promising direction to explore in Ruby.
3/16 Rest and keyword rest arguments can be forwarded anonymously.

In other words: if a method only references rest arguments to forward them to another method then these rest arguments can be unnamed.

Result: positional, keyword, and block arguments can be anonymous!
4/16 Ruby pattern matching is constantly evolving, and 3.2 is another step in its evolution.

The find pattern is no longer considered experimental.

Find pattern = one or more adjacent array items, with some items before or after them.
5/16 Regexp performance improvements / DoS protection

Many regexps can now be matched in linear time, providing DoS protection.

A match timeout can be set, providing a fallback protection.
6/16 Error reporting improvements

Syntax errors are more informative, and try to point to causes.

Type and argument errors are mapped to more specific locations in program text.

Such quality of life improvements DO accumulate, and help produce great developer experience.
7/16 WASI-based WebAssembly

The Ruby interpreter can now be run in WebAssembly environments (e.g. the browser), and interact with the operating system via WASI.

WASI = set of APIs WebAssembly code can use to manage files, open sockets, etc. outside of browsers.
8/16 YJIT is production-ready 🎉

YJIT is a just-in-time compiler developed by Shopify and GitHub. It's 40% faster in synthetic benchmarks than not using JIT.

Additionally, it supports arm64 now, e.g. Apple M1.

Enable via `ruby --yjit`
9/16 Procs taking one positional parameter + keyword parameters behave in a less surprising way

It's a bit of an edge case, but I'm sure you can totally imagine wasting time debugging it.

Fortunately, Ruby 3.2 is much less surprising here!
10/16 Left-to-right constant assignment on explicit objects

This was another potentially surprising behavior, which was made predictable in 3.2.
11/16 Bundler (but not RubyGems!) has switched its dependency resolution algorithm from Molinillo to PubGrub.

PubGrub is more efficient and offers more helpful error messages in case of conflicting package dependencies.

Another DX improvement!
12/16 Refinements and meta-programming

Ruby 3.2 offers more methods for reflection related to refinements. It's not something you'd use often, but it's there in case you're doing meta-programming.
13/16 MatchData can return a byte range, in addition to character range, for a capturing group.

Very helpful when working with regular expressions at a byte level, as it saves you from determining offsets manually.
14/16 String got three byte-level methods:

• byteindex - byte-level offset of a substring
• byterindex - same as above, but for the last occurence
• bytesplice - replace a range of bytes within the string
15/16 Other improvements:

• MJIT was reimplemented from C to Ruby
• Set is built-in
• Hash: shift returns nil even if there's a default
• Proc: dup and parameters improvements
• Some new parser options
• Struct can be initialized with keyword arguments by default
16/16 Last but not least, some removals:

• Fixnum, Bignum, and a few other consts
• taint- and trust- related methods
• No libyyaml and libffi
That's 99% of changes brought by Ruby 3.2.

I'll explore some of them in deep-dive threads and articles, so follow me @gregnavis not to miss them.

You can help other Rubyists catch up on the latest changed by liking and retweeting the thread.

• • •

Missing some Tweet in this thread? You can try to force a refresh
 

Keep Current with Greg Navis

Greg Navis Profile picture

Stay in touch and get notified when new unrolls are available from this author!

Read all threads

This Thread may be Removed Anytime!

PDF

Twitter may remove this content at anytime! Save it as PDF for later use!

Try unrolling a thread yourself!

how to unroll video
  1. Follow @ThreadReaderApp to mention us!

  2. From a Twitter thread mention us with a keyword "unroll"
@threadreaderapp unroll

Practice here first or read more on our help page!

More from @gregnavis

Oct 2, 2024
🆕 There were a few interesting releases in the last few days, so I wanted to bring them to your attention in case you missed them.

1. PostgreSQL 17.
2. Solid Queue 1.0.
3. Kamal 2.0.
4. Hotwire Native.
5. @dhh's keynote.

Let's have a quick look at each.
PostgreSQL 17

1. Vacuum, I/O performance, and query performance gains.
2. JSON_TABLE for converting JSON documents into tables.
3. More features added to MERGE.
4. Simpler upgrades when using logical replication + failover!

postgresql.org/about/news/pos…
Solid Queue 1.0 - database-backed job queue; Redis not required 🎊

In addition to generic job queue features, this release brings:

1. cron jobs.
2. Bulk enqueues.
3. Safe and atomic batch discards, retries, and unblocks.
4. Lifecycle hooks for supervisors and workers.

dev.37signals.com/solid-queue-v1…
Read 7 tweets
Apr 28, 2023
💡 Rails tip: Rails 7 shipped with error handling infrastructure

It's a small module, but I find it extremely useful, especially when integrating with third-party APIs, as you usually want to gracefully inform the user the API is down, but still report that internally.

Ready?
At a high level:

- there are multiple subscribers registered with the error reporter
- each error is passed to each subscriber
- the reporter offers methods for detecting, reporting, and swallowing exceptions thrown by the app

Let's take a close look at those methods. Image
Rails.error.handle - runs the block, swallows and records any exceptions raised by it

If no exceptions are raised then the block value is returned.

If an exception is raised then nil is returned, unless a fallback is given, but more on that in a minute.

Let's talk about ... Image
Read 11 tweets
Apr 5, 2023
💡 Ruby meta-programming tip: it's trivial to add support for object literals to Ruby

Object literals are frequently found in JavaScript: these are objects defined on the spot, both state and methods, without a prior class definition.

Let's try to add them to Ruby! ⬇️
Let's start with a JavaScript example: an app object comprised of a database connection and a router; there's a method to start the whole thing up.

The app object was instantiated without a class definition.

How would a Ruby counterpart look like? Image
Theoretically, we could define a Hash mapping keys to objects, some of these objects being Procs.

This would be a direct translation of JavaScript code, but it wouldn't fit the Ruby object model and would feel extremely unidiomatic.

Fortunately, we can do better. MUCH better!
Read 7 tweets
Mar 25, 2023
💡 Ruby meta-programming: lazy accessors are simple to implement and more robust than lazy computations via ||=

Meta-programming can be fun, productive, and helpful. Let's have a look at another example, including a bigger engineering lesson.

⬇️ Let's go!
What's a lazy accessor?

It's an accessor with a block of code to determine a value. That block of code is called only on first use; subsequent calls reuse the value the block returned.

In short: lazy accessor = laziness + caching
What are its applications?

Primarily, deferring expensive computations until needed and ensuring they are run only once.

Example: expensive database reporting query with further result processing in Ruby.

Let's have a look at the idiomatic way of handling that in Ruby ...
Read 9 tweets
Mar 24, 2023
💡 Ruby meta-programming idea: final classes can be easily implemented in Ruby

I've actually published a gem whose first feature is exactly that. More on that later though. Let's understand the concept of final classes first.

Ready? Set? Go!
What's a final class?

A final class is a class that cannot be inherited from. Any attempt to subclass it would result in an error (compile-time or runtime, depending on the language).

It's a foreign concept in Ruby land, so let's have a look at other languages.
In UIKit, Apple's UI framework, there's a view controller called UIAlertController for displaying all sorts of alerts.

Technically, it's NOT final, but the documentation says it should be used as-is and not subclassed.

That would be a perfect fit for being final.
Read 12 tweets
Mar 8, 2023
💡 Rails tip: as_json can be used to convert models into ... no, not JSON ... into hashes

It can be useful when building and working with APIs, so it's always a good idea to understand how it works. It's implemented by Active Model and is quite generic.

Let's dive in! 🤿 😅
Called without arguments it returns a hash including all columns in the model.

Is this a good idea? NO!

⚠️ Do that in a public API and it's guaranteed you'll leak sensitive data sooner or later. Therefore, you should use this rarely, if ever.

What's the alternative? Image
You can whitelist or blacklist columns (and wrap the output in a hash).

My recommendation: whitelist by default, unless you're sure blacklisting is better

You may think whitelisting and blacklisting are two sides of the same coin but they are NOT!

Let's discuss why. Image
Read 9 tweets

Did Thread Reader help you today?

Support us! We are indie developers!


This site is made by just two indie developers on a laptop doing marketing, support and development! Read more about the story.

Become a Premium Member ($3/month or $30/year) and get exclusive features!

Become Premium

Don't want to be a Premium member but still want to support us?

Make a small donation by buying us coffee ($5) or help with server cost ($10)

Donate via Paypal

Or Donate anonymously using crypto!

Ethereum

0xfe58350B80634f60Fa6Dc149a72b4DFbc17D341E copy

Bitcoin

3ATGMxNzCUFzxpMCHL5sWSt4DVtS8UqXpi copy

Thank you for your support!

Follow Us!

:(