Skip to content

Commit bba7aa6

Browse files
New concept exercise city-office (docs and typespecs) (#693)
1 parent 7afb9f1 commit bba7aa6

File tree

22 files changed

+1016
-37
lines changed

22 files changed

+1016
-37
lines changed

concepts/basics/about.md

Lines changed: 2 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -65,34 +65,11 @@ string = "this is a string! 1, 2, 3!"
6565
- Automatically imported.
6666
- Its functions can be used without the `Kernel.` prefix.
6767

68-
## Documentation
68+
## Code comments
6969

70-
- Elixir provides 3 ways to write [inline documentation][inline-documentation].
71-
72-
- Single line comments are preceded by `#`.
73-
- Functions may be documented with `@doc` preceding the named function definition
74-
75-
```elixir
76-
@doc """
77-
Function Documentation
78-
"""
79-
def function(), do: true
80-
```
81-
82-
- Modules may be documented with `@moduledoc` immediately following the module definition
83-
84-
```elixir
85-
defmodule Example do
86-
@moduledoc """
87-
Module documentation
88-
"""
89-
90-
#...
91-
end
92-
```
70+
Comments can be used to leave notes for other developers reading the source code. Single line comments in Elixir are preceded by `#`.
9371

9472
[match]: https://elixirschool.com/en/lessons/basics/pattern-matching/
95-
[inline-documentation]: https://elixirschool.com/en/lessons/basics/documentation/#inline-documentation
9673
[operators]: https://elixir-lang.org/getting-started/basic-types.html#basic-arithmetic
9774
[modules]: https://elixirschool.com/en/lessons/basics/modules/#modules
9875
[functions]: https://elixirschool.com/en/lessons/basics/functions/#named-functions

concepts/basics/introduction.md

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -63,13 +63,9 @@ Most built-in data types have a corresponding module that offers functions for w
6363

6464
A notable module is the `Kernel` module. It provides the basic capabilities on top of which the rest of the standard library is built, like arithmetic operators, control-flow macros, and much more. Functions for the `Kernel` module are automatically imported, so you can use them without the `Kernel.` prefix.
6565

66-
## Documentation
66+
## Code comments
6767

68-
Documentation is a priority in high-quality Elixir code bases, and there are 3 ways to write inline documentation:
69-
70-
- Comments can be used for inline documentation. Single line comments in Elixir are preceded by `#`.
71-
- Function-level documentation uses the `@doc` annotation preceding named function definitions
72-
- Module-level documentation uses the `@moduledoc` annotation following the module definition
68+
Comments can be used to leave notes for other developers reading the source code. Single line comments in Elixir are preceded by `#`.
7369

7470
[functional-programming]: https://en.wikipedia.org/wiki/Functional_programming
7571
[docs]: https://hexdocs.pm/elixir/Kernel.html#content

concepts/docs/about.md

Lines changed: 106 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,106 @@
1+
# About
2+
3+
Elixir documentation:
4+
5+
- A first-class citizen.
6+
- Written in [**Markdown**][markdown].
7+
- Added by using special module attributes.
8+
- Typically uses the heredoc syntax for multiline strings.
9+
10+
Module attributes used for documentation:
11+
12+
- `@moduledoc` - describes a module, appears on the first line of the module.
13+
- `@doc` - describes a function, appears right above the function's definition and its typespec.
14+
- `@typedoc`- describes a custom type, appears right above the type's definition.
15+
16+
```elixir
17+
defmodule String do
18+
@moduledoc """
19+
Strings in Elixir are UTF-8 encoded binaries.
20+
"""
21+
22+
@typedoc """
23+
A UTF-8 encoded binary.
24+
"""
25+
@type t :: binary
26+
27+
@doc """
28+
Converts all characters in the given string to uppercase according to `mode`.
29+
30+
## Examples
31+
32+
iex> String.upcase("abcd")
33+
"ABCD"
34+
35+
iex> String.upcase("olá")
36+
"OLÁ"
37+
"""
38+
def upcase(string, mode \\ :default)
39+
end
40+
```
41+
42+
## [Documentation vs. code comments][documentation-vs-comments]
43+
44+
Elixir treats documentation and code comments as two different concepts.
45+
46+
Documentation is an explicit contract between you and the users of your public API (which also includes your coworkers and your future self). Those users might or might not have access to the source code, so the documentation explains how to use your code.
47+
48+
Code comments are aimed at developers reading the source code. They are useful for leaving notes, explaining implementation details, marking opportunities for improvement, and so on.
49+
50+
Because documentation is meant to describe the public API of your code, trying to add a `@doc` attribute to a private function will result in a compilation warning. For explaining private functions, use code comments instead.
51+
52+
```
53+
warning: defp do_check_length/2 is private, @doc attribute is always discarded for private functions/macros/types
54+
lib/form.ex:33: Form.do_check_length/2
55+
```
56+
57+
## Consuming documentation
58+
59+
There are many different ways to access the documentation of an Elixir project.
60+
61+
### `hexdocs.pm` and `ExDoc`
62+
63+
[`hex.pm`][hex-pm] is a package repository for Elixir and Erlang. Every package published to `hex.pm` will get its documentation automatically published to [`hexdocs.pm`][hexdocs-pm]. There, you can find the documentation for all your favorite Elixir libraries, as well as [Elixir's official documentation][official-documentation] itself.
64+
65+
You can generate a documentation website for your project that looks exactly like Elixir's official documentation without having to publish a package to `hex.pm`. The tool that does it is called [`ExDoc`][ex-doc]. `ExDoc` will produce HTML files that you can browse from your local filesystem.
66+
67+
Make sure to follow the [official recommendations for writing documentation][writing-documentation-recommendations] to ensure best results when using `ExDoc`.
68+
69+
### The `h` IEx helper
70+
71+
You can access the documentation of the standard library, as well as any library you have installed and your Elixir project, directly from your computer.
72+
73+
If you have Elixir installed on your computer, you can use it in [the interactive mode][getting-started-iex] by running the `iex` command (or `iex -S mix` if you want to load the source of your current mix project).
74+
75+
In `iex`, you can type [`h`][iex-h], followed by a space and a module name or a function name, to read its documentation.
76+
77+
```elixir
78+
iex()> h String.upcase/1
79+
# def upcase(string, mode \\ :default)
80+
#
81+
# Converts all characters in the given string to uppercase according to mode.
82+
# (...)
83+
```
84+
85+
By pressing the tab key after providing a partial module or function name, you can leverage the autocomplete option to discover available modules and functions.
86+
87+
### Modern IDEs
88+
89+
Many modern IDEs that support Elixir can parse and display documentation and typespecs in useful pop-ups, for example [Visual Studio Code][vsc-documentation] or [Intellij with the Elixir plugin][intellij-elixir-documentation].
90+
91+
## Internal modules and function
92+
93+
If a module or a function is intended for internal usage only, you can mark it with `@moduledoc false` or `@doc false`. Those modules and functions will not be included in the generated documentation. Note that that doesn't make them private. They can still be invoked and/or imported. Check the [official documentation about hiding internal modules and functions][hiding-internal-modules-and-functions] to learn about potential solutions to this problem.
94+
95+
[markdown]: https://docs.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax
96+
[official-documentation]: https://hexdocs.pm/elixir/
97+
[ex-doc]: https://hexdocs.pm/ex_doc/readme.html
98+
[hex-pm]: https://hex.pm/
99+
[hexdocs-pm]: https://hexdocs.pm/
100+
[writing-documentation-recommendations]: https://hexdocs.pm/elixir/writing-documentation.html#recommendations
101+
[intellij-elixir-documentation]: https://github.com/KronicDeth/intellij-elixir#quick-documentation
102+
[vsc-documentation]: https://thinkingelixir.com/elixir-in-vs-code/#Documentation_displayed_on_hover
103+
[iex-h]: https://hexdocs.pm/iex/IEx.Helpers.html#h/1
104+
[getting-started-iex]: https://elixir-lang.org/getting-started/introduction.html#interactive-mode
105+
[hiding-internal-modules-and-functions]: https://hexdocs.pm/elixir/writing-documentation.html#hiding-internal-modules-and-functions
106+
[documentation-vs-comments]: https://hexdocs.pm/elixir/writing-documentation.html#documentation-code-comments

concepts/docs/introduction.md

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
# Introduction
2+
3+
Documentation in Elixir is a first-class citizen.
4+
5+
The two module attributes that commonly used to document your code - `@moduledoc` for documenting a module and `@doc` for documenting a function that follows the attribute. The `@moduledoc` attribute usually appears on the first line of the module, and the `@doc` attribute usually appears right before a function definition, or the function's typespec if it has one. The documentation is commonly written in a multiline string using the heredoc syntax.
6+
7+
Elixir documentation is written in [**Markdown**][markdown].
8+
9+
```elixir
10+
defmodule String do
11+
@moduledoc """
12+
Strings in Elixir are UTF-8 encoded binaries.
13+
"""
14+
15+
@doc """
16+
Converts all characters in the given string to uppercase according to `mode`.
17+
18+
## Examples
19+
20+
iex> String.upcase("abcd")
21+
"ABCD"
22+
23+
iex> String.upcase("olá")
24+
"OLÁ"
25+
"""
26+
def upcase(string, mode \\ :default)
27+
end
28+
```
29+
30+
[markdown]: https://docs.github.com/en/github/writing-on-github/basic-writing-and-formatting-syntax

concepts/docs/links.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[
2+
{
3+
"url": "https://hexdocs.pm/elixir/writing-documentation.html",
4+
"description": "Documentation - Writing Documentation"
5+
},
6+
{
7+
"url": "https://elixirschool.com/en/lessons/basics/documentation/",
8+
"description": "Elixir School - Documentation"
9+
}
10+
]

concepts/typespecs/about.md

Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
# Introduction
2+
3+
Elixir is a dynamically typed language, which means it doesn't provide compile-time type checks. Still, type specifications can be useful because they:
4+
5+
- Serve as documentation.
6+
- Can be used by static analysis tools like [Dialyzer][dialyzer] to find possible bugs.
7+
8+
A type specification can be added to a function using the `@spec` module attribute right before the function definition.
9+
10+
```elixir
11+
@spec longer_than?(String.t(), non_neg_integer()) :: boolean()
12+
def longer_than?(string, length), do: String.length(string) > length
13+
```
14+
15+
## Types
16+
17+
Expressions allowed in a typespec:
18+
19+
- Basic types, for example:
20+
- `boolean()`
21+
- `integer()`, `non_neg_integer()`, `pos_integer()`, `float()`
22+
- `list()`
23+
- `map()`
24+
- `any()`
25+
26+
- A union of types:
27+
- e.g. `integer() | list(integer())`
28+
29+
- Parameterized types:
30+
- e.g. `list(integer())` - a list of integers
31+
- e.g. `%{age: integer()}` - map with an integer value under the key `:age`
32+
33+
- Remote types (defined in some module), for example:
34+
- [`String.t()`][string-t]
35+
- [`Enum.t()`][enum-t]
36+
- [`Range.t()`][range-t]
37+
38+
- Literals, for example:
39+
- `%{}` - an empty map
40+
- `[]` - an empty list (but `[any()]` is a non-empty list)
41+
- e.g. `:ok` - an atom literal
42+
43+
- Built-in specialized types, for example:
44+
- `char()` - an integer from the range `0..0x10FFFF`
45+
- `charlist()` - a list of chars
46+
- `keyword()` - a list of two element tuples, where the first element is an atom
47+
48+
- Custom types
49+
50+
A full list of all types can be found in the ["Typespecs" section in the official documentation][types].
51+
52+
## Naming arguments
53+
54+
Arguments in the typespec could also be named which is useful for distinguishing multiple arguments of the same type.
55+
56+
```elixir
57+
@spec to_hex({hue :: integer, saturation :: integer, lightness :: integer}) :: String.t()
58+
```
59+
60+
## Custom types
61+
62+
Custom types can be defined in using one of the three module attributes:
63+
64+
- `@type` - defines a public type
65+
- `@typep` - defines a private type
66+
- `@opaque` - defines a public type whose structure is private
67+
68+
```elixir
69+
@type color :: {hue :: integer, saturation :: integer, lightness :: integer}
70+
71+
@spec to_hex(color()) :: String.t()
72+
```
73+
74+
## `String.t()` vs `binary()` vs `string()`
75+
76+
[`String.t()`][string-t] is the correct type to use for Elixir strings, which are UTF-8 encoded binaries. Technically, `String.t()` is defined as a `binary()`, and those two types are equivalent to analysis tools, but `String.t()` is the more intention-revealing choice for documenting functions that work with Elixir strings.
77+
78+
On the other hand, `string()` is a different type. It's an Erlang string, in Elixir known as a charlist. The `string()` type should be avoided in typespecs and `charlist()` should be used instead.
79+
80+
## Dialyzer
81+
82+
[Dialyzer][dialyzer] is a static analysis tool that can detect problems such as type errors in Erlang and Elixir code. The easiest way to use Dialyzer in an Elixir project is with [Dialyxir][dialyxir].
83+
84+
[types]: https://hexdocs.pm/elixir/typespecs.html#types-and-their-syntax
85+
[string-t]: https://hexdocs.pm/elixir/String.html#t:t/0
86+
[enum-t]: https://hexdocs.pm/elixir/Enum.html#t:t/0
87+
[range-t]: https://hexdocs.pm/elixir/Range.html#t:t/0
88+
[dialyzer]: http://erlang.org/doc/man/dialyzer.html
89+
[dialyxir]: https://hexdocs.pm/dialyxir/readme.html

concepts/typespecs/introduction.md

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
# Introduction
2+
3+
Elixir is a dynamically typed language, which means it doesn't provide compile-time type checks. Still, type specifications can be used as a form of documentation.
4+
5+
A type specification can be added to a function using the `@spec` module attribute right before the function definition. `@spec` is followed by the function name and a list of all of its arguments' types, in parentheses, separated by commas. The type of the return value is separated from the function's arguments with a double colon `::`.
6+
7+
```elixir
8+
@spec longer_than?(String.t(), non_neg_integer()) :: boolean()
9+
def longer_than?(string, length), do: String.length(string) > length
10+
```
11+
12+
## Types
13+
14+
Most commonly used types include:
15+
16+
- booleans: `boolean()`
17+
- strings: `String.t()`
18+
- numbers: `integer()`, `non_neg_integer()`, `pos_integer()`, `float()`
19+
- lists: `list()`
20+
- a value of any type: `any()`
21+
22+
Some types can also be parameterized, for example `list(integer)` is a list of integers.
23+
24+
Literal values can also be used as types.
25+
26+
A union of types can be written using the pipe `|`. For example, `integer() | :error` means either an integer of the atom literal `:error`.
27+
28+
A full list of all types can be found in the ["Typespecs" section in the official documentation][types].
29+
30+
## Naming arguments
31+
32+
Arguments in the typespec could also be named which is useful for distinguishing multiple arguments of the same type. The argument name, followed by a double colon, goes before the argument's type.
33+
34+
```elixir
35+
@spec to_hex({hue :: integer, saturation :: integer, lightness :: integer}) :: String.t()
36+
```
37+
38+
## Custom types
39+
40+
Typespecs aren't limited to just the built-in types. Custom types can be defined using the `@type` module attribute. A custom type definition starts with the type's name, followed by a double colon and then the type itself.
41+
42+
```elixir
43+
@type color :: {hue :: integer, saturation :: integer, lightness :: integer}
44+
45+
@spec to_hex(color()) :: String.t()
46+
```
47+
48+
A custom type can be used from the same module where it's defined, or from another module.
49+
50+
[types]: https://hexdocs.pm/elixir/typespecs.html#types-and-their-syntax

concepts/typespecs/links.json

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
[
2+
{
3+
"url": "https://hexdocs.pm/elixir/typespecs.html",
4+
"description": "Documentation - Typespecs"
5+
},
6+
{
7+
"url": "https://elixirschool.com/en/lessons/advanced/typespec/",
8+
"description": "Elixir School - Typespecs"
9+
}
10+
]

0 commit comments

Comments
 (0)