Skip to content

Commit d3238b8

Browse files
author
José Valim
committed
Merge pull request #870 from devinus/words-with-modifiers
Add support for %w and %W (words) sigils with return type modifiers
2 parents ec69bdf + b82b51a commit d3238b8

File tree

2 files changed

+103
-1
lines changed

2 files changed

+103
-1
lines changed

lib/elixir/lib/kernel.ex

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3427,6 +3427,55 @@ defmodule Kernel do
34273427
Macro.escape(regex)
34283428
end
34293429

3430+
@doc """
3431+
Handles the sigil %w. It returns a list of "words" split by whitespace.
3432+
3433+
## Modifiers
3434+
3435+
- `b`: binaries (default)
3436+
- `a`: atoms
3437+
- `c`: char lists
3438+
3439+
## Examples
3440+
3441+
iex> %w(foo \#{:bar} baz)
3442+
["foo", "bar", "baz"]
3443+
iex> %w(--source test/enum_test.exs)
3444+
["--source", "test/enum_test.exs"]
3445+
iex> %w(foo bar baz)a
3446+
[:foo, :bar, :baz]
3447+
3448+
"""
3449+
3450+
defmacro __w__({ :<<>>, _line, [string] }, modifiers) when is_binary(string) do
3451+
split_words(Macro.unescape_binary(string), modifiers)
3452+
end
3453+
3454+
defmacro __w__({ :<<>>, line, pieces }, modifiers) do
3455+
binary = { :<<>>, line, Macro.unescape_tokens(pieces) }
3456+
split_words(binary, modifiers)
3457+
end
3458+
3459+
@doc """
3460+
Handles the sigil %W. It returns a list of "words" split by whitespace
3461+
without escaping nor interpreting interpolations.
3462+
3463+
## Modifiers
3464+
3465+
- `b`: binaries (default)
3466+
- `a`: atoms
3467+
- `c`: char lists
3468+
3469+
## Examples
3470+
3471+
iex> %W(foo \#{bar} baz)
3472+
["foo", "\\\#{bar}", "baz"]
3473+
3474+
"""
3475+
defmacro __W__({ :<<>>, _line, [string] }, modifiers) when is_binary(string) do
3476+
split_words(string, modifiers)
3477+
end
3478+
34303479
## Private functions
34313480

34323481
# Extracts concatenations in order to optimize many
@@ -3472,4 +3521,22 @@ defmodule Kernel do
34723521
end
34733522

34743523
defp build_cond_clauses([], acc), do: acc
3524+
3525+
defp split_words(string, modifiers) do
3526+
quote do
3527+
mod = case unquote(modifiers) do
3528+
[] -> ?b
3529+
[mod] when mod in [?b, ?a, ?c] -> mod
3530+
_else -> raise ArgumentError, message: "modifier must be one of: b, a, c"
3531+
end
3532+
3533+
parts = String.split(unquote(string))
3534+
3535+
case mod do
3536+
?b -> parts
3537+
?a -> lc p inlist parts, do: binary_to_atom(p)
3538+
?c -> lc p inlist parts, do: binary_to_list(p)
3539+
end
3540+
end
3541+
end
34753542
end

lib/elixir/test/elixir/kernel/sigils_test.exs

Lines changed: 36 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,4 +48,39 @@ defmodule Kernel.SigilsTest do
4848
assert %C(f#{o}o) == 'f\#{o}o'
4949
assert %C(f\no) == 'f\\no'
5050
end
51-
end
51+
52+
test :__w__ do
53+
assert %w(foo bar baz) == ["foo", "bar", "baz"]
54+
assert %w(foo #{:bar} baz) == ["foo", "bar", "baz"]
55+
56+
assert %w(
57+
foo
58+
bar
59+
baz
60+
) == ["foo", "bar", "baz"]
61+
62+
assert %w(foo bar baz)b == ["foo", "bar", "baz"]
63+
assert %w(foo bar baz)a == [:foo, :bar, :baz]
64+
assert %w(foo bar baz)c == ['foo', 'bar', 'baz']
65+
66+
bad_modifier = quote do: %w(foo bar baz)x
67+
assert ArgumentError[] = catch_error(Code.eval_quoted(bad_modifier))
68+
end
69+
70+
test :__W__ do
71+
assert %W(foo #{bar} baz) == ["foo", "\#{bar}", "baz"]
72+
73+
assert %W(
74+
foo
75+
bar
76+
baz
77+
) == ["foo", "bar", "baz"]
78+
79+
assert %W(foo bar baz)b == ["foo", "bar", "baz"]
80+
assert %W(foo bar baz)a == [:foo, :bar, :baz]
81+
assert %W(foo bar baz)c == ['foo', 'bar', 'baz']
82+
83+
bad_modifier = quote do: %W(foo bar baz)x
84+
assert ArgumentError[] = catch_error(Code.eval_quoted(bad_modifier))
85+
end
86+
end

0 commit comments

Comments
 (0)