ð ruby-standard-library
Use when working with Ruby's standard library including Enumerable, File I/O, Time/Date, Regular Expressions, and core classes.
Overview
Master Ruby's rich standard library. Ruby comes with powerful built-in classes and modules that handle common programming tasks elegantly.
Enumerable
The Enumerable module provides iteration methods for collections.
Common Enumerable Methods
numbers = [1, 2, 3, 4, 5]
# map/collect - Transform elements
numbers.map { |n| n * 2 } # [2, 4, 6, 8, 10]
numbers.map(&:to_s) # ["1", "2", "3", "4", "5"]
# select/filter - Keep elements matching condition
numbers.select { |n| n.even? } # [2, 4]
numbers.filter(&:odd?) # [1, 3, 5]
# reject - Remove elements matching condition
numbers.reject { |n| n.even? } # [1, 3, 5]
# find/detect - First element matching condition
numbers.find { |n| n > 3 } # 4
# find_all - All elements matching condition (alias for select)
numbers.find_all { |n| n > 2 } # [3, 4, 5]
# reduce/inject - Accumulate values
numbers.reduce(0) { |sum, n| sum + n } # 15
numbers.reduce(:+) # 15
numbers.reduce(:*) # 120
# each - Iterate over elements
numbers.each { |n| puts n }
# each_with_index - Iterate with index
numbers.each_with_index { |n, i| puts "#{i}: #{n}" }
# each_with_object - Iterate with mutable object
numbers.each_with_object({}) { |n, hash| hash[n] = n * 2 }
# any? - True if any element matches
numbers.any? { |n| n > 4 } # true
numbers.any?(&:even?) # true
# all? - True if all elements match
numbers.all? { |n| n > 0 } # true
numbers.all?(&:even?) # false
# none? - True if no elements match
numbers.none? { |n| n < 0 } # true
# one? - True if exactly one element matches
numbers.one? { |n| n == 3 } # true
# partition - Split into two arrays [matching, non-matching]
evens, odds = numbers.partition(&:even?)
# group_by - Group elements by key
numbers.group_by { |n| n % 2 == 0 ? :even : :odd }
# => {:odd=>[1, 3, 5], :even=>[2, 4]}
# chunk - Group consecutive elements
[1, 2, 2, 3, 3, 3, 4].chunk(&:itself).to_a
# => [[1, [1]], [2, [2, 2]], [3, [3, 3, 3]], [4, [4]]]
# take - First n elements
numbers.take(3) # [1, 2, 3]
# drop - Skip first n elements
numbers.drop(3) # [4, 5]
# take_while - Elements until condition fails
numbers.take_while { |n| n < 4 } # [1, 2, 3]
# drop_while - Skip elements until condition fails
numbers.drop_while { |n| n < 4 } # [4, 5]
# zip - Combine arrays
[1, 2, 3].zip(['a', 'b', 'c']) # [[1, "a"], [2, "b"], [3, "c"]]
# min, max
numbers.min # 1
numbers.max # 5
numbers.minmax # [1, 5]
# sort
[3, 1, 4, 1, 5].sort # [1, 1, 3, 4, 5]
['cat', 'dog', 'bird'].sort_by(&:length)
# uniq - Remove duplicates
[1, 2, 2, 3, 3, 3].uniq # [1, 2, 3]
# compact - Remove nil values
[1, nil, 2, nil, 3].compact # [1, 2, 3]
# flat_map - Map and flatten
[[1, 2], [3, 4]].flat_map { |arr| arr.map { |n| n * 2 } } # [2, 4, 6, 8]
# tally - Count occurrences
['a', 'b', 'a', 'c', 'b', 'a'].tally # {"a"=>3, "b"=>2, "c"=>1}
Arrays
# Creation
arr = [1, 2, 3]
arr = Array.new(3, 0) # [0, 0, 0]
arr = Array.new(3) { |i| i * 2 } # [0, 2, 4]
# Access
arr[0] # First element
arr[-1] # Last element
arr[1..3] # Range
arr.first # 1
arr.last # 3
arr.at(1) # 2
# Modification
arr << 4 # Append
arr.push(5) # Append
arr.unshift(0) # Prepend
arr.pop # Remove and return last
arr.shift # Remove and return first
arr.delete_at(1) # Delete at index
arr.delete(3) # Delete value
arr.insert(1, 'a') # Insert at index
# Combination
[1, 2] + [3, 4] # [1, 2, 3, 4]
[1, 2] * 2 # [1, 2, 1, 2]
[1, 2, 3] - [2] # [1, 3]
[1, 2] & [2, 3] # [2] (intersection)
[1, 2] | [2, 3] # [1, 2, 3] (union)
# Query
arr.include?(2) # true
arr.empty? # false
arr.length # 3
arr.count # 3
arr.count(2) # Count occurrences
# Transformation
arr.reverse # [3, 2, 1]
arr.flatten # Flatten nested arrays
arr.compact # Remove nils
arr.uniq # Remove duplicates
arr.join(', ') # Convert to string
arr.sample # Random element
arr.shuffle # Random order
Hashes
# Creation
hash = { name: 'Alice', age: 30 }
hash = Hash.new(0) # Default value 0
hash = Hash.new { |h, k| h[k] = [] } # Default block
# Access
hash[:name] # 'Alice'
hash.fetch(:age) # 30
hash.fetch(:email, 'N/A') # With default
hash.dig(:person, :name) # Safe nested access
# Modification
hash[:email] = 'alice@example.com'
hash.delete(:age)
hash.merge!(other_hash)
hash.transform_keys(&:to_s)
hash.transform_values { |v| v.to_s }
# Iteration
hash.each { |key, value| puts "#{key}: #{value}" }
hash.each_key { |key| puts key }
hash.each_value { |value| puts value }
# Query
hash.key?(:name) # true
hash.value?('Alice') # true
hash.empty? # false
hash.size # 2
# Transformation
hash.keys # [:name, :age]
hash.values # ['Alice', 30]
hash.invert # Swap keys and values
hash.select { |k, v| v.is_a?(String) }
hash.reject { |k, v| v.nil? }
hash.compact # Remove nil values
hash.slice(:name, :age) # Extract subset
Strings
str = "Hello, World!"
# Case
str.upcase # "HELLO, WORLD!"
str.downcase # "hello, world!"
str.capitalize # "Hello, world!"
str.swapcase # "hELLO, wORLD!"
str.titleize # Requires ActiveSupport
# Trimming
" hello ".strip # "hello"
" hello ".lstrip # "hello "
" hello ".rstrip # " hello"
# Searching
str.include?("World") # true
str.start_with?("Hello") # true
str.end_with?("!") # true
str.index("World") # 7
str.rindex("o") # 8
# Splitting and joining
"a,b,c".split(",") # ["a", "b", "c"]
["a", "b", "c"].join("-") # "a-b-c"
# Replacement
str.sub("World", "Ruby") # Replace first
str.gsub("o", "0") # Replace all
str.delete("l") # Remove characters
str.tr("aeiou", "12345") # Translate characters
# Substring
str[0] # "H"
str[0..4] # "Hello"
str[7..] # "World!"
str.slice(0, 5) # "Hello"
# Query
str.empty? # false
str.length # 13
str.size # 13
str.count("l") # 3
# Conversion
"123".to_i # 123
"3.14".to_f # 3.14
:symbol.to_s # "symbol"
# Encoding
str.encoding # #<Encoding:UTF-8>
str.force_encoding("ASCII")
str.encode("ISO-8859-1")
# Multiline
text = <<~HEREDOC
This is a
multiline string
with indentation removed
HEREDOC
Regular Expressions
# Creation
regex = /pattern/
regex = Regexp.new("pattern")
# Matching
"hello" =~ /ll/ # 2 (index)
"hello" !~ /zz/ # true
"hello".match(/l+/) # #<MatchData "ll">
"hello".match?(/l+/) # true (faster, no MatchData)
# Match data
match = "hello123".match(/(\w+)(\d+)/)
match[0] # "hello123" (full match)
match[1] # "hello" (first group)
match[2] # "123" (second group)
# Named captures
match = "hello123".match(/(?<word>\w+)(?<num>\d+)/)
match[:word] # "hello"
match[:num] # "123"
# String methods with regex
"hello world".scan(/\w+/) # ["hello", "world"]
"a1b2c3".scan(/\d/) # ["1", "2", "3"]
"hello".sub(/l/, 'L') # "heLlo"
"hello".gsub(/l/, 'L') # "heLLo"
"a:b:c".split(/:/) # ["a", "b", "c"]
# Flags
/pattern/i # Case insensitive
/pattern/m # Multiline
/pattern/x # Extended (ignore whitespace)
# Common patterns
/\d+/ # One or more digits
/\w+/ # One or more word characters
/\s+/ # One or more whitespace
/^start/ # Start of string
/end$/ # End of string
/[aeiou]/ # Character class
/[^aeiou]/ # Negated class
/(cat|dog)/ # Alternation
File I/O
# Reading
content = File.read("file.txt")
lines = File.readlines("file.txt")
File.open("file.txt", "r") do |file|
file.each_line do |line|
puts line
end
end
# Writing
File.write("file.txt", "content")
File.open("file.txt", "w") do |file|
file.puts "line 1"
file.puts "line 2"
end
# Appending
File.open("file.txt", "a") do |file|
file.puts "appended line"
end
# File modes
# "r" - Read only
# "w" - Write (truncate)
# "a" - Append
# "r+" - Read and write
# "w+" - Read and write (truncate)
# "a+" - Read and append
# File operations
File.exist?("file.txt") # true/false
File.file?("file.txt") # Is it a file?
File.directory?("dir") # Is it a directory?
File.size("file.txt") # Size in bytes
File.mtime("file.txt") # Modification time
File.basename("/path/to/file.txt") # "file.txt"
File.dirname("/path/to/file.txt") # "/path/to"
File.extname("file.txt") # ".txt"
File.join("path", "to", "file.txt") # "path/to/file.txt"
# Directory operations
Dir.entries(".") # List directory
Dir.glob("*.rb") # Pattern matching
Dir.glob("**/*.rb") # Recursive
Dir.mkdir("new_dir")
Dir.rmdir("old_dir")
Dir.pwd # Current directory
Dir.chdir("/path") # Change directory
FileUtils.mkdir_p("a/b/c") # Create nested dirs
FileUtils.rm_rf("dir") # Remove recursively
FileUtils.cp("src", "dest") # Copy file
FileUtils.mv("src", "dest") # Move file
Time and Date
require 'time'
require 'date'
# Time
now = Time.now
utc = Time.now.utc
local = Time.now.localtime
# Components
now.year # 2024
now.month # 11
now.day # 25
now.hour # 14
now.min # 30
now.sec # 45
now.wday # Day of week (0=Sunday)
# Creation
Time.new(2024, 11, 25, 14, 30, 45)
Time.parse("2024-11-25 14:30:45")
Time.at(1700000000) # From Unix timestamp
# Formatting
now.strftime("%Y-%m-%d %H:%M:%S")
now.strftime("%B %d, %Y") # November 25, 2024
now.iso8601 # ISO 8601 format
# Arithmetic
now + 3600 # Add 1 hour (in seconds)
now - 86400 # Subtract 1 day
time2 - time1 # Difference in seconds
# Date
date = Date.today
date = Date.new(2024, 11, 25)
date = Date.parse("2024-11-25")
date.year # 2024
date.month # 11
date.day # 25
date.wday # 1 (Monday)
date + 7 # Add 7 days
date - 7 # Subtract 7 days
date.next_day # Tomorrow
date.prev_day # Yesterday
date.next_month # Next month
date.prev_year # Last year
# DateTime (combines Date and Time)
dt = DateTime.now
dt = DateTime.parse("2024-11-25T14:30:45")
Range
# Inclusive
(1..5).to_a # [1, 2, 3, 4, 5]
# Exclusive
(1...5).to_a # [1, 2, 3, 4]
# Methods
(1..10).include?(5) # true
(1..10).cover?(5) # true (faster)
(1..10).member?(5) # true
(1..5).each { |n| puts n }
(1..5).map { |n| n * 2 }
# String ranges
('a'..'e').to_a # ["a", "b", "c", "d", "e"]
# Case statement
case age
when 0..12
"child"
when 13..19
"teen"
else
"adult"
end
Set
require 'set'
# Creation
set = Set.new([1, 2, 3])
set = Set[1, 2, 3]
# Operations
set.add(4)
set << 5
set.delete(3)
# Set operations
set1 | set2 # Union
set1 & set2 # Intersection
set1 - set2 # Difference
set1 ^ set2 # Symmetric difference
# Query
set.include?(2) # true
set.empty? # false
set.size # 3
# Subset/superset
set1.subset?(set2)
set1.superset?(set2)
Best Practices
- Use Enumerable methods instead of manual loops
- Chain methods for readability:
array.select(&:even?).map(&:to_s) - Use symbol-to-proc (
&:method_name) when possible - Prefer File.open with blocks for automatic file closing
- Use
fetchfor hashes when you want to handle missing keys - Leverage lazy enumerables for large collections
- Use
Pathnamefor complex path operations
Anti-Patterns
â Don't use for loops - use Enumerable methods
â Don't forget to close files - use blocks with File.open
â Don't use each for transformation - use map
â Don't use each for filtering - use select or reject
â Don't mutate arrays while iterating - use methods that return new arrays
Related Skills
- ruby-oop - For understanding core classes
- ruby-blocks-procs-lambdas - For working with Enumerable
- ruby-metaprogramming - For advanced library usage