Compare commits

...
18 Commits
Author SHA1 Message Date
José Valim 524528b973 Add branch docs publishing 2023-05-30 11:23:49 +02:00
jendis a64d42f5d3 Fix elixir test assertion for erlang >=OTP-24.1 (#11309) 2021-10-13 23:48:14 +02:00
Tobias Pfeiffer 7636046bd9 Add missing --warnings-as-errors on mix test to Changelog (#11303)
Sources:
* https://dashbit.co/blog/tests-with-warnings-as-errors
* https://hexdocs.pm/mix/master/Mix.Tasks.Test.html
2021-10-08 13:30:42 +02:00
Justin Morrow 552b5abed8 docs(code.ex): fix ensure_loaded typos in Code docs (#11253)
Fixes two documentation typos in the code.ex `@moduledoc`
`ensure_lodead!` => `ensure_loaded!`
`ensure_lodead?` => `ensure_loaded?`
2021-09-17 08:50:38 +02:00
José Valim 74bfab8ee2 Release v1.12.3 2021-09-05 10:02:59 +02:00
José Valim e00cbe16cd Revert content tracking instead of mtime. 2021-08-24 08:31:52 +02:00
Marc-André Lafortune 9df7a548ed Make sure .beam files still exist for restored files (#11187) 2021-08-18 07:51:50 +02:00
José Valim 9137fd1cb2 Do not return context tuples on optimized eval 2021-07-22 08:10:38 +02:00
José Valim 5189b292ac Purge v8 manifests properly 2021-07-16 21:37:57 +02:00
Marc-André Lafortune 74f9a299ea Rely on modification time and hash to determine modified sources (#11080) 2021-07-16 21:37:57 +02:00
José Valim 2ce9d25552 Do not error autocompletion with module attribute, closes #11120 2021-07-16 19:21:36 +02:00
José Valim b558142819 Rename exit_code to exit_status for consistency 2021-07-15 20:52:20 +02:00
Łukasz Samson d7f96d8332 Keep backwards compatibility on Range and Date.Range (#11117) 2021-07-14 13:32:03 +02:00
José Valim 010efd8ec6 Fix regex 2021-07-13 11:29:26 +02:00
José Valim c0174044bc Fix regex 2021-07-13 11:12:08 +02:00
José Valim 616e0d8ccc Do not crash when handling ambiguity errors, closes #11111 2021-07-13 10:36:14 +02:00
José Valim 13ba96be3c Keep backwards compatibility on range usage, closes #11110 2021-07-12 12:32:22 +02:00
José Valim edb5e7e052 Document backwards incompatible change, closes #11105 2021-07-06 15:01:41 +02:00
28 changed files with 502 additions and 75 deletions
+87
View File
@@ -0,0 +1,87 @@
name: builds.hex.pm
on:
push:
branches:
- main
- v*.*
tags:
- v*
env:
ELIXIR_OPTS: "--warnings-as-errors"
ERLC_OPTS: "warnings_as_errors"
LANG: C.UTF-8
concurrency: builds_txt
jobs:
release_pre_built:
strategy:
fail-fast: true
max-parallel: 1
matrix:
include:
- otp: 23
otp_version: '23.3'
build_docs: build_docs
runs-on: ubuntu-20.04
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 50
- name: Get tags
run: git fetch --tags origin
- uses: ./.github/workflows/release_pre_built
with:
otp_version: ${{ matrix.otp_version }}
otp: ${{ matrix.otp }}
build_docs: ${{ matrix.build_docs }}
- name: Utils.sh
run: |
cat << 'EOF' > utils.sh
function purge_key() {
curl \
-X POST \
-H "Fastly-Key: ${FASTLY_KEY}" \
-H "Accept: application/json" \
-H "Content-Length: 0" \
"https://api.fastly.com/service/$1/purge/$2"
}
function purge() {
purge_key ${FASTLY_REPO_SERVICE_ID} $1
purge_key ${FASTLY_BUILDS_SERVICE_ID} $1
sleep 2
purge_key ${FASTLY_REPO_SERVICE_ID} $1
purge_key ${FASTLY_BUILDS_SERVICE_ID} $1
sleep 2
purge_key ${FASTLY_REPO_SERVICE_ID} $1
purge_key ${FASTLY_BUILDS_SERVICE_ID} $1
}
EOF
chmod +x utils.sh
- name: Upload Docs to S3
if: ${{ matrix.build_docs }}
env:
AWS_ACCESS_KEY_ID: ${{ secrets.HEX_AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.HEX_AWS_SECRET_ACCESS_KEY }}
AWS_REGION: ${{ secrets.HEX_AWS_REGION }}
AWS_S3_BUCKET: ${{ secrets.HEX_AWS_S3_BUCKET }}
FASTLY_REPO_SERVICE_ID: ${{ secrets.HEX_FASTLY_REPO_SERVICE_ID }}
FASTLY_BUILDS_SERVICE_ID: ${{ secrets.HEX_FASTLY_BUILDS_SERVICE_ID }}
FASTLY_KEY: ${{ secrets.HEX_FASTLY_KEY }}
run: |
source utils.sh
version=$(echo ${{ github.ref_name }} | sed -e 's/^v//g')
for f in doc/*; do
if [ -d "$f" ]; then
app=`echo $f | sed s/"doc\/"//`
tarball="${app}-${version}.tar.gz"
surrogate_key="docs/${app}-${version}"
tar -czf "${tarball}" -C "doc/${app}" .
aws s3 cp "${tarball}" "s3://${{ env.AWS_S3_BUCKET }}/docs/${tarball}" \
--cache-control "public,max-age=3600" \
--metadata "{\"surrogate-key\":\"${surrogate_key}\",\"surrogate-control\":\"public,max-age=604800\"}"
purge "${surrogate_key}"
fi
done
@@ -0,0 +1,51 @@
name: "Release pre built"
description: "Builds elixir release, ExDoc and generates docs"
inputs:
otp:
description: "The major OTP version"
otp_version:
description: "The exact OTP version (major.minor[.patch])"
build_docs:
description: "If docs have to be built or not"
runs:
using: "composite"
steps:
- uses: erlef/setup-beam@v1
with:
otp-version: ${{ inputs.otp_version }}
version-type: strict
- name: Build Elixir Release
shell: bash
run: |
make Precompiled.zip
mv Precompiled.zip elixir-otp-${{ inputs.otp }}.zip
shasum -a 1 elixir-otp-${{ inputs.otp }}.zip > elixir-otp-${{ inputs.otp }}.zip.sha1sum
shasum -a 256 elixir-otp-${{ inputs.otp }}.zip > elixir-otp-${{ inputs.otp }}.zip.sha256sum
echo "$PWD/bin" >> $GITHUB_PATH
- name: Get latest stable ExDoc version
if: ${{ inputs.build_docs }}
shell: bash
run: |
EX_DOC_LATEST_STABLE_VERSION=$(curl -s https://hex.pm/api/packages/ex_doc | jq --raw-output '.latest_stable_version')
echo "EX_DOC_LATEST_STABLE_VERSION=${EX_DOC_LATEST_STABLE_VERSION}" >> $GITHUB_ENV
- uses: actions/checkout@v3
if: ${{ inputs.build_docs }}
with:
repository: elixir-lang/ex_doc
ref: v${{ env.EX_DOC_LATEST_STABLE_VERSION }}
path: ex_doc
- name: Build ex_doc
if: ${{ inputs.build_docs }}
shell: bash
run: |
mv ex_doc ../ex_doc
cd ../ex_doc
../elixir/bin/mix do local.rebar --force, local.hex --force, deps.get, compile
cd ../elixir
- name: Build Docs
if: ${{ inputs.build_docs }}
shell: bash
run: |
make Docs.zip
shasum -a 1 Docs.zip > Docs.zip.sha1sum
shasum -a 256 Docs.zip > Docs.zip.sha256sum
+27
View File
@@ -90,6 +90,24 @@ As of Elixir v1.12, implicitly decreasing ranges are soft-deprecated and warning
Elixir v1.12 has the additional of many functions across the standard library. The `Enum` module received additions such as `Enum.count_until/2`, `Enum.product/1`, `Enum.zip_with/2`, and more. The `Integer` module now includes `Integer.pow/2` and `Integer.extended_gcd/2`. Finally, the `Kernel` module got two new functions, `Kernel.then/2` and `Kernel.tap/2`, which are specially useful in `|>` pipelines.
## v1.12.3 (2021-09-05)
### 1. Bug fixes
#### Elixir
* [Code] Make sure that bindings in the default context returned by `Code.eval_*` functions are not returned as tagged tuples
* [Kernel] Do not crash when handling ambiguity errors
* [Range] Still match on old range patterns throughout the stdlib
#### IEx
* [IEx.Autocomplete] Do not error autocompletion with module attribute
#### Mix
* [Mix] Rename inconsistent `:exit_code` option to `:exit_status` on `Mix.raise/2`
## v1.12.2 (2021-07-01)
### 1. Bug fixes
@@ -209,6 +227,7 @@ Elixir v1.12 has the additional of many functions across the standard library. T
* [mix release] Add `RELEASE_PROG` to releases with the name of the executable starting the release
* [mix release] Support `remote.vm.args` to customize how the connecting VM boots
* [mix test] Run all available tests if there are no pending `--failed` tests. This provides a better workflow as you no longer need to toggle the `--failed` flag between runs
* [mix test] Support `mix test --warnings-as-errors`, treating warnings as errors and returning a non-zero exit status (only applies to test files, not compilation)
### 2. Bug fixes
@@ -277,6 +296,14 @@ Elixir v1.12 has the additional of many functions across the standard library. T
* [mix compile] The `:xref` compiler is deprecated and it has no effect. Please remove it from your mix.exs file.
### 5. Backwards incompatible changes
A backward incompatible change was found on Elixir v1.12.0 after the release. This was not planned and it is documented below:
#### ExUnit
* [ExUnit.Formatter] `{:suite_finished, load_time, run_time}` message has been updated to `{:suite_finished, %{load: load_time, run: run_time, async: async_time}}`
## v1.11
The CHANGELOG for v1.11 releases can be found [in the v1.11 branch](https://github.com/elixir-lang/elixir/blob/v1.11/CHANGELOG.md).
+25 -17
View File
@@ -179,40 +179,48 @@ clean_residual_files:
LOGO_PATH = $(shell test -f ../docs/logo.png && echo "--logo ../docs/logo.png")
SOURCE_REF = $(shell tag="$(call GIT_TAG)" revision="$(call GIT_REVISION)"; echo "$${tag:-$$revision}")
DOCS_FORMAT = html
COMPILE_DOCS = CANONICAL=$(CANONICAL) bin/elixir ../ex_doc/bin/ex_doc "$(1)" "$(VERSION)" "lib/$(2)/ebin" --main "$(3)" --source-url "https://github.com/elixir-lang/elixir" --source-ref "$(call SOURCE_REF)" $(call LOGO_PATH) --output doc/$(2) --canonical "https://hexdocs.pm/$(2)/$(CANONICAL)" --homepage-url "https://elixir-lang.org/docs.html" --formatter "$(DOCS_FORMAT)" $(4)
DOCS_COMPILE = CANONICAL=$(CANONICAL) bin/elixir ../ex_doc/bin/ex_doc "$(1)" "$(VERSION)" "lib/$(2)/ebin" --main "$(3)" --source-url "https://github.com/elixir-lang/elixir" --source-ref "$(call SOURCE_REF)" $(call LOGO_PATH) --output doc/$(2) --canonical "https://hexdocs.pm/$(2)/$(CANONICAL)" --homepage-url "https://elixir-lang.org/docs.html" --formatter "$(DOCS_FORMAT)" $(4)
DOCS_CONFIG = bin/elixir lib/elixir/scripts/docs_config.exs "$(1)"
docs: compile ../ex_doc/bin/ex_doc docs_elixir docs_eex docs_mix docs_iex docs_ex_unit docs_logger
docs_elixir: compile ../ex_doc/bin/ex_doc
@ echo "==> ex_doc (elixir)"
$(Q) rm -rf doc/elixir
$(call COMPILE_DOCS,Elixir,elixir,Kernel,--config "lib/elixir/docs.exs")
$(call DOCS_COMPILE,Elixir,elixir,Kernel,--config "lib/elixir/scripts/elixir_docs.exs")
$(call DOCS_CONFIG,elixir)
docs_eex: compile ../ex_doc/bin/ex_doc
@ echo "==> ex_doc (eex)"
$(Q) rm -rf doc/eex
$(call COMPILE_DOCS,EEx,eex,EEx,--config "lib/mix/docs.exs")
$(call DOCS_COMPILE,EEx,eex,EEx,--config "lib/elixir/scripts/mix_docs.exs")
$(call DOCS_CONFIG,eex)
docs_mix: compile ../ex_doc/bin/ex_doc
@ echo "==> ex_doc (mix)"
$(Q) rm -rf doc/mix
$(call COMPILE_DOCS,Mix,mix,Mix,--config "lib/mix/docs.exs")
$(call DOCS_COMPILE,Mix,mix,Mix,--config "lib/elixir/scripts/mix_docs.exs")
$(call DOCS_CONFIG,mix)
docs_iex: compile ../ex_doc/bin/ex_doc
@ echo "==> ex_doc (iex)"
$(Q) rm -rf doc/iex
$(call COMPILE_DOCS,IEx,iex,IEx,--config "lib/mix/docs.exs")
$(call DOCS_COMPILE,IEx,iex,IEx,--config "lib/elixir/scripts/mix_docs.exs")
$(call DOCS_CONFIG,iex)
docs_ex_unit: compile ../ex_doc/bin/ex_doc
@ echo "==> ex_doc (ex_unit)"
$(Q) rm -rf doc/ex_unit
$(call COMPILE_DOCS,ExUnit,ex_unit,ExUnit,--config "lib/mix/docs.exs")
$(call DOCS_COMPILE,ExUnit,ex_unit,ExUnit,--config "lib/elixir/scripts/mix_docs.exs")
$(call DOCS_CONFIG,ex_unit)
docs_logger: compile ../ex_doc/bin/ex_doc
@ echo "==> ex_doc (logger)"
$(Q) rm -rf doc/logger
$(call COMPILE_DOCS,Logger,logger,Logger,--config "lib/mix/docs.exs")
$(call DOCS_COMPILE,Logger,logger,Logger,--config "lib/elixir/scripts/mix_docs.exs")
$(call DOCS_CONFIG,logger)
../ex_doc/bin/ex_doc:
@ echo "ex_doc is not found in ../ex_doc as expected. See README for more information."
@@ -221,23 +229,23 @@ docs_logger: compile ../ex_doc/bin/ex_doc
#==> Zip tasks
Docs.zip: docs
rm -f Docs-v$(VERSION).zip
zip -9 -r Docs-v$(VERSION).zip CHANGELOG.md doc NOTICE LICENSE README.md
@ echo "Docs file created $(CURDIR)/Docs-v$(VERSION).zip"
rm -f Docs.zip
zip -9 -r Docs.zip CHANGELOG.md doc NOTICE LICENSE README.md
@ echo "Docs file created $(CURDIR)/Docs.zip"
Precompiled.zip: build_man compile
rm -f Precompiled-v$(VERSION).zip
zip -9 -r Precompiled-v$(VERSION).zip bin CHANGELOG.md lib/*/ebin lib/*/lib LICENSE man NOTICE README.md VERSION
@ echo "Precompiled file created $(CURDIR)/Precompiled-v$(VERSION).zip"
rm -f Precompiled.zip
zip -9 -r Precompiled.zip bin CHANGELOG.md lib/*/ebin lib/*/lib LICENSE man NOTICE README.md VERSION
@ echo "Precompiled file created $(CURDIR)/Precompiled.zip"
zips: Precompiled.zip Docs.zip
@ echo ""
@ echo "### Checksums"
@ echo ""
@ shasum -a 1 < Precompiled-v$(VERSION).zip | sed -e "s/-//" | xargs echo " * Precompiled.zip SHA1:"
@ shasum -a 512 < Precompiled-v$(VERSION).zip | sed -e "s/-//" | xargs echo " * Precompiled.zip SHA512:"
@ shasum -a 1 < Docs-v$(VERSION).zip | sed -e "s/-//" | xargs echo " * Docs.zip SHA1:"
@ shasum -a 512 < Docs-v$(VERSION).zip | sed -e "s/-//" | xargs echo " * Docs.zip SHA512:"
@ shasum -a 1 < Precompiled.zip | sed -e "s/-//" | xargs echo " * Precompiled.zip SHA1:"
@ shasum -a 512 < Precompiled.zip | sed -e "s/-//" | xargs echo " * Precompiled.zip SHA512:"
@ shasum -a 1 < Docs.zip | sed -e "s/-//" | xargs echo " * Docs.zip SHA1:"
@ shasum -a 512 < Docs.zip | sed -e "s/-//" | xargs echo " * Docs.zip SHA512:"
@ echo ""
#==> Test tasks
+1 -1
View File
@@ -1 +1 @@
1.12.2
1.12.3
+1 -1
View File
@@ -14,7 +14,7 @@ Usage: $(basename "$0") [elixir switches] [compiler switches] [.ex files]
--no-docs Does not attach documentation to compiled modules
--profile time Profile the time to compile modules
--verbose Prints compilation status
--warnings-as-errors Treats warnings as errors and return non-zero exit code
--warnings-as-errors Treats warnings as errors and return non-zero exit status
Options given after -- are passed down to the executed code.
Options can be passed to the Erlang runtime using \$ELIXIR_ERL_OPTIONS.
+1 -1
View File
@@ -23,7 +23,7 @@ echo --no-debug-info Does not attach debug info to compiled modules
echo --no-docs Does not attach documentation to compiled modules
echo --profile time Profile the time to compile modules
echo --verbose Prints compilation status
echo --warnings-as-errors Treats warnings as errors and returns non-zero exit code
echo --warnings-as-errors Treats warnings as errors and returns non-zero exit status
echo.
echo ** Options given after -- are passed down to the executed code
echo ** Options can be passed to the Erlang runtime using ELIXIR_ERL_OPTIONS
+84 -24
View File
@@ -26,13 +26,15 @@ defmodule Date.Range do
defstruct [:first, :last, :first_in_iso_days, :last_in_iso_days, :step]
defimpl Enumerable do
def member?(%{first: %{calendar: calendar}} = range, %Date{calendar: calendar} = date) do
%{
first_in_iso_days: first_days,
last_in_iso_days: last_days,
step: step
} = range
def member?(
%Date.Range{
first: %{calendar: calendar},
first_in_iso_days: first_days,
last_in_iso_days: last_days,
step: step
} = range,
%Date{calendar: calendar} = date
) do
{days, _} = Date.to_iso_days(date)
cond do
@@ -47,24 +49,43 @@ defmodule Date.Range do
end
end
def member?(_, _) do
def member?(%Date.Range{step: _}, _) do
{:ok, false}
end
# TODO: Remove me on v2.0
def member?(
%{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =
date_range,
date
) do
step = if first_days <= last_days, do: 1, else: -1
member?(Map.put(date_range, :step, step), date)
end
def count(range) do
{:ok, size(range)}
end
def slice(range) do
%{
first_in_iso_days: first,
first: %{calendar: calendar},
step: step
} = range
def slice(
%Date.Range{
first_in_iso_days: first,
first: %{calendar: calendar},
step: step
} = range
) do
{:ok, size(range), &slice(first + &1 * step, step, &2, calendar)}
end
# TODO: Remove me on v2.0
def slice(
%{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =
date_range
) do
step = if first_days <= last_days, do: 1, else: -1
slice(Map.put(date_range, :step, step))
end
defp slice(current, _step, 1, calendar) do
[date_from_iso_days(current, calendar)]
end
@@ -76,17 +97,30 @@ defmodule Date.Range do
]
end
def reduce(range, acc, fun) do
%{
first_in_iso_days: first_days,
last_in_iso_days: last_days,
first: %{calendar: calendar},
step: step
} = range
def reduce(
%Date.Range{
first_in_iso_days: first_days,
last_in_iso_days: last_days,
first: %{calendar: calendar},
step: step
},
acc,
fun
) do
reduce(first_days, last_days, acc, fun, step, calendar)
end
# TODO: Remove me on v2.0
def reduce(
%{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =
date_range,
acc,
fun
) do
step = if first_days <= last_days, do: 1, else: -1
reduce(Map.put(date_range, :step, step), acc, fun)
end
defp reduce(_first_days, _last_days, {:halt, acc}, _fun, _step, _calendar) do
{:halted, acc}
end
@@ -135,6 +169,15 @@ defmodule Date.Range do
defp size(%Date.Range{first_in_iso_days: first_days, last_in_iso_days: last_days, step: step}),
do: abs(div(last_days - first_days, step)) + 1
# TODO: Remove me on v2.0
defp size(
%{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =
date_range
) do
step = if first_days <= last_days, do: 1, else: -1
size(Map.put(date_range, :step, step))
end
defp empty?(%Date.Range{
first_in_iso_days: first_days,
last_in_iso_days: last_days,
@@ -151,10 +194,21 @@ defmodule Date.Range do
when step < 0 and first_days < last_days,
do: true
defp empty?(%Date.Range{}), do: false
defp empty?(%Date.Range{step: _}), do: false
# TODO: Remove me on v2.0
defp empty?(
%{__struct__: Date.Range, first_in_iso_days: first_days, last_in_iso_days: last_days} =
date_range
) do
step = if first_days <= last_days, do: 1, else: -1
empty?(Map.put(date_range, :step, step))
end
end
defimpl Inspect do
import Kernel, except: [inspect: 2]
def inspect(%Date.Range{first: first, last: last, step: 1}, _) do
"#DateRange<" <> inspect(first) <> ", " <> inspect(last) <> ">"
end
@@ -162,5 +216,11 @@ defmodule Date.Range do
def inspect(%Date.Range{first: first, last: last, step: step}, _) do
"#DateRange<" <> inspect(first) <> ", " <> inspect(last) <> ", #{step}>"
end
# TODO: Remove me on v2.0
def inspect(%{__struct__: Date.Range, first: first, last: last} = date_range, opts) do
step = if first <= last, do: 1, else: -1
inspect(Map.put(date_range, :step, step), opts)
end
end
end
+2 -2
View File
@@ -38,8 +38,8 @@ defmodule Code do
are loaded as needed. In embedded mode the opposite happens, as all
modules need to be loaded upfront or explicitly.
You can use `ensure_loaded/1` (as well as `ensure_lodead?/1` and
`ensure_lodead!/1`) to check if a module is loaded before using it and
You can use `ensure_loaded/1` (as well as `ensure_loaded?/1` and
`ensure_loaded!/1`) to check if a module is loaded before using it and
act.
## `ensure_compiled/1` and `ensure_compiled!/1`
+6
View File
@@ -2661,6 +2661,12 @@ defmodule Enum do
end
end
# TODO: Remove me on v2.0
def slice(enumerable, %{__struct__: Range, first: first, last: last} = index_range) do
step = if first <= last, do: 1, else: -1
slice(enumerable, Map.put(index_range, :step, step))
end
defp slice_range(enumerable, first, last) when last >= first and last >= 0 and first >= 0 do
slice_any(enumerable, first, last - first + 1)
end
+32
View File
@@ -185,6 +185,12 @@ defmodule Range do
def size(first..last//step) when step < 0 and first < last, do: 0
def size(first..last//step), do: abs(div(last - first, step)) + 1
# TODO: Remove me on v2.0
def size(%{__struct__: Range, first: first, last: last} = range) do
step = if first <= last, do: 1, else: -1
size(Map.put(range, :step, step))
end
@doc """
Checks if two ranges are disjoint.
@@ -273,6 +279,12 @@ defimpl Enumerable, for: Range do
reduce(first, last, acc, fun, step)
end
# TODO: Remove me on v2.0
def reduce(%{__struct__: Range, first: first, last: last} = range, acc, fun) do
step = if first <= last, do: 1, else: -1
reduce(Map.put(range, :step, step), acc, fun)
end
defp reduce(_first, _last, {:halt, acc}, _fun, _step) do
{:halted, acc}
end
@@ -304,6 +316,13 @@ defimpl Enumerable, for: Range do
end
end
# TODO: Remove me on v2.0
def member?(%{__struct__: Range, first: first, last: last} = range, value)
when is_integer(value) do
step = if first <= last, do: 1, else: -1
member?(Map.put(range, :step, step), value)
end
def member?(_, _value) do
{:ok, false}
end
@@ -316,12 +335,19 @@ defimpl Enumerable, for: Range do
{:ok, Range.size(range), &slice(first + &1 * step, step, &2)}
end
# TODO: Remove me on v2.0
def slice(%{__struct__: Range, first: first, last: last} = range) do
step = if first <= last, do: 1, else: -1
slice(Map.put(range, :step, step))
end
defp slice(current, _step, 1), do: [current]
defp slice(current, step, remaining), do: [current | slice(current + step, step, remaining - 1)]
end
defimpl Inspect, for: Range do
import Inspect.Algebra
import Kernel, except: [inspect: 2]
def inspect(first..last//1, opts) do
concat([to_doc(first, opts), "..", to_doc(last, opts)])
@@ -330,4 +356,10 @@ defimpl Inspect, for: Range do
def inspect(first..last//step, opts) do
concat([to_doc(first, opts), "..", to_doc(last, opts), "//", to_doc(step, opts)])
end
# TODO: Remove me on v2.0
def inspect(%{__struct__: Range, first: first, last: last} = range, opts) do
step = if first <= last, do: 1, else: -1
inspect(Map.put(range, :step, step), opts)
end
end
+6
View File
@@ -2098,6 +2098,12 @@ defmodule String do
end
end
# TODO: Remove me on v2.0
def slice(string, %{__struct__: Range, first: first, last: last} = range) do
step = if first <= last, do: 1, else: -1
slice(string, Map.put(range, :step, step))
end
defp slice_range("", _, _), do: ""
defp slice_range(string, first, -1) when first >= 0 do
+19
View File
@@ -0,0 +1,19 @@
# Generate docs_config.js for version chooser in ExDoc
[app] = System.argv()
{text_tags, 0} = System.cmd("git", ["tag"])
skipped = Version.parse!("1.0.3")
list_contents =
text_tags
|> String.split()
|> Enum.map(fn "v" <> rest -> Version.parse!(rest) end)
|> Enum.filter(&(Version.compare(&1, skipped) == :gt))
|> Enum.sort({:desc, Version})
|> Enum.map_intersperse(", ", fn version ->
version_string = to_string(version)
~s[{"version":"v#{version_string}", "url":"https://hexdocs.pm/#{app}/#{version_string}"}]
end)
File.mkdir_p!("doc/#{app}")
File.write!("doc/#{app}/docs_config.js", ["var versionNodes = [", list_contents, "];\n"])
+1 -1
View File
@@ -252,7 +252,7 @@ eval_forms(Tree, RawBinding, OE) ->
case Erl of
{atom, _, Atom} ->
{Atom, Binding, NewE};
{Atom, RawBinding, NewE};
_ ->
Exprs =
+6 -10
View File
@@ -1161,23 +1161,19 @@ format_error({invalid_alias, Expr}) ->
"it at runtime. If instead you wanted to invoke a function or access a field, "
"wrap the function or field name in double quotes",
io_lib:format(Message, ['Elixir.Macro':to_string(Expr)]);
format_error({op_ambiguity, Name, {Op, _, [Arg]}}) ->
format_error({op_ambiguity, Name, Arg}) ->
NameString = atom_to_binary(Name, utf8),
OpString = atom_to_binary(Op, utf8),
ArgString = 'Elixir.Macro':to_string(Arg),
Message =
"\"~ts ~ts~ts\" looks like a function call but there is a variable named \"~ts\".\n"
"\"~ts ~ts\" looks like a function call but there is a variable named \"~ts\". "
"If you want to perform a function call, use parentheses:\n"
"\n"
" ~ts(~ts~ts)\n"
" ~ts(~ts)\n"
"\n"
"If you want to perform an operation on the variable ~ts, use even spaces instead:\n"
"\n"
" ~ts ~ts ~ts",
io_lib:format(Message, [NameString, OpString, ArgString, NameString,
NameString, OpString, ArgString, NameString,
NameString, OpString, ArgString]);
"If you want to perform an operation on the variable ~ts, use spaces "
"around the unary operator",
io_lib:format(Message, [NameString, ArgString, NameString, NameString, ArgString, NameString]);
format_error({invalid_clauses, Name}) ->
Message =
"the function \"~ts\" cannot handle clauses with the -> operator because it is not a macro. "
@@ -141,4 +141,71 @@ defmodule Date.RangeTest do
Date.range(~D[2000-01-01], ~D[2000-01-31], step)
end
end
describe "old date ranges" do
test "inspect" do
asc = %{
__struct__: Date.Range,
first: ~D[2021-07-14],
first_in_iso_days: 738_350,
last: ~D[2021-07-17],
last_in_iso_days: 738_353
}
desc = %{
__struct__: Date.Range,
first: ~D[2021-07-17],
first_in_iso_days: 738_353,
last: ~D[2021-07-14],
last_in_iso_days: 738_350
}
assert inspect(asc) == "#DateRange<~D[2021-07-14], ~D[2021-07-17]>"
assert inspect(desc) == "#DateRange<~D[2021-07-17], ~D[2021-07-14], -1>"
end
test "enumerable" do
asc = %{
__struct__: Date.Range,
first: ~D[2021-07-14],
first_in_iso_days: 738_350,
last: ~D[2021-07-17],
last_in_iso_days: 738_353
}
desc = %{
__struct__: Date.Range,
first: ~D[2021-07-17],
first_in_iso_days: 738_353,
last: ~D[2021-07-14],
last_in_iso_days: 738_350
}
# member? implementations tests also empty?
assert Enumerable.member?(asc, ~D[2021-07-15])
assert {:ok, 4, _} = Enumerable.slice(asc)
assert Enum.reduce(asc, [], fn x, acc -> [x | acc] end) == [
~D[2021-07-17],
~D[2021-07-16],
~D[2021-07-15],
~D[2021-07-14]
]
assert Enum.count(asc) == 4
# member? implementations tests also empty?
assert Enumerable.member?(desc, ~D[2021-07-15])
assert {:ok, 4, _} = Enumerable.slice(desc)
assert Enum.reduce(desc, [], fn x, acc -> [x | acc] end) == [
~D[2021-07-14],
~D[2021-07-15],
~D[2021-07-16],
~D[2021-07-17]
]
assert Enum.count(desc) == 4
end
end
end
+4
View File
@@ -167,6 +167,10 @@ defmodule CodeTest do
assert Code.eval_string("two = 1 + 1") == {2, [two: 2]}
end
test "keeps bindings on optimized evals" do
assert Code.eval_string("import Enum", x: 1) == {Enum, [x: 1]}
end
test "supports a %Macro.Env{} struct as the third argument" do
assert {3, _} = Code.eval_string("a + b", [a: 1, b: 2], __ENV__)
end
+5 -4
View File
@@ -470,11 +470,12 @@ defmodule ExceptionTest do
* min/1
"""
assert blame_message(:erlang, & &1.gt_cookie()) == """
function :erlang.gt_cookie/0 is undefined or private. Did you mean one of:
assert blame_message(:erlang, & &1.hal()) == """
function :erlang.hal/0 is undefined or private. Did you mean one of:
* get_cookie/0
* set_cookie/2
* halt/0
* halt/1
* halt/2
"""
end
@@ -2538,10 +2538,10 @@ defmodule Kernel.ExpansionTest do
describe "op ambiguity" do
test "raises when a call is ambiguous" do
# We use string_to_quoted! here to avoid the formatter adding parentheses
message = ~r["a -1" looks like a function call but there is a variable named "a"]
assert_raise CompileError, message, fn ->
# We use string_to_quoted! here to avoid the formatter adding parentheses to "a -1".
code =
Code.string_to_quoted!("""
a = 1
@@ -2550,6 +2550,18 @@ defmodule Kernel.ExpansionTest do
expand(code)
end
message = ~r["a -1\.\.a \+ 1" looks like a function call but there is a variable named "a"]
assert_raise CompileError, message, fn ->
code =
Code.string_to_quoted!("""
a = 1
a -1 .. a + 1
""")
expand(code)
end
end
end
+45
View File
@@ -94,4 +94,49 @@ defmodule RangeTest do
assert Range.disjoint?(1..1, 1..1) == false
end
end
describe "old ranges" do
test "inspect" do
asc = %{__struct__: Range, first: 1, last: 3}
desc = %{__struct__: Range, first: 3, last: 1}
assert inspect(asc) == "1..3"
assert inspect(desc) == "3..1//-1"
end
test "enum" do
asc = %{__struct__: Range, first: 1, last: 3}
desc = %{__struct__: Range, first: 3, last: 1}
assert Enum.to_list(asc) == [1, 2, 3]
assert Enum.member?(asc, 2)
assert Enum.count(asc) == 3
assert Enum.drop(asc, 1) == [2, 3]
assert Enum.slice([1, 2, 3, 4, 5, 6], asc) == [2, 3, 4]
# testing private Enum.aggregate
assert Enum.max(asc) == 3
assert Enum.sum(asc) == 6
assert Enum.min_max(asc) == {1, 3}
assert Enum.reduce(asc, 0, fn a, b -> a + b end) == 6
assert Enum.to_list(desc) == [3, 2, 1]
assert Enum.member?(desc, 2)
assert Enum.count(desc) == 3
assert Enum.drop(desc, 1) == [2, 1]
assert Enum.slice([1, 2, 3, 4, 5, 6], desc) == []
# testing private Enum.aggregate
assert Enum.max(desc) == 3
assert Enum.sum(desc) == 6
assert Enum.min_max(desc) == {1, 3}
assert Enum.reduce(desc, 0, fn a, b -> a + b end) == 6
end
test "string" do
asc = %{__struct__: Range, first: 1, last: 3}
desc = %{__struct__: Range, first: 3, last: 1}
assert String.slice("elixir", asc) == "lix"
assert String.slice("elixir", desc) == ""
end
end
end
+4
View File
@@ -163,6 +163,10 @@ defmodule IEx.Autocomplete do
{:ok, List.to_atom(var)}
end
defp expand_dot_path({:module_attribute, _}, _shell) do
:error
end
defp expand_dot_path({:dot, parent, call}, shell) do
case expand_dot_path(parent, shell) do
{:ok, %{} = map} -> Map.fetch(map, List.to_atom(call))
+4 -3
View File
@@ -161,6 +161,7 @@ defmodule IEx.AutocompleteTest do
assert expand('Xyz') == {:no, '', []}
assert expand('x.Foo') == {:no, '', []}
assert expand('x.Foo.get_by') == {:no, '', []}
assert expand('@foo.bar') == {:no, '', []}
end
test "Elixir root submodule completion" do
@@ -221,21 +222,21 @@ defmodule IEx.AutocompleteTest do
assert expand('map.f') == {:no, '', []}
end
test "autocompletion off a bound variable only works for modules and maps" do
test "bound variables for modules and maps" do
eval("num = 5; map = %{nested: %{num: 23}}")
assert expand('num.print') == {:no, '', []}
assert expand('map.nested.num.f') == {:no, '', []}
assert expand('map.nested.num.key.f') == {:no, '', []}
end
test "autocompletion using access syntax does is not supported" do
test "access syntax is not supported" do
eval("map = %{nested: %{deeply: %{num: 23}}}")
assert expand('map[:nested][:deeply].n') == {:no, '', []}
assert expand('map[:nested].deeply.n') == {:no, '', []}
assert expand('map.nested.[:deeply].n') == {:no, '', []}
end
test "autocompletion off of unbound variables is not supported" do
test "unbound variables is not supported" do
eval("num = 5")
assert expand('other_var.f') == {:no, '', []}
assert expand('a.b.c.d') == {:no, '', []}
+7 -6
View File
@@ -433,11 +433,11 @@ defmodule Mix do
end
@doc """
Raises a Mix error that is nicely formatted, defaulting to exit code `1`.
Raises a Mix error that is nicely formatted, defaulting to exit status `1`.
"""
@spec raise(binary) :: no_return
def raise(message) do
__MODULE__.raise(message, exit_code: 1)
__MODULE__.raise(message, exit_status: 1)
end
@doc """
@@ -445,13 +445,14 @@ defmodule Mix do
## Options
* `:exit_code` - defines exit code value, defaults to `1`
* `:exit_status` - defines exit status, defaults to `1`
"""
@doc since: "1.12.0"
@spec raise(binary, exit_code: non_neg_integer()) :: no_return
@doc since: "1.12.3"
@spec raise(binary, exit_status: non_neg_integer()) :: no_return
def raise(message, opts) when is_binary(message) and is_list(opts) do
Kernel.raise(Mix.Error, mix: Keyword.get(opts, :exit_code, 1), message: message)
status = opts[:exit_status] || opts[:exit_code] || 1
Kernel.raise(Mix.Error, mix: status, message: message)
end
@doc """
+1 -1
View File
@@ -52,7 +52,7 @@ defmodule Mix.Tasks.Compile.Elixir do
* `--debug-info` (`--no-debug-info`) - attaches (or not) debug info to compiled modules
* `--ignore-module-conflict` - does not emit warnings if a module was previously defined
* `--warnings-as-errors` - treats warnings in the current project as errors and
return a non-zero exit code
return a non-zero exit status
* `--long-compilation-threshold N` - sets the "long compilation" threshold
(in seconds) to `N` (see the docs for `Kernel.ParallelCompiler.compile/2`)
* `--profile` - if set to `time`, outputs timing information of compilation steps
+1 -1
View File
@@ -174,7 +174,7 @@ defmodule Mix.Tasks.Test do
Note that in trace mode test timeouts will be ignored as timeout is set to `:infinity`
* `--warnings-as-errors` - (since v1.12.0) treats warnings as errors and returns a non-zero
exit code. This option only applies to test files. To treat warnings as errors during
exit status. This option only applies to test files. To treat warnings as errors during
compilation and during tests, run:
MIX_ENV=test mix do compile --warnings-as-errors, test --warnings-as-errors
+2 -2
View File
@@ -20,7 +20,7 @@ defmodule Mix.CLITest do
end
@tag :unix
test "Mix.raise/2 can set exit code", %{tmp_dir: tmp_dir} do
test "Mix.raise/2 can set exit status", %{tmp_dir: tmp_dir} do
File.cd!(tmp_dir, fn ->
File.mkdir_p!("lib")
@@ -34,7 +34,7 @@ defmodule Mix.CLITest do
defp aliases do
[
custom: &error(&1, exit_code: 99),
custom: &error(&1, exit_status: 99),
]
end