Skip to content

Commit d4a5566

Browse files
committed
Use new protocol facilities
1 parent d0bcd85 commit d4a5566

File tree

1 file changed

+55
-69
lines changed

1 file changed

+55
-69
lines changed

lib/elixir/lib/json.ex

Lines changed: 55 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -3,57 +3,31 @@ defprotocol JSON.Encoder do
33
A protocol for custom JSON encoding of data structures.
44
"""
55

6-
@fallback_to_any true
6+
@undefined_impl_description """
7+
the protocol must be explicitly implemented.
78
8-
@doc """
9-
A function invoked to encode the given term.
10-
"""
11-
def encode(term, encoder)
12-
end
9+
If you have a struct, you can derive the implementation specifying \
10+
which fields should be encoded to JSON:
1311
14-
defimpl JSON.Encoder, for: Atom do
15-
def encode(value, encoder) do
16-
case value do
17-
nil -> "null"
18-
true -> "true"
19-
false -> "false"
20-
_ -> encoder.(Atom.to_string(value), encoder)
21-
end
22-
end
23-
end
12+
@derive {JSON.Encoder, only: [....]}
13+
defstruct ...
2414
25-
defimpl JSON.Encoder, for: BitString do
26-
def encode(value, _encoder) do
27-
:elixir_json.encode_binary(value)
28-
end
29-
end
15+
It is also possible to encode all fields, although this should be \
16+
used carefully to avoid accidentally leaking private information \
17+
when new fields are added:
3018
31-
defimpl JSON.Encoder, for: List do
32-
def encode(value, encoder) do
33-
:elixir_json.encode_list(value, encoder)
34-
end
35-
end
36-
37-
defimpl JSON.Encoder, for: Integer do
38-
def encode(value, _encoder) do
39-
:elixir_json.encode_integer(value)
40-
end
41-
end
19+
@derive JSON.Encoder
20+
defstruct ...
4221
43-
defimpl JSON.Encoder, for: Float do
44-
def encode(value, _encoder) do
45-
:elixir_json.encode_float(value)
46-
end
47-
end
22+
Finally, if you don't own the struct you want to encode to JSON, \
23+
you may use Protocol.derive/3 placed outside of any module:
4824
49-
defimpl JSON.Encoder, for: Map do
50-
def encode(value, encoder) do
51-
:elixir_json.encode_map(value, encoder)
52-
end
53-
end
25+
Protocol.derive(JSON.Encoder, NameOfTheStruct, only: [...])
26+
Protocol.derive(JSON.Encoder, NameOfTheStruct)\
27+
"""
5428

55-
defimpl JSON.Encoder, for: Any do
56-
defmacro __deriving__(module, _struct, opts) do
29+
@impl true
30+
defmacro __deriving__(module, opts) do
5731
fields = module |> Macro.struct_info!(__CALLER__) |> Enum.map(& &1.field)
5832
fields = fields_to_encode(fields, opts)
5933
vars = Macro.generate_arguments(length(fields), __MODULE__)
@@ -105,38 +79,50 @@ defimpl JSON.Encoder, for: Any do
10579
end
10680
end
10781

108-
def encode(%_{} = struct, _encoder) do
109-
raise Protocol.UndefinedError,
110-
protocol: @protocol,
111-
value: struct,
112-
description: """
113-
JSON.Encoder protocol must be explicitly implemented for structs
114-
115-
If you own the struct, you can derive the implementation specifying \
116-
which fields should be encoded to JSON:
117-
118-
@derive {JSON.Encoder, only: [....]}
119-
defstruct ...
82+
@doc """
83+
A function invoked to encode the given term.
84+
"""
85+
def encode(term, encoder)
86+
end
12087

121-
It is also possible to encode all fields, although this should be \
122-
used carefully to avoid accidentally leaking private information \
123-
when new fields are added:
88+
defimpl JSON.Encoder, for: Atom do
89+
def encode(value, encoder) do
90+
case value do
91+
nil -> "null"
92+
true -> "true"
93+
false -> "false"
94+
_ -> encoder.(Atom.to_string(value), encoder)
95+
end
96+
end
97+
end
12498

125-
@derive JSON.Encoder
126-
defstruct ...
99+
defimpl JSON.Encoder, for: BitString do
100+
def encode(value, _encoder) do
101+
:elixir_json.encode_binary(value)
102+
end
103+
end
127104

128-
Finally, if you don't own the struct you want to encode to JSON, \
129-
you may use Protocol.derive/3 placed outside of any module:
105+
defimpl JSON.Encoder, for: List do
106+
def encode(value, encoder) do
107+
:elixir_json.encode_list(value, encoder)
108+
end
109+
end
130110

131-
Protocol.derive(JSON.Encoder, NameOfTheStruct, only: [...])
132-
Protocol.derive(JSON.Encoder, NameOfTheStruct)
133-
"""
111+
defimpl JSON.Encoder, for: Integer do
112+
def encode(value, _encoder) do
113+
:elixir_json.encode_integer(value)
134114
end
115+
end
135116

117+
defimpl JSON.Encoder, for: Float do
136118
def encode(value, _encoder) do
137-
raise Protocol.UndefinedError,
138-
protocol: @protocol,
139-
value: value
119+
:elixir_json.encode_float(value)
120+
end
121+
end
122+
123+
defimpl JSON.Encoder, for: Map do
124+
def encode(value, encoder) do
125+
:elixir_json.encode_map(value, encoder)
140126
end
141127
end
142128

0 commit comments

Comments
 (0)