Compare commits
7
Commits
v1.9.1
...
v1.6.0-rc.0
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
182c730bdb | ||
|
|
3879f0d8b3 | ||
|
|
24369d5724 | ||
|
|
3d20f049e6 | ||
|
|
8d07fe6f59 | ||
|
|
d27b285687 | ||
|
|
1684c8067e |
+84
-11
@@ -1,16 +1,69 @@
|
||||
# Changelog for Elixir v1.6
|
||||
|
||||
## Compiler diagnostics
|
||||
|
||||
TODO.
|
||||
|
||||
## Code formatter
|
||||
|
||||
TODO.
|
||||
The big feature in Elixir v1.6 is the addition of a code formatter and an accompanying `mix format` task that adds automatic formatting to your projects.
|
||||
|
||||
## Stream data and property testing
|
||||
The goal of the formatter is to automate the styling of codebases into a unique and consistent layout used across teams and the whole community. Code is now easier to write, as you no longer need to concern yourself with formatting rules. Code is also easier to read, as you no longer need to convert the styles of other developers in your mind.
|
||||
|
||||
TODO.
|
||||
The formatter also helps new developers to learn the language, by giving immediate feedback on code structure, and eases code reviews by allowing teams to focus on business rules and code quality, rather than code style.
|
||||
|
||||
To automatically format your codebase, you can run the new `mix format` task. A `.formatter.exs` file may be added to your project root for rudimentary formatter configuration. The mix task also supports flags for CI integration. For instance, you can make your build or a Pull Request fail if the code is not formatted accordingly. We also recommend developers to check their favorite editor and see if they already provide key bindings for `mix format`, allowing a file or a code snippet to be formatted without ceremony.
|
||||
|
||||
The Elixir codebase itself has been already fully formatted and all further contributions are expected to contain formatted code. We recommend existing codebases to be formatted in steps. While the formatter will correctly handle long lines and complex expressions, refactoring the code by breaking those into variables or smaller functions as you format them will lead to overall cleaner and more readable codebases.
|
||||
|
||||
## Dynamic Supervisor
|
||||
|
||||
Supervisors in Elixir are responsible for starting, shutting down and restarting child process when things go wrong. Most of the interaction with supervisors happen with the Supervisor module and it contains three main strategies: `:one_for_one`, `:rest_for_one` and `:one_for_all`.
|
||||
|
||||
However, sometimes the children of a supervisor are not known upfront and are rather started dynamically. For example, if you are building a web server, you have each request beind handled by a separate supervised process. Those cases were handled in the Supervisor module under a special strategy called `:simple_one_for_one`.
|
||||
|
||||
Unfortunately, this special strategy changed the semantics of the supervisor in regards to initialization and shutdown. Plus some APIs expected different inputs or would be completely unavailable depending on the supervision strategy.
|
||||
|
||||
Elixir v1.6 addresses this issue by introducing a new `DynamicSupervisor` module, which encapsulates the old `:simple_one_for_one` strategy and APIs in a proper module while allowing the documentation and API of the `Supervisor` module to focus on its main use cases. Having a separate `DynamicSupervisor` module also makes it simpler to add new features to the dynamic supervisor, such as the new `:max_children` option that limits the maximum number of children supervised dynamically.
|
||||
|
||||
## @deprecated and @since attributes
|
||||
|
||||
This release also introduces two new attributes associated to function definitions: `@deprecated` and `@since`. The former says if a function or macro is deprecated, the latter says the version said API was added:
|
||||
|
||||
@doc "Breaks a collection into chunks"
|
||||
@since "1.0.0"
|
||||
@deprecated "Use chunk_every/2 instead"
|
||||
def chunk_every(collection, chunk_size) do
|
||||
...
|
||||
end
|
||||
|
||||
The `mix xref` task was also updated to warn if your project calls deprecated code. So if a definition is marked as `@deprecated` and a module invokes it, a warning will be emitted during compilation. This effectively provides libraries and frameworks a mechanism to deprecate code without causing multiple warnings to be printed in runtime and without impacting performance.
|
||||
|
||||
Note those attributes are not yet available to tools that generate documentation. Such functionality will be added in future releases as it requires changes to how Elixir stores documentation in BEAM files. We still recommend developers to properly annotate their APIs, as the information will then be already available when the tooling is updated.
|
||||
|
||||
## defguard and defguardp
|
||||
|
||||
Elixir provides the concepts of guards: expressions used alongside pattern matching to select a matching clause. Let's see an example straight from Elixir's home page:
|
||||
|
||||
def serve_drinks(%User{age: age}) when age >= 21 do
|
||||
# Code that serves drinks!
|
||||
end
|
||||
|
||||
`%User{age: age}` is matching on a `User` struct with an age field and `when age >= 21` is the guard.
|
||||
|
||||
Since only a handful of constructs are [allowed in guards](https://hexdocs.pm/elixir/guards.html#content), if you were in a situation where you had to check the age to be more than or equal to 21 in multiple times, extracting the guard to a separate function would be [less than obvious and error prone](https://github.com/elixir-lang/elixir/issues/2469). To address those issues, this release introduces `defguard/1` and `defguardp/1`:
|
||||
|
||||
defguard is_drinking_age(age) when age >= 21
|
||||
|
||||
def serve_drinks(%User{age: age}) when is_drinking_age(age) do
|
||||
# Code that serves drinks!
|
||||
end
|
||||
|
||||
## IEx improvements
|
||||
|
||||
IEx also got its share of improvements. The new code formatter allows us to pretty print code snippets, types and specifications, improving the overall experience when exploring code through the terminal.
|
||||
|
||||
The autocomplete mechanism also got smarter, being able to provide context autocompletion. For example, typing `t Enum.` and hitting TAB will autocomplete only the types in Enum (in contrast to all functions). Typing `b Enum` and hitting TAB will autocomplete only the behaviour callbacks.
|
||||
|
||||
Finally, the breakpoint functionality added in Elixir v1.5 has been improved to support pattern matching and guards. For example, to pattern match on a function call when the first argument is the atom `:foo`, you may do:
|
||||
|
||||
break! SomeFunction.call(:foo, _, _)
|
||||
|
||||
## mix xref
|
||||
|
||||
@@ -68,7 +121,9 @@ The `graph` command in `mix xref` can also output general statistics about the g
|
||||
|
||||
Those improvements will help developers better understand the relationship between files and reveal potentially complex parts of their systems.
|
||||
|
||||
## v1.6.0-dev
|
||||
Other improvements in Mix include the `mix xref` enhancements above, better compiler diagnostics for editor integration, support for the `--slowest N` flag in `mix test` that shows the slowest tests in your suite, and a new `mix profile.eprof` task that provides time based profiling, complementing the existing `mix profile.cprof` (count based) and `mix profile.fprof` (flame based).
|
||||
|
||||
## v1.6.0-rc.0 (2017-12-24)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
@@ -78,10 +133,14 @@ Those improvements will help developers better understand the relationship betwe
|
||||
|
||||
#### Elixir
|
||||
|
||||
* [Calendar] Add truncate to `Time`, `DateTime` and `NaiveDateTime` to facilitate microsecond precision pruning
|
||||
* [Code] Add `format_string!/2` and `format_file!/2` for automatic code formatting
|
||||
* [Code] Support column annotations in quoted expressions with `columns: true` in `Code.string_to_quoted/2`
|
||||
* [DynamicSupervisor] Add `DynamicSupervisor` designed to manage children that are added and removed dynamically
|
||||
* [Exception] Make `Exception.blame/3` extensible by adding an optional `blame/2` callback to exceptions
|
||||
* [Enumerable] Add `Enumerable.slice/1` and optimize many `Enum` operations with the new protocol. This allows data-structures with index-based random access to provide a non-linear implementation
|
||||
* [Inspect.Algebra] Add `:strict` and `:flex` breaks
|
||||
* [Inspect] Show UTF-8 BOM on inspected strings
|
||||
* [Inspect.Algebra] Add `:strict` and `:flex` breaks - this gives more control over the document fitting
|
||||
* [Inspect.Algebra] Allow a group to inherit the parent group break
|
||||
* [Inspect.Algebra] Add `force_unfit/1` and `next_break_fits/2` which give more control over document fitting
|
||||
* [Inspect.Algebra] Add `collapse_lines/1` for collapsing multiple lines to a maximum value
|
||||
@@ -89,11 +148,15 @@ Those improvements will help developers better understand the relationship betwe
|
||||
* [Kernel] Prefix variables with V when emitting Erlang code. This improves the integration with tools such as Erlang code formatters and the GUI debugger
|
||||
* [Kernel] Warn on the use of `length(x) == 0` in guards
|
||||
* [Kernel] Warn if `catch` comes before `rescue` in try
|
||||
* [Kernel] Add `defguard/1` and `defguardp/1` to make it easier to build guard-safe macros
|
||||
* [Kernel.ParallelCompiler] Add `compile/2`, `compile_to_path/3` and `require/2` which provide detailed information about warnings and errors
|
||||
* [Kernel.SpecialForms] Support the `uniq: true` flag in `for` comprehensions
|
||||
* [Module] Introduce `@deprecated` and `@since` attributes
|
||||
* [Stream] Add `Stream.intersperse/2`
|
||||
* [String] Update to Unicode 10
|
||||
* [String] Allow passing empty string `match` to `String.replace/4`
|
||||
* [Task] Allow a custom supervisor to be given to `Task.Supervisor.async_stream/3`
|
||||
* [String] Support context and language sensitive operations in `String.upcase/2` and `String.downcase/2`. Currently only the `:greek` context is supported
|
||||
* [String] Support `:ascii` conversion in `String.upcase/2` and `String.downcase/2`
|
||||
* [Time] Add `Time.add/3`
|
||||
|
||||
#### ExUnit
|
||||
@@ -103,11 +166,14 @@ Those improvements will help developers better understand the relationship betwe
|
||||
|
||||
#### IEx
|
||||
|
||||
* [IEx.Autocomplete] Provide contextual autocompletion: `t Enum.` will autocomplete types, `b Enum` will autocomplete callbacks
|
||||
* [IEx.Helpers] Automatically include specs when showing documentation for functions/macros
|
||||
* [IEx.Helpers] Improve formatting of behaviours and typespecs by using the formatter
|
||||
* [IEx.Helpers] Allow pattern matching and guard expressions when on `IEx.break!`
|
||||
|
||||
#### Mix
|
||||
|
||||
* [mix app.start] Add `--preload-modules` to `mix app.start`
|
||||
* [mix archive.build] Allow `mix archive.build` to bundle dot files via an option
|
||||
* [mix compile] Define a behavior for Mix compiler tasks and return diagnostics from compiler tasks
|
||||
* [mix compile] Track struct dependencies between files and recompile them only if the struct changes
|
||||
@@ -119,22 +185,28 @@ Those improvements will help developers better understand the relationship betwe
|
||||
* [mix xref] Support `--include-siblings` in reports for umbrella support
|
||||
* [mix xref] Add `mix xref graph --format stats`
|
||||
* [mix xref] Add `--only-nodes` and `--label` filters to mix xref graph
|
||||
* [mix xref] Add `mix xref deprecated` that shows the callsite of deprecated functions
|
||||
|
||||
### 2. Bug fixes
|
||||
|
||||
#### Elixir
|
||||
|
||||
* [CLI] Support path with spaces as argument to elixir.bat
|
||||
* [Integer] Do not raise on non-integer values in `is_odd`/`is_even`
|
||||
* [Kernel] Solve a precedence issue between `&` and `|`, such as `[&Foo.bar/1 | &Baz.bat/2]`
|
||||
* [Kernel] Do not load dynamic Elixir modules as `:in_memory` as this value is not officially supported by the code server. Instead, use an empty list, which is the same value used by Erlang.
|
||||
* [Kernel] Validate variable struct name is atom when used in pattern matching
|
||||
* [Macro] Fix `Macro.to_string/2` for tuple calls, such as `alias Foo.{Bar, Baz}`
|
||||
* [MapSet] Return valid MapSet when unioning a legacy MapSet
|
||||
* [String] Properly downcase the greek sigma letter in `String.downcase/1`
|
||||
* [Regex] Return a leading empty space when splitting on empty pattern. This makes the `split` operation consistent with the other operations in the `Regex` module
|
||||
* [Stream] Ensure `Stream.chunk_while/4` does not emit more elements than necessary when halted
|
||||
* [String] Return a leading empty space when splitting on empty string. This makes the `split` operation consistent with the other operations in the `String` module
|
||||
* [URI] Preserve empty fragments in `URI.parse/1`
|
||||
|
||||
#### Mix
|
||||
|
||||
* [mix app.start] Improve the quality of reports if app fails to boot
|
||||
* [mix cmd] Allow `mix cmd` to be invoked multiple times without marking it as executed
|
||||
* [mix deps] Ensure optional dependencies in umbrella applications are loaded
|
||||
* [mix xref] Take compile dependencies with higher priority than runtime ones when building a graph
|
||||
* [mix xref] Handle external files for xref callers and warnings
|
||||
@@ -146,6 +218,7 @@ Those improvements will help developers better understand the relationship betwe
|
||||
* [Inspect.Algebra] `surround/3` and `surround_many/6` are deprecated in favor of `container_doc/6`
|
||||
* [Kernel.ParallelCompiler] `files/2` and `files_to_path/3` are deprecated in favor of `compile/2` and `compile_to_path/3`
|
||||
* [Kernel.ParallelRequire] `files/2` is deprecated in favor of `Kernel.ParallelCompiler.require/2`
|
||||
* [GenServer] Warn if `init/1` is not defined in `GenServer`. This brings GenServer closer to the implementation in OTP and aligns all behaviours to require the `init/1` callback
|
||||
|
||||
#### ExUnit
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
REBAR ?= "$(CURDIR)/rebar"
|
||||
PREFIX ?= /usr/local
|
||||
SHARE_PREFIX ?= $(PREFIX)/share
|
||||
CANONICAL := master/
|
||||
CANONICAL := v1.6/
|
||||
ELIXIRC := bin/elixirc --verbose --ignore-module-conflict
|
||||
ERLC := erlc -I lib/elixir/include
|
||||
ERL := erl -I lib/elixir/include -noshell -pa lib/elixir/ebin
|
||||
|
||||
@@ -118,6 +118,13 @@ defmodule Module do
|
||||
The mix compiler automatically looks for calls to deprecated modules
|
||||
and emit warnings during compilation, computed via `mix xref warnings`.
|
||||
|
||||
We recommend using this feature with care, especially library authors.
|
||||
Deprecating code always pushes the burden towards library users. We
|
||||
also recommend for deprecated functionality to be maintained for long
|
||||
periods of time, even after deprecation, giving developers plenty of
|
||||
time to update (except for cases where keeping the deprecated API is
|
||||
undesired, such as in the presence of security issues).
|
||||
|
||||
### `@doc` (and `@since`)
|
||||
|
||||
Provides documentation for the function or macro that follows the
|
||||
|
||||
@@ -592,7 +592,7 @@ defmodule Supervisor do
|
||||
## Options
|
||||
|
||||
* `:strategy` - the restart strategy option. It can be either
|
||||
`:one_for_one`, `:rest_for_one`, `:one_for_all`, or
|
||||
`:one_for_one`, `:rest_for_one`, `:one_for_all`, or the deprecated
|
||||
`:simple_one_for_one`.
|
||||
|
||||
* `:max_restarts` - the maximum number of restarts allowed in
|
||||
@@ -722,14 +722,6 @@ defmodule Supervisor do
|
||||
#=> %{id: {Agent, 1},
|
||||
#=> start: {Agent, :start_link, [fn -> :ok end]}}
|
||||
|
||||
It may also be used when there is a need to change the number
|
||||
of arguments when starting a module under a `:simple_one_for_one`
|
||||
strategy, since most args may be given dynamically:
|
||||
|
||||
Supervisor.child_spec(Agent, start: {Agent, :start_link, []})
|
||||
#=> %{id: Agent,
|
||||
#=> start: {Agent, :start_link, []}}
|
||||
|
||||
"""
|
||||
@spec child_spec(child_spec() | {module, arg :: term} | module, keyword) :: child_spec()
|
||||
def child_spec(module_or_map, overrides)
|
||||
@@ -821,13 +813,13 @@ defmodule Supervisor do
|
||||
returns `{:error, error}` where `error` is a term containing information about
|
||||
the error and child specification.
|
||||
"""
|
||||
@spec start_child(supervisor, :supervisor.child_spec() | {module, term} | module) ::
|
||||
@spec start_child(supervisor, :supervisor.child_spec() | {module, term} | module | [term]) ::
|
||||
on_start_child
|
||||
def start_child(supervisor, {_, _, _, _, _, _} = child_spec) do
|
||||
call(supervisor, {:start_child, child_spec})
|
||||
end
|
||||
|
||||
# TODO: Deprecate this on Elixir v1.8
|
||||
# TODO: Deprecate this on Elixir v1.8. Remove and update typespec on v2.0.
|
||||
def start_child(supervisor, args) when is_list(args) do
|
||||
call(supervisor, {:start_child, args})
|
||||
end
|
||||
|
||||
@@ -20,11 +20,6 @@ defmodule Task.Supervisor do
|
||||
| {:restart, :supervisor.restart()}
|
||||
| {:shutdown, :supervisor.shutdown()}
|
||||
|
||||
@typedoc "Supervisor spec used by `async_stream`"
|
||||
@type async_stream_supervisor ::
|
||||
Supervisor.supervisor()
|
||||
| (term -> Supervisor.supervisor())
|
||||
|
||||
@doc false
|
||||
def child_spec(arg) do
|
||||
%{
|
||||
@@ -158,15 +153,6 @@ defmodule Task.Supervisor do
|
||||
own task. The tasks will be spawned under the given `supervisor` and
|
||||
linked to the current process, similarly to `async/4`.
|
||||
|
||||
You may also provide a function as the `supervisor`. Before each task is
|
||||
started, the function will be invoked (in a new process which is linked to
|
||||
the current process) with the stream entry that the to-be-spawned task will
|
||||
process as its argument. The function should return a supervisor pid or name,
|
||||
which will be used to spawn the task. This allows one to dynamically start
|
||||
tasks in different locations in the supervision tree(s) on the local (or
|
||||
another) node. Notably, this enables the distribution of concurrent stream
|
||||
tasks over multiple nodes.
|
||||
|
||||
When streamed, each task will emit `{:ok, value}` upon successful
|
||||
completion or `{:exit, reason}` if the caller is trapping exits.
|
||||
Results are emitted in the same order as the original `enumerable`.
|
||||
@@ -207,7 +193,7 @@ defmodule Task.Supervisor do
|
||||
Enum.to_list(stream)
|
||||
|
||||
"""
|
||||
@spec async_stream(async_stream_supervisor, Enumerable.t(), module, atom, [term], keyword) ::
|
||||
@spec async_stream(Supervisor.supervisor(), Enumerable.t(), module, atom, [term], keyword) ::
|
||||
Enumerable.t()
|
||||
def async_stream(supervisor, enumerable, module, function, args, options \\ [])
|
||||
when is_atom(module) and is_atom(function) and is_list(args) do
|
||||
@@ -224,7 +210,7 @@ defmodule Task.Supervisor do
|
||||
|
||||
See `async_stream/6` for discussion, options, and examples.
|
||||
"""
|
||||
@spec async_stream(async_stream_supervisor, Enumerable.t(), (term -> term), keyword) ::
|
||||
@spec async_stream(Supervisor.supervisor(), Enumerable.t(), (term -> term), keyword) ::
|
||||
Enumerable.t()
|
||||
def async_stream(supervisor, enumerable, fun, options \\ []) when is_function(fun, 1) do
|
||||
build_stream(supervisor, :link, enumerable, fun, options)
|
||||
@@ -241,7 +227,7 @@ defmodule Task.Supervisor do
|
||||
See `async_stream/6` for discussion, options, and examples.
|
||||
"""
|
||||
@spec async_stream_nolink(
|
||||
async_stream_supervisor,
|
||||
Supervisor.supervisor(),
|
||||
Enumerable.t(),
|
||||
module,
|
||||
atom,
|
||||
@@ -263,7 +249,7 @@ defmodule Task.Supervisor do
|
||||
|
||||
See `async_stream/6` for discussion and examples.
|
||||
"""
|
||||
@spec async_stream_nolink(async_stream_supervisor, Enumerable.t(), (term -> term), keyword) ::
|
||||
@spec async_stream_nolink(Supervisor.supervisor(), Enumerable.t(), (term -> term), keyword) ::
|
||||
Enumerable.t()
|
||||
def async_stream_nolink(supervisor, enumerable, fun, options \\ []) when is_function(fun, 1) do
|
||||
build_stream(supervisor, :nolink, enumerable, fun, options)
|
||||
@@ -354,27 +340,12 @@ defmodule Task.Supervisor do
|
||||
%Task{pid: pid, ref: ref, owner: owner}
|
||||
end
|
||||
|
||||
defp supervisor_fun(supervisor, {_module, _fun, _args})
|
||||
when is_function(supervisor, 1) do
|
||||
fn {_module, _fun, [entry | _rest_args]} -> supervisor.(entry) end
|
||||
end
|
||||
|
||||
defp supervisor_fun(supervisor, fun)
|
||||
when is_function(supervisor, 1) and is_function(fun, 1) do
|
||||
fn {_erlang, _apply, [_fun, [entry]]} -> supervisor.(entry) end
|
||||
end
|
||||
|
||||
defp supervisor_fun(supervisor, _fun) do
|
||||
fn _mfa -> supervisor end
|
||||
end
|
||||
|
||||
defp build_stream(supervisor, link_type, enumerable, fun, options) do
|
||||
supervisor_fun = supervisor_fun(supervisor, fun)
|
||||
shutdown = options[:shutdown]
|
||||
|
||||
&Task.Supervised.stream(enumerable, &1, &2, fun, options, fn owner, mfa ->
|
||||
args = [owner, :monitor, get_info(owner), mfa]
|
||||
{:ok, pid} = start_child_with_spec(supervisor_fun.(mfa), args, :temporary, shutdown)
|
||||
{:ok, pid} = start_child_with_spec(supervisor, args, :temporary, shutdown)
|
||||
if link_type == :link, do: Process.link(pid)
|
||||
{link_type, pid}
|
||||
end)
|
||||
|
||||
@@ -6,35 +6,15 @@ Erlang/OTP versioning is independent from the versioning of Elixir. Each version
|
||||
|
||||
Elixir version | Supported Erlang/OTP versions
|
||||
:------------- | :----------------------------
|
||||
v1.0.0 | 17
|
||||
v1.0.1 | 17
|
||||
v1.0.2 | 17
|
||||
v1.0.3 | 17
|
||||
v1.0.4 | 17
|
||||
v1.0.5 | 17-18
|
||||
v1.1.0 | 17-18
|
||||
v1.1.1 | 17-18
|
||||
v1.2.0 | 18
|
||||
v1.2.1 | 18
|
||||
v1.2.2 | 18
|
||||
v1.2.3 | 18
|
||||
v1.2.4 | 18
|
||||
v1.2.5 | 18
|
||||
v1.2.6 | 18-19
|
||||
v1.3.0 | 18-19
|
||||
v1.3.1 | 18-19
|
||||
v1.3.2 | 18-19
|
||||
v1.3.3 | 18-19
|
||||
v1.3.4 | 18-19
|
||||
v1.4.0 | 18-19
|
||||
v1.4.1 | 18-19
|
||||
v1.4.2 | 18-19
|
||||
v1.4.3 | 18-19
|
||||
v1.4.4 | 18-19
|
||||
v1.4.5 | 18-20
|
||||
v1.5.0 | 18-20
|
||||
v1.5.1 | 18-20
|
||||
v1.5.2 | 18-20
|
||||
1.0 | 17 - 17 (and OTP 18 from v1.0.5)
|
||||
1.1 | 17 - 18
|
||||
1.2 | 18 - 18 (and OTP 19 from v1.2.6)
|
||||
1.3 | 18 - 19
|
||||
1.4 | 18 - 19 (and OTP 20 from v1.4.5)
|
||||
1.5 | 18 - 20
|
||||
1.6 | 19 - 20
|
||||
|
||||
While Elixir often adds compatibility to new Erlang versions on released branches, such as support for OTP 20 in v1.4.5, those releases usually contain the minimum changes for Elixir to run without errors. Only the next minor release, in this case v1.5.0, does effectively leverage the new features provided by the latest Erlang release.
|
||||
|
||||
## Deprecations
|
||||
|
||||
@@ -112,4 +92,4 @@ Empty string in `String.starts_with?/2`, `String.ends_with?/2`, `String.contains
|
||||
[v1.3]: https://github.com/elixir-lang/elixir/blob/v1.3/CHANGELOG.md#4-deprecations
|
||||
[v1.4]: https://github.com/elixir-lang/elixir/blob/v1.4/CHANGELOG.md#4-deprecations
|
||||
[v1.5]: https://github.com/elixir-lang/elixir/blob/v1.5/CHANGELOG.md#4-deprecations
|
||||
[v1.6]: https://github.com/elixir-lang/elixir/blob/master/CHANGELOG.md#4-deprecations
|
||||
[v1.6]: https://github.com/elixir-lang/elixir/blob/v1.6/CHANGELOG.md#4-deprecations
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{application, elixir,
|
||||
[{description, "elixir"},
|
||||
{vsn, "1.5.2"},
|
||||
{vsn, "1.6.0-rc.0"},
|
||||
{modules, [
|
||||
elixir
|
||||
]},
|
||||
|
||||
@@ -22,19 +22,6 @@ defmodule Task.SupervisorTest do
|
||||
number
|
||||
end
|
||||
|
||||
def sleep_and_return_ancestor(number, :another_arg) do
|
||||
sleep_and_return_ancestor(number)
|
||||
end
|
||||
|
||||
def sleep_and_return_ancestor(number) do
|
||||
Process.sleep(number)
|
||||
{:dictionary, dictionary} = Process.info(self(), :dictionary)
|
||||
|
||||
dictionary
|
||||
|> Keyword.get(:"$ancestors")
|
||||
|> List.first()
|
||||
end
|
||||
|
||||
test "can be supervised directly", config do
|
||||
modules = [{Task.Supervisor, name: config.test}]
|
||||
assert {:ok, _} = Supervisor.start_link(modules, strategy: :one_for_one)
|
||||
@@ -319,80 +306,6 @@ defmodule Task.SupervisorTest do
|
||||
|
||||
refute_received _
|
||||
end
|
||||
|
||||
test "streams an enumerable with fun and supervisor fun", %{supervisor: supervisor} do
|
||||
{:ok, other_supervisor} = Task.Supervisor.start_link()
|
||||
|
||||
assert fn i -> if rem(i, 2) == 0, do: supervisor, else: other_supervisor end
|
||||
|> Task.Supervisor.async_stream(1..4, &sleep_and_return_ancestor/1, @opts)
|
||||
|> Enum.to_list() ==
|
||||
[ok: other_supervisor, ok: supervisor, ok: other_supervisor, ok: supervisor]
|
||||
end
|
||||
|
||||
test "streams an enumerable with mfa and supervisor fun", %{supervisor: supervisor} do
|
||||
{:ok, other_supervisor} = Task.Supervisor.start_link()
|
||||
fun = :sleep_and_return_ancestor
|
||||
|
||||
assert fn i -> if rem(i, 2) == 0, do: supervisor, else: other_supervisor end
|
||||
|> Task.Supervisor.async_stream(1..4, __MODULE__, fun, [], @opts)
|
||||
|> Enum.to_list() ==
|
||||
[ok: other_supervisor, ok: supervisor, ok: other_supervisor, ok: supervisor]
|
||||
end
|
||||
|
||||
test "streams an enumerable with mfa with args and supervisor fun", %{supervisor: supervisor} do
|
||||
{:ok, other_supervisor} = Task.Supervisor.start_link()
|
||||
fun = :sleep_and_return_ancestor
|
||||
|
||||
assert fn i -> if rem(i, 2) == 0, do: supervisor, else: other_supervisor end
|
||||
|> Task.Supervisor.async_stream(1..4, __MODULE__, fun, [:another_arg], @opts)
|
||||
|> Enum.to_list() ==
|
||||
[ok: other_supervisor, ok: supervisor, ok: other_supervisor, ok: supervisor]
|
||||
end
|
||||
|
||||
test "streams an enumerable with fun and executes supervisor fun in monitor process",
|
||||
context do
|
||||
%{supervisor: supervisor} = context
|
||||
parent = self()
|
||||
|
||||
supervisor_fun = fn _i ->
|
||||
{:links, links} = Process.info(self(), :links)
|
||||
assert parent in links
|
||||
send(parent, {parent, self()})
|
||||
supervisor
|
||||
end
|
||||
|
||||
assert supervisor_fun
|
||||
|> Task.Supervisor.async_stream(1..4, &sleep_and_return_ancestor/1, @opts)
|
||||
|> Enum.to_list() == [ok: supervisor, ok: supervisor, ok: supervisor, ok: supervisor]
|
||||
|
||||
receive do
|
||||
{^parent, linked} ->
|
||||
for _ <- 1..3, do: assert_received({^parent, ^linked})
|
||||
after
|
||||
0 ->
|
||||
flunk("Did not receive any message from monitor process.")
|
||||
end
|
||||
end
|
||||
|
||||
test "streams an enumerable with fun and bad supervisor fun" do
|
||||
Process.flag(:trap_exit, true)
|
||||
|
||||
stream =
|
||||
fn _i -> raise "bad" end
|
||||
|> Task.Supervisor.async_stream(1..4, &sleep_and_return_ancestor/1, @opts)
|
||||
|
||||
assert {{%RuntimeError{message: "bad"}, _stacktrace}, _mfa} = catch_exit(Stream.run(stream))
|
||||
|
||||
refute_received _
|
||||
|
||||
stream =
|
||||
fn _i -> :not_a_supervisor end
|
||||
|> Task.Supervisor.async_stream(1..4, &sleep_and_return_ancestor/1, @opts)
|
||||
|
||||
assert {{:noproc, _stacktrace}, _mfa} = catch_exit(Stream.run(stream))
|
||||
|
||||
refute_received _
|
||||
end
|
||||
end
|
||||
|
||||
describe "async_stream_nolink" do
|
||||
|
||||
Reference in New Issue
Block a user