Kernel#srand
srand(seed=nil) -> old_seed The srand method seeds Ruby’s pseudo-random number generator. By setting a specific seed, you can generate the same sequence of random numbers every time, which is essential for testing and debugging.
How it works
Ruby’s random number generator is deterministic—given the same seed, it produces the same sequence. This is useful when you need reproducible results.
Practical Examples
Basic Usage
# Seed with a specific number
srand(12345)
rand(10) # => 7 (always with seed 12345)
rand(10) # => 2
rand(10) # => 4
# Reset to same seed for reproducibility
srand(12345)
rand(10) # => 7 again!
rand(10) # => 2 again!
rand(10) # => 4 again!
The sequence is fully determined by the seed, so the same seed always produces the same chain of numbers. This is not a weakness; it is the whole point. When you want a test to pass the same way every time or a demo to show the same output, setting the seed up front is the simplest way to make randomness repeatable.
Testing and Debugging
# In tests, you want deterministic behavior
def shuffle_deck
srand(42) # Always same shuffle for testing
cards = (1..52).to_a.shuffle
# Now test can assert specific order
end
# With RSpec
before { srand(0) } # Deterministic rand for all tests
A common pattern in RSpec is to call srand(0) in a before block so every test run sees the same random values. This makes failures reproducible instead of flaky, which is especially helpful when the test exercises code that shuffles, samples, or generates random data. You can also use a dedicated seed per test case to create test-specific reproducible sequences.
Multiple random sequences
# Each seed gives different sequence
srand(1)
sequence1 = 5.times.map { rand(100) } # [17, 51, 64, 43, 47]
srand(2)
sequence2 = 5.times.map { rand(100) } # [72, 57, 8, 21, 51]
srand(1) # Back to seed 1
sequence1_again = 5.times.map { rand(100) } # Same as sequence1
Different seeds produce distinct chains, so you can pick a seed for each test scenario and know the output will stay consistent. Calling srand again with an earlier seed resets the generator to that state, letting you reproduce a specific sequence on demand.
Current Seed
# Get the current seed
current_seed = srand
puts current_seed # => some integer
# Returns old seed when setting new one
old = srand(999)
puts old # => previous seed
Calling srand with no argument returns the current seed without changing it. When you pass a seed, the method returns the previous seed, which lets you save and restore the generator state if you need to temporarily switch to a different sequence.
Game Development
# Deterministic game for replays
class Game
def initialize(seed = Time.now.to_i)
srand(seed)
@enemy_positions = generate_enemies
end
def generate_enemies
10.times.map { [rand(800), rand(600)] }
end
end
# Same seed = same gameplay
game1 = Game.new(12345)
game2 = Game.new(12345)
# game1.enemy_positions == game2.enemy_positions
Using the same seed to construct two Game instances gives identical enemy positions, which is perfect for replays or deterministic level generation. In production you would seed with Time.now.to_i for variety, but pinning the seed in tests and demos makes the output predictable every time.
Modern random (Ruby 1.9.2+)
# Ruby's modern Random class
rng = Random.new(12345)
rng.rand(10) # => 7
# Or use Random::DEFAULT with srand
srand(42)
rand(100)
Important Notes
- In Ruby 2.4+,
randwithoutsrandautomatically seeds from SecureRandom - For security-sensitive randomness, use the
securerandomgem - Setting seed 0 works same as any other seed
making random output repeatable
srand is most useful when the code needs a predictable sequence from rand, usually for testing, debugging, or a small demo that should show the same numbers every time. By setting the seed up front, the rest of the program can act as if the random source has a known starting point. That makes failures easier to reproduce and examples easier to explain.
The tradeoff is that deterministic randomness is only appropriate when repeatability matters more than unpredictability. For anything security-related, the code should use a stronger source instead. In other words, srand is for controlled randomness, not for secret values.
It is also useful in examples because the same seed makes the same sample output appear every time. That can make tests and docs easier to follow, since the numbers or shuffled lists do not change from run to run. When the program is supposed to behave the same way for a given seed, srand makes that expectation explicit.
That predictability can be a real help during debugging because the random path stops feeling random. If a test fails, setting the same seed again lets the code walk the same branch and produce the same sequence. That makes it much easier to compare one run with the next and understand where the behavior changed.