Ruby 3.1
ruby-lang.org
ruby-lang.org
> Values in Hash literals and keyword arguments can be omitted. [Feature #14579]
> {x:, y:} is a syntax sugar of {x: x, y: y}.
> foo(x:, y:) is a syntax sugar of foo(x: x, y: y).
This is going to be controversial and take some getting used to, but I think eventually everyone will love it. It’s not an easy syntax to learn - I remember when this came to JS it took a while to get my head around all the different ways this shorthand was used in the wild.
It’s hard to come up with new syntax that can peacefully coexist with the established language. I think in hindsight it would have been helpful for Ruby if it had done something like square braces instead of brackets for hash literals, or not allowed brackets for blocks. The most ambiguous syntax all involves hash literals vs blocks… this adds to that cognitive load.
But typing out a long hash literal just to capture a bunch of local variables or methods is so common, and the duplication is quite annoying, so on the whole I’m glad this was added and am sure I’ll use it a lot :)
foo x:
[1,2,3]
Or maybe that "punning" will work only inside of () and {}?See also https://zverok.github.io/blog/2021-12-08-value-omission-debu...
I'm a little disappointed that Ruby introduced it but no one is forcing me to use it so to each their own (and I'm not writing Ruby or much JS professionally anymore so it doesn't affect me too much).
It's saving a single character in your example. I can see liking it as solving a minor inconvenience. But love? I don't see that. To me it's just another thing to learn.
{width:, height:, x_pos:, y_pos:}
to be much more pleasant than
{width: width, height: height, x_pos: x_pos, y_pos: y_pos}
And the more items you add the more I find it useful. Yeah, it took some getting used to in Javascript after years and years without it, but I personally would not want to go back to not having it.
I'm not crazy about the colon/comma combo, but if I was writing in Ruby I suspect I'd get used to it after a while.
Arguably it was the right call considering where Ruby is now.
Ruby would benefit from a trimmed down stdlib, where effort could be spent keeping a smaller footprint stdlib more polished than it is today. Turning them into opt-in gems is a good first step.
A few examples:
- `rss` to parse RSS documents/streams
- `win32ole` for Microsoft Windows OLE Automation
- `dbm` for DBM databases
- `abbrev` for finding the shortest unique abbreviation amongst many strings
This page has more details: https://stdgems.org/
https://discuss.python.org/t/pep-594-removing-dead-batteries...
https://github.com/ruby/ruby/blob/master/NEWS.md
Just waiting another year!
Edit: LOL ko1 replied [1] on Twitter "ごめんよ。来年頑張るよ " / "Sorry. I'll do my best next year".
@ko1: Thanks for all your work on Ruby.
"By default, all C extensions are recognized as Ractor-unsafe. If C extension becomes Ractor-safe, the extension should call `rb_ext_ractor_safe(true)` at the `Init_` function and all defined method marked as Ractor-safe. Ractor-unsafe C-methods only been called from main-ractor. If non-main ractor calls it, then `Ractor::UnsafeError` is raised."
I've submitted a few such patches for my own personal use, and it's a very trivial change for extensions which keep no state in C-land that would need to be synchronized between Ractors, e.g. https://github.com/dearblue/ruby-extattr/pull/1
I am also wondering if anyone is using RBS in production. Apart from big shops like Stripe / Shopify.
[0] - https://sorbet.org/
I will take the opportunity to ask; does anyone have a good introduction to creating Ruby (not Rails) projects? I'm a bit confused between rake, bundle, testing frameworks, how to debug a program or structure a project and I can't seem to find a good up to date resource on that.
Rake is a Ruby equivalent of Make. Many Ruby gems will include rake tasks (Makefile targets) that can be used to drive pieces of an application. Most of the time your test framework of choice (rspec typically) will include “rake test” as a target for running the tests.
The tests usually live in a folder named “spec”, while application code lives in “lib” and your driver code lives in “bin” or just a top-level file… without some of the Rails initialization glue, you’ll have to do a little work to require files via relative paths or set up the $LOAD_PATH variable, etc.
Bundler is the package manager, and you’ll often see commands like “bundle exec rake”, this is similar in spirit to a virtualenv. Bundler will use the libraries defined in your Gemfile to run the given program (in this case, ‘rake’). The command “bundle” will read the Gemfile and resolve dependencies to concrete versions of libraries and write out a Gemfile.lock for you with all the versions explicitly defined.
For debugging, there are a number of tools out there, but I’m partial to ‘pry’. You add pry to your Gemfile, require it, and then can add a breakpoint by putting a call to “binding.pry” in your source code wherever. This will drop you into a REPL within the context of the program at that point.
pry is useful, but there are some other gems and settings files out there that can make it a little friendlier, pry-byebug comes to mind as having saner keyboard shortcuts iirc.
If you need help with overall file system layout, etc, the best place to look is going to be existing trivial gems on rubygems.org. Granted these will have a couple of minor differences from a “plain” application because they’re packaging as a library (*.gemspec file instead of Gemfile, and usually has a version.rb file somewhere).
Also I created a project with bundle, which gave me some structure, and downloaded Rubymine which is helping a lot as well, even if it's a tiny project, also it suggests me new cool things Ruby can do which I had not idea about.
rake is ruby make... aka a build utility but it can and is used for a variety of things like testing and building and distribution.
minitest is built in and is generally enough. rspec is the other big one and a lot of people like it but it's fairly complicated and it is better to stick to the basic one early on.
as for debugging puts debugging is common(though a lot of things are caught at the testing phase since testing is big with ruby). if you are familiar with debuggers that is also an option with something like vscode or the command line but vscode is more usable(or the rubymine one that is a paid app).
foo/
- foo.gemspec: needs to fix the TODOs to start, and this is where runtime deps will go
- Gemfile: where your development deps will go
- Gemfile.lock: built by 'bundle install' do not touch
- Rakefile: the build system (build gems, push gems, run tests, etc)
- bin/ drop binary scripts here or delete if you're making a library (generally make them tiny stubs that require "foo" or "foo/application" and call run on the app or something)
- lib/ this is where you put all your code. already setup with lib/foo.rb and lib/foo/version.rb which are accessible via `require "foo"` and `require "foo/version"` mostly you'll want to put code under lib/foo/ and then have `lib/foo.rb` be a pile of require statements (ish).
- spec/ this is where tests go. bundler will set you up with rspec installed to begin with with a spec_helper.rb already setup (this is where you tweak rspec). i would suggest using spec/unit/whatever_spec.rb to test lib/foo/whatever.rb and keeping those directory structures roughly in sync for your unit tests.
To get started: bundle install # updates all the gems in the Gemfile (plus the referenced gemspec file) and installs rspec and updated rake and stuff
bundle exec rake spec # runs all the spec/ tests
bundle exec rake # runs rake + rubocop/standard both
bundle exec rake -T # shows all the rake tasks
bundle exec rake release # will build and push the gem to rubygems publiclyI'm not using ruby anymore but the debugger experience I had from vscode via the rdebug-ide library a few years ago was _mostly pretty_ nice aside from very performance limitations ... a massive performance improvement on that front must feel great!
Python was easiest, since it took couple of days to master fundamentals and I was writing good code in no time.
Also anyone working on Typescript equivalent for ruby?
RBS (descs) + Steep (type checker) is a bit younger but I found it more usable in general, especially on the corner cases.
Beyond that, it's too intrusive in the code for me. I could live with 'sig' blocks above methods, but there's an immediate readability cost when you start having to wrap stuff in T.let, T.must, T.nilable, etc.
Personally I'd rather improve my testing skills here too. Knowing how to write a good test is a valuable skill.
Some syntax is a bit quirky (blocks in particular) but if you are solid in OOP then you soon see the beauty of the core class setup.
The primary difference to Python is that everything really is a method call on a object (even if that object is a class).
To master Ruby I would start with toy problems such as Advent of Code.
I’d suggest using metaprogramming (define_method, instance_variable_send, instance_eval, send) to implement a toy ruby-in-ruby DSL is the fastest way to figure out what different.
From the bug report [0] it sounds like they may also support ARM64 in the future.
I presume it will support ARM based chips pretty quickly.
That's pretty interesting. They deploy, I assume to jitted ruby on X64 boxes, but will develop on M1 Macbooks. I suppose they probably have some kind of automated performance/crash/leak/etc regression tests in the pipeline?
Development can be done locally, or it can be done via on-demand containers in the cloud with the IDE loading the code over a remote mount of the containers filesystem. I'm new to it all, but it's a very slick setup.
{x:, y:} is a syntax sugar of {x: x, y: y}.https://dev.to/baweaver/ruby-3-set-literal-3fp9
Unfortunately it looks like I can't edit or delete that comment now. :embarassed:
x, y = 1, 2
puts x: x, y: y
# ==> {:x=>1, :y=>2}
puts x:, y:
# ==> {:x=>1, :y=>2}
puts x, y
# ==> 1, 2
Which would be inconsistent and annoying.(and knowing Ruby, I imagine there might be some syntactical ambiguities as well)
x:, y:
but couldn't they drop the : if there are braces to indicate this is a hash? {x, y} 5.times { x }
This could either call the given block 5 times, or pass a hash of :x => x as the first argument.