Add destructure.

This commit is contained in:
José Valim
2012-03-28 11:09:19 +02:00
parent b3b73b889a
commit eaa2093b71
2 changed files with 107 additions and 0 deletions
+58
View File
@@ -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.
+49
View File
@@ -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