Skip to content

Commit dbf3729

Browse files
authored
Merge pull request #30 from ExpressApp/include-only-option
add :only option to include
2 parents 8a65c48 + a159ab5 commit dbf3729

File tree

2 files changed

+61
-3
lines changed

2 files changed

+61
-3
lines changed

lib/construct.ex

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,16 +113,36 @@ defmodule Construct do
113113
If included structure is invalid for some reason — this macro throws an
114114
`Struct.DefinitionError` exception with detailed reason.
115115
"""
116-
@spec include(t) :: Macro.t()
117-
defmacro include(struct) do
116+
@spec include(t, keyword) :: Macro.t()
117+
defmacro include(struct, opts \\ []) do
118118
quote do
119119
module = unquote(struct)
120120

121+
opts = unquote(opts)
122+
only = Keyword.get(opts, :only)
123+
121124
unless Construct.__is_construct_module__(module) do
122125
raise Construct.DefinitionError, "provided #{inspect(module)} is not Construct module"
123126
end
124127

125-
Enum.each(module.__construct__(:types), fn({name, {type, opts}}) ->
128+
types = module.__construct__(:types)
129+
130+
types =
131+
if is_list(only) do
132+
Enum.each(only, fn(field) ->
133+
unless Map.has_key?(types, field) do
134+
raise Construct.DefinitionError,
135+
"field #{inspect(field)} in :only option " <>
136+
"doesn't exist in #{inspect(module)}"
137+
end
138+
end)
139+
140+
Map.take(types, only)
141+
else
142+
types
143+
end
144+
145+
Enum.each(types, fn({name, {type, opts}}) ->
126146
Construct.__field__(__MODULE__, name, type, opts)
127147
end)
128148
end

test/integration/make_test.exs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -441,6 +441,44 @@ defmodule Construct.Integration.MakeTest do
441441
assert {:ok, %{a: 0, b: "b", c: "from module"}} = make(module, %{b: "b"})
442442
end
443443

444+
test "structure with `include` and only option" do
445+
include1_module = create_construct do
446+
field :a
447+
field :b
448+
end
449+
450+
include2_module = create_construct do
451+
field :c
452+
field :d
453+
end
454+
455+
include1 = name(include1_module)
456+
include2 = name(include2_module)
457+
458+
module = create_construct do
459+
include include1, only: [:a]
460+
include include2, only: []
461+
include include2, only: [:d]
462+
end
463+
464+
assert {:ok, %{a: "a", d: "d"}} = make(module, %{a: "a", b: "b", c: "c", d: "d"})
465+
end
466+
467+
test "structure with `include` where field in only option doesn't exist" do
468+
include_module = create_construct do
469+
field :a
470+
field :b
471+
end
472+
473+
include = name(include_module)
474+
475+
assert_raise(Construct.DefinitionError, "field :c in :only option doesn't exist in Construct.Integration.MakeTest_468", fn ->
476+
create_construct do
477+
include include, only: [:c]
478+
end
479+
end)
480+
end
481+
444482
test "field with `[CommaList, {:array, :integer}]` type" do
445483
module = create_construct do
446484
field :key, [CommaList, {:array, :integer}]

0 commit comments

Comments
 (0)