Skip to content

Commit 468e111

Browse files
committed
Convert sigils in Jason.Sigil to macros
1 parent e27e702 commit 468e111

File tree

1 file changed

+38
-15
lines changed

1 file changed

+38
-15
lines changed

lib/sigil.ex

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -4,34 +4,54 @@ defmodule Jason.Sigil do
44
55
Calls `Jason.decode!/2` with modifiers mapped to options.
66
7+
Given a string literal without interpolations, decodes the
8+
string at compile-time.
9+
710
## Modifiers
811
912
See `Jason.decode/2` for detailed descriptions.
1013
11-
* `a` - maps to `{:keys, :atoms}`
12-
* `A` - maps to `{:keys, :atoms!}`
13-
* `r` - maps to `{:strings, :reference}`
14-
* `c` - maps to `{:strings, :copy}`
14+
* `a` - equivalent to `{:keys, :atoms}` option
15+
* `A` - equivalent to `{:keys, :atoms!}` option
16+
* `r` - equivalent to `{:strings, :reference}` option
17+
* `c` - equivalent to `{:strings, :copy}` option
1518
1619
## Examples
1720
18-
iex> {~j"0", ~j"[1, 2, 3]", ~j'"string"'r, ~j"{}"}
19-
{0, [1, 2, 3], "string", %{}}
21+
iex> ~j"0"
22+
0
23+
24+
iex> ~j"[1, 2, 3]"
25+
[1, 2, 3]
26+
27+
iex> ~j'"string"'r
28+
"string"
29+
30+
iex> ~j"{}"
31+
%{}
2032
2133
iex> ~j'{"atom": "value"}'a
2234
%{atom: "value"}
2335
2436
iex> ~j'{"#{:j}": #{'"j"'}}'A
2537
%{j: "j"}
38+
2639
"""
27-
@spec sigil_j(binary, charlist) :: term | no_return
28-
def sigil_j(input, []), do: Jason.decode!(input)
29-
def sigil_j(input, modifiers), do: Jason.decode!(input, mods_to_opts(modifiers))
40+
defmacro sigil_j(term, modifiers)
41+
42+
defmacro sigil_j({:<<>>, _meta, [string]}, modifiers) when is_binary(string) do
43+
Macro.escape(Jason.decode!(string, mods_to_opts(modifiers)))
44+
end
45+
46+
defmacro sigil_j(term, modifiers) do
47+
quote(do: Jason.decode!(unquote(term), unquote(mods_to_opts(modifiers))))
48+
end
3049

3150
@doc ~S"""
3251
Handles the sigil `~J` for raw JSON strings.
3352
34-
Decodes a raw string ignoring Elixir interpolations and escape characters.
53+
Decodes a raw string ignoring Elixir interpolations and
54+
escape characters at compile-time.
3555
3656
## Examples
3757
@@ -42,13 +62,16 @@ defmodule Jason.Sigil do
4262
"x\\y"
4363
4464
iex> ~J'{"#{key}": "#{}"}'a
45-
%{"\#{key}": "#{}"}
65+
%{"\#{key}": "\#{}"}
4666
"""
47-
@spec sigil_J(binary, charlist) :: term | no_return
48-
def sigil_J(input, modifiers), do: sigil_j(input, modifiers)
67+
defmacro sigil_J(term, modifiers)
68+
69+
defmacro sigil_J({:<<>>, _meta, [string]}, modifiers) when is_binary(string) do
70+
Macro.escape(Jason.decode!(string, mods_to_opts(modifiers)))
71+
end
4972

50-
@spec mods_to_opts(charlist) :: [Jason.decode_opt()] | no_return
51-
def mods_to_opts(modifiers) do
73+
@spec mods_to_opts(charlist) :: [Jason.decode_opt()]
74+
defp mods_to_opts(modifiers) do
5275
modifiers
5376
|> Enum.map(fn
5477
?a -> {:keys, :atoms}

0 commit comments

Comments
 (0)