├── .gitignore
├── .travis.yml
├── CONTRIBUTING.md
├── README-zhCN.md
├── README.md
├── Rakefile
└── mix.exs
/.gitignore:
--------------------------------------------------------------------------------
1 | _build
2 | deps
3 | doc
4 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 |
3 | language: ruby
4 |
5 | rvm:
6 | - 2.3.0
7 |
8 | install:
9 | - gem install mdl rake
10 |
11 | script:
12 | - rake test
13 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing to the Elixir Style Guide
2 |
3 | First of all, thanks for wanting to contribute! :heart:
4 |
5 | You can contribute in several ways:
6 |
7 | * open up an issue if you find something plain old wrong in the style guide
8 | (e.g., typos or formatting);
9 | * open up an issue if you find inconsistencies in the style guide. This way, we
10 | can discuss the better way to eliminate those inconsistencies;
11 | * if you have any suggestions or opinions, open up an issue or (even better!) a
12 | pull request.
13 |
14 | If you edit the `README.md` file, please stick to this set of
15 | formatting/markup/style rules so that the style remains consistent:
16 |
17 | * don't make lines longer than 80 characters (most editors have an auto-wrapping
18 | functionality, for example [Emacs][Emacs LineWrap] or [Vim][Vim word wrap]);
19 | * use reference-style links, like `[an example][Example]`. Put the links in
20 | alphabetical order at the end of the document, and capitalize the first word
21 | of the link label.
22 |
23 | Use Ruby and [Markdownlint] to check your changes:
24 |
25 | ```sh
26 | gem install mdl rake
27 | rake test
28 | ```
29 |
30 | **IMPORTANT**: By submitting a patch, you agree that your work will be
31 | licensed under the license used by the project.
32 |
33 | ## The Project Board
34 |
35 | If you are looking for issues to work on, the [project board][Project KanBan]
36 | is the place to go. Usually, you look at the issues from right to left, as
37 | the ones in the rightmost part are the closer to get merged and have higher
38 | priority.
39 |
40 | If you just want to dive in and start writing, the backlog has the
41 | 'ready to be picked up' issues. These issues have been discussed already and
42 | are most likely just waiting for someone to make a PR. Just look for the
43 | issues with the `enhancement` and/or `help wanted` labels.
44 |
45 | ## Collaborators
46 |
47 | If you have contributed to the repository you can be appointed as a collaborator
48 | after submitting a change and getting it merged. Collaborators are invited to
49 | manage issues, make corrections to the style guide, review pull requests, and
50 | merge approved changes.
51 |
52 | 1. All changes must pass automatic checks before being merged.
53 | 1. Minor changes and corrections can be merged without review.
54 | 1. Significant changes or new style rules should be discussed and approved in a
55 | pull request.
56 |
57 | ## Translations
58 |
59 | If you would like to help translate the Style Guide, check if there is
60 | an [existing translation][Translations] to contribute to. To create a new
61 | translation:
62 |
63 | 1. [Fork] this repository.
64 | 1. Clone your fork locally.
65 | 1. Copy `README.md` to a new file named after the country/language, like
66 | `README-jaJP.md`, and commit your translations there.
67 | 1. Add the main [repo][Repo] as an upstream remote, to fetch and merge changes.
68 |
69 |
70 | [Emacs LineWrap]: http://emacswiki.org/emacs/LineWrap
71 | [Fork]: https://github.com/christopheradams/elixir_style_guide#fork-destination-box
72 | [Markdownlint]: https://github.com/mivok/markdownlint
73 | [Project KanBan]: https://github.com/christopheradams/elixir_style_guide/projects/1
74 | [Repo]: https://github.com/christopheradams/elixir_style_guide.git
75 | [Translations]: README.md#translations
76 | [Vim word wrap]: http://vim.wikia.com/wiki/Automatic_word_wrapping
77 |
--------------------------------------------------------------------------------
/README-zhCN.md:
--------------------------------------------------------------------------------
1 | # [Elixir 风格指南][Elixir Style Guide]
2 |
3 | ## 目录
4 |
5 | * __[序幕](#序幕)__
6 | * __[风格指南](#风格指南)__
7 | * [组织](#组织)
8 | * [语法](#语法)
9 | * [命名](#命名)
10 | * [注释](#注释)
11 | * [注解](#注解)
12 | * [模块](#模块)
13 | * [文档](#文档)
14 | * [类型声明](#类型声明)
15 | * [结构](#结构)
16 | * [异常](#异常)
17 | * 集合
18 | * [字符串](#字符串)
19 | * 正则表达式
20 | * [元编程](#元编程)
21 | * [测试](#测试)
22 | * [更多风格指南](#更多风格指南)
23 | * [工具](#工具)
24 | * __[参与文档](#参与文档)__
25 | * [贡献](#贡献)
26 | * [口耳相传](#口耳相传)
27 | * __[授权](#授权)__
28 | * [协议](#协议)
29 |
30 | ## 序幕
31 |
32 | > 液体架构。像爵士乐一样 - 你们一起即兴演奏,互相回应着对方,你们在创作着音乐,他们在创作着音乐。
33 | >
34 | > —Frank Gehry
35 |
36 | 风格很重要。
37 | [Elixir] 有着大量的风格指南,但是像其他语言一样,这些指南都有可能被扼杀。
38 | 请不要扼杀这份指南。
39 |
40 | ## 风格指南
41 |
42 | 这是一份社群维护的 [Elixir 编程语言][Elixir] 风格指南。
43 |
44 | 欢迎提交 pull requests 和建议来完善这份指南,成为 Elixir 富有活力的社区的一员。
45 |
46 | 你可以在 [Hex 官网][Hex] 寻找其他的项目来贡献代码。
47 |
48 | ### 组织
49 |
50 | *
51 | 使用两个 **空格** 进行缩进,不要使用 Hard Tab。
52 | [[link](#spaces-indentation)]
53 |
54 | ```elixir
55 | # 不好 - 四个空格
56 | def some_function do
57 | do_something
58 | end
59 |
60 | # 好
61 | def some_function do
62 | do_something
63 | end
64 | ```
65 |
66 | *
67 | 使用 Unix 风格换行符 (包括 \*BSD/Solaris/Linux/OSX 的用户, Windows 用户要特别小心)。
68 | [[link](#line-endings)]
69 |
70 | *
71 | 如果你使用 Git,可以使用下面的配置来避免 Windows 风格换行符:
72 | [[link](#autocrlf)]
73 |
74 | ```sh
75 | git config --global core.autocrlf true
76 | ```
77 |
78 | *
79 | 在运算符的两侧添加空格,在逗号`,`,冒号`:`,分号`;`,之后添加空格。
80 | 不要在配对的括号两侧添加空格,例如,小括号`()`,大括号`{}`,等等。
81 | 空格一般来说对 (大部分) Elixir 编译器是无关紧要的,但是恰当的使用空格是写出可读性高的代码的关键。
82 | [[link](#spaces)]
83 |
84 | ```elixir
85 | sum = 1 + 2
86 | {a, b} = {2, 3}
87 | [first | rest] = [1, 2, 3]
88 | Enum.map(["one", <<"two">>, "three"], fn num -> IO.puts num end)
89 | ```
90 |
91 | *
92 | 在仅有一个参数的运算符之后,或者是范围运算符前后,不要添加空格。
93 | [[link](#no-spaces)]
94 |
95 | ```elixir
96 | 0 - 1 == -1
97 | ^pinned = some_func()
98 | 5 in 1..10
99 | ```
100 |
101 | *
102 | 在 `def` 直接使用空行,并且把函数分成合乎逻辑的段落。
103 | [[link](#def-spacing)]
104 |
105 | ```elixir
106 | def some_function(some_data) do
107 | altered_data = Module.function(data)
108 | end
109 |
110 | def some_function do
111 | result
112 | end
113 |
114 | def some_other_function do
115 | another_result
116 | end
117 |
118 | def a_longer_function do
119 | one
120 | two
121 |
122 | three
123 | four
124 | end
125 | ```
126 |
127 | *
128 | ...但是具有相同函数名的单行 `def` 写在一起。
129 | [[link](#single-line-defs)]
130 |
131 | ```elixir
132 | def some_function(nil), do: {:err, "No Value"}
133 | def some_function([]), do: :ok
134 | def some_function([first | rest]) do
135 | some_function(rest)
136 | end
137 | ```
138 |
139 | *
140 | 当你使用 `do:` 的语法声明函数时,如果函数体太长,将 `do:` 放在新的一行,并且进行缩进。
141 | [[link](#long-dos)]
142 |
143 | ```elixir
144 | def some_function(args),
145 | do: Enum.map(args, fn(arg) -> arg <> " is on a very long line!" end)
146 | ```
147 |
148 | 当你使用了上面的风格,并且同时 `do:` 声明多个函数子句时,请把所有的 `do:` 函数子句主体放在
149 |
150 | ```elixir
151 | # 不好
152 | def some_function([]), do: :empty
153 | def some_function(_),
154 | do: :very_long_line_here
155 |
156 | # 好
157 | def some_function([]),
158 | do: :empty
159 | def some_function(_),
160 | do: :very_long_line_here
161 | ```
162 |
163 | *
164 | 如果你使用了多行的 `def`,请不要再使用单行的 `def`。
165 | [[link](#multiple-function-defs)]
166 |
167 | ```elixir
168 | def some_function(nil) do
169 | {:err, "No Value"}
170 | end
171 |
172 | def some_function([]) do
173 | :ok
174 | end
175 |
176 | def some_function([first | rest]) do
177 | some_function(rest)
178 | end
179 |
180 | def some_function([first | rest], opts) do
181 | some_function(rest, opts)
182 | end
183 | ```
184 |
185 | *
186 | 使用管道运算符 (`|>`) 时,函数添加括号。
187 | [[link](#parentheses-pipe-operator)]
188 |
189 | ```elixir
190 | # 不好
191 | some_string |> String.downcase |> String.strip
192 |
193 | # 好
194 | some_string |> String.downcase() |> String.strip()
195 | ```
196 |
197 | *
198 | 使用管道运算符链接多个函数。
199 | [[link](#pipe-operator)]
200 |
201 | ```elixir
202 | # 不好
203 | String.strip(String.downcase(some_string))
204 |
205 | # 好
206 | some_string |> String.downcase() |> String.strip()
207 |
208 | # 多行管道不需要缩进
209 | some_string
210 | |> String.downcase()
211 | |> String.strip()
212 |
213 | # 多行管道在模式匹配的右侧要在下一行缩进
214 | sanitized_string =
215 | some_string
216 | |> String.downcase()
217 | |> String.strip()
218 | ```
219 |
220 | 虽然这是推荐的写法,务必记得在 IEx 中直接粘贴多行管道时,可能会引起错误。这是由于 IEx 会
221 | 直接解释第一行,而不会意识到下一行管道的存在。
222 |
223 | *
224 | 避免只使用一次的管道。
225 | [[link](#avoid-single-pipelines)]
226 |
227 | ```elixir
228 | # 不好
229 | some_string |> String.downcase()
230 |
231 | # 好
232 | String.downcase(some_string)
233 | ```
234 |
235 | *
236 |
237 | 把纯变量放在函数调用链的开头。
238 |
239 | [[link](#bare-variables)]
240 |
241 | ```elixir
242 | # 非常不好!
243 | # 这会被编译为 String.strip("nope" |> String.downcase()).
244 | String.strip "nope" |> String.downcase()
245 |
246 | # 不好
247 | String.strip(some_string) |> String.downcase() |> String.codepoints()
248 |
249 | # 好
250 | some_string |> String.strip() |> String.downcase() |> String.codepoints()
251 | ```
252 |
253 | *
254 |
255 | 多行列表进行赋值时,另起一行,并且列表的元素要进行对齐。
256 |
257 | [[link](#multiline-list-assign)]
258 |
259 | ```elixir
260 | # 不好 - 没有缩进
261 | list = [:first_item, :second_item, :next_item,
262 | :last_item]
263 |
264 | # 好一点 - 进行缩进
265 | list = [:first_item, :second_item, :next_item,
266 | :last_item]
267 |
268 | # 好 - 列表另起一行
269 | # 适合更短,更紧凑的列表
270 | list =
271 | [:first_item, :second_item, :next_item,
272 | :last_item]
273 |
274 | # 同样很好 - 列表的每个元素另起一行
275 | # 适合长列表,长元素列表,或者有注释的列表
276 | list = [
277 | :first_item,
278 | :second_item,
279 | :next_item,
280 | # comment
281 | :many_items,
282 | :last_item
283 | ]
284 | ```
285 |
286 | *
287 | 避免行尾的空白 (trailing whitespace)。
288 | [[link](#trailing-whitespace)]
289 |
290 | *
291 |
292 | 用新的一行来结束源文件。
293 |
294 | [[link](#newline-eof)]
295 |
296 | ### 语法
297 |
298 | *
299 |
300 | 有参函数使用括号,否则省略括号。
301 |
302 | [[link](#parentheses)]
303 |
304 | ```elixir
305 | # 不好
306 | def some_function arg1, arg2 do
307 | # body omitted
308 | end
309 |
310 | def some_function() do
311 | # body omitted
312 | end
313 |
314 | # 好
315 | def some_function(arg1, arg2) do
316 | # body omitted
317 | end
318 |
319 | def some_function do
320 | # body omitted
321 | end
322 | ```
323 |
324 | *
325 |
326 | 多行赋值后添加空行,表示赋值结束。
327 |
328 | [[link](#add-blank-line-after-multiline-assignment)]
329 |
330 | ```elixir
331 | # 不好
332 | some_string =
333 | "Hello"
334 | |> String.downcase()
335 | |> String.strip()
336 | another_string <> some_string
337 |
338 | # 好
339 | some_string =
340 | "Hello"
341 | |> String.downcase()
342 | |> String.strip()
343 |
344 | another_string <> some_string
345 | ```
346 |
347 | ```elixir
348 | # 不好
349 | something =
350 | if x == 2 do
351 | "Hi"
352 | else
353 | "Bye"
354 | end
355 | String.downcase(something)
356 |
357 | # 好
358 | something =
359 | if x == 2 do
360 | "Hi"
361 | else
362 | "Bye"
363 | end
364 |
365 | String.downcase(something)
366 | ```
367 |
368 | *
369 |
370 | 多行 `if/unless` 时,避免使用 `do:`。
371 |
372 | [[link](#do-with-multi-line-if-unless)]
373 |
374 | ```elixir
375 | # 不好
376 | if some_condition, do:
377 | # a line of code
378 | # another line of code
379 | # note no end in this block
380 |
381 | # 好
382 | if some_condition do
383 | # some
384 | # lines
385 | # of code
386 | end
387 | ```
388 |
389 | *
390 |
391 | 单行 `if/unless` 时使用 `do:`。
392 |
393 | [[link](#do-with-single-line-if-unless)]
394 |
395 | ```elixir
396 | # 好
397 | if some_condition, do: # some_stuff
398 | ```
399 |
400 | *
401 |
402 | 避免使用 `unless` 搭配 `else`,将它们改写为肯定条件。
403 |
404 | [[link](#unless-with-else)]
405 |
406 | ```elixir
407 | # 不好
408 | unless success? do
409 | IO.puts 'failure'
410 | else
411 | IO.puts 'success'
412 | end
413 |
414 | # 好
415 | if success? do
416 | IO.puts 'success'
417 | else
418 | IO.puts 'failure'
419 | end
420 | ```
421 |
422 | *
423 |
424 | `cond` 的最后一个条件一定是 `true` 。
425 |
426 | [[link](#true-as-last-condition)]
427 |
428 | ```elixir
429 | # 不好
430 | cond do
431 | 1 + 2 == 5 ->
432 | "Nope"
433 | 1 + 3 == 5 ->
434 | "Uh, uh"
435 | :else ->
436 | "OK"
437 | end
438 |
439 | # 好
440 | cond do
441 | 1 + 2 == 5 ->
442 | "Nope"
443 | 1 + 3 == 5 ->
444 | "Uh, uh"
445 | true ->
446 | "OK"
447 | end
448 | ```
449 |
450 | *
451 |
452 | 不要在函数名和左括号之间添加空格。
453 |
454 | [[link](#function-names-with-parentheses)]
455 |
456 | ```elixir
457 | # 不好
458 | f (3 + 2) + 1
459 |
460 | # 好
461 | f(3 + 2) + 1
462 | ```
463 |
464 | *
465 |
466 | 函数调用时使用括号,特别在使用管道时。
467 |
468 | [[link](#function-calls-and-parentheses)]
469 |
470 | ```elixir
471 | # 不好
472 | f 3
473 |
474 | # 好
475 | f(3)
476 |
477 | # 不好
478 | 2 |> rem 3 |> g
479 |
480 | # 好
481 | 2 |> rem(3) |> g
482 | ```
483 |
484 | *
485 |
486 | 当使用 `do` 块调用宏时,省略括号。
487 |
488 | [[link](#macro-calls-and-parentheses)]
489 |
490 | ```elixir
491 | # 不好
492 | quote(do
493 | foo
494 | end)
495 |
496 | # 好
497 | quote do
498 | foo
499 | end
500 | ```
501 |
502 | *
503 |
504 | 当函数调用在管道之外,并且最后一个参数是函数表达式时,可以选择性的省略括号。
505 |
506 | [[link](#parentheses-and-function-expressions)]
507 |
508 | ```elixir
509 | # 好
510 | Enum.reduce(1..10, 0, fn x, acc ->
511 | x + acc
512 | end)
513 |
514 | # 同样好
515 | Enum.reduce 1..10, 0, fn x, acc ->
516 | x + acc
517 | end
518 | ```
519 |
520 | *
521 |
522 | 无参函数调用时添加括号,以便和变量进行区分。
523 |
524 | 从 Elixir 1.4 开始,编译器会在有歧义的地方发出警告。
525 |
526 | [[link](#parentheses-and-functions-with-zero-arity)]
527 |
528 | ```elixir
529 | defp do_stuff, do: ...
530 |
531 | # 不好
532 | def my_func do
533 | do_stuff # 这是变量还是函数调用?
534 | end
535 |
536 | # 好用
537 | def my_func do
538 | do_stuff() # 这是一个明确的函数调用
539 | end
540 | ```
541 |
542 | *
543 |
544 | 关键字列表总是使用特殊语法。
545 |
546 | [[link](#keyword-list-syntax)]
547 |
548 | ```elixir
549 | # 不好
550 | some_value = [{:a, "baz"}, {:b, "qux"}]
551 |
552 | # 好
553 | some_value = [a: "baz", b: "qux"]
554 | ```
555 |
556 | *
557 |
558 | 当关键字列表的括号可选时则省略。
559 |
560 | [[link](#keyword-list-brackets)]
561 |
562 | ```elixir
563 | # 不好
564 | some_function(foo, bar, [a: "baz", b: "qux"])
565 |
566 | # 好
567 | some_function(foo, bar, a: "baz", b: "qux")
568 | ```
569 |
570 | *
571 |
572 | 缩排 `with` 的多个条件,`do` 的参数在新的一行正常缩进。
573 |
574 | [[link](#with-clauses)]
575 |
576 | ```elixir
577 | with {:ok, foo} <- fetch(opts, :foo),
578 | {:ok, bar} <- fetch(opts, :bar),
579 | do: {:ok, foo, bar}
580 | ```
581 |
582 | *
583 |
584 | 如果 `with` 表达式 `do` 块超过了一行,或者使用了 `else`,请使用多行语法。
585 |
586 | [[link](#with-else)]
587 |
588 | ```elixir
589 | with {:ok, foo} <- fetch(opts, :foo),
590 | {:ok, bar} <- fetch(opts, :bar) do
591 | {:ok, foo, bar}
592 | else
593 | :error ->
594 | {:error, :bad_arg}
595 | end
596 | ```
597 |
598 | ### 命名
599 |
600 | *
601 |
602 | 符号,方法,变量,使用蛇底式 (`snake_case`)。
603 |
604 | [[link](#snake-case)]
605 |
606 | ```elixir
607 | # 不好
608 | :"some atom"
609 | :SomeAtom
610 | :someAtom
611 |
612 | someVar = 5
613 |
614 | def someFunction do
615 | ...
616 | end
617 |
618 | def SomeFunction do
619 | ...
620 | end
621 |
622 | # 好
623 | :some_atom
624 |
625 | some_var = 5
626 |
627 | def some_function do
628 | ...
629 | end
630 | ```
631 |
632 | *
633 |
634 | 模块名使用驼峰式 (`CamelCase`) (保留像是 HTTP, RFC, XML 这种缩写为大写形式)。
635 |
636 | [[link](#camel-case)]
637 |
638 | ```elixir
639 | # 不好
640 | defmodule Somemodule do
641 | ...
642 | end
643 |
644 | defmodule Some_Module do
645 | ...
646 | end
647 |
648 | defmodule SomeXml do
649 | ...
650 | end
651 |
652 | # 好
653 | defmodule SomeModule do
654 | ...
655 | end
656 |
657 | defmodule SomeXML do
658 | ...
659 | end
660 | ```
661 |
662 | *
663 |
664 | 可以在 `guard clause` 中使用的谓词宏 (编译期生成返回布尔值的函数),命名应该使用 `is_` 前缀。
665 |
666 | 允许的表达式列表,请参考 [Guard][Guard Expressions] 文档。
667 |
668 | [[link](#predicate-macro-names-with-guards)]
669 |
670 | ```elixir
671 | defmacro is_cool(var) do
672 | quote do: unquote(var) == "cool"
673 | end
674 | ```
675 |
676 | *
677 |
678 | 谓词函数,无法在 `guard clause` 中使用,命名时应该以 `?` 结尾,而不是 `is_` 作为前缀。
679 |
680 | [[link](#predicate-macro-names-no-guards)]
681 |
682 | ```elixir
683 | def cool?(var) do
684 | # Complex check if var is cool not possible in a pure function.
685 | end
686 | ```
687 |
688 | *
689 |
690 | 当私有函数和公共函数具有相同的名称时,使用 `do_` 作为前缀。
691 |
692 | [[link](#private-functions-with-same-name-as-public)]
693 |
694 | ```elixir
695 | def sum(list), do: do_sum(list, 0)
696 |
697 | # private functions
698 | defp do_sum([], total), do: total
699 | defp do_sum([head | tail], total), do: do_sum(tail, head + total)
700 | ```
701 |
702 | ### 注释
703 |
704 | *
705 |
706 | 编写富有表现力的代码,通过控制流,结构和命名来表达程序的意图。
707 |
708 | [[link](#expressive-code)]
709 |
710 | *
711 |
712 | 在注释的 `#` 之后,保留一个空格。
713 |
714 | [[link](#comment-leading-spaces)]
715 |
716 | ```elixir
717 | String.first(some_string) #不好
718 | String.first(some_string) # 好
719 | ```
720 |
721 | *
722 |
723 | 一个字以上的注释需要使用正确的英文大小写以及标点符号,并且在句号后添加空格。
724 |
725 | [[link](#comment-grammar)]
726 |
727 | ```elixir
728 | # 不好
729 | # these lowercase comments are missing punctuation
730 |
731 | # 好
732 | # Capitalization example
733 | # Use punctuation for complete sentences.
734 | ```
735 |
736 | #### 注解
737 |
738 | *
739 |
740 | 注解通常写在相关代码的上一行。
741 |
742 | [[link](#annotations)]
743 |
744 | *
745 |
746 | 注解关键字要大写,紧接着是一个冒号和一个空格,然后是问题的描述。
747 |
748 | [[link](#annotation-keyword)]
749 |
750 | ```elixir
751 | # TODO: Deprecate in v1.5.
752 | def some_function(arg), do: {:ok, arg}
753 | ```
754 |
755 | *
756 |
757 | 在问题显而易见的情况下,任何说明都是多余的,注解要放到代码的最后并且不带任何解释。
758 |
759 | 这个用法是特例而不是规则。
760 |
761 | [[link](#exceptions-to-annotations)]
762 |
763 | ```elixir
764 | start_task()
765 | Process.sleep(5000) # FIXME
766 | ```
767 |
768 | *
769 |
770 | 使用 `TODO` 来标记未来要实现功能或特性。
771 |
772 | [[link](#todo-notes)]
773 |
774 | *
775 |
776 | 使用 `FIXME` 来标记要被修复的代码。
777 |
778 | [[link](#fixme-notes)]
779 |
780 | *
781 |
782 | 使用 `OPTIMIZE` 来标记可能会引起性能问题的缓慢或者低效的代码。
783 |
784 | [[link](#optimize-notes)]
785 |
786 | *
787 |
788 | 使用 `HACK` 来比较代码中的坏味道,这些有问题的编码实践应当被重构。
789 |
790 | [[link](#hack-notes)]
791 |
792 | *
793 |
794 | 使用 `REVIEW` 来标记需要确认是否正常工作的地方。
795 |
796 | 例如: `REVIEW: Are we sure this is how the client does X currently?`
797 | [[link](#review-notes)]
798 |
799 | *
800 |
801 | 如果你觉得需要的话,使用其他自定义的关键字,并将它们记录到 `README` 或者其他类似的文档中。
802 |
803 | [[link](#custom-keywords)]
804 |
805 | ### 模块
806 |
807 | *
808 |
809 | 每个源文件内只有一个模块,除非模块只在另一个模块内部使用 (例如测试)。
810 |
811 | [[link](#one-module-per-file)]
812 |
813 | *
814 |
815 | 文件名使用 `蛇底式` (`snake_case`),模块名使用 `驼峰式` (`CamelCase`)。
816 |
817 | [[link](#underscored-filenames)]
818 |
819 | ```elixir
820 | # file is called some_module.ex
821 |
822 | defmodule SomeModule do
823 | end
824 | ```
825 |
826 | *
827 |
828 | 嵌套模块命名中的每一层代表一层文件夹。
829 |
830 | [[link](#module-name-nesting)]
831 |
832 | ```elixir
833 | # file is called parser/core/xml_parser.ex
834 |
835 | defmodule Parser.Core.XMLParser do
836 | end
837 | ```
838 |
839 | *
840 |
841 | `defmodule` 之后不要添加空行。
842 |
843 | [[link](#defmodule-spacing)]
844 |
845 | *
846 |
847 | 模块代码之后添加空行。
848 |
849 | [[link](#module-block-spacing)]
850 |
851 | *
852 |
853 | 模块属性和指令要按照下面的顺序:
854 |
855 | [[link](#module-attribute-ordering)]
856 |
857 | 1. `@moduledoc`
858 | 2. `@behaviour`
859 | 3. `use`
860 | 4. `import`
861 | 5. `alias`
862 | 6. `require`
863 | 7. `defstruct`
864 | 8. `@type`
865 | 9. `@module_attribute`
866 | 10. `@callback`
867 | 11. `@macrocallback`
868 | 12. `@optional_callbacks`
869 |
870 | 在每一组属性或者指令后加入空行,并且本组的项目 (例如,模块名) 要按照字母排序。
871 |
872 | 这里有一个完整的例子:
873 |
874 | ```elixir
875 | defmodule MyModule do
876 | @moduledoc """
877 | An example module
878 | """
879 |
880 | @behaviour MyBehaviour
881 |
882 | use GenServer
883 |
884 | import Something
885 | import SomethingElse
886 |
887 | alias My.Long.Module.Name
888 | alias My.Other.Module.Example
889 |
890 | require Integer
891 |
892 | defstruct name: nil, params: []
893 |
894 | @type params :: [{binary, binary}]
895 |
896 | @module_attribute :foo
897 | @other_attribute 100
898 |
899 | @callback some_function(term) :: :ok | {:error, term}
900 |
901 | @macrocallback macro_name(term) :: Macro.t
902 |
903 | @optional_callbacks macro_name: 1
904 |
905 | ...
906 | end
907 | ```
908 |
909 | *
910 | 当模块引用自身时使用 `__MODULE__` 伪变量。
911 |
912 | 如果模块名称修改,可以避免更新对模块自身的引用。
913 |
914 | [[link](#module-pseudo-variable)]
915 |
916 | ```elixir
917 | defmodule SomeProject.SomeModule do
918 | defstruct [:name]
919 |
920 | def name(%__MODULE__{name: name}), do: name
921 | end
922 | ```
923 |
924 | *
925 |
926 | 设置一个别名,可以让模块名更具可读性。
927 |
928 | [[link](#alias-self-referencing-modules)]
929 |
930 | ```elixir
931 | defmodule SomeProject.SomeModule do
932 | alias __MODULE__, as: SomeModule
933 |
934 | defstruct [:name]
935 |
936 | def name(%SomeModule{name: name}), do: name
937 | end
938 | ```
939 |
940 | *
941 | 避免在模块名和命名空间中使用重复的名称,这样提高可读性并且消除 [ambiguous aliases][Conflicting Aliases]。
942 |
943 | [[link](#repetitive-module-names)]
944 |
945 | ```elixir
946 | # 不好
947 | defmodule Todo.Todo do
948 | ...
949 | end
950 |
951 | # 好
952 | defmodule Todo.Item do
953 | ...
954 | end
955 | ```
956 |
957 | ### 文档
958 |
959 | 使用模块变量 (Module Attributes) `@moduledoc` 和 `@doc` 声明文档 (在 `iex` 使用 `h`查看或者使用 [ExDoc] 生成)。
960 |
961 | *
962 |
963 | 在 `defmodule` 之后下一行总是定义 `@moduledoc` 变量。
964 |
965 | [[link](#moduledocs)]
966 |
967 | ```elixir
968 | # 不好
969 |
970 | defmodule SomeModule do
971 |
972 | @moduledoc """
973 | About the module
974 | """
975 | ...
976 | end
977 |
978 | defmodule AnotherModule do
979 | use SomeModule
980 | @moduledoc """
981 | About the module
982 | """
983 | ...
984 | end
985 |
986 | # 好
987 |
988 | defmodule SomeModule do
989 | @moduledoc """
990 | About the module
991 | """
992 | ...
993 | end
994 | ```
995 |
996 | *
997 |
998 | 使用 `@moduledoc false`,如果你不想为这个模块增加文档。
999 |
1000 | [[link](#moduledoc-false)]
1001 |
1002 | ```elixir
1003 | defmodule SomeModule do
1004 | @moduledoc false
1005 | ...
1006 | end
1007 | ```
1008 |
1009 | *
1010 |
1011 | `@moduledoc` 之后添加一个空行,与其他代码分开。
1012 |
1013 | [[link](#moduledoc-spacing)]
1014 |
1015 | ```elixir
1016 | # 不好
1017 |
1018 | defmodule SomeModule do
1019 | @moduledoc """
1020 | About the module
1021 | """
1022 | use AnotherModule
1023 | end
1024 |
1025 | # 好
1026 | defmodule SomeModule do
1027 | @moduledoc """
1028 | About the module
1029 | """
1030 |
1031 | use AnotherModule
1032 | end
1033 | ```
1034 |
1035 | *
1036 |
1037 | 在文档内使用 `heredocs` 和 `markdown`。
1038 |
1039 | [[link](#heredocs)]
1040 |
1041 | ```elixir
1042 | # 不好
1043 |
1044 | defmodule SomeModule do
1045 | @moduledoc "About the module"
1046 | end
1047 |
1048 | defmodule SomeModule do
1049 | @moduledoc """
1050 | About the module
1051 |
1052 | Examples:
1053 | iex> SomeModule.some_function
1054 | :result
1055 | """
1056 | end
1057 |
1058 | # 好
1059 | defmodule SomeModule do
1060 | @moduledoc """
1061 | About the module
1062 |
1063 | ## Examples
1064 |
1065 | iex> SomeModule.some_function
1066 | :result
1067 | """
1068 | end
1069 | ```
1070 |
1071 | ### 类型声明 (Typespecs)
1072 |
1073 | Typespecs是用于声明类型和规格的符号,主要用于文档或是静态分析工具,例如 Dialyzer。
1074 |
1075 | 自定义类型应当与其他指令一起位于模块的顶部。 (详见 [模块](#modules)).
1076 |
1077 | *
1078 |
1079 | 同时使用 `@typedoc` 和 `@type`,并且每对之间使用空行间隔。
1080 |
1081 | [[link](#typedocs)]
1082 |
1083 | ```elixir
1084 | defmodule SomeModule do
1085 | @moduledoc false
1086 |
1087 | @typedoc "The name"
1088 | @type name :: atom
1089 |
1090 | @typedoc "The result"
1091 | @type result :: {:ok, term} | {:error, term}
1092 |
1093 | ...
1094 | end
1095 | ```
1096 |
1097 | *
1098 |
1099 | 如果联合类型 (union type) 声明超过一行,增加新的一行并且使用空格缩进,保持类型对齐。
1100 |
1101 | [[link](#union-types)]
1102 |
1103 | ```elixir
1104 | # 不好 - 没有缩进
1105 | @type long_union_type :: some_type | another_type | some_other_type |
1106 | a_final_type
1107 |
1108 | # 好
1109 | @type long_union_type :: some_type | another_type | some_other_type |
1110 | a_final_type
1111 |
1112 | # 同样好 - 每一个类型单独一行
1113 | @type long_union_type :: some_type |
1114 | another_type |
1115 | some_other_type |
1116 | a_final_type
1117 | ```
1118 |
1119 | *
1120 |
1121 | 模块的主类型命名为 `t`,例子:结构的类型声明。
1122 |
1123 | [[link](#naming-main-types)]
1124 |
1125 | ```elixir
1126 | defstruct name: nil, params: []
1127 |
1128 | @type t :: %__MODULE__{
1129 | name: String.t | nil,
1130 | params: Keyword.t
1131 | }
1132 | ```
1133 |
1134 | *
1135 |
1136 | 将函数的类型声明放到函数定义之上,不用空行间隔。
1137 |
1138 | [[link](#spec-spacing)]
1139 |
1140 | ```elixir
1141 | @spec some_function(term) :: result
1142 | def some_function(some_data) do
1143 | {:ok, some_data}
1144 | end
1145 | ```
1146 |
1147 | ### 结构
1148 |
1149 | *
1150 | 默认值为 `nil` 的结构字段使用原子符号列表 (list of atoms),后面紧跟着其他关键字。
1151 |
1152 | [[link](#nil-struct-field-defaults)]
1153 |
1154 | ```elixir
1155 | # 不好
1156 | defstruct name: nil, params: nil, active: true
1157 |
1158 | # 好
1159 | defstruct [:name, :params, active: true]
1160 | ```
1161 |
1162 | *
1163 |
1164 | 如果 `defstruct` 的参数是关键字列表 (keyword list),则省略括号。
1165 |
1166 | [[link](#struct-def-brackets)]
1167 |
1168 | ```elixir
1169 | # 不好
1170 | defstruct [params: [], active: true]
1171 |
1172 | # 好
1173 | defstruct params: [], active: true
1174 |
1175 | # 必须 - 由于至少有一个原子符号,括号不可以省略
1176 | defstruct [:name, params: [], active: true]
1177 | ```
1178 |
1179 | *
1180 |
1181 | 如果结构定义是多行,保持每行第一个键缩进对齐。
1182 |
1183 | [[link](#additional-struct-def-lines)]
1184 |
1185 | ```elixir
1186 | defstruct foo: "test", bar: true, baz: false,
1187 | qux: false, quux: 1
1188 | ```
1189 |
1190 | ### 异常
1191 |
1192 | *
1193 |
1194 | 异常的命名以 `Error` 结尾。
1195 |
1196 | [[link](#exception-names)]
1197 |
1198 | ```elixir
1199 | # 不好
1200 | defmodule BadHTTPCode do
1201 | defexception [:message]
1202 | end
1203 |
1204 | defmodule BadHTTPCodeException do
1205 | defexception [:message]
1206 | end
1207 |
1208 | # 好
1209 | defmodule BadHTTPCodeError do
1210 | defexception [:message]
1211 | end
1212 | ```
1213 |
1214 | *
1215 |
1216 | 抛出异常时,异常信息使用小写,并且最后不需要添加标点符号。
1217 |
1218 | [[link](#lowercase-error-messages)]
1219 |
1220 | ```elixir
1221 | # 不好
1222 | raise ArgumentError, "This is not valid."
1223 |
1224 | # 好
1225 | raise ArgumentError, "this is not valid"
1226 | ```
1227 |
1228 | ### 集合
1229 |
1230 | 暂无内容。
1231 |
1232 | ### 字符串
1233 |
1234 | *
1235 |
1236 | 字符串进行模式匹配时,使用字符串拼接的方式而不要使用二进制的方式。
1237 |
1238 | [[link](#strings-matching-with-concatenator)]
1239 |
1240 | ```elixir
1241 | # 不好
1242 | <<"my"::utf8, _rest>> = "my string"
1243 |
1244 | # 好
1245 | "my" <> _rest = "my string"
1246 | ```
1247 |
1248 | ### 正则表达式
1249 |
1250 | 暂无内容。
1251 |
1252 | ### 元编程 (metaprogramming)
1253 |
1254 | *
1255 | 避免不必要的元编程。
1256 | [[link](#avoid-metaprogramming)]
1257 |
1258 | ### 测试
1259 |
1260 | *
1261 |
1262 | 在编写 [ExUnit] 断言 (assertions) 时,保持预期值和测试值顺序的一致性。
1263 |
1264 | 尽量把预期值放在右边,除非这条断言在进行模式匹配。
1265 |
1266 | [[link](#testing-assert-order)]
1267 |
1268 | ```elixir
1269 | # 好 - 预期值在右边
1270 | assert actual_function(1) == true
1271 | assert actual_function(2) == false
1272 |
1273 | # 不好 - 顺序不一致
1274 | assert actual_function(1) == true
1275 | assert false == actual_function(2)
1276 |
1277 | # 必要 - 断言是模式匹配
1278 | assert {:ok, expected} = actual_function(3)
1279 | ```
1280 |
1281 | ### 更多风格指南
1282 |
1283 | * [Aleksei Magusev's Elixir Style Guide](https://github.com/lexmag/elixir-style-guide#readme)
1284 | — An opinionated Elixir style guide stemming from the coding style practiced
1285 | in the Elixir core libraries.
1286 | Developed by [Aleksei Magusev](https://github.com/lexmag) and
1287 | [Andrea Leopardi](https://github.com/whatyouhide), members of Elixir core team.
1288 | While the Elixir project doesn't adhere to any specific style guide,
1289 | this is the closest available guide to its conventions.
1290 |
1291 | * [Credo's Elixir Style Guide](https://github.com/rrrene/elixir-style-guide#readme)
1292 | — Style Guide for the Elixir language, implemented by
1293 | [Credo](http://credo-ci.org) static code analysis tool.
1294 |
1295 | ### 工具
1296 |
1297 | 参考 [Awesome Elixir][Code Analysis] 来了解可以帮助代码分析的库和工具。
1298 |
1299 | ## 参与文档
1300 |
1301 | ### 贡献
1302 |
1303 | 我们希望这将成为社区讨论 Elixir 最佳实践的中心。
1304 |
1305 | 欢迎发起讨论或提交一个带有改进性质的更新请求。在此提前感谢你的帮助!
1306 |
1307 | 参考 [contributing guidelines][Contributing]
1308 | 和 [code of conduct][Code Of Conduct] 获得更多信息。
1309 |
1310 | ### 口耳相传
1311 |
1312 | 一份社区驱动的风格指南,如果没多少人知道, 对一个社区来说就没有多少用处。
1313 |
1314 | 请转发,关注这份指南,让每一个 Elixir 程序员都知晓这份指南,让每一个 Elixir 程序员都可以贡献这份指南!
1315 |
1316 | ## 授权
1317 |
1318 | ### 协议
1319 |
1320 | 
1321 | 本指南基于
1322 | [Creative Commons Attribution 3.0 Unported License][License] 授权许可。
1323 |
1324 |
1325 | [Chinese Simplified]: https://github.com/geekerzp/elixir_style_guide/blob/master/README-zhCN.md
1326 | [Chinese Traditional]: https://github.com/elixirtw/elixir_style_guide/blob/master/README_zhTW.md
1327 | [Code Analysis]: https://github.com/h4cc/awesome-elixir#code-analysis
1328 | [Code Of Conduct]: https://github.com/christopheradams/elixir_style_guide/blob/master/CODE_OF_CONDUCT.md
1329 | [Conflicting Aliases]: https://elixirforum.com/t/using-aliases-for-fubar-fubar-named-module/1723
1330 | [Contributing]: https://github.com/elixir-lang/elixir/blob/master/CODE_OF_CONDUCT.md
1331 | [Contributors]: https://github.com/christopheradams/elixir_style_guide/graphs/contributors
1332 | [Elixir Style Guide]: https://github.com/christopheradams/elixir_style_guide
1333 | [Elixir]: http://elixir-lang.org
1334 | [ExDoc]: https://github.com/elixir-lang/ex_doc
1335 | [ExUnit]: https://hexdocs.pm/ex_unit/ExUnit.html
1336 | [Guard Expressions]: http://elixir-lang.org/getting-started/case-cond-and-if.html#expressions-in-guard-clauses
1337 | [Hex]: https://hex.pm/packages
1338 | [Japanese]: https://github.com/kenichirow/elixir_style_guide/blob/master/README-jaJP.md
1339 | [Korean]: https://github.com/marocchino/elixir_style_guide/blob/new-korean/README-koKR.md
1340 | [License]: http://creativecommons.org/licenses/by/3.0/deed.en_US
1341 | [Module Attributes]: http://elixir-lang.org/getting-started/module-attributes.html#as-annotations
1342 | [Portuguese]: https://github.com/gusaiani/elixir_style_guide/blob/master/README_ptBR.md
1343 | [Ruby community style guide]: https://github.com/bbatsov/ruby-style-guide
1344 | [Sentence Spacing]: http://en.wikipedia.org/wiki/Sentence_spacing
1345 | [Spanish]: https://github.com/albertoalmagro/elixir_style_guide/blob/spanish/README_esES.md
1346 | [Stargazers]: https://github.com/christopheradams/elixir_style_guide/stargazers
1347 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # [The Elixir Style Guide][Elixir Style Guide]
2 |
3 | ## Table of Contents
4 |
5 | * __[Prelude](#prelude)__
6 | * __[The Guide](#the-guide)__
7 | * [Source Code Layout](#source-code-layout)
8 | * [Syntax](#syntax)
9 | * [Naming](#naming)
10 | * [Comments](#comments)
11 | * [Comment Annotations](#comment-annotations)
12 | * [Modules](#modules)
13 | * [Documentation](#documentation)
14 | * [Typespecs](#typespecs)
15 | * [Structs](#structs)
16 | * [Exceptions](#exceptions)
17 | * _Collections_
18 | * [Strings](#strings)
19 | * _Regular Expressions_
20 | * [Metaprogramming](#metaprogramming)
21 | * [Testing](#testing)
22 | * [Alternative Style Guides](#alternative-style-guides)
23 | * [Tools](#tools)
24 | * __[Getting Involved](#getting-involved)__
25 | * [Contributing](#contributing)
26 | * [Spread the Word](#spread-the-word)
27 | * __[Copying](#copying)__
28 | * [License](#license)
29 | * [Attribution](#attribution)
30 |
31 | ## Prelude
32 |
33 | > Liquid architecture. It's like jazz — you improvise, you work together, you
34 | > play off each other, you make something, they make something.
35 | >
36 | > —Frank Gehry
37 |
38 | Style matters.
39 | [Elixir] has plenty of style but like all languages it can be stifled.
40 | Don't stifle the style.
41 |
42 | ## The Guide
43 |
44 | This is community style guide for the [Elixir programming language][Elixir].
45 | Please feel free to make pull requests and suggestions, and be a part of
46 | Elixir's vibrant community.
47 |
48 | If you're looking for other projects to contribute to please see the
49 | [Hex package manager site][Hex].
50 |
51 |
52 | Translations of the guide are available in the following languages:
53 |
54 | * [Chinese Simplified]
55 | * [Chinese Traditional]
56 | * [Japanese]
57 | * [Korean]
58 | * [Portuguese]
59 | * [Spanish]
60 |
61 | ### Source Code Layout
62 |
63 | *
64 | Use two **spaces** per indentation level.
65 | No hard tabs.
66 | [[link](#spaces-indentation)]
67 |
68 | ```elixir
69 | # not preferred - four spaces
70 | def some_function do
71 | do_something
72 | end
73 |
74 | # preferred
75 | def some_function do
76 | do_something
77 | end
78 | ```
79 |
80 | *
81 | Use Unix-style line endings (\*BSD/Solaris/Linux/OSX users are covered by
82 | default, Windows users have to be extra careful).
83 | [[link](#line-endings)]
84 |
85 | *
86 | If you're using Git you might want to add the following configuration
87 | setting to protect your project from Windows line endings creeping in:
88 | [[link](#autocrlf)]
89 |
90 | ```sh
91 | git config --global core.autocrlf true
92 | ```
93 |
94 | *
95 | Use spaces around operators, after commas, colons and semicolons.
96 | Do not put spaces around matched pairs like brackets, parentheses, etc.
97 | Whitespace might be (mostly) irrelevant to the Elixir runtime, but its proper
98 | use is the key to writing easily readable code.
99 | [[link](#spaces)]
100 |
101 | ```elixir
102 | sum = 1 + 2
103 | {a, b} = {2, 3}
104 | [first | rest] = [1, 2, 3]
105 | Enum.map(["one", <<"two">>, "three"], fn num -> IO.puts num end)
106 | ```
107 |
108 | *
109 | Do not use spaces after non-word operators that only take one argument; or
110 | around the range operator.
111 | [[link](#no-spaces)]
112 |
113 | ```elixir
114 | 0 - 1 == -1
115 | ^pinned = some_func()
116 | 5 in 1..10
117 | ```
118 |
119 | *
120 | Use blank lines between `def`s to break up a function into logical
121 | paragraphs.
122 | [[link](#def-spacing)]
123 |
124 | ```elixir
125 | def some_function(some_data) do
126 | altered_data = Module.function(data)
127 | end
128 |
129 | def some_function do
130 | result
131 | end
132 |
133 | def some_other_function do
134 | another_result
135 | end
136 |
137 | def a_longer_function do
138 | one
139 | two
140 |
141 | three
142 | four
143 | end
144 | ```
145 |
146 | *
147 | ...but run single-line `def`s that match for the same function together.
148 | [[link](#single-line-defs)]
149 |
150 | ```elixir
151 | def some_function(nil), do: {:err, "No Value"}
152 | def some_function([]), do: :ok
153 | def some_function([first | rest]) do
154 | some_function(rest)
155 | end
156 | ```
157 |
158 | *
159 | If you use the `do:` syntax with functions and the line that makes up the
160 | function body is long, put the `do:` on a new line indented one level more
161 | than the previous line.
162 | [[link](#long-dos)]
163 |
164 | ```elixir
165 | def some_function(args),
166 | do: Enum.map(args, fn(arg) -> arg <> " is on a very long line!" end)
167 | ```
168 |
169 | When you use the convention above and you have more than one function clause
170 | using the `do:` syntax, put the `do:` on a new line for each function clause:
171 |
172 | ```elixir
173 | # not preferred
174 | def some_function([]), do: :empty
175 | def some_function(_),
176 | do: :very_long_line_here
177 |
178 | # preferred
179 | def some_function([]),
180 | do: :empty
181 | def some_function(_),
182 | do: :very_long_line_here
183 | ```
184 |
185 | *
186 | If you have more than one multi-line `def`s do not use single-line `def`s.
187 | [[link](#multiple-function-defs)]
188 |
189 | ```elixir
190 | def some_function(nil) do
191 | {:err, "No Value"}
192 | end
193 |
194 | def some_function([]) do
195 | :ok
196 | end
197 |
198 | def some_function([first | rest]) do
199 | some_function(rest)
200 | end
201 |
202 | def some_function([first | rest], opts) do
203 | some_function(rest, opts)
204 | end
205 | ```
206 |
207 | *
208 | Use parentheses for one-arity functions when using the pipe operator (`|>`).
209 | [[link](#parentheses-pipe-operator)]
210 |
211 | ```elixir
212 | # not preferred
213 | some_string |> String.downcase |> String.strip
214 |
215 | # preferred
216 | some_string |> String.downcase() |> String.strip()
217 | ```
218 |
219 | *
220 | Use the pipe operator to chain functions together.
221 | [[link](#pipe-operator)]
222 |
223 | ```elixir
224 | # not preferred
225 | String.strip(String.downcase(some_string))
226 |
227 | # preferred
228 | some_string |> String.downcase() |> String.strip()
229 |
230 | # Multiline pipelines are not further indented
231 | some_string
232 | |> String.downcase()
233 | |> String.strip()
234 |
235 | # Multiline pipelines on the right side of a pattern match
236 | # should be indented on a new line
237 | sanitized_string =
238 | some_string
239 | |> String.downcase()
240 | |> String.strip()
241 | ```
242 |
243 | While this is the preferred method, take into account that copy-pasting
244 | multiline pipelines into IEx might result in a syntax error, as IEx will
245 | evaluate the first line without realizing that the next line has a pipeline.
246 |
247 | *
248 | Avoid using the pipe operator just once.
249 | [[link](#avoid-single-pipelines)]
250 |
251 | ```elixir
252 | # not preferred
253 | some_string |> String.downcase()
254 |
255 | # preferred
256 | String.downcase(some_string)
257 | ```
258 |
259 | *
260 | Use _bare_ variables in the first part of a function chain.
261 | [[link](#bare-variables)]
262 |
263 | ```elixir
264 | # THE WORST!
265 | # This actually parses as String.strip("nope" |> String.downcase()).
266 | String.strip "nope" |> String.downcase()
267 |
268 | # not preferred
269 | String.strip(some_string) |> String.downcase() |> String.codepoints()
270 |
271 | # preferred
272 | some_string |> String.strip() |> String.downcase() |> String.codepoints()
273 | ```
274 |
275 | *
276 | When assigning a list that spans multiple lines, start the list on a newline,
277 | and indent the elements to keep them aligned.
278 | [[link](#multiline-list-assign)]
279 |
280 | ```elixir
281 | # not preferred - no indentation
282 | list = [:first_item, :second_item, :next_item,
283 | :last_item]
284 |
285 | # better, but not preferred - with indentation
286 | list = [:first_item, :second_item, :next_item,
287 | :last_item]
288 |
289 | # preferred - list starts on its own line
290 | # good for shorter, more compact lists
291 | list =
292 | [:first_item, :second_item, :next_item,
293 | :last_item]
294 |
295 | # also preferred - when each element is on its own line
296 | # good for long lists, lists with long elements, or lists with comments
297 | list = [
298 | :first_item,
299 | :second_item,
300 | :next_item,
301 | # comment
302 | :many_items,
303 | :last_item
304 | ]
305 | ```
306 |
307 | *
308 | Avoid trailing whitespace.
309 | [[link](#trailing-whitespace)]
310 |
311 | *
312 | End each file with a newline.
313 | [[link](#newline-eof)]
314 |
315 | ### Syntax
316 |
317 | *
318 | Use parentheses when a `def` has arguments, and omit them when it doesn't.
319 | [[link](#parentheses)]
320 |
321 | ```elixir
322 | # not preferred
323 | def some_function arg1, arg2 do
324 | # body omitted
325 | end
326 |
327 | def some_function() do
328 | # body omitted
329 | end
330 |
331 | # preferred
332 | def some_function(arg1, arg2) do
333 | # body omitted
334 | end
335 |
336 | def some_function do
337 | # body omitted
338 | end
339 | ```
340 |
341 | *
342 | Add a blank line after a multiline assignment as a
343 | visual cue that the assignment is 'over'.
344 | [[link](#add-blank-line-after-multiline-assignment)]
345 |
346 | ```elixir
347 | # not preferred
348 | some_string =
349 | "Hello"
350 | |> String.downcase()
351 | |> String.strip()
352 | another_string <> some_string
353 |
354 | # preferred
355 | some_string =
356 | "Hello"
357 | |> String.downcase()
358 | |> String.strip()
359 |
360 | another_string <> some_string
361 | ```
362 |
363 | ```elixir
364 | # also not preferred
365 | something =
366 | if x == 2 do
367 | "Hi"
368 | else
369 | "Bye"
370 | end
371 | String.downcase(something)
372 |
373 | # preferred
374 | something =
375 | if x == 2 do
376 | "Hi"
377 | else
378 | "Bye"
379 | end
380 |
381 | String.downcase(something)
382 | ```
383 |
384 | *
385 | Never use `do:` for multi-line `if/unless`.
386 | [[link](#do-with-multi-line-if-unless)]
387 |
388 | ```elixir
389 | # not preferred
390 | if some_condition, do:
391 | # a line of code
392 | # another line of code
393 | # note no end in this block
394 |
395 | # preferred
396 | if some_condition do
397 | # some
398 | # lines
399 | # of code
400 | end
401 | ```
402 |
403 | *
404 | Use `do:` for single line `if/unless` statements.
405 | [[link](#do-with-single-line-if-unless)]
406 |
407 | ```elixir
408 | # preferred
409 | if some_condition, do: # some_stuff
410 | ```
411 |
412 | *
413 | Never use `unless` with `else`.
414 | Rewrite these with the positive case first.
415 | [[link](#unless-with-else)]
416 |
417 | ```elixir
418 | # not preferred
419 | unless success? do
420 | IO.puts 'failure'
421 | else
422 | IO.puts 'success'
423 | end
424 |
425 | # preferred
426 | if success? do
427 | IO.puts 'success'
428 | else
429 | IO.puts 'failure'
430 | end
431 | ```
432 |
433 | *
434 | Use `true` as the last condition of the `cond` special form when you need a
435 | clause that always matches.
436 | [[link](#true-as-last-condition)]
437 |
438 | ```elixir
439 | # not preferred
440 | cond do
441 | 1 + 2 == 5 ->
442 | "Nope"
443 | 1 + 3 == 5 ->
444 | "Uh, uh"
445 | :else ->
446 | "OK"
447 | end
448 |
449 | # preferred
450 | cond do
451 | 1 + 2 == 5 ->
452 | "Nope"
453 | 1 + 3 == 5 ->
454 | "Uh, uh"
455 | true ->
456 | "OK"
457 | end
458 | ```
459 |
460 | *
461 | Never put a space between a function name and the opening parenthesis.
462 | [[link](#function-names-with-parentheses)]
463 |
464 | ```elixir
465 | # not preferred
466 | f (3 + 2) + 1
467 |
468 | # preferred
469 | f(3 + 2) + 1
470 | ```
471 |
472 | *
473 | Use parentheses in function calls, especially inside a pipeline.
474 | [[link](#function-calls-and-parentheses)]
475 |
476 | ```elixir
477 | # not preferred
478 | f 3
479 |
480 | # preferred
481 | f(3)
482 |
483 | # not preferred and parses as rem(2, (3 |> g)), which is not what you want.
484 | 2 |> rem 3 |> g
485 |
486 | # preferred
487 | 2 |> rem(3) |> g
488 | ```
489 |
490 | *
491 | Omit parentheses in macro calls when a do block is passed.
492 | [[link](#macro-calls-and-parentheses)]
493 |
494 | ```elixir
495 | # not preferred
496 | quote(do
497 | foo
498 | end)
499 |
500 | # preferred
501 | quote do
502 | foo
503 | end
504 | ```
505 |
506 | *
507 | Optionally omit parentheses in function calls (outside a pipeline) when the
508 | last argument is a function expression.
509 | [[link](#parentheses-and-function-expressions)]
510 |
511 | ```elixir
512 | # preferred
513 | Enum.reduce(1..10, 0, fn x, acc ->
514 | x + acc
515 | end)
516 |
517 | # also preferred
518 | Enum.reduce 1..10, 0, fn x, acc ->
519 | x + acc
520 | end
521 | ```
522 |
523 | *
524 | Use parentheses for calls to functions with zero arity, so they can be
525 | distinguished from variables.
526 | Starting in Elixir 1.4, the compiler will warn you about
527 | locations where this ambiguity exists.
528 | [[link](#parentheses-and-functions-with-zero-arity)]
529 |
530 | ```elixir
531 | defp do_stuff, do: ...
532 |
533 | # not preferred
534 | def my_func do
535 | do_stuff # is this a variable or a function call?
536 | end
537 |
538 | # preferred
539 | def my_func do
540 | do_stuff() # this is clearly a function call
541 | end
542 | ```
543 |
544 | *
545 | Always use the special syntax for keyword lists.
546 | [[link](#keyword-list-syntax)]
547 |
548 | ```elixir
549 | # not preferred
550 | some_value = [{:a, "baz"}, {:b, "qux"}]
551 |
552 | # preferred
553 | some_value = [a: "baz", b: "qux"]
554 | ```
555 |
556 | *
557 | Omit square brackets from keyword lists whenever they are optional.
558 | [[link](#keyword-list-brackets)]
559 |
560 | ```elixir
561 | # not preferred
562 | some_function(foo, bar, [a: "baz", b: "qux"])
563 |
564 | # preferred
565 | some_function(foo, bar, a: "baz", b: "qux")
566 | ```
567 |
568 | *
569 | Indent and align successive `with` clauses.
570 | Put the `do:` argument on a new line, indented normally.
571 | [[link](#with-clauses)]
572 |
573 | ```elixir
574 | with {:ok, foo} <- fetch(opts, :foo),
575 | {:ok, bar} <- fetch(opts, :bar),
576 | do: {:ok, foo, bar}
577 | ```
578 |
579 | *
580 | If the `with` expression has a `do` block with more than one line, or has an
581 | `else` option, use multiline syntax.
582 | [[link](#with-else)]
583 |
584 | ```elixir
585 | with {:ok, foo} <- fetch(opts, :foo),
586 | {:ok, bar} <- fetch(opts, :bar) do
587 | {:ok, foo, bar}
588 | else
589 | :error ->
590 | {:error, :bad_arg}
591 | end
592 | ```
593 |
594 | ### Naming
595 |
596 | *
597 | Use `snake_case` for atoms, functions and variables.
598 | [[link](#snake-case)]
599 |
600 | ```elixir
601 | # not preferred
602 | :"some atom"
603 | :SomeAtom
604 | :someAtom
605 |
606 | someVar = 5
607 |
608 | def someFunction do
609 | ...
610 | end
611 |
612 | def SomeFunction do
613 | ...
614 | end
615 |
616 | # preferred
617 | :some_atom
618 |
619 | some_var = 5
620 |
621 | def some_function do
622 | ...
623 | end
624 | ```
625 |
626 | *
627 | Use `CamelCase` for modules (keep acronyms like HTTP, RFC, XML uppercase).
628 | [[link](#camel-case)]
629 |
630 | ```elixir
631 | # not preferred
632 | defmodule Somemodule do
633 | ...
634 | end
635 |
636 | defmodule Some_Module do
637 | ...
638 | end
639 |
640 | defmodule SomeXml do
641 | ...
642 | end
643 |
644 | # preferred
645 | defmodule SomeModule do
646 | ...
647 | end
648 |
649 | defmodule SomeXML do
650 | ...
651 | end
652 | ```
653 |
654 | *
655 | The names of predicate macros (compile-time generated functions that return a
656 | boolean value) _that can be used within guards_ should be prefixed with `is_`.
657 | For a list of allowed expressions, see the [Guard][Guard Expressions] docs.
658 | [[link](#predicate-macro-names-with-guards)]
659 |
660 | ```elixir
661 | defmacro is_cool(var) do
662 | quote do: unquote(var) == "cool"
663 | end
664 | ```
665 |
666 | *
667 | The names of predicate functions _that cannot be used within guards_ should
668 | have a trailing question mark (`?`) rather than the `is_` (or similar) prefix.
669 | [[link](#predicate-macro-names-no-guards)]
670 |
671 | ```elixir
672 | def cool?(var) do
673 | # Complex check if var is cool not possible in a pure function.
674 | end
675 | ```
676 |
677 | *
678 | Private functions with the same name as public functions should start with
679 | `do_`.
680 | [[link](#private-functions-with-same-name-as-public)]
681 |
682 | ```elixir
683 | def sum(list), do: do_sum(list, 0)
684 |
685 | # private functions
686 | defp do_sum([], total), do: total
687 | defp do_sum([head | tail], total), do: do_sum(tail, head + total)
688 | ```
689 |
690 | ### Comments
691 |
692 | *
693 | Write expressive code and try to convey your program's intention through
694 | control-flow, structure and naming.
695 | [[link](#expressive-code)]
696 |
697 | *
698 | Use one space between the leading `#` character of the comment and the text of
699 | the comment.
700 | [[link](#comment-leading-spaces)]
701 |
702 | ```elixir
703 | String.first(some_string) #not preferred
704 | String.first(some_string) # preferred
705 | ```
706 |
707 | *
708 | Comments longer than a word are capitalized, and sentences use punctuation.
709 | Use [one space][Sentence Spacing] after periods.
710 | [[link](#comment-grammar)]
711 |
712 | ```elixir
713 | # not preferred
714 | # these lowercase comments are missing punctuation
715 |
716 | # preferred
717 | # Capitalization example
718 | # Use punctuation for complete sentences.
719 | ```
720 |
721 | #### Comment Annotations
722 |
723 | *
724 | Annotations should usually be written on the line immediately above the
725 | relevant code.
726 | [[link](#annotations)]
727 |
728 | *
729 | The annotation keyword is uppercase, and is followed by a colon and a space,
730 | then a note describing the problem.
731 | [[link](#annotation-keyword)]
732 |
733 | ```elixir
734 | # TODO: Deprecate in v1.5.
735 | def some_function(arg), do: {:ok, arg}
736 | ```
737 |
738 | *
739 | In cases where the problem is so obvious that any documentation would be
740 | redundant, annotations may be left at the end of the offending line with no
741 | note.
742 | This usage should be the exception and not the rule.
743 | [[link](#exceptions-to-annotations)]
744 |
745 | ```elixir
746 | start_task()
747 | Process.sleep(5000) # FIXME
748 | ```
749 |
750 | *
751 | Use `TODO` to note missing features or functionality that should be added at a
752 | later date.
753 | [[link](#todo-notes)]
754 |
755 | *
756 | Use `FIXME` to note broken code that needs to be fixed.
757 | [[link](#fixme-notes)]
758 |
759 | *
760 | Use `OPTIMIZE` to note slow or inefficient code that may cause performance
761 | problems.
762 | [[link](#optimize-notes)]
763 |
764 | *
765 | Use `HACK` to note code smells where questionable coding practices were used
766 | and should be refactored away.
767 | [[link](#hack-notes)]
768 |
769 | *
770 | Use `REVIEW` to note anything that should be looked at to confirm it is
771 | working as intended.
772 | For example: `REVIEW: Are we sure this is how the client does X currently?`
773 | [[link](#review-notes)]
774 |
775 | *
776 | Use other custom annotation keywords if it feels appropriate, but be sure to
777 | document them in your project's `README` or similar.
778 | [[link](#custom-keywords)]
779 |
780 | ### Modules
781 |
782 | *
783 | Use one module per file unless the module is only used internally by another
784 | module (such as a test).
785 | [[link](#one-module-per-file)]
786 |
787 | *
788 | Use `snake_case` file names for `CamelCase` module names.
789 | [[link](#underscored-filenames)]
790 |
791 | ```elixir
792 | # file is called some_module.ex
793 |
794 | defmodule SomeModule do
795 | end
796 | ```
797 |
798 | *
799 | Represent each level of nesting within a module name as a directory.
800 | [[link](#module-name-nesting)]
801 |
802 | ```elixir
803 | # file is called parser/core/xml_parser.ex
804 |
805 | defmodule Parser.Core.XMLParser do
806 | end
807 | ```
808 |
809 | *
810 | Don't put a blank line after `defmodule`.
811 | [[link](#defmodule-spacing)]
812 |
813 | *
814 | Put a blank line after module-level code blocks.
815 | [[link](#module-block-spacing)]
816 |
817 | *
818 | List module attributes and directives in the following order:
819 | [[link](#module-attribute-ordering)]
820 |
821 | 1. `@moduledoc`
822 | 1. `@behaviour`
823 | 1. `use`
824 | 1. `import`
825 | 1. `alias`
826 | 1. `require`
827 | 1. `defstruct`
828 | 1. `@type`
829 | 1. `@module_attribute`
830 | 1. `@callback`
831 | 1. `@macrocallback`
832 | 1. `@optional_callbacks`
833 |
834 | Add a blank line between each grouping, and sort the terms (like module names)
835 | alphabetically.
836 | Here's an overall example of how you should order things in your modules:
837 |
838 | ```elixir
839 | defmodule MyModule do
840 | @moduledoc """
841 | An example module
842 | """
843 |
844 | @behaviour MyBehaviour
845 |
846 | use GenServer
847 |
848 | import Something
849 | import SomethingElse
850 |
851 | alias My.Long.Module.Name
852 | alias My.Other.Module.Example
853 |
854 | require Integer
855 |
856 | defstruct name: nil, params: []
857 |
858 | @type params :: [{binary, binary}]
859 |
860 | @module_attribute :foo
861 | @other_attribute 100
862 |
863 | @callback some_function(term) :: :ok | {:error, term}
864 |
865 | @macrocallback macro_name(term) :: Macro.t
866 |
867 | @optional_callbacks macro_name: 1
868 |
869 | ...
870 | end
871 | ```
872 |
873 | *
874 | Use the `__MODULE__` pseudo variable when a module refers to itself. This
875 | avoids having to update any self-references when the module name changes.
876 | [[link](#module-pseudo-variable)]
877 |
878 | ```elixir
879 | defmodule SomeProject.SomeModule do
880 | defstruct [:name]
881 |
882 | def name(%__MODULE__{name: name}), do: name
883 | end
884 | ```
885 |
886 | *
887 | If you want a prettier name for a module self-reference, set up an alias.
888 | [[link](#alias-self-referencing-modules)]
889 |
890 | ```elixir
891 | defmodule SomeProject.SomeModule do
892 | alias __MODULE__, as: SomeModule
893 |
894 | defstruct [:name]
895 |
896 | def name(%SomeModule{name: name}), do: name
897 | end
898 | ```
899 |
900 | *
901 | Avoid repeating fragments in module names and namespaces.
902 | This improves overall readability and
903 | eliminates [ambiguous aliases][Conflicting Aliases].
904 | [[link](#repetitive-module-names)]
905 |
906 | ```elixir
907 | # not preferred
908 | defmodule Todo.Todo do
909 | ...
910 | end
911 |
912 | # preferred
913 | defmodule Todo.Item do
914 | ...
915 | end
916 | ```
917 |
918 | ### Documentation
919 |
920 | Documentation in Elixir (when read either in `iex` with `h` or generated with
921 | [ExDoc]) uses the [Module Attributes] `@moduledoc` and `@doc`.
922 |
923 | *
924 | Always include a `@moduledoc` attribute in the line right after `defmodule` in
925 | your module.
926 | [[link](#moduledocs)]
927 |
928 | ```elixir
929 | # not preferred
930 |
931 | defmodule SomeModule do
932 |
933 | @moduledoc """
934 | About the module
935 | """
936 | ...
937 | end
938 |
939 | defmodule AnotherModule do
940 | use SomeModule
941 | @moduledoc """
942 | About the module
943 | """
944 | ...
945 | end
946 |
947 | # preferred
948 |
949 | defmodule SomeModule do
950 | @moduledoc """
951 | About the module
952 | """
953 | ...
954 | end
955 | ```
956 |
957 | *
958 | Use `@moduledoc false` if you do not intend on documenting the module.
959 | [[link](#moduledoc-false)]
960 |
961 | ```elixir
962 | defmodule SomeModule do
963 | @moduledoc false
964 | ...
965 | end
966 | ```
967 |
968 | *
969 | Separate code after the `@moduledoc` with a blank line.
970 | [[link](#moduledoc-spacing)]
971 |
972 | ```elixir
973 | # not preferred
974 |
975 | defmodule SomeModule do
976 | @moduledoc """
977 | About the module
978 | """
979 | use AnotherModule
980 | end
981 |
982 | # preferred
983 | defmodule SomeModule do
984 | @moduledoc """
985 | About the module
986 | """
987 |
988 | use AnotherModule
989 | end
990 | ```
991 |
992 | *
993 | Use heredocs with markdown for documentation.
994 | [[link](#heredocs)]
995 |
996 | ```elixir
997 | # not preferred
998 |
999 | defmodule SomeModule do
1000 | @moduledoc "About the module"
1001 | end
1002 |
1003 | defmodule SomeModule do
1004 | @moduledoc """
1005 | About the module
1006 |
1007 | Examples:
1008 | iex> SomeModule.some_function
1009 | :result
1010 | """
1011 | end
1012 |
1013 | # preferred
1014 | defmodule SomeModule do
1015 | @moduledoc """
1016 | About the module
1017 |
1018 | ## Examples
1019 |
1020 | iex> SomeModule.some_function
1021 | :result
1022 | """
1023 | end
1024 | ```
1025 |
1026 | ### Typespecs
1027 |
1028 | Typespecs are notation for declaring types and specifications, for
1029 | documentation or for the static analysis tool Dialyzer.
1030 |
1031 | Custom types should be defined at the top of the module with the other
1032 | directives (see [Modules](#modules)).
1033 |
1034 | *
1035 | Place `@typedoc` and `@type` definitions together, and separate each
1036 | pair with a blank line.
1037 | [[link](#typedocs)]
1038 |
1039 | ```elixir
1040 | defmodule SomeModule do
1041 | @moduledoc false
1042 |
1043 | @typedoc "The name"
1044 | @type name :: atom
1045 |
1046 | @typedoc "The result"
1047 | @type result :: {:ok, term} | {:error, term}
1048 |
1049 | ...
1050 | end
1051 | ```
1052 |
1053 | *
1054 | If a union type is too long to fit on a single line, add a newline
1055 | and indent with spaces to keep the types aligned.
1056 | [[link](#union-types)]
1057 |
1058 | ```elixir
1059 | # not preferred - no indentation
1060 | @type long_union_type :: some_type | another_type | some_other_type |
1061 | a_final_type
1062 |
1063 | # preferred
1064 | @type long_union_type :: some_type | another_type | some_other_type |
1065 | a_final_type
1066 |
1067 | # also preferred - one type per line
1068 | @type long_union_type :: some_type |
1069 | another_type |
1070 | some_other_type |
1071 | a_final_type
1072 | ```
1073 |
1074 | *
1075 | Name the main type for a module `t`, for example: the type specification for a
1076 | struct.
1077 | [[link](#naming-main-types)]
1078 |
1079 | ```elixir
1080 | defstruct name: nil, params: []
1081 |
1082 | @type t :: %__MODULE__{
1083 | name: String.t | nil,
1084 | params: Keyword.t
1085 | }
1086 | ```
1087 |
1088 | *
1089 | Place specifications right before the function definition,
1090 | without separating them by a blank line.
1091 | [[link](#spec-spacing)]
1092 |
1093 | ```elixir
1094 | @spec some_function(term) :: result
1095 | def some_function(some_data) do
1096 | {:ok, some_data}
1097 | end
1098 | ```
1099 |
1100 | ### Structs
1101 |
1102 | *
1103 | Use a list of atoms for struct fields that default to `nil`, followed by the
1104 | other keywords.
1105 | [[link](#nil-struct-field-defaults)]
1106 |
1107 | ```elixir
1108 | # not preferred
1109 | defstruct name: nil, params: nil, active: true
1110 |
1111 | # preferred
1112 | defstruct [:name, :params, active: true]
1113 | ```
1114 |
1115 | *
1116 | Omit square brackets when the argument of a `defstruct` is a keyword list.
1117 | [[link](#struct-def-brackets)]
1118 |
1119 | ```elixir
1120 | # not preferred
1121 | defstruct [params: [], active: true]
1122 |
1123 | # preferred
1124 | defstruct params: [], active: true
1125 |
1126 | # required - brackets are not optional, with at least one atom in the list
1127 | defstruct [:name, params: [], active: true]
1128 | ```
1129 |
1130 | *
1131 | Indent additional lines of the struct definition, keeping the first keys
1132 | aligned.
1133 | [[link](#additional-struct-def-lines)]
1134 |
1135 | ```elixir
1136 | defstruct foo: "test", bar: true, baz: false,
1137 | qux: false, quux: 1
1138 | ```
1139 |
1140 | ### Exceptions
1141 |
1142 | *
1143 | Make exception names end with a trailing `Error`.
1144 | [[link](#exception-names)]
1145 |
1146 | ```elixir
1147 | # not preferred
1148 | defmodule BadHTTPCode do
1149 | defexception [:message]
1150 | end
1151 |
1152 | defmodule BadHTTPCodeException do
1153 | defexception [:message]
1154 | end
1155 |
1156 | # preferred
1157 | defmodule BadHTTPCodeError do
1158 | defexception [:message]
1159 | end
1160 | ```
1161 |
1162 | *
1163 | Use lowercase error messages when raising exceptions, with no trailing
1164 | punctuation.
1165 | [[link](#lowercase-error-messages)]
1166 |
1167 | ```elixir
1168 | # not preferred
1169 | raise ArgumentError, "This is not valid."
1170 |
1171 | # preferred
1172 | raise ArgumentError, "this is not valid"
1173 | ```
1174 |
1175 | ### Collections
1176 |
1177 | _No guidelines for collections have been added yet._
1178 |
1179 | ### Strings
1180 |
1181 | *
1182 | Match strings using the string concatenator rather than binary patterns:
1183 | [[link](#strings-matching-with-concatenator)]
1184 |
1185 | ```elixir
1186 | # not preferred
1187 | <<"my"::utf8, _rest>> = "my string"
1188 |
1189 | # preferred
1190 | "my" <> _rest = "my string"
1191 | ```
1192 |
1193 | ### Regular Expressions
1194 |
1195 | _No guidelines for regular expressions have been added yet._
1196 |
1197 | ### Metaprogramming
1198 |
1199 | *
1200 | Avoid needless metaprogramming.
1201 | [[link](#avoid-metaprogramming)]
1202 |
1203 | ### Testing
1204 |
1205 | *
1206 | When writing [ExUnit] assertions, be consistent with the order of the expected
1207 | and actual values under testing.
1208 | Prefer placing the expected result on the right, unless the assertion is a
1209 | pattern match.
1210 | [[link](#testing-assert-order)]
1211 |
1212 | ```elixir
1213 | # preferred - expected result on the right
1214 | assert actual_function(1) == true
1215 | assert actual_function(2) == false
1216 |
1217 | # not preferred - inconsistent order
1218 | assert actual_function(1) == true
1219 | assert false == actual_function(2)
1220 |
1221 | # required - the assertion is a pattern match
1222 | assert {:ok, expected} = actual_function(3)
1223 | ```
1224 |
1225 | ### Alternative Style Guides
1226 |
1227 | * [Aleksei Magusev's Elixir Style Guide](https://github.com/lexmag/elixir-style-guide#readme)
1228 | — An opinionated Elixir style guide stemming from the coding style practiced
1229 | in the Elixir core libraries.
1230 | Developed by [Aleksei Magusev](https://github.com/lexmag) and
1231 | [Andrea Leopardi](https://github.com/whatyouhide), members of Elixir core team.
1232 | While the Elixir project doesn't adhere to any specific style guide,
1233 | this is the closest available guide to its conventions.
1234 |
1235 | * [Credo's Elixir Style Guide](https://github.com/rrrene/elixir-style-guide#readme)
1236 | — Style Guide for the Elixir language, implemented by
1237 | [Credo](http://credo-ci.org) static code analysis tool.
1238 |
1239 | ### Tools
1240 |
1241 | Refer to [Awesome Elixir][Code Analysis] for libraries and tools that can help
1242 | with code analysis and style linting.
1243 |
1244 | ## Getting Involved
1245 |
1246 | ### Contributing
1247 |
1248 | It's our hope that this will become a central hub for community discussion on
1249 | best practices in Elixir.
1250 | Feel free to open tickets or send pull requests with improvements.
1251 | Thanks in advance for your help!
1252 |
1253 | Check the [contributing guidelines][Contributing]
1254 | and [code of conduct][Code Of Conduct] for more information.
1255 |
1256 | ### Spread the Word
1257 |
1258 | A community style guide is meaningless without the community's support. Please
1259 | tweet, [star][Stargazers], and let any Elixir programmer know
1260 | about [this guide][Elixir Style Guide] so they can contribute.
1261 |
1262 | ## Copying
1263 |
1264 | ### License
1265 |
1266 | 
1267 | This work is licensed under a
1268 | [Creative Commons Attribution 3.0 Unported License][License]
1269 |
1270 | ### Attribution
1271 |
1272 | The structure of this guide, bits of example code, and many of the initial
1273 | points made in this document were borrowed from the [Ruby community style guide].
1274 | A lot of things were applicable to Elixir and allowed us to get _some_ document
1275 | out quicker to start the conversation.
1276 |
1277 | Here's the [list of people who have kindly contributed][Contributors] to this
1278 | project.
1279 |
1280 |
1281 | [Chinese Simplified]: https://github.com/geekerzp/elixir_style_guide/blob/master/README-zhCN.md
1282 | [Chinese Traditional]: https://github.com/elixirtw/elixir_style_guide/blob/master/README_zhTW.md
1283 | [Code Analysis]: https://github.com/h4cc/awesome-elixir#code-analysis
1284 | [Code Of Conduct]: https://github.com/christopheradams/elixir_style_guide/blob/master/CODE_OF_CONDUCT.md
1285 | [Conflicting Aliases]: https://elixirforum.com/t/using-aliases-for-fubar-fubar-named-module/1723
1286 | [Contributing]: https://github.com/elixir-lang/elixir/blob/master/CODE_OF_CONDUCT.md
1287 | [Contributors]: https://github.com/christopheradams/elixir_style_guide/graphs/contributors
1288 | [Elixir Style Guide]: https://github.com/christopheradams/elixir_style_guide
1289 | [Elixir]: http://elixir-lang.org
1290 | [ExDoc]: https://github.com/elixir-lang/ex_doc
1291 | [ExUnit]: https://hexdocs.pm/ex_unit/ExUnit.html
1292 | [Guard Expressions]: http://elixir-lang.org/getting-started/case-cond-and-if.html#expressions-in-guard-clauses
1293 | [Hex]: https://hex.pm/packages
1294 | [Japanese]: https://github.com/kenichirow/elixir_style_guide/blob/master/README-jaJP.md
1295 | [Korean]: https://github.com/marocchino/elixir_style_guide/blob/new-korean/README-koKR.md
1296 | [License]: http://creativecommons.org/licenses/by/3.0/deed.en_US
1297 | [Module Attributes]: http://elixir-lang.org/getting-started/module-attributes.html#as-annotations
1298 | [Portuguese]: https://github.com/gusaiani/elixir_style_guide/blob/master/README_ptBR.md
1299 | [Ruby community style guide]: https://github.com/bbatsov/ruby-style-guide
1300 | [Sentence Spacing]: http://en.wikipedia.org/wiki/Sentence_spacing
1301 | [Spanish]: https://github.com/albertoalmagro/elixir_style_guide/blob/spanish/README_esES.md
1302 | [Stargazers]: https://github.com/christopheradams/elixir_style_guide/stargazers
1303 |
--------------------------------------------------------------------------------
/Rakefile:
--------------------------------------------------------------------------------
1 | task :test do
2 | exit_code = 0
3 | files = ["README.md", "CONTRIBUTING.md"]
4 | # 'MD036' # Emphasis used instead of a header
5 | # 'MD033' # Inline HTML - allow for anchor links in each bullet point
6 | rules = ['~MD036', '~MD033'].join(",")
7 | files.each do |file|
8 | begin
9 | sh "mdl --rules #{rules} #{file}"
10 | rescue Exception => ex
11 | exit_code = 1
12 | end
13 | end
14 |
15 | exit exit_code
16 | end
17 |
--------------------------------------------------------------------------------
/mix.exs:
--------------------------------------------------------------------------------
1 | defmodule ElixirStyleGuide.Mixfile do
2 | use Mix.Project
3 |
4 | @project_description """
5 | A community driven style guide for Elixir
6 | """
7 |
8 | @version "0.1.0"
9 | @source_url "https://github.com/christopheradams/elixir_style_guide"
10 |
11 | def project do
12 | [app: :elixir_style_guide,
13 | version: @version,
14 | elixir: "~> 1.0",
15 | build_embedded: Mix.env == :prod,
16 | start_permanent: Mix.env == :prod,
17 | docs: docs(),
18 | description: @project_description,
19 | source_url: @source_url,
20 | package: package(),
21 | deps: deps()]
22 | end
23 |
24 | def application do
25 | [applications: [:logger]]
26 | end
27 |
28 | defp deps do
29 | []
30 | end
31 |
32 | defp docs() do
33 | [
34 | source_ref: "v#{@version}",
35 | main: "readme",
36 | extras: [
37 | "README.md": [title: "README"]
38 | ]
39 | ]
40 | end
41 |
42 | defp package do
43 | [
44 | name: :elixir_style_guide,
45 | maintainers: ["Christopher Adams"],
46 | licenses: ["CC-by"],
47 | links: %{
48 | "GitHub" => @source_url
49 | }
50 | ]
51 | end
52 | end
53 |
--------------------------------------------------------------------------------