This makes me so happy. Pattern matching is amazing, and I use find patterns quite extensively. And I’ll be even happier to run tests without RUBYOPT='-W0' moving forward.
Also great to see Regexp.timeout as well as the ability to initialize a Struct using kwargs without keyword_init: true.
I have been playing around with django for the first time in almost 5 years recently, and it’s so much more productive. Wondering if I should try out rails.
Django feels like a loose set of tools. That could be bad or good. You have to take more architectural decisions, every project can end up with a very different structure. You can split it into sub applications each one with its own urls file, models, controllers and migrations. Tests lay in the same directory of code. The templating language is quite constrained and inflexible. The source of truth of the database are the models and I discorage using inheritance in models or you end up with a database that no other application will ever be able to understand, humans included. The ORM feels verbose. The admin tool is good. No tools for deployment, maybe docker? In general there is a feeling of overengineering everywhere as if it was designed to keep up with every possible use case.
Rails is more constrained, it's really on rails. Again, this can be both bad and good. Two projects will look the same except for those companies that adopt the services / commands / etc sub structure of the code and the ones that stick to the plain models directory, possibly lib. The source of truth of the db is the db and if you want to turn it into a tangle you have to do it yourself explicitly. The ORM is OK for the usual use cases. There is only one file for routing. Tests are in their own directory. The templating language is Ruby itself so you have one less thing to learn but in theory you can shoot in your foot and write your application there, but you can always find a way to shoot yourself even in Django. There is no standard admin tool, you have to pick one yourself so you usually end up without an admin tool unless the customer pays you for that. The traditional tools for deployment were Capistrano and Mina. Maybe docker now.
I made about the same amount of money from them in the past many years. I enjoyed more the weeks spent on Rails.
From a very long time rubyist: if you care a lot about code elegance, I think you could like ruby/rails more. If for you it's more important that there is only one correct way to do things, then probably sticking with python /Django makes sense.
My point is that your productivity with a given tool also depends on your own preferences/cognitive style. Between Ruby/Rails and Python/Django, my assessment, even if I don't know the latter anywhere as well as the first, is that your results will depend a lot on your preferences and cognitive style.
Django is more comprehensive than FastAPI in terms of features and use cases it tries to address, so I assume they mean Rails offers more than Django. More != better.
It looks great, really! My first thought is that it would make a very handy solargraph diagnostic reporter, so I think I'll whip that up in the next few days.
ractors, due to its "no shared or immutable only memory" constraints, is fundamentally incompatible with 99% of ruby code in the wild. I don't see it getting much adoption until some of those constraints are relaxed.
They would. Some of the constraints were senseless. You used to not be able to use class variables, even if they were already initialized and frozen. However, using static variables, and worse, changing them, was fine.
Ruby uses a lot of pure lazy memorization. That's an aspect I'd like to see more accepted. A system that enforces rather than recommends, is a less usable system.
This can be said of most actor systems. Using actors is a fundamentally different way of programming than non-actor-based multi-threaded systems. You do have to change your paradigm; but, when I have, I've found the experience to be really wonderful.
Celluloid was an actor library which worked well with most ruby code. This is not the case for ractor. For starters, the ruby standard library is itself incompatible with ractor. Go ahead and try using logger inside one. Beyond that, a lot of mature libraries would have to be rewritten to fit ractors, and that's quite risky. Something as simple as a connection pool has to be done completely differently. That's a big red flag, considering that the value of ruby is its ecosystem.
I actually tried making the libs I maintain ractor compatible. I recorded the constraints and suggested removing some of fhe annoying ones. Some got accepted, but it's not enough.
True, but other languages/platforms have better built-in support for immutable data structures and don't force you to fight the standard library to implement a share-nothing approach.
I was looking into this question a few weeks ago and couldn't find any libraries I would use in typical applications (eg. background jobs, etc) implementing Ractors.
There are occasional comments in GH issues discussing the possibility of implementing Ractors, but nothing material.
Not from what I have seen, It’s kinda risky because the fact that Ractors still is in experimental stage means that there couls be major breaking changes at any time, both how you use it and internally.
> The following deprecated methods are removed: Dir.exists? File.exists?
These names were really elegant, I wonder why they were removed. Searching the web, the only explanation I can find is they were removed because they were deprecated. So why were they deprecated?
For better or worse, the convention in Ruby is to name methods in a second-person style [0], as if addressing the object directly: “file, do you `#exist?`”; “string, do you `#start_with?` foo?”. So, for consistency, `Dir.exist?` and `File.exist?` have been preferred for a long time.
MJIT pastes together snippets of C code that implement Ruby VM bytecode instructions. It then hands off that C code to GCC which compiles it to native code while the Ruby VM is running.
YJIT compiles from Ruby VM bytecode straight to native code using a JIT technique called basic block versioning (which is slightly different from how JITs like V8 work because the unit of reuse is a basic block instead of a function).
I can't influence people at work to use Ruby correctly or to learn it.
It's a battle to ship linters amongst people who don't have CS degrees and express hostile disdain for any suggestions of software craftsmanship, much less curiosity.
They want to use their dumb patterns and bad habits, and aren't interested in changing.
Are hashes guaranteed to be ordered in some way (not just incidentally implemented that way, but specified so that changing it in the future would be considered breaking)? I thought they weren't, in which case there wouldn't really be any obvious way to define `last`, but I might be mistaken
`{}.first` works, so no reason why `{}.last` shouldn't. I would argue, though, that it's best not to rely on hashes for ordering, though that's a relatively loose preference, and I've certainly use it for quick 'n' dirty scriptss
Ya, it's one of things you have to make a team/org-level call on.
For me, ruby is full of a lot of little conveniences that shouldn't necessarily be used in production systems. I always cry loud that code should be quickly "scannable", and the data-structures we choose to use can help a lot in the quicker understanding an unfamiliar piece of code.
But I stress again: these types of decisions are best left up to the team or org. It's ultimately low-stakes.
key ordering is something to rely on now, in Ruby as well as in JavaScript and Python
That ship has sailed - it was partly for the convenience of debugging, but the general purpose dict is now ordered.
It's only by insertion order - it's expensive to change the order - but the order can by relied upon and is being used.
Edit: some detail on changing the order - you can either remove all the key/value pairs up to the first one you want to change and add them back, or you can create a new dict with the pairs in the desired order. With Rust you can choose whether or not to have insertion order preserved https://stackoverflow.com/questions/42723065/how-to-sort-has...
Ya, my preference still stands whether the ship is docked or not. As you point out: it's good for debugging. As I mentioned, I like it for quick things in throwaway scripts. I don't like it in production code because when I'm reading something quickly that I don't care to deeply understand: Hashes are records and arrays order ordered lists. I very much like the way Rust does it (and I like a lot of what I've seen in Rust)--if we had `OrderedHash` in Ruby, I will feel completely different.
I already implied it was politics by saying that it is something that needs to be determined at the team/org level.
I don't feel it's arbitrary, though, and to get a little clever about it I feel that ordered hashes are arbitrary and that's why I don't like to rely on it in _production_ code.
"Records" (aka hashes, aks dicts, aka maps, etc) are inherently unordered. Relying on insertion order or keyed values is super brittle.
So again, the fact that they are ordered is super convenient! It shines in one-off, temporary situations like debugging or writing a quick script to group something by a specific value without having to do any further sorting. But I don't believe it should ever be replied on in a production system, just for the fact that if the order ever changes, there are possibly many places that have to change.
Might be some kind of linked list like implementation under the hood. Getting the first element is performant but traversing everything to find the last one would be slow.
Even for singly linked lists, implementations for general purpose use usually keep pointers to the first and last elements so that you can use it as an O(1) FIFO queue, as well as prepend in O(1) time.
If you only keep a pointer to the head of the linked list, then it can be practically used a LIFO queue (stack), and a few other corner cases, but not much else. (A FIFO isn't very useful if adding an item is O(1) but removing an item is O(N), or vice versa.)
Yeah, that's strange to me too. In Clojure (similar conceptual mode with Ruby, with sequences, hashes, etc.), the code is very similar, with predictable results: