Why not Ruby?

I was absent mindedly watching some programming videos on Youtube, and one of them was a short featuring Bjarne Stroustrup and the top 5 languages he would recommend people to know. Obviously, you can guess he would name C++ as the top one:

  1. C++
  2. Java
  3. Python
  4. Ruby
  5. Javascript

What really caught my interest here was that he mentioned Ruby. Is that still a thing? I recall Ruby, specifically with the Rails framework, was incredibly popular about 20 years ago. Back then, I was only interested in game development, so I didn’t have much of a care in the world regarding the web. Later on however, when I actually became a programmer by trade, I’d use things like Python/Flask, Java/Spring, dabble a little bit with Django and Node.js, though everythin just felt kind of off.

Now I’ve been looking to learn something new, and unfortunately Zig was not quite it. It shares the same issues I have with Odin, in that its a growing, not yet mature language, that also does not see much use yet. I have never seen or heard of a Zig job listing, for example. Since I know absolutely nothing about Ruby, but also never thought there was anything that seemed bad about it, I figured I might actually look into it a little bit more.

def hello(name = "World")
    puts "Hello #{name}"
end

hello "Ruby"

Already the syntax feels very Python like, except you can skip parenthesis wherever you have 1 or no arguments like the call to my hello() function. The oop semantics are likewise very minimalistic:

class User
 def initialize(email)
   @email = email
 end
 def get_email
   return @email
 end
end

jocke = User.new("jocke@mail.com")
puts jocke.get_email

Prefixing a variable with @ makes it an instance variable, which is only accessible from inside the class. You can also extend your class anytime:

class User
  def get_email_domain
    return @email.split("@", 2)[1]
  end
end

puts jocke.email_domain

This prints “mail.com”, continuing on the previous code example. Not only can you extend a class by adding methods like this, you can also overwrite methods by re-defining them. Also, everything is an object in Ruby, so you’re able to redefine just about anything. Which means that we need some way of making sure that our program is acting like its supposed to.

Testing

Using gem to install RSpec:

gem install rspec

we can now write a simple test to verify the behaviour of the User class:

require 'rspec/autorun'

describe User do
    it "create user with email" do
        user = User.new("jocke@gmail.com")
        expect(user.get_email).to eq "jocke@gmail.com"
        expect(user.get_email).to eq "gmail.com"
    end
end

There are many ways to do it, but here is an interesting take on FizzBuzz:

1.upto 20 do |i|
  out = 'Fizz' if (i % 3).zero?
  (out ||= '') << 'Buzz' if (i % 5).zero?
  puts out || i
end

In this case, we used a “conditional assignment”, which means that if out was undefined or falsy, we would then assign an empty string to it, which allows us to concatenate ‘Buzz’ in the case that it wasn’t already set to ‘Fizz’. We just need to encase that first assignment in parenthesis, otherwise it would conditionally assign Buzz to it only if it was nil, meaning we never see FizzBuzz. Interesting how we can study syntax in such depth with such a simple concept!

Check for a substring in a string is also quite succinct:

if "hello world"["world"]
  puts "true"
end

Ruby is also very convenient for shellscripts, because to execute a shell command all you need to do is to encase it within backticks:

`ls`

The Gem is in the rough

I had high expectations coming in to the package system for Ruby. Seeing how this is a complete disaster for Python, requiring you to bundle a shit ton of crap in your project when it really shouldn’t need to, such as complete virtual environments, or the airline-crashed-into-trainwreck farce that is NPM, I was thinking I could tell everyone that gem is package management done right, seeing how old and stable I would assume it is.

I was mistaken.

In fact, it reared its ugly head as soon as I wanted to use what practically everyone is using, Ruby on Rails. The official documentation makes it look so easy:

Run gem install rails and verify your installation with rail --version

Great. Except, running that tiny little convenient command will turn my console into a christmas light show of errors. It turns out I need to install ruby-dev for my command to actually work. Perhaps this is the fault of the Ubuntu package people not marking this as a requirement for gem…

So finally getting the Rails framework installed, thumbing to the next, very convenient commandline in the official documentation

Run rails new blog and switch to the created folder

Great - except the console will again absolutely explode with errors, which the official guide comfortably ignores, because it was probably written by someone with a tricked out and configured installation. This is the getting started guide! Not only do I need to install dependencies not mentioned in the guide, gem is trying to install packages where it does not have write permissions, and fails as a result! So, since chmod 777 -R / is not in order here, I figured i will just change the group of whatever directories Gem wants to use, so I can actually get started. Except, it still doesn’t work, because it does not do its job:

Installing psych 5.1.2 with native extensions
Gem::Ext::BuildError: ERROR: Failed to build gem native extension.

    current directory: /var/lib/gems/3.2.0/gems/psych-5.1.2/ext/psych
/usr/bin/ruby3.2 -I/usr/lib/ruby/vendor_ruby extconf.rb
checking for yaml.h... no
yaml.h not found

So here is the official explanation of what Gem is:

RubyGems is a Ruby packaging system designed to facilitate the creation, sharing and installation of libraries (in some ways, it is a distribution packaging system similar to, say, apt-get, but targeted at Ruby software).

In my world, it is not the job for this tool to complain that something is missing, it is the job of this tool to install said missing things. Imagine if Maven would just throw its hands in the air when some dependency was missing and just in a line among hundreds instructed you to do yourself what you asked it to do. You may come up and say that “yaml.h is not Ruby software!” which sure, it may not be, but it is apparantly a dependency, so somewhere, something is messed up. You could at least inform about this in the official get started guide, dude.

So after some fucking around, here is what you need on Ubuntu to make it work:

apt install sqlite3 libyaml-dev ruby-dev
gem install bundler
chgrp YOUR-GROUP /var/lib/gems -R
chgrp YOUR-GROUP /usr/local/bin
chmod 770 -R /var/lib/gems
chmod 770 -R /usr/local/bin

I’m sure you can customize some configuration file hidden away from mention, but if you just want to get started learning something new, and you have your own damn machine that you can do with as you please, then just get going. Apparantly, that is a requirement anyway. Are these the misgivings of a newbie that doesn’t understand the system? Yes, it absolutely is. Doesn’t make it any less frustrating, though.

Conclusion

I’ve only looked into this language for a few days, but I could easily see it take over the role of “script language for things too big for sh”, which currently is Python for me. I looked into Rails, but it’s looking quite complicated at this stage. Sinatra seems to be able to fill the same niche that Flask does, so there is that to look into as well. Besides from some terrible experience with Gem I feel that this is a very interesting language, and will keep looking into it.


Comments