| name | Ruby |
| description | Dynamic, interpreted programming language known for elegance and productivity with a focus on simplicity and programmer happiness. |
| license | BSD 2-Clause "Simplified" |
| compatibility | Ruby 3.0+ |
| audience | Web developers (Ruby on Rails), automation scripters, DevOps engineers |
| category | Programming Languages |
Ruby
What I do
I am a dynamic, interpreted programming language created by Yukihiro Matsumoto in 1995. I emphasize programmer happiness and productivity with elegant, natural-feeling syntax. I am the language behind Ruby on Rails, one of the most popular web frameworks. I support multiple programming paradigms including procedural, object-oriented, and functional programming. I feature dynamic typing, duck typing, metaprogramming capabilities, and a "everything is an object" design where even primitive types are objects.
When to use me
Use Ruby when building web applications with Ruby on Rails, rapid prototyping and MVP development, automation scripts and DevOps tooling, code generation and scaffolding tools, domain-specific languages (DSLs), or when developer happiness and productivity are top priorities.
Core Concepts
- Everything is an Object: Even nil, true, false, and numbers are objects with methods.
- Duck Typing: If an object walks like a duck and quacks like a duck, treat it as a duck.
- Dynamic Typing: Variable types are determined at runtime, methods can be added to classes at runtime.
- Blocks, Procs, and Lambdas: First-class callable objects for iteration, callbacks, and functional patterns.
- Mixins via Modules: Composition pattern using modules for code reuse without multiple inheritance.
- Metaprogramming: Ability to modify classes and objects at runtime, defining methods dynamically.
- Open Classes: Can reopen and modify existing classes including built-in types (monkey patching).
- Convention over Configuration: Rails-style defaults reducing boilerplate configuration.
- Garbage Collection: Automatic memory management for objects.
- Symbol Interning: Symbols are immutable, cached strings used as identifiers and keys.
Code Examples
Blocks and Iterators:
numbers = [1, 2, 3, 4, 5]
squares = numbers.map { |n| n ** 2 }
evens = numbers.select(&:even?)
sum = numbers.reduce(0, :+)
puts "Squares: #{squares}"
puts "Evens: #{evens}"
puts "Sum: #{sum}"
hash = { a: 1, b: 2, c: 3 }
transformed = hash.transform_values { |v| v * 10 }
puts "Transformed: #{transformed}"
result = 10.times do |i|
puts "Iteration #{i}"
end
[1, 2, 3].each_with_index do |num, index|
puts "Element #{index}: #{num}"
end
class LazyProcessor
def initialize
@steps = []
end
def add_step(name, &block)
@steps << [name, block]
self
end
def ()
.reduce(input) ||
puts
block.call(data)
processor = .new
processor
.add_step() { || x * }
.add_step() { || x + }
.add_step() { || x ** }
result = processor.process()
puts
Modules and Mixins:
module Loggable
def log(message)
puts "[#{Time.now}] #{self.class}: #{message}"
end
end
module Encryptable
def encrypt(data)
data.bytes.map { |b| b + 1 }.pack("C*")
end
def decrypt(data)
data.bytes.map { |b| b - 1 }.pack("C*")
end
end
class User
include Loggable
attr_accessor :name, :email
def initialize(name, email)
@name = name
@email = email
end
def authenticate(password)
log("Authentication attempt for #{email}")
password == "secret"
end
end
class SecureMessage
()
= content
encrypted = encrypt(content)
log()
encrypted
user = .new(, )
user.authenticate()
message = .new()
encrypted = message.send
puts
Metaprogramming:
class ActiveRecord
def self.attr_accessor_with_history(*names)
names.each do |name|
define_method(name) { instance_variable_get("@#{name}") }
define_method("#{name}=") do |value|
history = instance_variable_get("@#{name}_history") || []
history << instance_variable_get("@#{name}")
instance_variable_set("@#{name}_history", history)
instance_variable_set("@#{name}", value)
end
define_method("#{name}_history") { instance_variable_get("@#{name}_history") }
end
end
attr_accessor_with_history :name, :email
def initialize(attributes = {})
attributes.each do |key, value|
send("#{key}=", value) if respond_to?("#{key}=")
end
end
end
class User < ActiveRecord
end
user = User.new
user.name =
user.name =
user.name =
puts user.name_history.inspect
puts user.email_history.inspect
Blocks and Yield:
class DataProcessor
def initialize(data)
@data = data
end
def filter(&block)
filtered = @data.select(&block)
DataProcessor.new(filtered)
end
def map(&block)
mapped = @data.map(&block)
DataProcessor.new(mapped)
end
def reduce(initial = nil, &block)
if block_given?
@data.reduce(initial, &block)
else
@data.reduce
end
end
def each(&block)
@data.each(&block)
self
end
def to_a
@data
end
end
processor = DataProcessor.new([1, 2, 3, 4, 5])
result = processor
.filter { |n| n.even? }
.map { |n| n * 10 }
.each { |n| puts "Value: #{n}" }
.reduce() { || sum + n }
puts
start = .now
elapsed = .now - start
puts
with_timing { sleep() }
Best Practices
- Follow Ruby Style Guide: Use consistent naming conventions (snake_case for variables/methods, PascalCase for classes/modules).
- Prefer Blocks Over Procs: Use blocks for simple callbacks, procs/lambdas when you need to pass around callable objects.
- Use Symbol for Keys: Use symbols as hash keys (symbol: value syntax) for better performance than strings.
- Avoid Monkey Patching Core Classes: While possible, modifying built-in classes can lead to confusion and bugs.
- Use Hash.fetch for Missing Keys: Use Hash#fetch with default values instead of || operator for missing keys.
- Prefer reduce Over Manual Accumulation: Use inject/reduce for accumulating values in loops.
- Use Safe Navigation Operator (&.): Use &. for chaining methods that might return nil.
- Keep Methods Short: Methods should do one thing; if you need "and" in the description, split it.
- Write Tests with RSpec/Minitest: Use BDD-style tests with RSpec or simpler tests with Minitest.
- Use Bundle for Dependencies: Always use Bundler (Gemfile) to manage dependencies for reproducibility.