Welcome to Radical Ruby Online! The most tubular place on the world wide web to learn the Ruby programming language. Grab your favorite soda, boot up your PC, and let's get coding!
Select a tutorial below to get started:
Ruby is an awesome, object-oriented programming language designed for programmer happiness! Let's start by learning how to display text on the screen, known as "printing" to the console.
Here is the syntax breakdown:
puts (short for "put string") prints the text and automatically adds a new line (like pressing Enter) at the very end.print outputs exactly what you type without adding a new line. The next thing you print will show up right next to it!# creates a comment. The computer completely ignores anything written after a hashtag on that line. Use it to leave notes for yourself!"Hello" is called a String.# This is a comment!
puts "Hello, World!" # This prints the text and moves to the next line
print "This text "
print "will be on the same line."
# The \n is a special character that means "new line"
puts "\nBut this will be on a new line!"
Save this in a file called hello.rb. The .rb extension tells the computer it's a Ruby file. Run it from your MS-DOS prompt or terminal by typing: ruby hello.rb
Variables are named containers used to save data. To create one, you write a name, an equals sign =, and the data you want to store. Unlike some languages, Ruby uses "Dynamic Typing", meaning you don't have to announce what kind of data the variable will hold.
# STRINGS: Text wrapped in quotes
name = "Radical Surfer"
# INTEGERS: Whole numbers (no decimals, no quotes!)
age = 15
# FLOATS: Numbers with decimal points
high_score = 999.99
# BOOLEANS: Simply 'true' or 'false'
is_cool = true
# ARRAYS: A list of items wrapped in square brackets [] and separated by commas
inventory = ["CD Player", "Skateboard", "Pager"]
# HASHES: A dictionary mapping 'Keys' to 'Values' using =>
stats = { "speed" => 90, "power" => 100 }
# STRING INTERPOLATION:
# If you put #{variable_name} inside a double-quoted string,
# Ruby replaces it with the variable's actual value!
puts "My name is #{name} and I am #{age} years old."
# ARRAY ACCESS:
# You can get a specific item from an array using its index number in brackets.
# CRITICAL: Computers start counting at 0, not 1!
puts "My first inventory item is my #{inventory[0]}!" # Prints "CD Player"
Programs need to make logic-based decisions and repeat actions. For decisions, we use if blocks. Every if block must be closed with the word end.
password = "admin"
# IF STATEMENT SYNTAX:
# == checks if two things are EXACTLY equal (Warning: = is for assigning variables, == is for comparing!)
if password == "admin"
puts "Access Granted."
elsif password == "guest" # 'elsif' provides an alternative condition
puts "Access Limited."
else # 'else' is the catch-all if nothing above was true
puts "Access Denied."
end
# The 'unless' keyword is literally just 'if not'. It's great for readability!
unless password == "admin"
puts "Alert! Unauthorized user!"
end
To repeat code, Ruby uses "Loops" and "Blocks". A block is a chunk of code wrapped in either do ... end (for multi-line blocks) or curly braces { ... } (for single-line blocks).
# The .times method repeats the block exactly that many times.
3.times do
puts "Downloading more RAM..."
end
# The .each method steps through an array one by one.
games = ["Doom", "Quake", "Myst"]
# The variable inside pipes |game| represents the current item in the loop.
games.each do |game|
puts "Currently playing: #{game}"
end
Methods (often called functions) are named, reusable blocks of code. You define them using the def keyword, followed by the method's name, and optionally, variables it should accept (called arguments) in parentheses.
# METHOD SYNTAX:
# 'def' starts it. 'person' and 'mood' are the arguments we are passing in.
# mood = "bodacious" provides a default value if the user forgets to supply one!
def greet(person, mood = "bodacious")
# IMPLICIT RETURN:
# In Ruby, you don't need to type the word 'return'.
# Whatever the last line of the method evaluates to is sent back automatically!
"What's up, #{person}? You're looking #{mood} today!"
end # Always close your method with 'end'
# Calling the method:
# Here we provide just the 'person'. It uses the default mood.
puts greet("Dude")
# Here we provide both, overriding the default mood!
puts greet("Keanu", "excellent")
Let's use user input! We use gets to "get" a string from the user. However, when a user types a number and hits "Enter", the "Enter" keypress is captured as a newline character (\n). The .chomp method literally bites off that invisible newline character at the end!
# 'loop do' creates an infinite loop. It will run forever until it hits a 'break'.
loop do
puts "Enter first number:"
# We use .to_f to convert the String input into a Float (a decimal number).
num1 = gets.chomp.to_f
puts "Enter second number:"
num2 = gets.chomp.to_f
puts "Choose operation (+, -, *, /) OR 'quit':"
# We leave this as a string, because we are looking for letters/symbols.
op = gets.chomp
# Break immediately stops the loop.
# .downcase converts their text to lowercase to prevent capitalization bugs.
break if op.downcase == 'quit'
# A Case Statement acts like a super-powered 'if/elsif' chain.
result = case op
when "+" then num1 + num2
when "-" then num1 - num2
when "*" then num1 * num2
when "/"
# THE TERNARY OPERATOR: (condition ? if_true : if_false)
# It's a 1-line 'if/else' statement!
num2 == 0 ? "You can't divide by zero, dude!" : num1 / num2
else "Bogus operation!"
end
puts "RESULT: #{result}"
end
Ruby is famous for "Enumerables"—powerful methods attached to Arrays and Hashes that let you change lists of data fast. Here we introduce single-line blocks using curly braces { |variable| code }.
mixtape = ["Smells Like Teen Spirit", "Wonderwall", "Creep", "Loser"]
# THE MAP METHOD:
# .map goes through every item, runs the block, and spits out a BRAND NEW ARRAY
# with the altered results. Here, .upcase capitalizes every letter.
shouting_mixtape = mixtape.map { |song| song.upcase }
# THE SELECT METHOD:
# .select goes through every item and asks "Is this true?"
# If the code inside the block results in 'true', it keeps the item.
long_titles = mixtape.select { |song| song.length > 5 }
puts "Shouting: #{shouting_mixtape}"
puts "Long titles: #{long_titles}"
A Hash is like a real-world dictionary: you look up a word (the Key) to find its definition (the Value). In Ruby, we frequently use Symbols for the Keys.
What is a Symbol? Unlike a String ("name") which requires memory to be allocated every single time you type it, a Symbol (:name) starts with a colon and is stored in memory exactly once. It is incredibly fast and efficient for labeling data!
# OLD-SCHOOL HASH SYNTAX (Using the Hash Rocket =>)
user_profile = {
:username => "CyberPunk99",
:level => 42
}
# MODERN HASH SYNTAX (Looks like JSON from JavaScript!)
# Notice the colon moved to the right side of the word. Under the hood, this is still a Symbol!
modern_profile = {
username: "NetSurfer",
level: 10,
status: "Offline"
}
# To grab a value, put the Symbol Key inside square brackets:
puts "User: #{modern_profile[:username]}" # Outputs "NetSurfer"
In Object-Oriented Programming (OOP), you build digital blueprints called Classes. From those blueprints, you create real, usable Instances (objects).
# Define a blueprint with the 'class' keyword. Class names ALWAYS start with a Capital Letter.
class Tamagotchi
# attr_accessor is a Ruby magic trick!
# It automatically allows us to read and write to the @name and @hunger variables from outside the class.
attr_accessor :name, :hunger
# The 'initialize' method is unique.
# The instant you type .new on your class, this method triggers to set up the object.
def initialize(name)
# The @ symbol creates an "Instance Variable".
# Normal variables die when a method ends. Instance variables live as long as the object lives!
@name = name
@hunger = 50
end
# A custom method specific to Tamagotchis
def feed
@hunger -= 10 # This is shorthand for @hunger = @hunger - 10
puts "#{@name} says: YUM! Hunger is down to #{@hunger}."
end
end
# We use the blueprint to construct a real object using .new
pet = Tamagotchi.new("Dino")
# We call methods on the object using a dot!
pet.feed
Storing text to a user's hard drive requires File Input/Output (I/O). You do this using the built-in File class.
# WRITING TO A FILE:
# We open "secret.txt". The "w" mode stands for "Write" (it will create the file, or OVERWRITE it completely).
# Providing a block (do |file|) is good practice because Ruby will automatically securely close the file when the block ends!
File.open("secret.txt", "w") do |file|
# We use the variable we defined in the block '|file|' to refer to our opened document.
file.puts "Hack the planet!"
end
# READING FROM A FILE:
# File.exist? prevents our application from crashing by checking if the file is truly there.
if File.exist?("secret.txt")
# File.read slaps the entire contents of the text file directly into the 'contents' string variable.
contents = File.read("secret.txt")
puts "File contents: #{contents}"
end
Let's look at advanced syntax chaining to build a real app that remembers your notes!
todos = []
if File.exist?("todos.txt")
# File.readlines turns every line of the text file into an item in an array.
# .map(&:chomp) is advanced shorthand syntax! It applies the .chomp method
# to every item in the array to strip away the \n linebreaks.
todos = File.readlines("todos.txt").map(&:chomp)
end
loop do
puts "\n--- YOUR TO-DOS ---"
# each_with_index is an enumerable that gives you both the item (task) AND its number (i)
todos.each_with_index { |task, i| puts "#{i + 1}. #{task}" }
puts "Type 'add [task]', 'done [number]', or 'exit'"
# .split(" ", 2) takes what the user typed and chops it into an array of two pieces at the first space.
# Ex: "add go shopping" becomes => ["add", "go shopping"]
input = gets.chomp.split(" ", 2)
command = input[0].downcase
case command
when 'add'
# The shovel operator << "shovels" an item onto the very end of an Array. Super fast!
todos << input[1]
when 'done'
# .to_i converts the user's string ("1") into an Integer (1). We subtract 1 because Arrays start at 0!
index = input[1].to_i - 1
todos.delete_at(index) if index >= 0 # Only delete if the math isn't negative
when 'exit'
break # Leave the loop
end
end
# Save the altered Array back into the hard drive before the program shuts down.
File.open("todos.txt", "w") do |f|
todos.each { |task| f.puts(task) }
end
puts "Saved! Catch ya later."