Ruby
Optimised for programmer happiness.
Ruby is an elegant, expressive language best known for Ruby on Rails, the framework behind GitHub, Shopify and Basecamp. Its readable style makes it a joy for building web apps, and gems like ruby_llm bring AI into Rails apps.
Why learn Ruby?
Ruby reads almost like English and lets you build working web products remarkably fast with Rails.
- Readable: concise, expressive code with few symbols.
- Rails: build full web apps quickly with strong conventions.
- AI in Rails: gems like ruby_llm and langchainrb add chat, tools and RAG.
Set up and run your first program
Install Ruby 3.3+ with a version manager such as rbenv, asdf or RubyInstaller on Windows.
ruby -v
ruby hello.rb
gem install railsname = "Ada"
puts "Hello, AI! Welcome to Ruby, #{name}."Variables and types
No declarations needed. Strings interpolate with #{}. Symbols (:fp16) are lightweight names. Everything, even numbers, is an object with methods.
layers = 32
lr = 3e-4
model = "llama3.1"
params = 8_030_000_000
precision = :fp16
puts "#{model}: #{layers} layers, FP16 #{(params * 2 / 1e9).round(1)} GB"
puts 42.even?, precision.classControl flow and blocks
Ruby has if, unless, case/when and loops, but most iteration uses blocks: code passed to methods like each and times.
3.times { |epoch| puts "epoch #{epoch}" }
%w[H100 B200].each_with_index do |gpu, i|
puts "#{i}: #{gpu}"
end
bits = 8
name = case bits
when 32 then "FP32"
when 16 then "FP16"
when 8 then "FP8"
else "other"
end
puts name unless bits > 16Arrays and hashes
Arrays and hashes come with dozens of methods such as select, map, sum and sort_by that take blocks.
vram = { "H100" => 80, "H200" => 141, "B200" => 180 }
big = vram.select { |_, gb| gb > 100 }.keys
puts big.inspect # ["H200", "B200"]
puts vram.values.sum / vram.size
puts vram.sort_by { |_, gb| -gb }.first.inspectClasses and modules
Define classes with class, attributes with attr_reader, and share behaviour with modules mixed in by include.
module Describable
def describe = "#{name}: #{vram_gb} GB"
end
class Gpu
include Describable
attr_reader :name, :vram_gb
def initialize(name, vram_gb)
@name, @vram_gb = name, vram_gb
end
def fits?(gb) = gb <= vram_gb
end
g = Gpu.new("RTX 5090", 32)
puts g.describe, g.fits?(16)Errors and files
Handle errors with begin/rescue. File and JSON handling are built into the standard library.
require "json"
begin
data = JSON.parse(File.read("config.json"))
puts data["model"]
rescue Errno::ENOENT
puts "config.json not found"
rescue JSON::ParserError => e
puts "Bad JSON: #{e.message}"
endAI with Ruby
Ruby is used to put AI into web products: chat features in Rails apps, document Q&A with pgvector, and background jobs that classify or summarise content using LLM APIs.
The essential libraries
Gradient descent from scratch
Learn y = 3x + 0.5 with plain Ruby.
n = 100
xs = (0...n).map { |i| -1 + 2.0 * i / (n - 1) }
ys = xs.map { |x| 3 * x + 0.5 + (rand - 0.5) * 0.2 }
w = b = 0.0
lr = 0.1
500.times do
gw = gb = 0.0
xs.each_with_index do |x, i|
err = w * x + b - ys[i]
gw += 2 * err * x / n
gb += 2 * err / n
end
w -= lr * gw
b -= lr * gb
end
puts format("w=%.2f b=%.2f", w, b)Build an AI agent in Ruby
The standard library's net/http and json are enough to run the tool-calling loop against a local model.
require "net/http"
require "json"
URL = URI("http://localhost:11434/v1/chat/completions")
TOOLS = [{ type: "function", function: { name: "get_weather", description: "Weather for a city",
parameters: { type: "object", properties: { city: { type: "string" } }, required: ["city"] } } }]
def get_weather(city) = "It is 24°C and sunny in #{city}."
messages = [{ role: "user", content: "Should I take an umbrella in Lahore today?" }]
5.times do
res = Net::HTTP.post(URL, { model: "llama3.1", messages: messages, tools: TOOLS }.to_json,
"Content-Type" => "application/json")
msg = JSON.parse(res.body)["choices"][0]["message"]
messages << msg
calls = msg["tool_calls"] || []
if calls.empty?
puts msg["content"]
break
end
calls.each do |call|
args = JSON.parse(call["function"]["arguments"])
messages << { role: "tool", tool_call_id: call["id"], content: get_weather(args["city"]) }
end
endThe ruby_llm gem offers the same loop with tools defined as Ruby classes.
ollama pull llama3.1, and keep it running. The code talks to its OpenAI-compatible API at http://localhost:11434/v1, so the same program also works with vLLM, llama.cpp server or a cloud API by changing the URL, model name and adding an API key.Ruby learning roadmap
Tick items off as you go. Your progress is saved in this browser.
Beginner
Intermediate
Advanced
Projects to build
Ruby cheat sheet
| Task | Syntax |
|---|---|
puts "Hi #{name}" | |
| Array | [1, 2, 3].map { |x| x * 2 } |
| Hash | { a: 1, b: 2 } |
| Method | def add(a, b) = a + b |
| Class | class P; attr_reader :x; end |
| Rescue | begin ... rescue => e ... end |
Common mistakes
nilhas methods too; calling a missing one raises NoMethodError, so check with&..- Mutating strings that are shared can surprise you; use
.dupor frozen string literals. - Forgetting
endis the most common syntax error.
Where to go next
- Ruby docs — official
- Rails Guides — framework
- RubyLLM — AI in Ruby
On TensorCore.si: Python volume, PHP volume.
Keyboard: [ previous language · ] next language · / search the library