Skip to content

Commit 21b1e51

Browse files
author
José Valim
committed
Start new records API
1 parent 9e96966 commit 21b1e51

File tree

3 files changed

+107
-9
lines changed

3 files changed

+107
-9
lines changed

lib/elixir/lib/record.ex

Lines changed: 63 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,78 @@
11
defmodule Record do
22
@doc """
3-
Extract record information from an Erlang file.
3+
Extracts record information from an Erlang file.
44
55
Returns the fields as a list of tuples.
66
77
## Examples
88
9-
Record.extract(:file_info, from_lib: "kernel/include/file.hrl")
10-
#=> [size: :undefined, type: :undefined, access: :undefined, atime: :undefined,
11-
mtime: :undefined, ctime: :undefined, mode: :undefined, links: :undefined,
12-
major_device: :undefined, minor_device: :undefined, inode: :undefined,
13-
uid: :undefined, gid: :undefined]
14-
15-
defrecord FileInfo, Record.extract(:file_info, from_lib: "kernel/include/file.hrl")
9+
iex> Record.extract(:file_info, from_lib: "kernel/include/file.hrl")
10+
[size: :undefined, type: :undefined, access: :undefined, atime: :undefined,
11+
mtime: :undefined, ctime: :undefined, mode: :undefined, links: :undefined,
12+
major_device: :undefined, minor_device: :undefined, inode: :undefined,
13+
uid: :undefined, gid: :undefined]
1614
1715
"""
1816
def extract(name, opts) do
1917
Record.Extractor.extract(name, opts)
2018
end
2119

20+
@doc """
21+
Checks if the given `data` is a record of `kind`.
22+
23+
This is implemented as a macro so it can be used in guard clauses.
24+
25+
## Examples
26+
27+
iex> Record.record?({ User, "jose", 27 }, User)
28+
true
29+
30+
"""
31+
defmacro record?(data, kind) do
32+
case __CALLER__.in_guard? do
33+
true ->
34+
quote do
35+
is_tuple(unquote(data)) and tuple_size(unquote(data)) > 0
36+
and :erlang.element(1, unquote(data)) == unquote(kind)
37+
end
38+
false ->
39+
quote do
40+
result = unquote(data)
41+
is_tuple(result) and tuple_size(result) > 0
42+
and :erlang.element(1, result) == unquote(kind)
43+
end
44+
end
45+
end
46+
47+
@doc """
48+
Checks if the given `data` is a record.
49+
50+
This is implemented as a macro so it can be used in guard clauses.
51+
52+
## Examples
53+
54+
iex> Record.record?({ User, "jose", 27 })
55+
true
56+
iex> Record.record?(13)
57+
false
58+
59+
"""
60+
defmacro record?(data) do
61+
case __CALLER__.in_guard? do
62+
true ->
63+
quote do
64+
is_tuple(unquote(data)) and tuple_size(unquote(data)) > 0
65+
and is_atom(:erlang.element(1, unquote(data)))
66+
end
67+
false ->
68+
quote do
69+
result = unquote(data)
70+
is_tuple(result) and tuple_size(result) > 0
71+
and is_atom(:erlang.element(1, result))
72+
end
73+
end
74+
end
75+
2276
@doc false
2377
def defmacros(name, values, env, tag \\ nil) do
2478
Record.Deprecated.defmacros(name, values, env, tag)
@@ -33,4 +87,4 @@ defmodule Record do
3387
def deffunctions(values, env) do
3488
Record.Deprecated.deffunctions(values, env)
3589
end
36-
end
90+
end

lib/elixir/test/doc_test.exs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ defmodule KernelTest do
2424
doctest Path
2525
doctest Protocol.Consolidation
2626
doctest Range
27+
doctest Record
2728
doctest Regex
2829
doctest Stream
2930
doctest String
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
Code.require_file "test_helper.exs", __DIR__
2+
3+
defmodule RecordTest do
4+
use ExUnit.Case, async: true
5+
6+
require Record
7+
8+
test "extract/2 extracts information from an Erlang file" do
9+
assert Record.extract(:file_info, from_lib: "kernel/include/file.hrl") ==
10+
[size: :undefined, type: :undefined, access: :undefined, atime: :undefined,
11+
mtime: :undefined, ctime: :undefined, mode: :undefined, links: :undefined,
12+
major_device: :undefined, minor_device: :undefined, inode: :undefined,
13+
uid: :undefined, gid: :undefined]
14+
end
15+
16+
test "extract/2 handles nested records too" do
17+
namespace = Record.extract(:xmlElement, from_lib: "xmerl/include/xmerl.hrl")[:namespace]
18+
assert is_tuple(namespace)
19+
assert elem(namespace, 0) == :xmlNamespace
20+
end
21+
22+
# We need indirection to avoid warnings
23+
defp record?(data, kind) do
24+
Record.record?(data, kind)
25+
end
26+
27+
test "record?/2" do
28+
assert record?({ User, "jose", 27 }, User)
29+
refute record?({ User, "jose", 27 }, Author)
30+
refute record?(13, Author)
31+
end
32+
33+
# We need indirection to avoid warnings
34+
defp record?(data) do
35+
Record.record?(data)
36+
end
37+
38+
test "record?/1" do
39+
assert record?({ User, "jose", 27 })
40+
refute record?({ "jose", 27 })
41+
refute record?(13)
42+
end
43+
end

0 commit comments

Comments
 (0)