Add destructure.
This commit is contained in:
@@ -884,6 +884,64 @@ defmodule Elixir.Builtin do
|
||||
quote do: if(!unquote(clause), unquote(options))
|
||||
end
|
||||
|
||||
@doc """
|
||||
Allows you to destructure two lists, assigning each
|
||||
term in the right to the left. Differently from pattern
|
||||
matching via `=`, if the sizes of the left and right
|
||||
lists don't match,, structuring simply stops instead
|
||||
of raising an error.
|
||||
|
||||
## Examples
|
||||
|
||||
destructure [x,y,z], [1,2,3,4,5]
|
||||
x #=> 1
|
||||
y #=> 2
|
||||
z #=> 3
|
||||
|
||||
Notice in the example above, even though the right
|
||||
size has more entries than the left, structuring works
|
||||
fine. If the right size is smaller, the remaining items
|
||||
are simply assigned to nil:
|
||||
|
||||
destructure [x,y,z], [1]
|
||||
x #=> 1
|
||||
y #=> nil
|
||||
z #=> nil
|
||||
|
||||
The left side supports any expression you would use
|
||||
on the left side of a match:
|
||||
|
||||
x = 1
|
||||
destructure [^x,y,z], [1,2,3]
|
||||
|
||||
The example above will only work if x matches
|
||||
the first value from the right side.
|
||||
"""
|
||||
defmacro destructure([head|tail], right) do
|
||||
# For the first match, we need to ensure the element given
|
||||
# is an array. For the other matches, we don't care because
|
||||
# we have validated it is a list.
|
||||
head = quote do
|
||||
case unquote(right) do
|
||||
match: [unquote(head)|t]
|
||||
t
|
||||
match: []
|
||||
unquote(head) = nil
|
||||
end
|
||||
end
|
||||
|
||||
List.foldl tail, head, fn(item, acc) ->
|
||||
quote do
|
||||
case unquote(acc) do
|
||||
match: [unquote(item)|t]
|
||||
t
|
||||
match: _
|
||||
unquote(item) = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@doc """
|
||||
Concatenates two binaries.
|
||||
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
Code.require_file "../../test_helper", __FILE__
|
||||
|
||||
defmodule Kernel.DestructureTest do
|
||||
use ExUnit.Case
|
||||
|
||||
test :less do
|
||||
destructure [x,y,z], [1,2,3,4,5]
|
||||
assert_equal 1, x
|
||||
assert_equal 2, y
|
||||
assert_equal 3, z
|
||||
end
|
||||
|
||||
test :more do
|
||||
destructure [a,b,c,d,e], [1,2,3]
|
||||
assert_equal 1, a
|
||||
assert_equal 2, b
|
||||
assert_equal 3, c
|
||||
assert_equal nil, d
|
||||
assert_equal nil, e
|
||||
end
|
||||
|
||||
test :equal do
|
||||
destructure [a,b,c], [1,2,3]
|
||||
assert_equal 1, a
|
||||
assert_equal 2, b
|
||||
assert_equal 3, c
|
||||
end
|
||||
|
||||
test :none do
|
||||
destructure [a,b,c], []
|
||||
assert_equal nil, a
|
||||
assert_equal nil, b
|
||||
assert_equal nil, c
|
||||
end
|
||||
|
||||
test :match do
|
||||
destructure [1,b,_], [1,2,3]
|
||||
assert_equal 2, b
|
||||
end
|
||||
|
||||
test :invalid_match do
|
||||
a = 3
|
||||
assert_raises MatchError, fn ->
|
||||
destructure [^a,b,c], a_list
|
||||
end
|
||||
end
|
||||
|
||||
defp a_list, do: [1,2,3]
|
||||
end
|
||||
Reference in New Issue
Block a user