Ruby Get Started (Hello World)
Every programming language has a rite of passage: printing the words "Hello, World!" to the screen. It looks trivial, but that one line touches almost everything you need to get productive in Ruby — how to write a script, how to run it, and how Ruby’s built-in tools for showing output actually behave. This lesson walks through installing nothing more than Ruby itself, writing your first program, running it two different ways, and the handful of beginner mistakes that trip almost everyone up in their first week.
Overview: How Ruby Programs Run
Ruby is an interpreted, object-oriented language. When you run a Ruby file, the ruby interpreter reads your source code from top to bottom, parses it into an internal representation, and executes it immediately — there is no separate compile step you need to run yourself. A Ruby program is just a plain text file, conventionally saved with a .rb extension, containing a sequence of expressions.
A defining trait of Ruby is that everything is an object, including things that are primitives in many other languages. The number 1 is an instance of Integer, the string "Hello" is an instance of String, and even nil — Ruby’s representation of "nothing" — is the sole instance of NilClass. You can prove this to yourself at any time by calling .class on anything, even nil.class or 1.class. This matters from lesson one because it explains why methods like puts work on virtually any value: they call to_s on the object you give them and print the resulting string.
To get output on the screen, Ruby gives you three closely related but distinctly different methods, all defined on Kernel so they’re available everywhere without any setup:
| Method | Adds a newline? | What it prints | Typical use |
|---|---|---|---|
puts |
Yes (unless the string already ends with one) | The human-readable string form (to_s) of each argument |
Everyday program output |
print |
No | The human-readable string form (to_s) of each argument |
Output you want to control the line breaks for yourself |
p |
Yes | The programmer-readable, inspectable form (inspect) of each argument |
Debugging — shows quotes around strings, distinguishes nil from an empty string, etc. |
You can run Ruby code in two ways: save it to a file and run ruby yourfile.rb from the terminal, or launch irb (Interactive Ruby), a REPL (read-eval-print loop) that lets you type expressions one at a time and immediately see their return value. This distinction matters more than it sounds — it is itself a very common source of beginner confusion, covered below in Common Mistakes.
Syntax
There is no special "program entry point" syntax in Ruby, unlike languages that require a main function. A Ruby file is simply executed top to bottom:
puts "Hello, World!"
putsis a method call. Ruby lets you omit parentheses around arguments, soputs "Hello, World!"andputs("Hello, World!")are identical."Hello, World!"is aStringliteral, written with double quotes so it supports interpolation (explained in the Examples section).- No semicolons are needed at the end of a line; a newline ends the statement. Semicolons are legal but idiomatic Ruby avoids them.
- To run this from a terminal, save it as
hello.rband runruby hello.rb.
$ ruby --version
ruby 3.3.0 (2023-12-25 revision 5124f9ac75) [x86_64-linux]
$ ruby hello.rb
Hello, World!
Examples
Example 1: The classic Hello World
puts "Hello, World!"
Hello, World!
Ruby executes the single line, calls the puts method with the string as its argument, and puts writes the string to standard output followed by a newline character. That’s the entire program — no imports, no class definitions, no boilerplate required.
Example 2: puts vs. print vs. p
puts "Hello"
print "Hello"
p "Hello"
puts nil
p nil
puts [1, 2, 3]
p [1, 2, 3]
Hello
Hello"Hello"
nil
1
2
3
[1, 2, 3]
Trace it line by line: puts "Hello" prints Hello and a newline. print "Hello" prints Hello with no trailing newline, so the very next output lands on the same line. p "Hello" prints the string’s inspect form, quotes included, which is why you see "Hello" stuck right after the print output with no space between them. Then puts nil prints only a newline — an empty line — because nil.to_s is an empty string, while p nil prints the literal word nil, because inspect shows you what the object actually is, not its blank textual form. Finally, puts on an array prints one element per line, while p on an array prints the whole array in its literal, inspectable syntax on one line. This is exactly why experienced Rubyists reach for p when debugging: it never hides the difference between nil, false, an empty string, and an empty array the way puts does.
Example 3: A friendlier Hello World with keyword arguments
def greet(name:, time_of_day: "day") = "Good #{time_of_day}, #{name}! Welcome to Ruby."
puts greet(name: "Ava")
puts greet(name: "Sam", time_of_day: "morning")
Good day, Ava! Welcome to Ruby.
Good morning, Sam! Welcome to Ruby.
This introduces several modern, idiomatic pieces at once. def greet(name:, time_of_day: "day") = ... is an endless method (stable since Ruby 3.0): a one-line method definition without a matching end, whose body is a single expression that becomes the method’s return value — every Ruby method returns the value of the last expression it evaluates, whether or not you write return. name: and time_of_day: are keyword arguments; time_of_day: has a default of "day", so callers can omit it. Inside the string, #{time_of_day} and #{name} are string interpolation — Ruby evaluates the expression inside #{} and splices its to_s result directly into the surrounding double-quoted string.
How It Works Step by Step
When you run ruby hello.rb from a terminal, several things happen in order:
- The
rubyinterpreter reads the entire file and parses it into an abstract syntax tree, checking that the syntax is valid (matchingdo/endpairs, balanced quotes and brackets, and so on). This is the exact check this site’s code examples are automatically run through. - Ruby then evaluates the file from top to bottom. A
defstatement does not run the method’s body; it only defines the method (attaching it to the current class, or toObjectif it’s top-level) so it can be called later. - When execution reaches a method call like
greet(name: "Ava"), Ruby looks up the method by name along the object’s method resolution order (its singleton class, its class, any included modules, then superclasses) and jumps into that method’s body with the arguments bound. - The method body runs, its final expression’s value becomes the return value, and control returns to the calling line — here, straight into
puts, which converts that value to a string and writes it to standard output. - Once the last line of the file has executed, the interpreter exits. There’s no explicit "stop" statement needed.
Running irb instead works differently: it reads and evaluates one expression at a time, and after each one it automatically prints the return value with an => prefix — a convenience the plain ruby command does not give you.
irb(main):001:0> "Hello, World!"
=> "Hello, World!"
irb(main):002:0> puts "Hello, World!"
Hello, World!
=> nil
Notice the second line: puts returns nil (it always does), and irb dutifully echoes that nil after printing the actual text — a small detail, but a useful one for understanding what a method "gives back" versus what it prints.
Common Mistakes
Mistake 1: Expecting a saved script to auto-print, like irb does
Because irb prints the value of every line automatically, beginners often assume a saved .rb file behaves the same way.
"Hello, World!"
Run this with ruby hello.rb and it prints nothing at all. The string is evaluated and then discarded — nothing tells Ruby to display it. Only irb’s REPL loop echoes return values for you; a script has to call puts, print, or p explicitly.
puts "Hello, World!"
Mistake 2: Using single quotes and expecting interpolation
name = "Ruby"
puts 'Hello, #{name}!'
Hello, #{name}!
This runs without error, which makes it sneaky — it just prints the wrong thing. Single-quoted strings in Ruby are literal: #{...} has no special meaning inside them, so it’s printed as plain text. Interpolation only happens inside double-quoted strings.
name = "Ruby"
puts "Hello, #{name}!"
Hello, Ruby!
Mistake 3: Forgetting a matching end
def greet(name)
puts "Hello, #{name}!"
greet("Ruby")
Every def, if, class, module, and multi-line do block needs a matching end. Leaving one off produces a SyntaxError such as unexpected end-of-input, expecting 'end', and the script won’t run at all — the parser has no way to know where the method body was supposed to stop.
def greet(name)
puts "Hello, #{name}!"
end
greet("Ruby")
Hello, Ruby!
Best Practices
- Use
putsfor ordinary program output meant for a human to read; reach forp(or its cousinppfor larger structures) whenever you’re debugging and need to see an object’s true, unambiguous form. - Prefer double-quoted strings by default so interpolation is available; some style guides prefer single quotes for strings with no interpolation and no escape sequences — pick one convention and stay consistent within a project.
- Name script files in
snake_case.rb(e.g.hello_world.rb), matching Ruby’s own naming conventions for methods and variables. - Use
irb(or a project’sbin/console, common in gems) to experiment with a single expression before committing it to a file — it’s faster feedback than editing and re-running a script. - Remember that a method’s return value is always its last evaluated expression; don’t rely on
putsinside a method to communicate a result back to a caller —putsalways returnsnil. - Check your Ruby version with
ruby --versionbefore relying on newer syntax like endless methods (def foo = ..., Ruby 3.0+) or pattern matching (case/in, stabilized in Ruby 3.0+).
Practice Exercises
- Write a script that prints your name and favorite programming language on two separate lines using two calls to
puts. - Write a method
shout(message)that returns the message in uppercase with three exclamation marks appended (hint: look upString#upcase), then call it withputs shout("hello")and predict the output before running it. - Predict, then verify, what
pprints for each of these on its own line:p "",p nil,p false,p 0. (Hint: in Ruby, onlynilandfalseare falsy —0and""are both truthy, even though they print differently.)
Summary
- A Ruby program is a plain text file, usually saved as
name.rb, executed top to bottom by therubyinterpreter with no separate compile step. putsprints a human-readable form with a trailing newline,printdoes the same with no trailing newline, andpprints the programmer-readableinspectform — invaluable for debuggingnil, empty strings, and empty collections.irbis an interactive REPL that echoes every expression’s return value automatically; a saved script does not do this, so scripts must callputs/print/pexplicitly.- Only double-quoted strings support
#{...}interpolation; single-quoted strings are literal. - Every
def,if,class, and multi-line block needs a matchingend, unless you use a single-line endless method definition. - Everything in Ruby, including numbers, strings, and
nil, is an object — a theme you’ll see reinforced throughout this course.
