Skip to content

Commit e27e702

Browse files
authored
Support ~j and ~J sigils. (michalmuskala#121)
1 parent 6611ce6 commit e27e702

File tree

1 file changed

+61
-0
lines changed

1 file changed

+61
-0
lines changed

lib/sigil.ex

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
defmodule Jason.Sigil do
2+
@doc ~S"""
3+
Handles the sigil `~j` for JSON strings.
4+
5+
Calls `Jason.decode!/2` with modifiers mapped to options.
6+
7+
## Modifiers
8+
9+
See `Jason.decode/2` for detailed descriptions.
10+
11+
* `a` - maps to `{:keys, :atoms}`
12+
* `A` - maps to `{:keys, :atoms!}`
13+
* `r` - maps to `{:strings, :reference}`
14+
* `c` - maps to `{:strings, :copy}`
15+
16+
## Examples
17+
18+
iex> {~j"0", ~j"[1, 2, 3]", ~j'"string"'r, ~j"{}"}
19+
{0, [1, 2, 3], "string", %{}}
20+
21+
iex> ~j'{"atom": "value"}'a
22+
%{atom: "value"}
23+
24+
iex> ~j'{"#{:j}": #{'"j"'}}'A
25+
%{j: "j"}
26+
"""
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))
30+
31+
@doc ~S"""
32+
Handles the sigil `~J` for raw JSON strings.
33+
34+
Decodes a raw string ignoring Elixir interpolations and escape characters.
35+
36+
## Examples
37+
38+
iex> ~J'"#{string}"'
39+
"\#{string}"
40+
41+
iex> ~J'"\u0078\\y"'
42+
"x\\y"
43+
44+
iex> ~J'{"#{key}": "#{}"}'a
45+
%{"\#{key}": "#{}"}
46+
"""
47+
@spec sigil_J(binary, charlist) :: term | no_return
48+
def sigil_J(input, modifiers), do: sigil_j(input, modifiers)
49+
50+
@spec mods_to_opts(charlist) :: [Jason.decode_opt()] | no_return
51+
def mods_to_opts(modifiers) do
52+
modifiers
53+
|> Enum.map(fn
54+
?a -> {:keys, :atoms}
55+
?A -> {:keys, :atoms!}
56+
?r -> {:strings, :reference}
57+
?c -> {:strings, :copy}
58+
m -> raise ArgumentError, "unknown sigil modifier #{<<?", m, ?">>}"
59+
end)
60+
end
61+
end

0 commit comments

Comments
 (0)