ruby.onl / hidden-gems

Splat Operators: Exploding and Imploding Arrays Like a Pro

2026-03-20

The splat operator (*) is Ruby's way of handling variable-length argument lists and array expansion. Double splat (**) does the same for hashes. If Perl's list flattening always felt implicit and magical, Ruby's splat is the explicit, controlled version. You say exactly when things expand and when they don't.

Part 1: Destructuring Assignment

# Grab first, rest becomes array first, *rest = lines # first = lines[0], rest = lines[1..] # Grab all but last *head, last = lines # head = lines[0..-2], last = lines[-1] # Grab both ends a, b, *middle, z = arr # a = first, b = second, z = last, middle = everything else
Perl equivalent: my ($first, @rest) = @lines;. Same idea, different syntax.

Part 2: Array Expansion

# Expand array into method arguments args = %w~-l -a /tmp~ system("ls", *args) # same as: system("ls", "-l", "-a", "/tmp") # Combine arrays [1, 2, *other_array, 9, 10] # splat inserts other_array's elements

Part 3: Range to Array

x = [*0..5] # => [0, 1, 2, 3, 4, 5] letters = [*'a'..'z'] # => ["a", "b", ... "z"] # Alternative (more explicit): (0..5).to_a # => [0, 1, 2, 3, 4, 5]
Perl equivalent: my @x = (0..5);

Part 4: Universal Iteration

Handle single items and arrays with the same code:
# Process regardless of whether input is single item or array def process(items) [*items].each do |item| puts "Processing: #{item}" end end process("single_file.txt") # Works! process(%w~file1.txt file2.txt~) # Also works!

Part 5: Splat on Non-Arrays

Splat calls to_a implicitly, so it works on anything with a to_a method:
# Regex match destructuring match, text, number = *"Something 981".match(%r~([A-z]*) ([0-9]*)~) # match => "Something 981" # text => "Something" # number => "981" # Struct destructuring Job = Struct.new(:name, :occupation) tom = Job.new("Tom", "Developer") name, occupation = *tom

Part 6: Double Splat for Hashes

# Merge hashes defaults = { sort: true, limit: 50 } opts = { **defaults, limit: 10 } # => { sort: true, limit: 10 } # Pass hash as keyword arguments def connect(host:, port:, user:) puts "#{user}@#{host}:#{port}" end config = { host: "db1", port: 5432, user: "admin" } connect(**config) # expands hash into keyword args

Part 7: Discarding Parameters with Bare Splat

# Accept and ignore any arguments def hello(*) puts "Hello!" end hello(1, 2, 3) # Works, arguments silently ignored # Ignore middle arguments def process(keep_first, *, keep_last) puts "#{keep_first} ... #{keep_last}" end
Perl equivalent: just not accessing @_. Ruby makes it explicit.

Part 8: The Gotcha

h = { name: "Bob" } [*h] # => [[:name, "Bob"]] - flattened to array of pairs! [h].flatten(1) # => [{:name=>"Bob"}] - preserved!
Splat destroys hashes by converting them to arrays of pairs. Use [items].flatten if you need to preserve hash structure.

Created By: Wildcard Wizard. Copyright 2026