Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e35ffc5a90 | ||
|
|
178643f9eb | ||
|
|
75677b9dab | ||
|
|
25ab648502 | ||
|
|
8493f1934a | ||
|
|
c63aeb9f77 | ||
|
|
d89fabe5e4 | ||
|
|
d51153b56e | ||
|
|
69990a5d1d | ||
|
|
930ec69739 | ||
|
|
d7478095e0 | ||
|
|
b823f9efdf | ||
|
|
6ecb430614 | ||
|
|
b615c8435a | ||
|
|
120467f83c | ||
|
|
4b09a836e0 | ||
|
|
55c05d943e | ||
|
|
8e61baacab | ||
|
|
7426acb1b9 |
+41
-13
@@ -162,17 +162,15 @@ Both encoder and decoder fully conform to [RFC 8259](https://tools.ietf.org/html
|
||||
|
||||
Encoding can be done via `JSON.encode!/1` and `JSON.encode_to_iodata!/1` functions. The default encoding rules are applied as follows:
|
||||
|
||||
| **Elixir** | **JSON** |
|
||||
|------------------------|----------|
|
||||
| `integer() \| float()` | Number |
|
||||
| `true \| false ` | Boolean |
|
||||
| `nil` | Null |
|
||||
| `binary()` | String |
|
||||
| `atom()` | String |
|
||||
| `list()` | Array |
|
||||
| `%{binary() => _}` | Object |
|
||||
| `%{atom() => _}` | Object |
|
||||
| `%{integer() => _}` | Object |
|
||||
| **Elixir** | **JSON** |
|
||||
|-----------------------------|----------|
|
||||
| `integer() \| float()` | Number |
|
||||
| `true \| false ` | Boolean |
|
||||
| `nil` | Null |
|
||||
| `binary()` | String |
|
||||
| `atom()` | String |
|
||||
| `list()` | Array |
|
||||
| `%{String.Chars.t() => _}` | Object |
|
||||
|
||||
You may also implement the `JSON.Encoder` protocol for custom data structures. Elixir already implements the protocol for all Calendar types.
|
||||
|
||||
@@ -225,7 +223,37 @@ You may also prefer to write using guards:
|
||||
|
||||
def foo(x, y, z) when x == y and y == z
|
||||
|
||||
## v1.18.2 (2024-01-22)
|
||||
## v1.18.3 (2025-03-06)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
#### Elixir
|
||||
|
||||
* [JSON] Encode any JSON key to string
|
||||
* [Kernel] Allow `<<_::3*8>>` in typespecs
|
||||
|
||||
#### Mix
|
||||
|
||||
* [mix loadpaths] Support `--no-listeners` option
|
||||
|
||||
### 2. Bug fixes
|
||||
|
||||
#### Elixir
|
||||
|
||||
* [CLI] Fix `--no-color` not setting `:ansi_enabled` to false
|
||||
* [Protocol] Return correct implementation for an invalid struct pointing to `nil`
|
||||
* [Stream] Do not raise when `Stream.cycle/1` is explicitly halted
|
||||
|
||||
#### ExUnit
|
||||
|
||||
* [ExUnit.Diff] Fix regression when diffing nested improper lists
|
||||
|
||||
#### IEx
|
||||
|
||||
* [IEx.Autocomplete] Fix autocomplete crash when expanding struct with `__MODULE__`
|
||||
* [IEx.Helpers] Do not purge on `recompile` if IEx is not running
|
||||
|
||||
## v1.18.2 (2025-01-22)
|
||||
|
||||
### 1. Enhancements
|
||||
|
||||
@@ -252,7 +280,7 @@ You may also prefer to write using guards:
|
||||
|
||||
#### IEx
|
||||
|
||||
* [IEx.Autocomplete] Fix crashing whhen autocompleting structs with runtime values
|
||||
* [IEx.Autocomplete] Fix crashing when autocompleting structs with runtime values
|
||||
|
||||
#### Mix
|
||||
|
||||
|
||||
+1
-1
@@ -2,7 +2,7 @@
|
||||
|
||||
## Shipping a new version
|
||||
|
||||
1. Update version in /VERSION, bin/elixir, bin/elixir.bat, and bin/elixir.ps1
|
||||
1. Update version in /VERSION, bin/elixir, and bin/elixir.bat
|
||||
|
||||
2. Ensure /CHANGELOG.md is updated, versioned and add the current date
|
||||
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
#!/bin/sh
|
||||
set -e
|
||||
|
||||
ELIXIR_VERSION=1.18.2
|
||||
ELIXIR_VERSION=1.18.3
|
||||
|
||||
if [ $# -eq 0 ] || { [ $# -eq 1 ] && { [ "$1" = "--help" ] || [ "$1" = "-h" ]; }; }; then
|
||||
cat <<USAGE >&2
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
@echo off
|
||||
|
||||
set ELIXIR_VERSION=1.18.2
|
||||
set ELIXIR_VERSION=1.18.3
|
||||
|
||||
if ""%1""=="""" if ""%2""=="""" goto documentation
|
||||
if /I ""%1""==""--help"" if ""%2""=="""" goto documentation
|
||||
|
||||
@@ -283,7 +283,6 @@ defmodule Code.Typespec do
|
||||
end
|
||||
|
||||
defp typespec_to_quoted({:type, anno, :binary, [arg1, arg2]}) do
|
||||
[arg1, arg2] = for arg <- [arg1, arg2], do: typespec_to_quoted(arg)
|
||||
line = meta(anno)[:line]
|
||||
|
||||
case {typespec_to_quoted(arg1), typespec_to_quoted(arg2)} do
|
||||
@@ -329,10 +328,14 @@ defmodule Code.Typespec do
|
||||
{erl_to_ex_var(var), meta(anno), nil}
|
||||
end
|
||||
|
||||
defp typespec_to_quoted({:op, anno, op, arg}) do
|
||||
defp typespec_to_quoted({:op, anno, op, arg}) when op in [:+, :-] do
|
||||
{op, meta(anno), [typespec_to_quoted(arg)]}
|
||||
end
|
||||
|
||||
defp typespec_to_quoted({:op, anno, :*, arg1, arg2}) do
|
||||
{:*, meta(anno), [typespec_to_quoted(arg1), typespec_to_quoted(arg2)]}
|
||||
end
|
||||
|
||||
defp typespec_to_quoted({:remote_type, anno, [mod, name, args]}) do
|
||||
remote_type(anno, mod, name, args)
|
||||
end
|
||||
|
||||
@@ -3837,6 +3837,9 @@ defmodule Enum do
|
||||
@doc """
|
||||
Enumerates the `enumerable`, removing all duplicate elements.
|
||||
|
||||
The first occurrence of each element is kept and all following
|
||||
duplicates are removed. The overall order is preserved.
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Enum.uniq([1, 2, 3, 3, 2, 1])
|
||||
@@ -3862,7 +3865,8 @@ defmodule Enum do
|
||||
considered duplicates if the return value of `fun` is equal for
|
||||
both of them.
|
||||
|
||||
The first occurrence of each element is kept.
|
||||
The first occurrence of each element is kept and all following
|
||||
duplicates are removed. The overall order is preserved.
|
||||
|
||||
## Example
|
||||
|
||||
|
||||
+33
-13
@@ -146,8 +146,30 @@ end
|
||||
|
||||
defimpl JSON.Encoder, for: Map do
|
||||
def encode(value, encoder) do
|
||||
:elixir_json.encode_map(value, encoder)
|
||||
case :maps.next(:maps.iterator(value)) do
|
||||
:none ->
|
||||
"{}"
|
||||
|
||||
{key, value, iterator} ->
|
||||
[?{, key(key, encoder), ?:, encoder.(value, encoder) | next(iterator, encoder)]
|
||||
end
|
||||
end
|
||||
|
||||
defp next(iterator, encoder) do
|
||||
case :maps.next(iterator) do
|
||||
:none ->
|
||||
"}"
|
||||
|
||||
{key, value, iterator} ->
|
||||
[?,, key(key, encoder), ?:, encoder.(value, encoder) | next(iterator, encoder)]
|
||||
end
|
||||
end
|
||||
|
||||
# Erlang supports only numbers, binaries, and atoms as keys,
|
||||
# we support anything that implements the String.Chars protocol.
|
||||
defp key(key, encoder) when is_atom(key), do: encoder.(Atom.to_string(key), encoder)
|
||||
defp key(key, encoder) when is_binary(key), do: encoder.(key, encoder)
|
||||
defp key(key, encoder), do: encoder.(String.Chars.to_string(key), encoder)
|
||||
end
|
||||
|
||||
defimpl JSON.Encoder, for: [Date, Time, NaiveDateTime, DateTime, Duration] do
|
||||
@@ -175,17 +197,15 @@ defmodule JSON do
|
||||
|
||||
Elixir built-in data structures are encoded to JSON as follows:
|
||||
|
||||
| **Elixir** | **JSON** |
|
||||
|------------------------|----------|
|
||||
| `integer() \| float()` | Number |
|
||||
| `true \| false ` | Boolean |
|
||||
| `nil` | Null |
|
||||
| `binary()` | String |
|
||||
| `atom()` | String |
|
||||
| `list()` | Array |
|
||||
| `%{binary() => _}` | Object |
|
||||
| `%{atom() => _}` | Object |
|
||||
| `%{integer() => _}` | Object |
|
||||
| **Elixir** | **JSON** |
|
||||
|----------------------------|----------|
|
||||
| `integer() \| float()` | Number |
|
||||
| `true \| false ` | Boolean |
|
||||
| `nil` | Null |
|
||||
| `binary()` | String |
|
||||
| `atom()` | String |
|
||||
| `list()` | Array |
|
||||
| `%{String.Chars.t() => _}` | Object |
|
||||
|
||||
You may also implement the `JSON.Encoder` protocol for custom data structures.
|
||||
|
||||
@@ -403,7 +423,7 @@ defmodule JSON do
|
||||
do: :elixir_json.encode_list(value, encoder)
|
||||
|
||||
def protocol_encode(%{} = value, encoder) when not is_map_key(value, :__struct__),
|
||||
do: :elixir_json.encode_map(value, encoder)
|
||||
do: JSON.Encoder.Map.encode(value, encoder)
|
||||
|
||||
def protocol_encode(value, encoder),
|
||||
do: JSON.Encoder.encode(value, encoder)
|
||||
|
||||
@@ -301,7 +301,7 @@ defmodule Kernel.CLI do
|
||||
end
|
||||
|
||||
defp parse_argv([~c"--no-color" | t], config) do
|
||||
Application.put_env(:elixir, :ansi_enabled, true)
|
||||
Application.put_env(:elixir, :ansi_enabled, false)
|
||||
parse_argv(t, config)
|
||||
end
|
||||
|
||||
|
||||
@@ -493,6 +493,24 @@ defmodule Kernel.Typespec do
|
||||
state}
|
||||
end
|
||||
|
||||
defp typespec(
|
||||
{:<<>>, meta, [{:"::", _, [{:_, _, ctx1}, {:*, prod_meta, [size, unit]}]}]},
|
||||
_,
|
||||
_,
|
||||
state
|
||||
)
|
||||
when is_atom(ctx1) and is_integer(size) and size >= 0 and unit in 1..256 do
|
||||
location = location(meta)
|
||||
prod_location = location(prod_meta)
|
||||
|
||||
{{:type, location, :binary,
|
||||
[
|
||||
{:op, prod_location, :*, {:integer, prod_location, size},
|
||||
{:integer, prod_location, unit}},
|
||||
{:integer, location, 0}
|
||||
]}, state}
|
||||
end
|
||||
|
||||
defp typespec({:<<>>, meta, [{:"::", size_meta, [{:_, _, ctx}, size]}]}, _, _, state)
|
||||
when is_atom(ctx) and is_integer(size) and size >= 0 do
|
||||
location = location(meta)
|
||||
|
||||
@@ -946,7 +946,8 @@ defmodule Module do
|
||||
@doc """
|
||||
Concatenates two aliases and returns a new alias.
|
||||
|
||||
It handles binaries and atoms.
|
||||
It handles binaries and atoms. If one of the aliases
|
||||
is nil, it is discarded.
|
||||
|
||||
## Examples
|
||||
|
||||
@@ -956,6 +957,9 @@ defmodule Module do
|
||||
iex> Module.concat(Foo, "Bar")
|
||||
Foo.Bar
|
||||
|
||||
iex> Module.concat(Foo, nil)
|
||||
Foo
|
||||
|
||||
"""
|
||||
@spec concat(binary | atom, binary | atom) :: atom
|
||||
def concat(left, right)
|
||||
|
||||
@@ -439,10 +439,16 @@ defmodule Module.ParallelChecker do
|
||||
|
||||
defp cache_chunk(table, module, exports) do
|
||||
Enum.each(exports, fn {{fun, arity}, info} ->
|
||||
# TODO: Match on signature directly in Elixir v1.22+
|
||||
sig =
|
||||
case info do
|
||||
%{sig: {:strong, _, _} = sig} -> sig
|
||||
%{sig: {:infer, _} = sig} -> sig
|
||||
_ -> :none
|
||||
end
|
||||
|
||||
:ets.insert(
|
||||
table,
|
||||
{{module, {fun, arity}}, Map.get(info, :deprecated), Map.get(info, :sig, :none)}
|
||||
{{module, {fun, arity}}, Map.get(info, :deprecated), sig}
|
||||
)
|
||||
end)
|
||||
|
||||
|
||||
@@ -219,6 +219,16 @@ defmodule Process do
|
||||
|
||||
Inlined by the compiler.
|
||||
|
||||
> #### Differences to `Kernel.exit/1` {: .info }
|
||||
>
|
||||
> The functions `Kernel.exit/1` and `Process.exit/2` are
|
||||
> named similarly but provide very different functionalities. The
|
||||
> `Kernel:exit/1` function should be used when the intent is to stop the current
|
||||
> process while `Process.exit/2` should be used when the intent is to send an
|
||||
> exit signal to another process. Note also that `Kernel.exit/1` can be caught
|
||||
> with `try/1` while `Process.exit/2` can only be handled by trapping exits and
|
||||
> when the signal is different than `:kill`.
|
||||
|
||||
## Examples
|
||||
|
||||
Process.exit(pid, :kill)
|
||||
|
||||
@@ -347,7 +347,7 @@ defmodule Protocol do
|
||||
end
|
||||
|
||||
defp assert_impl!(protocol, base, extra) do
|
||||
impl = Module.concat(protocol, base)
|
||||
impl = Protocol.__concat__(protocol, base)
|
||||
|
||||
try do
|
||||
Code.ensure_compiled!(impl)
|
||||
@@ -678,7 +678,7 @@ defmodule Protocol do
|
||||
end
|
||||
|
||||
defp load_impl(protocol, for) do
|
||||
Module.concat(protocol, for)
|
||||
Protocol.__concat__(protocol, for)
|
||||
end
|
||||
|
||||
# Finally compile the module and emit its bytecode.
|
||||
@@ -831,7 +831,7 @@ defmodule Protocol do
|
||||
# Define the implementation for built-ins
|
||||
:lists.foreach(
|
||||
fn {guard, mod} ->
|
||||
target = Module.concat(__MODULE__, mod)
|
||||
target = Protocol.__concat__(__MODULE__, mod)
|
||||
|
||||
Kernel.def impl_for(data) when :erlang.unquote(guard)(data) do
|
||||
case Code.ensure_compiled(unquote(target)) do
|
||||
@@ -875,7 +875,7 @@ defmodule Protocol do
|
||||
|
||||
# Internal handler for Structs
|
||||
Kernel.defp struct_impl_for(struct) do
|
||||
case Code.ensure_compiled(Module.concat(__MODULE__, struct)) do
|
||||
case Code.ensure_compiled(Protocol.__concat__(__MODULE__, struct)) do
|
||||
{:module, module} -> module
|
||||
{:error, _} -> unquote(any_impl_for)
|
||||
end
|
||||
@@ -948,7 +948,7 @@ defmodule Protocol do
|
||||
quote do
|
||||
protocol = unquote(protocol)
|
||||
for = unquote(for)
|
||||
name = Module.concat(protocol, for)
|
||||
name = Protocol.__concat__(protocol, for)
|
||||
|
||||
Protocol.assert_protocol!(protocol)
|
||||
Protocol.__ensure_defimpl__(protocol, for, __ENV__)
|
||||
@@ -994,7 +994,7 @@ defmodule Protocol do
|
||||
else
|
||||
# TODO: Deprecate this on Elixir v1.22+
|
||||
assert_impl!(protocol, Any, extra)
|
||||
{Module.concat(protocol, Any), [for, Macro.struct!(for, env), opts]}
|
||||
{Protocol.__concat__(protocol, Any), [for, Macro.struct!(for, env), opts]}
|
||||
end
|
||||
|
||||
# Clean up variables from eval context
|
||||
@@ -1006,7 +1006,7 @@ defmodule Protocol do
|
||||
else
|
||||
__ensure_defimpl__(protocol, for, env)
|
||||
assert_impl!(protocol, Any, extra)
|
||||
impl = Module.concat(protocol, Any)
|
||||
impl = Protocol.__concat__(protocol, Any)
|
||||
|
||||
funs =
|
||||
for {fun, arity} <- protocol.__protocol__(:functions) do
|
||||
@@ -1031,7 +1031,11 @@ defmodule Protocol do
|
||||
def __impl__(:for), do: unquote(for)
|
||||
end
|
||||
|
||||
Module.create(Module.concat(protocol, for), [quoted | funs], Macro.Env.location(env))
|
||||
Module.create(
|
||||
Protocol.__concat__(protocol, for),
|
||||
[quoted | funs],
|
||||
Macro.Env.location(env)
|
||||
)
|
||||
end
|
||||
end)
|
||||
end
|
||||
@@ -1070,4 +1074,17 @@ defmodule Protocol do
|
||||
is_reference: Reference
|
||||
]
|
||||
end
|
||||
|
||||
@doc false
|
||||
def __concat__(left, right) do
|
||||
String.to_atom(
|
||||
ensure_prefix(Atom.to_string(left)) <> "." <> remove_prefix(Atom.to_string(right))
|
||||
)
|
||||
end
|
||||
|
||||
defp ensure_prefix("Elixir." <> _ = left), do: left
|
||||
defp ensure_prefix(left), do: "Elixir." <> left
|
||||
|
||||
defp remove_prefix("Elixir." <> right), do: right
|
||||
defp remove_prefix(right), do: right
|
||||
end
|
||||
|
||||
@@ -209,17 +209,14 @@ defmodule Regex do
|
||||
|
||||
## Examples
|
||||
|
||||
iex> Regex.compile("foo")
|
||||
{:ok, ~r/foo/}
|
||||
Regex.compile("foo")
|
||||
#=> {:ok, ~r/foo/}
|
||||
|
||||
iex> Regex.compile("*foo")
|
||||
{:error, {~c"nothing to repeat", 0}}
|
||||
Regex.compile("foo", "i")
|
||||
#=>{:ok, ~r/foo/i}
|
||||
|
||||
iex> Regex.compile("foo", "i")
|
||||
{:ok, ~r/foo/i}
|
||||
|
||||
iex> Regex.compile("foo", [:caseless])
|
||||
{:ok, Regex.compile!("foo", [:caseless])}
|
||||
Regex.compile("*foo")
|
||||
#=> {:error, {~c"nothing to repeat", 0}}
|
||||
|
||||
"""
|
||||
@spec compile(binary, binary | [term]) :: {:ok, t} | {:error, term}
|
||||
|
||||
@@ -1444,7 +1444,7 @@ defmodule Stream do
|
||||
defp check_cycle_first_element(reduce) do
|
||||
fn acc ->
|
||||
case reduce.(acc) do
|
||||
{state, []} when state in [:done, :halted] ->
|
||||
{state, []} when state in [:done, :halted] and elem(acc, 0) != :halt ->
|
||||
raise ArgumentError, "cannot cycle over an empty enumerable"
|
||||
|
||||
other ->
|
||||
|
||||
@@ -488,6 +488,15 @@ defmodule String do
|
||||
iex> String.split(String.normalize("é", :nfc), "e")
|
||||
["é"]
|
||||
|
||||
When using both the `:trim` and the `:parts` option, the empty values
|
||||
are removed as the parts are computed (if any). No trimming happens
|
||||
after all parts are computed:
|
||||
|
||||
iex> String.split(" a b c ", " ", trim: true, parts: 2)
|
||||
["a", " b c "]
|
||||
iex> String.split(" a b c ", " ", trim: true, parts: 3)
|
||||
["a", "b", " c "]
|
||||
|
||||
"""
|
||||
@spec split(t, pattern | Regex.t(), keyword) :: [t]
|
||||
def split(string, pattern, options \\ [])
|
||||
|
||||
@@ -11,36 +11,40 @@ Keyword lists are a data-structure used to pass options to functions. Let's see
|
||||
Imagine you want to split a string of numbers. Initially, we can invoke `String.split/2` passing two strings as arguments:
|
||||
|
||||
```elixir
|
||||
iex> String.split("1 2 3", " ")
|
||||
["1", "2", "3"]
|
||||
iex> String.split("1 2 3 4", " ")
|
||||
["1", "2", "3", "4"]
|
||||
```
|
||||
|
||||
However, what happens if there is an additional space between the numbers:
|
||||
What if you only want to split at most 2 times? The `String.split/3` function allows the `parts` option to be set to the maximum number of entries in the result:
|
||||
|
||||
```elixir
|
||||
iex> String.split("1 2 3", " ")
|
||||
["1", "", "2", "", "3"]
|
||||
iex> String.split("1 2 3 4", " ", [parts: 3])
|
||||
["1", "2", "3 4"]
|
||||
```
|
||||
|
||||
As you can see, there are now empty strings in our results. Luckily, the `String.split/3` function allows the `trim` option to be set to true:
|
||||
As you can see, we got 3 parts, the last one containing the remaining of the input without splitting it.
|
||||
|
||||
Now imagine that some of the inputs you must split on contains additional spaces between the numbers:
|
||||
|
||||
```elixir
|
||||
iex> String.split("1 2 3", " ", [trim: true])
|
||||
["1", "2", "3"]
|
||||
iex> String.split("1 2 3 4", " ", [parts: 3])
|
||||
["1", "", "2 3 4"]
|
||||
```
|
||||
|
||||
We can also use options to limit the splitting algorithm to a maximum number of parts, as shown next:
|
||||
As you can see, the additional spaces lead to empty entries in the output. Luckily, we can also set the `trim` option to `true` to remove them:
|
||||
|
||||
```elixir
|
||||
iex> String.split("1 2 3", " ", [trim: true, parts: 2])
|
||||
["1", "2 3"]
|
||||
iex> String.split("1 2 3 4", " ", [parts: 3, trim: true])
|
||||
["1", "2", " 3 4"]
|
||||
```
|
||||
|
||||
`[trim: true]` and `[trim: true, parts: 2]` are keyword lists. When a keyword list is the last argument of a function, we can skip the brackets and write:
|
||||
Once again we got 3 parts, with the last one containing the leftovers.
|
||||
|
||||
`[parts: 3]` and `[parts: 3, trim: true]` are keyword lists. When a keyword list is the last argument of a function, we can skip the brackets and write:
|
||||
|
||||
```elixir
|
||||
iex> String.split("1 2 3", " ", trim: true, parts: 2)
|
||||
["1", "2 3"]
|
||||
iex> String.split("1 2 3 4", " ", parts: 3, trim: true)
|
||||
["1", "2", " 3 4"]
|
||||
```
|
||||
|
||||
As shown in the example above, keyword lists are mostly used as optional arguments to functions.
|
||||
@@ -48,7 +52,7 @@ As shown in the example above, keyword lists are mostly used as optional argumen
|
||||
As the name implies, keyword lists are simply lists. In particular, they are lists consisting of 2-item tuples where the first element (the key) is an atom and the second element can be any value. Both representations are the same:
|
||||
|
||||
```elixir
|
||||
iex> [{:trim, true}, {:parts, 2}] == [trim: true, parts: 2]
|
||||
iex> [{:parts, 3}, {:trim, true}] == [parts: 3, trim: true]
|
||||
true
|
||||
```
|
||||
|
||||
|
||||
@@ -191,12 +191,19 @@ canonical = System.fetch_env!("CANONICAL")
|
||||
before_closing_body_tag: fn
|
||||
:html ->
|
||||
"""
|
||||
<script defer src="https://cdn.jsdelivr.net/npm/mermaid@10.2.3/dist/mermaid.min.js"></script>
|
||||
<script>
|
||||
function mermaidLoaded() {
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
theme: document.body.className.includes("dark") ? "dark" : "default"
|
||||
});
|
||||
let initialized = false;
|
||||
|
||||
window.addEventListener("exdoc:loaded", () => {
|
||||
if (!initialized) {
|
||||
mermaid.initialize({
|
||||
startOnLoad: false,
|
||||
theme: document.body.className.includes("dark") ? "dark" : "default"
|
||||
});
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
let id = 0;
|
||||
for (const codeEl of document.querySelectorAll("pre code.mermaid")) {
|
||||
const preEl = codeEl.parentElement;
|
||||
@@ -210,9 +217,8 @@ canonical = System.fetch_env!("CANONICAL")
|
||||
preEl.remove();
|
||||
});
|
||||
}
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script async src="https://cdn.jsdelivr.net/npm/mermaid@10.2.3/dist/mermaid.min.js" onload="mermaidLoaded();"></script>
|
||||
"""
|
||||
|
||||
_ ->
|
||||
|
||||
@@ -165,7 +165,12 @@ dynamic_form(#{module := Module, relative_file := RelativeFile,
|
||||
{Def, Defmacro, Macros, Exports, Functions} =
|
||||
split_definition(Definitions, Unreachable, Line, [], [], [], [], {[], []}),
|
||||
|
||||
FilteredOpts = lists:filter(fun({no_warn_undefined, _}) -> false; (_) -> true end, Opts),
|
||||
FilteredOpts = lists:filter(fun(
|
||||
{no_warn_undefined, _}) -> false;
|
||||
(debug_info) -> false;
|
||||
(_) -> true
|
||||
end, Opts),
|
||||
|
||||
Location = {elixir_utils:characters_to_list(RelativeFile), Line},
|
||||
|
||||
Prefix = [{attribute, Line, file, Location},
|
||||
|
||||
@@ -1517,6 +1517,18 @@ defmodule EnumTest do
|
||||
assert Enum.zip([], []) == []
|
||||
end
|
||||
|
||||
test "zip/2 with infinite streams" do
|
||||
assert Enum.zip([], Stream.cycle([1, 2])) == []
|
||||
assert Enum.zip([], Stream.cycle(1..2)) == []
|
||||
assert Enum.zip(.., Stream.cycle([1, 2])) == []
|
||||
assert Enum.zip(.., Stream.cycle(1..2)) == []
|
||||
|
||||
assert Enum.zip(Stream.cycle([1, 2]), ..) == []
|
||||
assert Enum.zip(Stream.cycle(1..2), ..) == []
|
||||
assert Enum.zip(Stream.cycle([1, 2]), ..) == []
|
||||
assert Enum.zip(Stream.cycle(1..2), ..) == []
|
||||
end
|
||||
|
||||
test "zip/1" do
|
||||
assert Enum.zip([[:a, :b], [1, 2], ["foo", "bar"]]) == [{:a, 1, "foo"}, {:b, 2, "bar"}]
|
||||
|
||||
|
||||
@@ -1,29 +0,0 @@
|
||||
defmodule Dialyzer.ProtocolOpaque do
|
||||
def circus() do
|
||||
duck = Dialyzer.ProtocolOpaque.Duck.new()
|
||||
Dialyzer.ProtocolOpaque.Entity.speak(duck)
|
||||
end
|
||||
end
|
||||
|
||||
defprotocol Dialyzer.ProtocolOpaque.Entity do
|
||||
@fallback_to_any true
|
||||
def speak(entity)
|
||||
end
|
||||
|
||||
defmodule Dialyzer.ProtocolOpaque.Duck do
|
||||
@opaque t :: %__MODULE__{feathers: :white_and_grey}
|
||||
defstruct feathers: :white_and_grey
|
||||
|
||||
@spec new :: t
|
||||
def new(), do: %__MODULE__{}
|
||||
|
||||
defimpl Dialyzer.ProtocolOpaque.Entity do
|
||||
def speak(%Dialyzer.ProtocolOpaque.Duck{}), do: "Quack!"
|
||||
end
|
||||
end
|
||||
|
||||
defimpl Dialyzer.ProtocolOpaque.Entity, for: Any do
|
||||
def speak(_any) do
|
||||
"I can be anything"
|
||||
end
|
||||
end
|
||||
@@ -33,8 +33,8 @@ defmodule JSONTest do
|
||||
end
|
||||
|
||||
test "maps" do
|
||||
assert JSON.encode!(%{1 => 2, 3.0 => 4.0, key: :bar}) ==
|
||||
"{\"1\":2,\"3.0\":4.0,\"key\":\"bar\"}"
|
||||
assert JSON.encode!(%{1 => 2, 3.0 => 4.0, ~c"list" => ~c"list", key: :bar}) ==
|
||||
"{\"1\":2,\"3.0\":4.0,\"key\":\"bar\",\"list\":[108,105,115,116]}"
|
||||
end
|
||||
|
||||
test "lists" do
|
||||
@@ -80,8 +80,8 @@ defmodule JSONTest do
|
||||
end
|
||||
|
||||
test "maps" do
|
||||
assert protocol_encode(%{1 => 2, 3.0 => 4.0, key: :bar}) ==
|
||||
"{\"1\":2,\"3.0\":4.0,\"key\":\"bar\"}"
|
||||
assert protocol_encode(%{1 => 2, 3.0 => 4.0, ~c"list" => ~c"list", key: :bar}) ==
|
||||
"{\"1\":2,\"3.0\":4.0,\"key\":\"bar\",\"list\":[108,105,115,116]}"
|
||||
end
|
||||
|
||||
test "lists" do
|
||||
|
||||
@@ -119,23 +119,6 @@ defmodule Kernel.DialyzerTest do
|
||||
assert_dialyze_no_warnings!(context)
|
||||
end
|
||||
|
||||
@tag warnings: [:specdiffs]
|
||||
test "no warnings on protocol calls with opaque types", context do
|
||||
alias Dialyzer.ProtocolOpaque
|
||||
|
||||
copy_beam!(context, ProtocolOpaque)
|
||||
copy_beam!(context, ProtocolOpaque.Entity)
|
||||
copy_beam!(context, ProtocolOpaque.Entity.Any)
|
||||
copy_beam!(context, ProtocolOpaque.Duck)
|
||||
assert_dialyze_no_warnings!(context)
|
||||
|
||||
# Also ensure no warnings after consolidation.
|
||||
Code.prepend_path(context.base_dir)
|
||||
{:ok, binary} = Protocol.consolidate(ProtocolOpaque.Entity, [ProtocolOpaque.Duck, Any])
|
||||
File.write!(Path.join(context.outdir, "#{ProtocolOpaque.Entity}.beam"), binary)
|
||||
assert_dialyze_no_warnings!(context)
|
||||
end
|
||||
|
||||
test "no warnings on and/2 and or/2", context do
|
||||
copy_beam!(context, Dialyzer.BooleanCheck)
|
||||
assert_dialyze_no_warnings!(context)
|
||||
|
||||
@@ -428,10 +428,9 @@ end
|
||||
defmodule OptionsParserDeprecationsTest do
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
@warning ~r[not passing the :switches or :strict option to OptionParser is deprecated]
|
||||
|
||||
def assert_deprecated(fun) do
|
||||
assert ExUnit.CaptureIO.capture_io(:stderr, fun) =~ @warning
|
||||
assert ExUnit.CaptureIO.capture_io(:stderr, fun) =~
|
||||
"not passing the :switches or :strict option to OptionParser is deprecated"
|
||||
end
|
||||
|
||||
test "parses boolean option" do
|
||||
|
||||
@@ -106,15 +106,18 @@ defmodule ProtocolTest do
|
||||
assert Sample.impl_for(%ImplStruct{}) == Sample.ProtocolTest.ImplStruct
|
||||
assert Sample.impl_for(%ImplStructExplicitFor{}) == Sample.ProtocolTest.ImplStructExplicitFor
|
||||
assert Sample.impl_for(%NoImplStruct{}) == nil
|
||||
assert is_nil(Sample.impl_for(%{__struct__: nil}))
|
||||
end
|
||||
|
||||
test "protocol implementation with Any and struct fallbacks" do
|
||||
assert WithAny.impl_for(%NoImplStruct{}) == WithAny.Any
|
||||
# Derived
|
||||
assert WithAny.impl_for(%ImplStruct{}) == ProtocolTest.WithAny.ProtocolTest.ImplStruct
|
||||
assert WithAny.impl_for(%{__struct__: nil}) == WithAny.Any
|
||||
assert WithAny.impl_for(%{__struct__: "foo"}) == WithAny.Map
|
||||
assert WithAny.impl_for(%{}) == WithAny.Map
|
||||
assert WithAny.impl_for(self()) == WithAny.Any
|
||||
|
||||
# Derived
|
||||
assert WithAny.impl_for(%ImplStruct{}) == ProtocolTest.WithAny.ProtocolTest.ImplStruct
|
||||
end
|
||||
|
||||
test "protocol not implemented" do
|
||||
|
||||
@@ -3,39 +3,6 @@ Code.require_file("test_helper.exs", __DIR__)
|
||||
defmodule RegexTest do
|
||||
use ExUnit.Case, async: true
|
||||
|
||||
@re_21_3_little %Regex{
|
||||
re_pattern:
|
||||
{:re_pattern, 1, 0, 0,
|
||||
<<69, 82, 67, 80, 94, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 99, 0, 0, 0, 0, 0, 1, 0, 0, 0, 64, 0, 6, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 102, 111, 111, 0, 131, 0, 20, 29, 99, 133,
|
||||
0, 7, 0, 1, 29, 100, 119, 0, 5, 29, 101, 120, 0, 12, 120, 0, 20, 0>>},
|
||||
re_version: {"8.42 2018-03-20", :little},
|
||||
source: "c(?<foo>d|e)"
|
||||
}
|
||||
|
||||
@re_21_3_big %Regex{
|
||||
re_pattern:
|
||||
{:re_pattern, 1, 0, 0,
|
||||
<<80, 67, 82, 69, 0, 0, 0, 86, 0, 0, 0, 0, 0, 0, 0, 17, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 0, 99, 0, 0, 0, 0, 0, 1, 0, 0, 0, 56, 0, 6, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 1, 102, 111, 111, 0, 131, 0, 20, 29, 99, 133, 0, 7, 0, 1, 29, 100, 119,
|
||||
0, 5, 29, 101, 120, 0, 12, 120, 0, 20, 0>>},
|
||||
re_version: {"8.42 2018-03-20", :big},
|
||||
source: "c(?<foo>d|e)"
|
||||
}
|
||||
|
||||
@re_19_3_little %Regex{
|
||||
re_pattern:
|
||||
{:re_pattern, 1, 0, 0,
|
||||
<<69, 82, 67, 80, 94, 0, 0, 0, 0, 0, 0, 0, 17, 0, 0, 0, 255, 255, 255, 255, 255, 255, 255,
|
||||
255, 99, 0, 0, 0, 0, 0, 1, 0, 0, 0, 64, 0, 6, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 102, 111, 111, 0, 125, 0, 20, 29, 99, 127,
|
||||
0, 7, 0, 1, 29, 100, 113, 0, 5, 29, 101, 114, 0, 12, 114, 0, 20, 0>>},
|
||||
re_version: {"8.33 2013-05-29", :little},
|
||||
source: "c(?<foo>d|e)"
|
||||
}
|
||||
|
||||
doctest Regex
|
||||
|
||||
test "multiline" do
|
||||
@@ -68,16 +35,9 @@ defmodule RegexTest do
|
||||
test "literal source" do
|
||||
assert Regex.source(Regex.compile!("foo")) == "foo"
|
||||
assert Regex.source(~r"foo") == "foo"
|
||||
assert Regex.re_pattern(Regex.compile!("foo")) == Regex.re_pattern(~r"foo")
|
||||
|
||||
assert Regex.source(Regex.compile!("\a\b\d\e\f\n\r\s\t\v")) == "\a\b\d\e\f\n\r\s\t\v"
|
||||
assert Regex.source(~r<\a\b\d\e\f\n\r\s\t\v>) == "\\a\\b\\d\\e\\f\\n\\r\\s\\t\\v"
|
||||
|
||||
assert Regex.re_pattern(Regex.compile!("\a\b\d\e\f\n\r\s\t\v")) ==
|
||||
Regex.re_pattern(~r"\x07\x08\x7F\x1B\x0C\x0A\x0D\x20\x09\x0B")
|
||||
|
||||
assert Regex.re_pattern(Regex.compile!("\\a\\b\\d\e\f\\n\\r\\s\\t\\v")) ==
|
||||
Regex.re_pattern(~r"\a\b\d\e\f\n\r\s\t\v")
|
||||
end
|
||||
|
||||
test "Unicode" do
|
||||
@@ -116,16 +76,6 @@ defmodule RegexTest do
|
||||
end
|
||||
end
|
||||
|
||||
test "recompile/1" do
|
||||
new_regex = ~r/foo/
|
||||
{:ok, %Regex{}} = Regex.recompile(new_regex)
|
||||
assert %Regex{} = Regex.recompile!(new_regex)
|
||||
|
||||
old_regex = Map.delete(~r/foo/, :re_version)
|
||||
{:ok, %Regex{}} = Regex.recompile(old_regex)
|
||||
assert %Regex{} = Regex.recompile!(old_regex)
|
||||
end
|
||||
|
||||
test "opts/1" do
|
||||
assert Regex.opts(Regex.compile!("foo", "i")) == [:caseless]
|
||||
assert Regex.opts(Regex.compile!("foo", [:ucp])) == [:ucp]
|
||||
@@ -179,16 +129,6 @@ defmodule RegexTest do
|
||||
assert Regex.run(~r"bar", "foobar", offset: 2, return: :index) == [{3, 3}]
|
||||
end
|
||||
|
||||
test "run/3 with regexes compiled in different systems" do
|
||||
assert Regex.run(@re_21_3_little, "abcd abce", capture: :all_names) == ["d"]
|
||||
assert Regex.run(@re_21_3_big, "abcd abce", capture: :all_names) == ["d"]
|
||||
assert Regex.run(@re_19_3_little, "abcd abce", capture: :all_names) == ["d"]
|
||||
end
|
||||
|
||||
test "run/3 with regexes with options compiled in different systems" do
|
||||
assert Regex.run(%{~r/foo/i | re_version: "bad version"}, "FOO") == ["FOO"]
|
||||
end
|
||||
|
||||
test "scan/2" do
|
||||
assert Regex.scan(~r"c(d|e)", "abcd abce") == [["cd", "d"], ["ce", "e"]]
|
||||
assert Regex.scan(~r"c(?:d|e)", "abcd abce") == [["cd"], ["ce"]]
|
||||
@@ -207,16 +147,6 @@ defmodule RegexTest do
|
||||
assert Regex.scan(~r"^foo", "foobar", offset: 1) == []
|
||||
end
|
||||
|
||||
test "scan/2 with regexes compiled in different systems" do
|
||||
assert Regex.scan(@re_21_3_little, "abcd abce", capture: :all_names) == [["d"], ["e"]]
|
||||
assert Regex.scan(@re_21_3_big, "abcd abce", capture: :all_names) == [["d"], ["e"]]
|
||||
assert Regex.scan(@re_19_3_little, "abcd abce", capture: :all_names) == [["d"], ["e"]]
|
||||
end
|
||||
|
||||
test "scan/2 with regexes with options compiled in different systems" do
|
||||
assert Regex.scan(%{~r/foo/i | re_version: "bad version"}, "FOO") == [["FOO"]]
|
||||
end
|
||||
|
||||
test "split/2,3" do
|
||||
assert Regex.split(~r",", "") == [""]
|
||||
assert Regex.split(~r",", "", trim: true) == []
|
||||
|
||||
@@ -393,6 +393,7 @@ defmodule TypespecTest do
|
||||
@type size :: <<_::3>>
|
||||
@type unit :: <<_::_*8>>
|
||||
@type size_and_unit :: <<_::3, _::_*8>>
|
||||
@type size_prod_unit :: <<_::3*8>>
|
||||
end
|
||||
|
||||
assert [
|
||||
@@ -401,17 +402,15 @@ defmodule TypespecTest do
|
||||
type: {:size, {:type, _, :binary, [{:integer, _, 3}, {:integer, _, 0}]}, []},
|
||||
type:
|
||||
{:size_and_unit, {:type, _, :binary, [{:integer, _, 3}, {:integer, _, 8}]}, []},
|
||||
type:
|
||||
{:size_prod_unit,
|
||||
{:type, _, :binary,
|
||||
[{:op, _, :*, {:integer, _, 3}, {:integer, _, 8}}, {:integer, _, 0}]}, []},
|
||||
type: {:unit, {:type, _, :binary, [{:integer, _, 0}, {:integer, _, 8}]}, []}
|
||||
] = types(bytecode)
|
||||
end
|
||||
|
||||
test "@type with invalid binary spec" do
|
||||
assert_raise Kernel.TypespecError, ~r"invalid binary specification", fn ->
|
||||
test_module do
|
||||
@type my_type :: <<_::3*8>>
|
||||
end
|
||||
end
|
||||
|
||||
assert_raise Kernel.TypespecError, ~r"invalid binary specification", fn ->
|
||||
test_module do
|
||||
@type my_type :: <<_::atom()>>
|
||||
@@ -1217,6 +1216,7 @@ defmodule TypespecTest do
|
||||
quote(do: @type(binary_type1() :: <<_::_*8>>)),
|
||||
quote(do: @type(binary_type2() :: <<_::3>>)),
|
||||
quote(do: @type(binary_type3() :: <<_::3, _::_*8>>)),
|
||||
quote(do: @type(binary_type4() :: <<_::3*8>>)),
|
||||
quote(do: @type(tuple_type() :: {integer()})),
|
||||
quote(do: @type(ftype() :: (-> any()) | (-> integer()) | (integer() -> integer()))),
|
||||
quote(do: @type(cl() :: charlist())),
|
||||
|
||||
@@ -1156,6 +1156,7 @@ defmodule ExUnit.Diff do
|
||||
else
|
||||
other
|
||||
|> Map.to_list()
|
||||
|> Enum.map(&escape_pair/1)
|
||||
|> build_map_or_struct(struct)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -707,7 +707,7 @@ defmodule ExUnit.AssertionsTest do
|
||||
rescue
|
||||
error in [ExUnit.AssertionError] ->
|
||||
"foo" = error.left
|
||||
~r{a} = error.right
|
||||
%Regex{} = error.right
|
||||
end
|
||||
end
|
||||
|
||||
@@ -722,7 +722,7 @@ defmodule ExUnit.AssertionsTest do
|
||||
rescue
|
||||
error in [ExUnit.AssertionError] ->
|
||||
"foo" = error.left
|
||||
~r"o" = error.right
|
||||
%Regex{} = error.right
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -330,6 +330,8 @@ defmodule ExUnit.DiffTest do
|
||||
"[[[[], \"Hello-,- \"] | \"world\"] | \"!\"]",
|
||||
"[[[[], \"Hello \"] | \"world\"] | \"!\"]"
|
||||
)
|
||||
|
||||
refute_diff(:foo = %{bar: [:a | :b]}, "", "")
|
||||
end
|
||||
|
||||
test "proper lists" do
|
||||
|
||||
@@ -503,6 +503,17 @@ defmodule ExUnit.FormatterTest do
|
||||
"""
|
||||
end
|
||||
|
||||
test "formats assertions with nested improper list diffing" do
|
||||
failure = [{:error, catch_assertion(assert :foo = %{bar: [1 | 2]}), []}]
|
||||
|
||||
assert format_test_all_failure(test_module(), failure, 1, :infinity, &diff_formatter/2) =~ """
|
||||
match (=) failed
|
||||
code: assert :foo = %{bar: [1 | 2]}
|
||||
left: :foo
|
||||
right: %{bar: [1 | 2]}
|
||||
"""
|
||||
end
|
||||
|
||||
defmodule BadInspect do
|
||||
defstruct key: 0
|
||||
|
||||
|
||||
@@ -378,7 +378,8 @@ defmodule IEx.Autocomplete do
|
||||
case Code.Fragment.container_cursor_to_quoted(code) do
|
||||
{:ok, quoted} ->
|
||||
case Macro.path(quoted, &match?({:__cursor__, _, []}, &1)) do
|
||||
[cursor, {:%{}, _, pairs}, {:%, _, [{:__aliases__, _, aliases}, _map]} | _] ->
|
||||
[cursor, {:%{}, _, pairs}, {:%, _, [{:__aliases__, _, aliases = [h | _]}, _map]} | _]
|
||||
when is_atom(h) ->
|
||||
container_context_struct(cursor, pairs, aliases, shell)
|
||||
|
||||
[
|
||||
@@ -386,8 +387,9 @@ defmodule IEx.Autocomplete do
|
||||
pairs,
|
||||
{:|, _, _},
|
||||
{:%{}, _, _},
|
||||
{:%, _, [{:__aliases__, _, aliases}, _map]} | _
|
||||
] ->
|
||||
{:%, _, [{:__aliases__, _, aliases = [h | _]}, _map]} | _
|
||||
]
|
||||
when is_atom(h) ->
|
||||
container_context_struct(cursor, pairs, aliases, shell)
|
||||
|
||||
[cursor, pairs, {:|, _, [{variable, _, nil} | _]}, {:%{}, _, _} | _] ->
|
||||
|
||||
@@ -12,10 +12,18 @@ defmodule IEx.MixListener do
|
||||
|
||||
@doc """
|
||||
Unloads all modules invalidated by external compilations.
|
||||
|
||||
Returns `:noop` if there is no module to purge or if
|
||||
the listener is not running (it may happen when connecting
|
||||
via --remsh to a node that was started without IEx).
|
||||
"""
|
||||
@spec purge :: :ok | :noop
|
||||
def purge do
|
||||
GenServer.call(@name, :purge, :infinity)
|
||||
if Process.whereis(@name) do
|
||||
GenServer.call(@name, :purge, :infinity)
|
||||
else
|
||||
:noop
|
||||
end
|
||||
end
|
||||
|
||||
@impl true
|
||||
|
||||
@@ -416,6 +416,9 @@ defmodule IEx.AutocompleteTest do
|
||||
assert {:yes, ~c"ry: ", []} = expand(~c"%URI{path: \"foo\", que")
|
||||
assert {:no, [], []} = expand(~c"%URI{path: \"foo\", unkno")
|
||||
assert {:no, [], []} = expand(~c"%Unknown{path: \"foo\", unkno")
|
||||
|
||||
assert {:yes, [], _} = expand(~c"%__MODULE__{")
|
||||
assert {:yes, [], _} = expand(~c"%__MODULE__.Some{")
|
||||
end
|
||||
|
||||
test "completion for struct keys in update syntax" do
|
||||
|
||||
@@ -349,7 +349,7 @@ defmodule IEx.HelpersTest do
|
||||
assert captured =~ "-spec sleep(Time) -> ok when Time :: timeout()."
|
||||
else
|
||||
assert captured =~ "sleep(Time)"
|
||||
assert captured =~ "@spec sleep(time) :: :ok when time: timeout()"
|
||||
assert captured =~ "@spec sleep(time) :: :ok when time: "
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -63,7 +63,7 @@ defmodule Mix.Tasks.Cmd do
|
||||
|> Enum.map(&String.to_atom/1)
|
||||
|
||||
if apps != [] do
|
||||
IO.warn("the --app in mix cmd is deprecated")
|
||||
IO.warn("the --app in mix cmd is deprecated. Use mix do --app instead.")
|
||||
end
|
||||
|
||||
if apps == [] or Mix.Project.config()[:app] in apps do
|
||||
|
||||
@@ -23,6 +23,7 @@ defmodule Mix.Tasks.Deps.Loadpaths do
|
||||
* `--no-compile` - does not compile even if files require compilation
|
||||
* `--no-deps-check` - does not check or compile deps, only load available ones
|
||||
* `--no-elixir-version-check` - does not check Elixir version
|
||||
* `--no-listeners` - does not start Mix listeners
|
||||
* `--no-optional-deps` - does not compile or load optional deps
|
||||
|
||||
"""
|
||||
@@ -71,7 +72,9 @@ defmodule Mix.Tasks.Deps.Loadpaths do
|
||||
|
||||
# For now we only allow listeners defined in dependencies, so
|
||||
# we start them right after adding adding deps to the path
|
||||
Mix.PubSub.start_listeners()
|
||||
if "--no-listeners" not in args do
|
||||
Mix.PubSub.start_listeners()
|
||||
end
|
||||
|
||||
:ok
|
||||
end
|
||||
|
||||
@@ -21,6 +21,7 @@ defmodule Mix.Tasks.Loadpaths do
|
||||
* `--no-compile` - does not compile dependencies, only check and load them
|
||||
* `--no-deps-check` - does not check dependencies, only load available ones
|
||||
* `--no-elixir-version-check` - does not check Elixir version
|
||||
* `--no-listeners` - does not start Mix listeners
|
||||
* `--no-optional-deps` - does not compile or load optional deps
|
||||
|
||||
"""
|
||||
|
||||
@@ -389,6 +389,10 @@ defmodule Mix.Tasks.CompileTest do
|
||||
File.write!("src/b.erl", "-module(b).")
|
||||
File.write!("src/c.erl", "-module(c).")
|
||||
|
||||
# Ensure we can boot with compilation and listeners if desired
|
||||
assert mix(["loadpaths", "--no-compile", "--no-listeners"]) == ""
|
||||
|
||||
# Now setup dependencies
|
||||
mix(["deps.compile"])
|
||||
|
||||
parent = self()
|
||||
|
||||
Reference in New Issue
Block a user