First, *Rest: list processing in Ruby
Context
In functional languages lists are often manipulated by getting the first argument and then associating the remainder of the list to a separate local for future processing. In clojure the API looks like:
(rest [1 2 3]) ; => (2,3)
(first [1 2 3]) ; => 1
Splat Arguments for array-ifying an expression
Such idoms are often nice in OO languages when dealing with array like returns. For example, a regular expression in Ruby:
regex = /(\d{3})/
# the normal way
match_data = "555-867-5309".match(regex)
# normally we don't really care about the match data
# what we really want are the memoized matches
match_data[1] #=> "555"
# splat the return
match_data, area_code = *"555-867-5309".match(regex)
area_code #=> "555"
So in the previous code snippet we have used the splat operator to 'cast' the return of String#match
into an array and then destructuring that array with parallel assignment.
First, Rest Assignment in Ruby
In a similar vein, we can also use splat args on the assignment side to mimic the functional idiom as demonstrated in clojure:
# first, rest
a, *b = [1,2,3]
a #=> 1
b # => [2,3]
# rest, last
*a, b = [1,2,3]
a #=> [1,2]
b #=> 3
Application
Returning to our Regular Expression example:
#works even better with more captures
regex = /(\d{3})-(\d{3})-(\d{4})/
match, area_code, *locals = *"555-867-5309".match(regex)
locals #=> ["867", "5309"]
area_code #=> "555"
How can we use this in other situations?
Take a query in Rails
users = Users.where(...)
first_user = users.first #=> this is a query
other_users = users[1..-1] #=> back to the database
# or we could just go to the db once
first_user, *others = Users.where(...) #=> one query
Happy Splatting!
Written by Jed Schneider
Related protips
Have a fresh tip? Share with Coderwall community!
Post
Post a tip
Best
#Ruby
Authors
Sponsored by #native_company# — Learn More
#native_title#
#native_desc#