This reflects my experience working with Ruby over the years as well. I find it a perfectly pleasant language, but as with many other scripting languages, things get difficult as a project increases in size, complexity, and number of contributors.
Types are a great way to remove certain classes of issues. It's my hope that newer versions of Ruby really push gradual typing features I've been hearing about forward into common use. The productivity gains of preventing all silly Nil and type errors will be enormous.
In a broad and abstract sense (and IMHO), Ruby has a substantial core and community-wide commitment of aiming for that pleasantness, and a track record of achieving it.
I usually compare/contrast to Python's 10 Principles / Zen of Python, which are rather explicitly about the code itself; instead, Ruby has "developer happiness" and "ruby is nice so we are nice". These show up in many, many small ways throughout both the code ecosystem and within the human community (rubyconf!).
There are ofc concrete things to point to, but other comments have already done so, and this bit is a personal fav :)
For a lot of people it's the syntax that makes Ruby pleasant. As evidence of this, I refer to other comments claiming languages like Crystal or Elixir are alternative (or better?) versions of Ruby, even though the only thing they have in common is their syntax.
I don't know if it's fair to just declare that semantics are the important bit.
I suspect that for many users, much of what they like about Ruby is the syntax and core library, and to the degree that Crystal follows that, it will provide much of the same delight that Ruby does.
What semantics is crystal lacking? Obviously it's not a 1:1 replacement as the ecosystem is different, gem management (shards) is different, etc. Crystal also has union types and concurrency.
For people who want a syntax like ruby + performance/concurrency, but are willing to deal with a different ecosystem and having to do more stuff by hand, Crystal is a nice choice.
Local variables, method calls, basics like that are basically entirely different. Take the Ruby specification test suite and try to run it on Crystal, even with adding typing and other minor changes, and see how far you get.
Your criticism does not seem rigorously considered. Toy programs can often simply be renamed from .rb to .cr and be compiled and run as Crystal code. Crystal is not, however, trying to be a drop-in replacement: among other things, an enforced type system is not a minor change. Compilation is not a minor change to a language either. It's valid to say that you don't like the tradeoffs (and of course ideally you would have a full understanding of what those are), but it's incorrect to suggest that these languages are not extremely similar.
My argument is - if you swapped out the syntax of Crystal to not look like Ruby, would anyone think 'this is like Ruby'. I don't think so. Super fundamental parts of the language semantics, like method dispatch rules, are completely different between Ruby and Crystal.
> Your criticism does not seem rigorously considered.
I'm a major contributor to the Ruby specifcation, and I've got a decade of full-time experience in writing about and implementing Ruby and its semantics, so I'm not just doing a drive-by comment.
It still has a very similar feel to Ruby. A lot of the standard library is a very close match to Ruby. And the metaprogramming bits are possible to simulate with macros.
I find this discussion often go into the weird "it's static Ruby" / "not almost nothing like Ruby" extremes. I'd go with looks - same, feel - very familiar, inner workings - you can find ways around differences.
Suffice it to say that I don't think the details of message passing are what most people care about with Ruby. I can see how your experience would lead you to believe otherwise.
I strongly disagree. The message passing semantics are a pretty core part of why you can write pretty complex metaprogramming in Ruby and, without writing a lot of code, make a lot of stuff happen. And even somebody who "doesn't care" about that is critically indebted to it--because that's how Rails happens.
This is not always for the best, of course, but I reach for Ruby pretty consistently when I need to do that sort of thing--often in a dynamic programming context or where I'm binding a lot of state to present a straightforward DSL to an end user (which Sorbet helps with quite a lot, too). Sometimes, for practical reasons, I'll do that sort of work in TypeScript, but the result usually has a lot more sandpaper to it.
Crystal...just isn't that. At all. It's a fine language for what it is; it doesn't just offer anything that Ruby, TypeScript, Kotlin, and Rust don't, so I have no use for it. But it's definitely not Ruby and it doesn't even smell like Ruby.
Crystal has local variables. I didn't mean to imply that ruby & crystal are 1:1 drop-in replacements, but there are a great many similarities. Enough for me as a ruby/rails dev to start on crystal projects with relatively little issue once I learned a bit about the standard library and the ecosystem.
Ruby's way of handling types is abhorrent compared to Crystal, though. Sorbet/RBS are unfortunate systems tacked on after people realized that type systems are actually really good and not really that verbose.
The block syntax is a wonderful way to build and chain flexible iterative logic, the object model is fairly straightforward and the standard library strikes a good balance between functionality and brevity. Once you start to pick up on ruby idioms, the language is pretty fun to use IMO.
what does Ruby offer fhat makes it so "pleasant" to use?
For me, it fits my mental model of approaching problems quite well. I tend to write a lot of smaller programs for small tasks and when it comes to general chucking data around, Ruby isn't fast, but I can go from problem to solution with as little extraneous nonsense as possible.
Python is also quite good at this, but I find it a bit less consistent and tend to question my approach far more unless there's a library that already does the thing I want to do (more often the case with Python, though, to be fair).
Python and Ruby have similar conciseness:readability ratios for me, but Ruby has the added benefits of slightly better writability into the mix.
That's a very good question. I think in the old days people would have said "Ruby offers the most flexible meta-programming available in a popular script language." Back around 2005 there was a major flamewar between Lisp advocates and Ruby advocates:
But nowadays, when I want beautiful meta-programming, I use Clojure.
I think Ruby survives now because of Rails. And Rails is a major technology, so that is a valid reason for Ruby to survive. But it is good to be clear where the advantage is coming from: the framework and not the language.
Ruby has fallen behind, if you want great meta programming, you can get all the joy, plus much better speed, by using something like Clojure. That also gives you access to the vast ecosystem of Java libraries.
But Rails is a different story. For jumpstarting a greenfield API or CRUD app, there is nothing quite as good as Rails. Django and Symfony and other frameworks have tried to imitate Rails, but Rails is still way out in front, with better tools, and the marriage of Rails tools with Ruby's advanced meta-programming is something difficult to replicate elsewhere.
If your company needs a custom CRM or CMS, Rails remains the best starting place.
Initially? Not a whole lot. The point though, is that you used ruby/rails to rapidly build a startup, and then you have a successful business that is _stuck with a massive ruby/rails monolith_. This is where you start extracting services, or refactoring around engines, or some other strategy - doing that involves a huge amount of careful refactoring, and Sorbet can really help.
Types are a great way to remove certain classes of issues. It's my hope that newer versions of Ruby really push gradual typing features I've been hearing about forward into common use. The productivity gains of preventing all silly Nil and type errors will be enormous.