Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
7340ca2d92 | ||
|
|
3beb72e6f4 | ||
|
|
45f9c9c1ce | ||
|
|
cde12f75fc | ||
|
|
eb7e0984bd | ||
|
|
57a52b9a05 | ||
|
|
c352766f43 | ||
|
|
15222304eb | ||
|
|
f6aced3072 | ||
|
|
5e5eaca78f | ||
|
|
ab61c09b3d | ||
|
|
ccf939e9e7 | ||
|
|
331a70ade9 | ||
|
|
4329429823 |
+28
-1
@@ -14,7 +14,17 @@ Or:
|
||||
|
||||
saudação = "Bom dia!"
|
||||
|
||||
Elixir follows the recommendations in [Unicode Annex #31](http://unicode.org/reports/tr31/) to make the language more accessible to other languages and communities. Identifiers must still be a sequence of letters, followed by digits and combining marks. This means symbols, such as mathematical notations and emoji, are not allowed identifiers.
|
||||
Elixir follows the recommendations in [Unicode Annex #31](http://unicode.org/reports/tr31/) to make the language more accessible to other languages and communities. Identifiers must start with a letter or underscore, optionally followed by letters, digits, and underscores. Here letter means any UTF-8 letter-character (optionally with a combining mark) and digit means a UTF-8 decimal-digit-character. If you're using ASCII, this does what you'd expect.
|
||||
|
||||
Examples of valid variables are:
|
||||
|
||||
name josé _age まつもと _42 адрес
|
||||
|
||||
Examples of invalid variables include:
|
||||
|
||||
name• a±2 42
|
||||
|
||||
Symbols, such as mathematical notations and emoji, are not allowed identifiers.
|
||||
|
||||
For a complete reference on Elixir syntax, see the [Syntax Reference](https://hexdocs.pm/elixir/syntax-reference.html). For technical details on Unicode support, see [Unicode Syntax](https://hexdocs.pm/elixir/unicode-syntax.html).
|
||||
|
||||
@@ -156,6 +166,23 @@ Overall, using `@impl` has the following advantages:
|
||||
|
||||
This release brings further improvements to Calendar types. It adds arithmetic and others functions to `Time`, `Date`, `NaiveDateTime` and `Datetime` as well as conversion between different calendars.
|
||||
|
||||
## v1.5.3 (2017-12-19)
|
||||
|
||||
### 1. Bug fixes
|
||||
|
||||
#### Elixir
|
||||
|
||||
* [Calendar] Consider microseconds in maximum possible Calendar.ISO datetime
|
||||
* [Enum] Fix `chunk_every/4` when `step > count`
|
||||
* [Kernel] Warn duplicate definitions in macros
|
||||
* [Kernel] Remove dialyzer warnings from else in with clauses
|
||||
* [Kernel] Do not warning on upcoming `@deprecated` and `@since` attributes for v1.6
|
||||
* [MapSet] Return valid MapSet when union-ing a legacy MapSet
|
||||
|
||||
#### ExUnit
|
||||
|
||||
* [ExUnit] Fix compiler warnings in `assert_receive/3`
|
||||
|
||||
## v1.5.2 (2017-09-29)
|
||||
|
||||
### 1. Enhacements
|
||||
|
||||
@@ -17,7 +17,7 @@ defmodule Calendar.ISO do
|
||||
|
||||
@unix_epoch 62167219200
|
||||
@unix_start 1_000_000 * -@unix_epoch
|
||||
@unix_end 1_000_000 * (315569519999 - @unix_epoch)
|
||||
@unix_end 315569519999999999 - @unix_epoch * 1_000_000
|
||||
@unix_range_microseconds @unix_start..@unix_end
|
||||
|
||||
@type year :: 0..9999
|
||||
|
||||
@@ -362,6 +362,9 @@ defmodule Enum do
|
||||
iex> Enum.chunk_every([1, 2, 3, 4], 10)
|
||||
[[1, 2, 3, 4]]
|
||||
|
||||
iex> Enum.chunk_every([1, 2, 3, 4, 5], 2, 3, [])
|
||||
[[1, 2], [4, 5]]
|
||||
|
||||
"""
|
||||
@spec chunk_every(t, pos_integer, pos_integer, t | :discard) :: [list]
|
||||
def chunk_every(enumerable, count, step, leftover \\ [])
|
||||
|
||||
@@ -353,7 +353,8 @@ defmodule MapSet do
|
||||
%{map_set | map: Map.merge(map1, map2)}
|
||||
end
|
||||
def union(%MapSet{map: map1}, %MapSet{map: map2}) do
|
||||
new_from_list(Map.keys(map1) ++ Map.keys(map2), [])
|
||||
map = new_from_list(Map.keys(map1) ++ Map.keys(map2), [])
|
||||
%MapSet{map: map}
|
||||
end
|
||||
|
||||
defp order_by_size(map1, map2) when map_size(map1) > map_size(map2), do: {map2, map1}
|
||||
|
||||
@@ -22,7 +22,7 @@ defmodule Stream.Reducers do
|
||||
{:cont, new_state}
|
||||
end
|
||||
end, fn {acc_buffer, acc_count} ->
|
||||
if leftover == :discard or acc_count == 0 do
|
||||
if leftover == :discard or acc_count == 0 or (step > count and acc_count >= count) do
|
||||
{:cont, []}
|
||||
else
|
||||
{:cont, :lists.reverse(acc_buffer, Enum.take(leftover, count - acc_count)), []}
|
||||
|
||||
@@ -82,7 +82,7 @@ defmodule Supervisor do
|
||||
supervisor will automatically start a new one, with the initial stack
|
||||
of `[:hello]`:
|
||||
|
||||
GenServer.call(MyStack, :pop)
|
||||
GenServer.call(Stack, :pop)
|
||||
#=> :hello
|
||||
|
||||
Supervisors support different strategies; in the example above, we
|
||||
|
||||
@@ -96,6 +96,10 @@ store_definition(Kind, CheckClauses, Call, Body, Pos) ->
|
||||
%% extract meta information like file and context.
|
||||
{_, Meta, _} = Call,
|
||||
DoCheckClauses = (not lists:keymember(context, 1, Meta)) andalso (CheckClauses),
|
||||
Generated = case lists:keyfind(generated, 1, Meta) of
|
||||
{generated, true} -> ?generated([]);
|
||||
_ -> []
|
||||
end,
|
||||
|
||||
%% Check if there is a file information in the definition.
|
||||
%% If so, we assume this come from another source and
|
||||
@@ -114,7 +118,6 @@ store_definition(Kind, CheckClauses, Call, Body, Pos) ->
|
||||
LinifyArgs = elixir_quote:linify(Line, Key, Args),
|
||||
LinifyGuards = elixir_quote:linify(Line, Key, Guards),
|
||||
LinifyBody = elixir_quote:linify(Line, Key, Body),
|
||||
Generated = case DoCheckClauses of true -> []; false -> ?generated([]) end,
|
||||
|
||||
{EL, MetaLocation} =
|
||||
case retrieve_location(Location, ?key(E, module)) of
|
||||
|
||||
@@ -371,11 +371,31 @@ translate_with_else(Meta, [{else, Else}], S) ->
|
||||
RaiseExpr = {{'.', Generated, [erlang, error]}, Generated, [{with_clause, RaiseVar}]},
|
||||
RaiseClause = {'->', Generated, [[RaiseVar], RaiseExpr]},
|
||||
|
||||
GeneratedElse = [{'->', ?generated(ElseMeta), ElseArgs} || {'->', ElseMeta, ElseArgs} <- Else],
|
||||
GeneratedElse = [build_generated_clause(Generated, ElseClause) || ElseClause <- Else],
|
||||
|
||||
Case = {'case', [{export_vars, false} | Generated], [ElseVarEx, [{do, GeneratedElse ++ [RaiseClause]}]]},
|
||||
{TranslatedCase, SC} = elixir_erl_pass:translate(Case, SV),
|
||||
{{clause, ?ann(Generated), [ElseVarErl], [], [TranslatedCase]}, SC}.
|
||||
|
||||
build_generated_clause(Generated, {'->', _, [Args, Clause]}) ->
|
||||
NewArgs = [build_generated_clause_arg(Generated, Arg) || Arg <- Args],
|
||||
{'->', Generated, [NewArgs, Clause]}.
|
||||
|
||||
build_generated_clause_arg(Generated, Arg) ->
|
||||
{Expr, Guards} = elixir_utils:extract_guards(Arg),
|
||||
NewGuards = [build_generated_guard(Generated, Guard) || Guard <- Guards],
|
||||
concat_guards(Generated, Expr, NewGuards).
|
||||
|
||||
build_generated_guard(Generated, {{'.', _, _} = Call, _, Args}) ->
|
||||
{Call, Generated, [build_generated_guard(Generated, Arg) || Arg <- Args]};
|
||||
build_generated_guard(_, Expr) ->
|
||||
Expr.
|
||||
|
||||
concat_guards(_Meta, Expr, []) ->
|
||||
Expr;
|
||||
concat_guards(Meta, Expr, [Guard | Tail]) ->
|
||||
{'when', Meta, [Expr, concat_guards(Meta, Guard, Tail)]}.
|
||||
|
||||
translate_with_do([{'<-', Meta, [Left, Expr]} | Rest], Do, Else, S) ->
|
||||
{Args, Guards} = elixir_utils:extract_guards(Left),
|
||||
{TExpr, SR} = elixir_erl_pass:translate(Expr, S),
|
||||
|
||||
@@ -318,7 +318,7 @@ beam_location(#{lexical_tracker := Pid, module := Module}) ->
|
||||
%% Handle unused attributes warnings and special cases.
|
||||
|
||||
warn_unused_attributes(File, Data, PersistedAttrs) ->
|
||||
ReservedAttrs = [after_compile, before_compile, moduledoc, on_definition | PersistedAttrs],
|
||||
ReservedAttrs = [after_compile, before_compile, deprecated, moduledoc, on_definition, since | PersistedAttrs],
|
||||
Keys = ets:select(Data, [{{'$1', '_', '_', '$2'}, [{is_atom, '$1'}, {is_integer, '$2'}], [['$1', '$2']]}]),
|
||||
[elixir_errors:form_warn([{line, Line}], File, ?MODULE, {unused_attribute, Key}) ||
|
||||
[Key, Line] <- Keys, not lists:member(Key, ReservedAttrs)].
|
||||
|
||||
@@ -230,12 +230,12 @@ defmodule DateTimeTest do
|
||||
assert DateTime.from_unix(-62167219201) == {:error, :invalid_unix_time}
|
||||
|
||||
max_datetime = %DateTime{
|
||||
calendar: Calendar.ISO, day: 31, hour: 23, microsecond: {0, 0},
|
||||
calendar: Calendar.ISO, day: 31, hour: 23, microsecond: {999999, 6},
|
||||
minute: 59, month: 12, second: 59, std_offset: 0, time_zone: "Etc/UTC",
|
||||
utc_offset: 0, year: 9999, zone_abbr: "UTC"
|
||||
}
|
||||
|
||||
assert DateTime.from_unix(253402300799) == {:ok, max_datetime}
|
||||
assert DateTime.from_unix(253402300799999999, :microsecond) == {:ok, max_datetime}
|
||||
assert DateTime.from_unix(253402300800) == {:error, :invalid_unix_time}
|
||||
|
||||
minus_datetime = %DateTime{
|
||||
|
||||
@@ -70,6 +70,11 @@ defmodule EnumTest do
|
||||
assert Enum.chunk_every([1, 2, 3, 4, 5, 6], 3, 2, []) == [[1, 2, 3], [3, 4, 5], [5, 6]]
|
||||
assert Enum.chunk_every([1, 2, 3, 4, 5, 6], 3, 3, []) == [[1, 2, 3], [4, 5, 6]]
|
||||
assert Enum.chunk_every([1, 2, 3, 4, 5], 4, 4, 6..10) == [[1, 2, 3, 4], [5, 6, 7, 8]]
|
||||
assert Enum.chunk_every([1, 2, 3, 4, 5], 2, 3, []) == [[1, 2], [4, 5]]
|
||||
assert Enum.chunk_every([1, 2, 3, 4, 5, 6], 2, 3, []) == [[1, 2], [4, 5]]
|
||||
assert Enum.chunk_every([1, 2, 3, 4, 5, 6, 7], 2, 3, []) == [[1, 2], [4, 5], [7]]
|
||||
assert Enum.chunk_every([1, 2, 3, 4, 5, 6, 7], 2, 3, [8]) == [[1, 2], [4, 5], [7, 8]]
|
||||
assert Enum.chunk_every([1, 2, 3, 4, 5, 6, 7], 2, 4, []) == [[1, 2], [5, 6]]
|
||||
end
|
||||
|
||||
test "chunk_by/2" do
|
||||
|
||||
@@ -1,13 +1,25 @@
|
||||
defmodule Dialyzer.With do
|
||||
def with_else do
|
||||
with :ok <- ok_or_error(),
|
||||
:ok <- ok_or_other_error() do
|
||||
:ok <- ok_or_other_error(),
|
||||
:ok <- ok_or_tuple_error(),
|
||||
:ok <- ok_or_tuple_list_error() do
|
||||
:ok
|
||||
else
|
||||
:error ->
|
||||
:error
|
||||
|
||||
:other_error ->
|
||||
:other_error
|
||||
|
||||
{:error, msg} when is_list(msg) or is_tuple(msg) ->
|
||||
:error
|
||||
|
||||
{:error, msg} when is_list(msg) when is_tuple(msg) ->
|
||||
:error
|
||||
|
||||
{:error, _msg} ->
|
||||
:error
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,4 +32,14 @@ defmodule Dialyzer.With do
|
||||
defp ok_or_other_error do
|
||||
Enum.random([:ok, :other_error])
|
||||
end
|
||||
|
||||
@spec ok_or_tuple_error() :: :ok | {:error, :err}
|
||||
defp ok_or_tuple_error do
|
||||
Enum.random([:ok, {:error, :err}])
|
||||
end
|
||||
|
||||
@spec ok_or_tuple_list_error() :: :ok | {:error, [:err]}
|
||||
defp ok_or_tuple_list_error do
|
||||
Enum.random([:ok, {:error, [:err]}])
|
||||
end
|
||||
end
|
||||
|
||||
@@ -487,6 +487,27 @@ defmodule Kernel.WarningTest do
|
||||
purge Sample
|
||||
end
|
||||
|
||||
test "generated clause not match" do
|
||||
assert capture_err(fn ->
|
||||
Code.eval_string("""
|
||||
defmodule Sample do
|
||||
defmacro __using__(_) do
|
||||
quote do
|
||||
def hello, do: nil
|
||||
def hello, do: nil
|
||||
end
|
||||
end
|
||||
end
|
||||
defmodule UseSample do
|
||||
use Sample
|
||||
end
|
||||
""")
|
||||
end) =~ "this clause cannot match because a previous clause at line 10 always matches"
|
||||
after
|
||||
purge(Sample)
|
||||
purge(UseSample)
|
||||
end
|
||||
|
||||
test "clause with defaults should be first" do
|
||||
assert capture_err(fn ->
|
||||
Code.eval_string ~S"""
|
||||
|
||||
@@ -108,4 +108,38 @@ defmodule MapSetTest do
|
||||
list = MapSet.to_list(MapSet.new(5..120))
|
||||
assert Enum.sort(list) == Enum.to_list(5..120)
|
||||
end
|
||||
|
||||
test "MapSet v1 compatibility" do
|
||||
result = 1..5 |> map_set_v1() |> MapSet.new()
|
||||
assert MapSet.equal?(result, MapSet.new(1..5))
|
||||
|
||||
result = MapSet.put(map_set_v1(1..5), 6)
|
||||
assert MapSet.equal?(result, MapSet.new(1..6))
|
||||
|
||||
result = MapSet.union(map_set_v1(1..5), MapSet.new(6..10))
|
||||
assert MapSet.equal?(result, MapSet.new(1..10))
|
||||
|
||||
result = MapSet.intersection(map_set_v1(1..10), MapSet.new(6..15))
|
||||
assert MapSet.equal?(result, MapSet.new(6..10))
|
||||
|
||||
result = MapSet.difference(map_set_v1(1..10), MapSet.new(6..50))
|
||||
assert MapSet.equal?(result, MapSet.new(1..5))
|
||||
|
||||
result = MapSet.delete(map_set_v1(1..10), 1)
|
||||
assert MapSet.equal?(result, MapSet.new(2..10))
|
||||
|
||||
assert MapSet.size(map_set_v1(1..5)) == 5
|
||||
assert MapSet.to_list(map_set_v1(1..5)) == Enum.to_list(1..5)
|
||||
|
||||
assert MapSet.disjoint?(map_set_v1(1..5), MapSet.new(10..15))
|
||||
refute MapSet.disjoint?(map_set_v1(1..5), MapSet.new(5..10))
|
||||
|
||||
assert MapSet.subset?(map_set_v1(3..7), MapSet.new(1..10))
|
||||
refute MapSet.subset?(map_set_v1(7..12), MapSet.new(1..10))
|
||||
end
|
||||
|
||||
defp map_set_v1(enumerable) do
|
||||
map = Map.new(enumerable, &{&1, true})
|
||||
%{__struct__: MapSet, map: map}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -109,7 +109,7 @@ defmodule ExUnit.Assertions do
|
||||
# is not nil nor false. We need to rewrite the if
|
||||
# to avoid silly warnings though.
|
||||
return =
|
||||
no_warning(quote do
|
||||
suppress_warning(quote do
|
||||
case right do
|
||||
x when x in [nil, false] ->
|
||||
raise ExUnit.AssertionError,
|
||||
@@ -121,7 +121,7 @@ defmodule ExUnit.Assertions do
|
||||
end)
|
||||
|
||||
match_expr =
|
||||
no_warning(quote do
|
||||
suppress_warning(quote do
|
||||
case right do
|
||||
unquote(left) ->
|
||||
unquote(return)
|
||||
@@ -401,6 +401,40 @@ defmodule ExUnit.Assertions do
|
||||
quote(do: unquote(left) = received)
|
||||
end
|
||||
|
||||
pattern_finder =
|
||||
quote do
|
||||
fn message ->
|
||||
unquote(suppress_warning(quote do
|
||||
case message do
|
||||
unquote(pattern) ->
|
||||
_ = unquote(vars)
|
||||
true
|
||||
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end))
|
||||
end
|
||||
end
|
||||
|
||||
failure_message_hit =
|
||||
failure_message || quote do
|
||||
"""
|
||||
Found message matching #{unquote(binary)} after #{timeout}ms.
|
||||
|
||||
This means the message was delivered too close to the timeout value, you may want to either:
|
||||
|
||||
1. Give an increased timeout to `assert_receive/2`
|
||||
2. Increase the default timeout to all `assert_receive` in your
|
||||
test_helper.exs by setting ExUnit.configure(assert_receive_timeout: ...)
|
||||
"""
|
||||
end
|
||||
|
||||
failure_message_miss =
|
||||
failure_message || quote do
|
||||
"No message matching #{unquote(binary)} after #{timeout}ms."
|
||||
end
|
||||
|
||||
quote do
|
||||
timeout = unquote(timeout)
|
||||
|
||||
@@ -412,29 +446,10 @@ defmodule ExUnit.Assertions do
|
||||
timeout ->
|
||||
{:messages, messages} = Process.info(self(), :messages)
|
||||
|
||||
pattern_finder = fn message ->
|
||||
case message do
|
||||
unquote(pattern) ->
|
||||
_ = unquote(vars)
|
||||
true
|
||||
_ ->
|
||||
false
|
||||
end
|
||||
end
|
||||
|
||||
if Enum.any?(messages, pattern_finder) do
|
||||
flunk(unquote(failure_message) || """
|
||||
Found message matching #{unquote(binary)} after #{timeout}ms.
|
||||
|
||||
This means the message was delivered too close to the timeout value, you may want to either:
|
||||
|
||||
1. Give an increased timeout to `assert_receive/2`
|
||||
2. Increase the default timeout to all `assert_receive` in your
|
||||
test_helper.exs by setting ExUnit.configure(assert_receive_timeout: ...)
|
||||
""")
|
||||
if Enum.any?(messages, unquote(pattern_finder)) do
|
||||
flunk(unquote(failure_message_hit))
|
||||
else
|
||||
failure_message = unquote(failure_message) || "No message matching #{unquote(binary)} after #{timeout}ms."
|
||||
flunk(failure_message <>
|
||||
flunk(unquote(failure_message_miss) <>
|
||||
ExUnit.Assertions.__pins__(unquote(pins)) <>
|
||||
ExUnit.Assertions.__mailbox__(messages))
|
||||
end
|
||||
@@ -515,7 +530,7 @@ defmodule ExUnit.Assertions do
|
||||
|> elem(1)
|
||||
end
|
||||
|
||||
defp no_warning({name, meta, [expr, [do: clauses]]}) do
|
||||
defp suppress_warning({name, meta, [expr, [do: clauses]]}) do
|
||||
clauses = Enum.map clauses, fn {:->, meta, args} ->
|
||||
{:->, [generated: true] ++ meta, args}
|
||||
end
|
||||
|
||||
@@ -179,6 +179,12 @@ defmodule ExUnit.AssertionsTest do
|
||||
:hello = assert_receive :hello
|
||||
end
|
||||
|
||||
test "assert receive accepts custom failure message" do
|
||||
send self(), :hello
|
||||
assert_receive message, 0, "failure message"
|
||||
:hello = message
|
||||
end
|
||||
|
||||
test "assert receive with message in mailbox after timeout, but before reading mailbox tells user to increase timeout" do
|
||||
parent = self()
|
||||
# This is testing a race condition, so it's not
|
||||
@@ -297,7 +303,7 @@ defmodule ExUnit.AssertionsTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "assert received leaks" do
|
||||
test "assert received binds variables" do
|
||||
send self(), {:hello, :world}
|
||||
assert_received {:hello, world}
|
||||
:world = world
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
{application, elixir,
|
||||
[{description, "elixir"},
|
||||
{vsn, "1.5.2"},
|
||||
{vsn, "1.5.3"},
|
||||
{modules, [
|
||||
elixir
|
||||
]},
|
||||
|
||||
Reference in New Issue
Block a user