Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 29 additions & 6 deletions lib/elixir/lib/record.ex
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,28 @@ defmodule Record do
end
end

@doc """
Import public record definition as a set of private macros (as defined by defrecordp/2)

## Usage

Record.import Record.Module, as: macro_name

## Example

defmodule Test do
Record.import File.Stat, as: :file_stat

def size(file_stat(size: size)), do: size
end

"""
defmacro import(module, as: name) do
quote do
Record.defmacros(unquote(name), unquote(module).__record__(:fields), __ENV__, unquote(module))
end
end

@doc """
Main entry point for private records definition. It defines
a set of macros with the given `name` and the fields specified
Expand Down Expand Up @@ -128,31 +150,32 @@ defmodule Record do
end

"""
def defmacros(name, values, env) do
def defmacros(name, values, env, tag // nil) do
escaped = lc value inlist values do
{ key, value } = convert_value(value)
{ key, Macro.escape(value) }
end

contents = quote do

defmacrop unquote(name)() do
Record.access(__MODULE__, unquote(escaped), [], __CALLER__)
Record.access(unquote(tag) || __MODULE__, unquote(escaped), [], __CALLER__)
end

defmacrop unquote(name)(record) when is_tuple(record) do
Record.to_keywords(__MODULE__, unquote(escaped), record)
Record.to_keywords(unquote(tag) || __MODULE__, unquote(escaped), record)
end

defmacrop unquote(name)(args) do
Record.access(__MODULE__, unquote(escaped), args, __CALLER__)
Record.access(unquote(tag) || __MODULE__, unquote(escaped), args, __CALLER__)
end

defmacrop unquote(name)(record, key) when is_atom(key) do
Record.get(__MODULE__, unquote(escaped), record, key)
Record.get(unquote(tag) || __MODULE__, unquote(escaped), record, key)
end

defmacrop unquote(name)(record, args) do
Record.dispatch(__MODULE__, unquote(escaped), record, args, __CALLER__)
Record.dispatch(unquote(tag) || __MODULE__, unquote(escaped), record, args, __CALLER__)
end
end

Expand Down
2 changes: 1 addition & 1 deletion lib/elixir/src/elixir_dispatch.erl
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ default_functions() ->
default_macros() ->
[ { ?BUILTIN, ordsets:union(in_elixir_macros(), in_erlang_macros()) } ].
default_requires() ->
[ ?BUILTIN, 'Elixir.Kernel.Typespec' ].
[ ?BUILTIN, 'Elixir.Kernel.Typespec', 'Elixir.Record' ].

find_import(Meta, Name, Arity, S) ->
Tuple = { Name, Arity },
Expand Down
2 changes: 1 addition & 1 deletion lib/elixir/test/elixir/kernel/errors_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -119,7 +119,7 @@ defmodule Kernel.ErrorsTest do
end

test :unrequired_macro do
assert "nofile:2: tried to invoke macro Kernel.ErrorsTest.UnproperMacro.unproper/1 but module was not required. Required: Kernel, Kernel.Typespec" ==
assert "nofile:2: tried to invoke macro Kernel.ErrorsTest.UnproperMacro.unproper/1 but module was not required. Required: Kernel, Kernel.Typespec, Record" ==
format_rescue 'defmodule Foo do\nKernel.ErrorsTest.UnproperMacro.unproper([])\nend'
end

Expand Down
15 changes: 15 additions & 0 deletions lib/elixir/test/elixir/record_test.exs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,16 @@ Code.require_file "../test_helper.exs", __FILE__
defrecord RecordTest.FileInfo,
Record.extract(:file_info, from_lib: "kernel/include/file.hrl")

defmodule RecordTest.FileInfo.Helper do
Record.import RecordTest.FileInfo, as: :file_info

def new do
file_info
end

def size(file_info(size: size)), do: size
end

defrecord RecordTest.SomeRecord, a: 0, b: 1
defrecord RecordTest.WithNoField, []

Expand Down Expand Up @@ -183,6 +193,11 @@ defmodule RecordTest do
end)
end

test :import do
assert RecordTest.FileInfo.Helper.new == RecordTest.FileInfo.new
assert RecordTest.FileInfo.Helper.size(RecordTest.FileInfo.new(size: 100)) == 100
end

defp file_info do
{ :ok, file_info } = :file.read_file_info(__FILE__)
file_info
Expand Down