https://railsatscale.com/2023-12-19-irb-for-ruby-3-3/ [ras_icon_n] Rails at Scale [shopify_gl] [ ] About Unveiling the big leap in Ruby 3.3's IRB 2023-12-24 * Stan Lo In this blog post, we will delve into the major enhancements introduced in Ruby 3.3's IRB, as well as what's currently planned for the next year. In a nutshell, Ruby 3.3's IRB offers improved debugging capabilities, an enhanced autocompletion experience, and an overall improved user experience. It's worth noting that even if you don't upgrade to Ruby 3.3 immediately, you can still install the same version of IRB (v1.11.0) in any Ruby 2.7+ projects by adding gem "irb" to its Gemfile. Table Of Contents * Advancing Debugging with IRB + Accessing irb:rdbg from binding.break / debugger * Enhancing Autocompletion + Addressing Completion Dropdown Issues + Customizing Dropdown UI with Reline::Face + Experimenting with More Accurate Completion Using RBS * Quality of Life Improvements + Pager Support + Omitting Return Value Inspection with ; + History Command + Streamlined Prompt + Enhanced show_source Command * What's on the Horizon for Ruby 3.4? + The help Command Will Print Help Message + Enhancing Extensibility: Command and Helper Method * Acknowledgements Advancing Debugging with IRB In Ruby 3.2's IRB (v1.6), we introduced a set of shortcut commands such as debug and next that allowed for a swift transition to the debug gem's session from a binding.irb breakpoint. (To avoid confusion, I'll refer to the debug gem's session as rdbg from here on.) This was a significant improvement. However, with the switch, users would instantly lose certain IRB features, such as multi-line input: irb(main):001:0> debug (ruby) if true eval error: (rdbg)/test.rb:1: syntax error, unexpected end-of-input, expecting `then' or ';' or '\n' if true ^ nil (rdbg) This year, we've taken the user experience to a new level by introducing the irb:rdbg session, which allows users to execute all rdbg commands without exiting the IRB session. irb(main):001> debug irb:rdbg(main):002* if true irb:rdbg(main):003* puts "Multi-line input and more!" irb:rdbg(main):004> end Multi-line input and more! nil irb:rdbg(main):005> th # `th` (show all threads) is a example of a command only present in a `rdbg` session --> #0 (sleep)@test.rb:2:in `
' irb:rdbg(main):006> This deep integration offers several advantages: * Access to both IRB and rdbg's commands * Multi-line input * Autocompletion * Symbol aliases to commands, like @ (whereami) and $ (show_source) * Pager support But most importantly, it offers users a debugging experience equivalent to pry-byebug. Accessing irb:rdbg from binding.break / debugger With the debug gem v1.9.0, which will also be part of Ruby 3.3, you can configure it to run irb:rdbg either by: * Setting its irb_console config through the RUBY_DEBUG_IRB_CONSOLE =1 environment variable * Running the irb command in a rdbg session Doing so will give you the same irb:rdbg session in your debug console: $ RUBY_DEBUG_IRB_CONSOLE=1 bundle exec rdbg test.rb [1, 1] in test.rb => 1| a = 1 =>#0
at test.rb:1 irb:rdbg(main):002> Enhancing Autocompletion Addressing Completion Dropdown Issues In Ruby 3.1, IRB introduced the autocompletion feature. While it has proven to be a useful feature for many users, it also came with some issues that were hard to overlook: * The dropdown could push up the prompt when the candidate list is long. This not only distracts users but also pushes up the output history, forcing users to frequently scroll up and down through the session. * The dropdown's colors are not configurable, making text hard to read with some terminal themes. * Under certain conditions, the dropdown could erase previously rendered content. Here's a short demonstration of these issues: autocompletion issues demo However, thanks to several fixes on the Reline gem (a pure-Ruby replacement of readline), these issues have been addressed. improved autocompletion demo We are aware that there are other existing issues, such as the lack of debouncing or tab-completion options. And we will keep improving the feature in future releases. Customizing Dropdown UI with Reline::Face With Reline v0.4.0+, you can use the Reline::Face class to customize the dropdown UI's style in your .irbrc. For instance, this snippet will change the dropdown from its default color scheme to a black-and-white theme: Reline::Face.config(:completion_dialog) do |conf| conf.define :default, foreground: :white, background: :black conf.define :enhanced, foreground: :black, background: :white conf.define :scrollbar, foreground: :white, background: :black end The result can be seen below: [black-and-] left: default, right: with the customization Experimenting with More Accurate Completion Using RBS Currently, IRB's autocompletion is powered by a combination of regular expressions and runtime information from Binding. This provides a decent result for the first level of completion, but can't support chained method calls. For example, when the user types 'Ruby'.up, IRB can list upcase and upcase!, because it knows 'Ruby' is a String. But when the user types 'Ruby'.upcase., IRB can't make another suggestion. This is because it cannot evaluate 'Ruby'.upcase to get its value as it risks causing side-effects (for example, calling User.all. in a Rails app). However, there is another way we can get an object's information without evaluation in Ruby: gradual typing. Therefore, this year @tompng initiated the repl_type_completor project to explore if it's a feasible replacement for the current regexp-based completor. To give it a try, you need to add this to your Gemfile: gem "repl_type_completor", group: [:development, :test] And to activate it: * Pass the --type-completor flag when starting IRB * Or add this to your irbrc file: IRB.conf[:COMPLETOR] = :type # default is :regexp For more details, please refer to IRB readme's type completion section. Quality of Life Improvements Pager Support This year, IRB has introduced pager support on the output of: * The show_source, ls, and show_cmds commands * The new history command * Evaluation result When these outputs' height exceeds your terminal's, IRB will now paginate them: pager demo This offers several benefits: * You can freely scroll up and down with your arrow-up/down keys * You won't overscroll to some previous IRB output * By typing /[search_term], like /foo, inside a pager, you can easily search any text that contains foo + This could be extremely useful when inspecting record(s) in a Rails console We understand that for some users or under certain conditions, a pager could be more of a hindrance than a help. Therefore, it's also possible to disable it with the --no-pager flag, or by adding this to your irbrc file: IRB.conf[:USE_PAGER] = false Omitting Return Value Inspection with ; Even though paging evaluation result should make long output easier to inspect, sometimes we simply don't want to see the return value of certain expressions. For example, the result of users = User.all when it returns hundreds of records. In such cases, the new IRB allows users to omit the return value by adding a ; at the end, like users = User.all;. Example irb(main):001> long_string = "foo" * 10000; irb(main):002> long_string.size => 30000 History Command IRB now has a history command to display all stored input history (which by default is limited to 1000). Since we usually have a long input history, this command also comes with a -g [term] flag for filtering. irb(main):006> history -g self 1000: history -g self 803: self 769: self 731: watch self @foo 698: break self.inspect 584: self 582: self Streamlined Prompt As you may have noticed, IRB's prompt is now a bit shorter: Before irb(main):001:0> After irb(main):001> The removed part is the indent level number, which became redundant after IRB implemented a robust auto-indent feature for multi-line input. Enhanced show_source Command The show_source command has always been an essential tool for many IRB users, especially for debugging. This year it received two enhancements that will make it even more useful: * You can now use -s to get the method's super definition if it has one * It can now display private methods too The -s Flag Given this script: class Foo def foo "foo" end end class Bar < Foo def foo super + "bar" end end You can now get both Bar#foo and its super method (Foo#foo)'s definition: irb(main):001> show_source Bar#foo From: test.rb:8 def foo super + "bar" end => nil irb(main):002> show_source Bar#foo -s From: test.rb:2 def foo "foo" end => nil You can also stack the flag, like -ss, to walk up the super method chain. And if IRB can't find the super definition anymore, it'll notify you with: irb(main):003> show_source Bar#foo -ss Error: Couldn't locate a super definition for Bar#foo => nil What's on the Horizon for Ruby 3.4? The help Command Will Print Help Message When we use a terminal-based application, the first thing we normally do is to type help and learn how to use it. However, due to historical reasons, IRB's help command opens up an ri input for Ruby document lookup instead. This unconventional design can make it hard, especially for new Ruby developers, to learn IRB's usage. So we decided to change it in several steps: 1. In Ruby 3.2, we added show_cmds to print the help message and show_doc command as an alias to the help command. 2. In Ruby 3.3, IRB will warn users that help is going to be repurposed to act as show_cmds. 3. In early 2024, we plan to release IRB v2.0, with the repurposing of help command being one of the breaking changes. Enhancing Extensibility: Command and Helper Method Several major Ruby web frameworks, such as Rails and Hanami, utilize IRB as a platform for their consoles. Additionally, other libraries extend IRB with their custom features via commands. However, until now, there have been no standard APIs on the IRB side to accommodate new commands or helper methods. This situation leads to several challenges: * IRB is unable to display these extended features in its help message. * Refactoring the relevant parts becomes challenging because they are essentially public when private APIs are used directly. * Projects need to devise their own ways to utilize IRB, often resulting in similar but slightly different solutions. To address these issues, we plan to provide official APIs and relevant documentation to help libraries and applications extend IRB. Our goal is to transform IRB from not just a great tool, but also into a great platform for other tools. Acknowledgements The remarkable progress we see on IRB was made possible by the IRB/ Reline maintainers team: * Tomoya Ishida (tompng) * Mari Imaizumi (ima1zumi) * Hitoshi Hasumi (hasumikin) * Stan Lo (st0012) And also, a big thank you to all the community contributors. Subscribe * Shopify Engineering The Ruby and Rails Infrastructure team at Shopify exists to help ensure that Ruby and Rails are 100-year tools that will continue to merit being our toolchain of choice. * * Creative Commons License This work is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.