From 2c5a83889a1bada27badaae3052420fdce48940f Mon Sep 17 00:00:00 2001 From: mikulely Date: Mon, 25 Nov 2013 09:19:19 +0800 Subject: [PATCH 01/40] to_binary has been deprecated, to_string works Tested on Interactive Elixir (0.11.2-dev) --- getting_started/3.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getting_started/3.markdown b/getting_started/3.markdown index 8e297cb2c..311fb3777 100644 --- a/getting_started/3.markdown +++ b/getting_started/3.markdown @@ -464,6 +464,6 @@ In other words, we are simply calling the function `flatten` on the atom `:lists ```iex iex> is_atom(List) true -iex> to_binary(List) +iex> to_string(List) "Elixir.List" ``` From 0135851f34079fd73b81f4ff44da3c24d152e90b Mon Sep 17 00:00:00 2001 From: mikulely Date: Mon, 25 Nov 2013 20:27:31 +0800 Subject: [PATCH 02/40] Key-value pair stores in a list, not in a tuple Tested on Interactive Elixir (0.11.2-dev) --- getting_started/4.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getting_started/4.markdown b/getting_started/4.markdown index 95cd7d42a..15a383705 100644 --- a/getting_started/4.markdown +++ b/getting_started/4.markdown @@ -188,7 +188,7 @@ If we inspect our `HashDict`, we can see it is a simple tuple: ```elixir inspect(dict, raw: true) -#=> { HashDict, 1, [{:hello,"world"}] } +#=> "{HashDict, 1, [[:hello | \"world\"]]}" ``` Since `HashDict` is a data structure that contains values, it would be convenient to implement the `Blank` protocol for it too: From 595a460b96918dec5b83211e711c6aed26f7147a Mon Sep 17 00:00:00 2001 From: mikulely Date: Mon, 25 Nov 2013 21:34:38 +0800 Subject: [PATCH 03/40] The second element of tuple has been added some metadata. Tested on Interactive Elixir (0.11.2-dev) --- getting_started/5.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/getting_started/5.markdown b/getting_started/5.markdown index b72deeba5..7c07af3e0 100644 --- a/getting_started/5.markdown +++ b/getting_started/5.markdown @@ -28,7 +28,7 @@ Operators are also represented as such tuples: ```iex iex> quote do: 1 + 2 -{ :+, [], [1, 2] } +{:+, [context: Elixir, import: Kernel], [1, 2]} ``` Even a tuple is represented as a call to `{}`: @@ -49,7 +49,7 @@ When quoting more complex expressions, we can see the representation is composed ```iex iex> quote do: sum(1, 2 + 3, 4) -{ :sum, [], [1, { :+, [], [2, 3] }, 4] } +{:sum, [], [1, {:+, [context: Elixir, import: Kernel], [2, 3]}, 4]} ``` In general, each node (tuple) above follows the following format: From d60a1dde2933a02039f441e3438e1e3d8409197d Mon Sep 17 00:00:00 2001 From: mikulely Date: Tue, 26 Nov 2013 09:16:46 +0800 Subject: [PATCH 04/40] Update partial function example Tested on Interactive Elixir (0.11.2-dev),the function `atom_to_binary/1`'s arity is 1, a function which arity is 2 should be used here to demonstrate the usage of partial function. --- getting_started/6.markdown | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/getting_started/6.markdown b/getting_started/6.markdown index 6f047f4f2..f4a81ac00 100644 --- a/getting_started/6.markdown +++ b/getting_started/6.markdown @@ -177,13 +177,13 @@ iex> fun.("hello") A capture also allows the captured functions to be partially applied, for example: ```iex -iex> fun = &atom_to_binary(&1, :utf8) -#Function<6.17052888 in :erl_eval.expr/5> -iex> fun.(:hello) -"hello" +iex> fun = &rem(&1, 2) +#Function<6.80484245 in :erl_eval.expr/5> +iex> fun.(4) +0 ``` -In the example above, we use `&1` as a placeholder, generating a function with one argument. The capture above is equivalent to `fn(x) -> atom_to_binary(x, :utf8) end`. +In the example above, we use `&1` as a placeholder, generating a function with one argument. The capture above is equivalent to `fn(x) -> rem(x, 2) end`. Since operators are treated as regular function calls in Elixir, they are also supported, although they require explicit parentheses: From d0fe022eb42c62608653f7b1b957a4f29d7e97bc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E4=BD=B3=E9=9F=B3?= Date: Sat, 30 Nov 2013 20:46:09 +0800 Subject: [PATCH 05/40] Binary.Inspect now is Inspect Tested on Interactive Elixir (0.11.2) --- getting_started/4.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getting_started/4.markdown b/getting_started/4.markdown index 15a383705..20c78876e 100644 --- a/getting_started/4.markdown +++ b/getting_started/4.markdown @@ -239,7 +239,7 @@ iex> Enum.reduce 1..3, 0, fn(x, acc) -> x + acc end 6 ``` -* `Binary.Inspect` - this protocol is used to transform any data structure into a readable textual representation. This is what tools like IEx use to print results: +* `Inspect` - this protocol is used to transform any data structure into a readable textual representation. This is what tools like IEx use to print results: ```iex iex> { 1, 2, 3 } From 7bd4e7c6f3876804a2e55502daae9462647c5ee8 Mon Sep 17 00:00:00 2001 From: Yuki Ito Date: Sat, 7 Dec 2013 15:35:46 +0900 Subject: [PATCH 06/40] IO.puts accepts number --- getting_started/3.markdown | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/getting_started/3.markdown b/getting_started/3.markdown index 311fb3777..4a9a8b6f5 100644 --- a/getting_started/3.markdown +++ b/getting_started/3.markdown @@ -75,8 +75,7 @@ defmodule Math do end end -# IO.puts expects a list or a binary, so we use the string representation of the sum -IO.puts to_string(Math.sum(1, 2)) +IO.puts Math.sum(1, 2) ``` And execute it as: From 7767e18ef27bf5bf4171beb619664dd64aaed213 Mon Sep 17 00:00:00 2001 From: Richard Jones Date: Sun, 8 Dec 2013 12:00:05 +0000 Subject: [PATCH 07/40] Fix erlang code example Shouldn't call a function "fun" in erlang code, update the erlang function naming to match the Elixir code. --- crash-course.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/crash-course.markdown b/crash-course.markdown index 495a16a4b..d9fc22a1b 100644 --- a/crash-course.markdown +++ b/crash-course.markdown @@ -376,14 +376,14 @@ Each Erlang module lives in its own file which has the following structure: ```erlang -module(hello_module). --export([some_fun/0, fun/1]). +-export([some_fun/0, some_fun/1]). % A "Hello world" function some_fun() -> io:format('~s~n', ['Hello world!']). % This one works only with lists -fun(List) when is_list(List) -> +some_fun(List) when is_list(List) -> io:format('~s~n', List). % Non-exported functions are private From b61b1fe3487fa0a5a3d2c04366ebbb5b6f521d4e Mon Sep 17 00:00:00 2001 From: Rafael Rosa Fu Date: Thu, 12 Dec 2013 01:27:11 -0500 Subject: [PATCH 08/40] Fixing minor typo on blog post --- _posts/2013-08-08-elixir-design-goals.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2013-08-08-elixir-design-goals.markdown b/_posts/2013-08-08-elixir-design-goals.markdown index d69e5a38b..f62442ac8 100644 --- a/_posts/2013-08-08-elixir-design-goals.markdown +++ b/_posts/2013-08-08-elixir-design-goals.markdown @@ -88,7 +88,7 @@ This simple example illustrates how a developer can leverage macros to provide a Those examples are just scratching the surface of what can be achieved with macros in Elixir. For example, we are currently using macros to compile routes from a web application into a bunch of patterns that are highly optimizable by the VM, providing an expressive but heavily optimized routing algorithm. -The macro system also caused a huge imapct on the syntax, which we will discuss briefly before moving to the last goal. +The macro system also caused a huge impact on the syntax, which we will discuss briefly before moving to the last goal. ### Syntax From 6344c2fb91a83325b4151f13790de985fb09b173 Mon Sep 17 00:00:00 2001 From: Peter Minten Date: Wed, 11 Dec 2013 16:42:48 +0100 Subject: [PATCH 09/40] Blog post about the new enumerators --- ...xir-s-new-continuable-enumerators.markdown | 209 ++++++++++++++++++ 1 file changed, 209 insertions(+) create mode 100644 _posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown diff --git a/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown b/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown new file mode 100644 index 000000000..7ba92b8a1 --- /dev/null +++ b/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown @@ -0,0 +1,209 @@ +--- +layout: post +title: Elixir's new continuable enumerators +author: Peter Minten +category: "What's New in Elixir" +excerpt: In 0.12.0 Elixir's enumerators have gained the ability to suspend value + production and to terminate early. +--- + +As you may have heard in the upcoming 0.12.0 release Elixir's enumerators gained +some new features. In this blog post I'll explain what's new, what it enables +and how it works. + +For those of you who use the development version of Elixir these changes are +already available. For the exact differences in code you can look at the +[relevant pull request](https://github.com/elixir-lang/elixir/pull/1922). + +## A recap of enumerators, and some terminology + +The basic idea of enumerators is that you traverse some data structure or +resource (lines from a file) by putting the thing that is traversed in control. +That is if you're reading from a file you have a loop that reads lines from a +file and for each line calls a function. Just calling a function isn't all that +useful for most tasks as there'd be no way to remember previous lines (ugly +hacks aside), so some accumulator value is passed to the function and a new +accumulator is returned by it. + +For example here's how you can count the total length of strings in a list. + +```elixir +Enumerable.reduce(l, 0, fn x, acc -> String.length(x) + acc end) +``` + +Often the actual call to `Enumerable.reduce/3` is hidden inside another +function. Say that we want to define a `sum` function. The usual way is to +write it like this: + +```elixir +def sum(coll) do + Enumerable.reduce(coll, 0, fn x, acc -> x + acc end) +end +``` + +This could get called as `Enum.map(1..10, &(&1 * &1)) |> sum()` to get the sum of +squares. Desugaring this means `sum(Enum.map(1..10, &(&1 * &1)))`. + +The general pattern is this: + +```elixir +def outer_function(coll, ...) do + ... + Enumerable.reduce(coll, initial_consumer_acc, consumer) + ... +end + +something_that_returns_an_enumerable(...) |> outer_function(...) +``` + +You'll notice the slightly uncommon terminology of "outer function" and +"consumer" (normally called an "iteratee"). That's intentional, naming an +iteratee a consumer better reflects that it consumes values. + +Along the same lines I call the reduce function for a specific enumerable a +producer, it produces values which are given to a consumer. + +The outer function is the function to which the enumerable is passed. +Syntactically it looks like this is the consumer, but it's really a function +that combines the producer and the consumer. For simple consumers (say `fn x, +acc -> length(x) + acc end`) the consumer will often be written directly in the +source text of the outer function, but let's try to keep those concepts +distinguished. + +## Two issues with classic Elixir enumerators + +Enumerators are great, but they have their limitations. One issue is that it's +not possible to define a function that only returns at most 3 elements without +traversing all elements or using ugly tricks such as `throw` (with a +`try...catch` construct in the outer function). The `throw` trick is used in +`Enum` and `Stream` to implement functions such as `Enum.take/2` and +`Stream.take_while/2`. It works, but it's not what I'd call stylish. + +A bigger problem, that doesn't have a workaround, is that there's no way to +interleave two enumerables. That is, it's not possible to define a function that +for two enumerables `A` and `B` returns a list `[A1, B1, A2, B2, A3, ...]` +(where `A1` is the first element of A) without first traversing both lists and +then interleaving the collected values. Interleaving is important because it's +the basis of a zip function. Without interleaving you cannot implement +`Stream.zip/2`. + +The underlying problem, in both cases, is that the producer is fully in control. +The producer simply pushes out as many elements to the consumer as it wants and +then says "I'm done". There's no way aside from `throw`/`raise` for a consumer +to tell a producer "stop producing". There is definitely no way to tell a +producer "stop for now but be prepared to continue where you left off later". + +## Power to the consumer! + +At CodeMeshIO José Valim and Jessica Kerr sat down and discussed this problem. +They came up with a solution inspired by a [Monad.Reader +article](http://themonadreader.files.wordpress.com/2010/05/issue16.pdf) (third +article). It's an elegant extension of the old system, based on a simple idea. +Instead of returning only an accumulator at every step (for every produced +value) the consumer returns a combination of an accumulator and an instruction +to the producer. Three instructions are available: + +* `:cont` - Keep producing. +* `:halt` - Stop producing. +* `:suspend` - Temporarily stop producing. + +A consumer that always returns `:cont` makes the producer behave exactly the +same as in the old system. A consumer may return `:halt` to have the producer +terminate earlier than it normally would. + +The real magic is in `:suspend` though. It tells a producer to return the +accumulator and a continuation function. + +```elixir +{ :suspended, n_, cont } = Enumerable.reduce(1..5, { :cont, 0 }, fn x, n -> + if x == 3 do + { :suspend, n } + else + { :cont, n + x } + end +end) +``` + +After running this code `n_` will be `3` (1 + 2) and `cont` will be a +function. We'll get back to `cont` in a minute but first take a look at some of +the new elements here. The initial accumulator has an instruction as well, so +you could suspend or halt a producer immediately, if you really want to. The +value passed to the consumer (`n`) does not contain the instruction. The return +value of the producer also has a symbol in it. Like with the instructions of +consumers there are three possible values: + +* `:done` - Completed normally. +* `:halted` - Consumer returned a `:halt` instruction. +* `:suspended` - Consumer return a `:suspend` instruction. + +Together with the other values returned the possible return values from a +producer are `{ :done, acc } | { :halted, acc } | { :suspended, acc, +continuation }`. + +Back to the continuation. A continuation is a function that given an accumulator +returns a new producer result. In other words it's a way to swap out the +accumulator but keep the same producer in the same state. + +## Implementing `interleave` + +Using the power of suspension it is now possible to create an interleave +function. + +```elixir +def interleave(a, b) do + step = fn x, acc -> [x|acc] end + af = &Enumerable.reduce(a, &1, step) + bf = &Enumerable.reduce(b, &1, step) + do_interleave(af, bf, []) |> :lists.reverse() +end + +defp do_interleave(a, b, acc) do + case a.({ :cont, acc }) do + { :suspended, acc, a } -> + case b.({ :cont, acc }) do + { :suspended, acc, b } -> + do_interleave(a, b, acc) + { :done, acc } -> + # Get remainder of a's entries + { :done, acc } = a.({ :cont, acc }, fn x, acc -> [x|acc] end) + acc + end + { :done, acc } -> + { :done, acc } = b.({ :cont, acc }, fn x, acc -> [x|acc] end) + acc + end +end +``` + +Lets go through this step by step. The main `interleave` function first +partially applies `Enumerable.reduce/3` to get function values that work just +like the continuations. This makes things easier for `do_interleave`. + +The `do_interleave` function first calls `a` (`af` from `interleave`) with the +`step` function so that the available element of `a` gets added to the +accumulator and `a` immediately suspends afterwards. Then the same is done for +`b`. If either producer is done all the remaining elements of the other get +added to the accumulator list. + +Note that `acc` is sometimes used to mean a tuple like `{ :cont, x }` and +sometimes the accumulator value proper. It's a bit confusing, yes. + +This example shows that through clever combination of an outer function +(`do_interleave`) and an inner function `step` two producers can be interleaved. + +## `Enum.reduce` and `Enumerable.reduce` are now slightly different + +In the old system `Enum.reduce/3` simply called `Enumerable.reduce/3` with the +same arguments. In order to keep the `Enum.reduce/3` function simple to use this +is no longer the case in the new system. `Enum.reduce/3` now calls +`Enumerable.reduce/3` +with a very simple wrapper around the passed function: `fn x, acc -> { :cont, +f.(x, acc) } end`. Thus `Enum.reduce/3` works just as it has always done, it +calls the supplied function for every produced element without the possibility +of halting or suspending the producer. + +## Conclusion + +The new system of enumerators certainly makes things a bit more complicated but +also adds power. I suspect many interesting and "interesting" functions can be +built on top of it. From 8affba4f6e4799674a86ace0a76b80b01dbad362 Mon Sep 17 00:00:00 2001 From: Steffen Bauer Date: Thu, 12 Dec 2013 10:16:18 +0100 Subject: [PATCH 10/40] Added link to Elixir GtkSourceView --- _includes/important-links.html | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/_includes/important-links.html b/_includes/important-links.html index ed9f35a05..69e53e5f0 100644 --- a/_includes/important-links.html +++ b/_includes/important-links.html @@ -25,7 +25,8 @@

Code editor support

  • Emacs Mode
  • Textmate Bundle
  • Vim Elixir
  • +
  • GtkSourceView (gedit)
  • -{% include sponsors.html %} \ No newline at end of file +{% include sponsors.html %} From 3d76e737b767df3f89a54609c5a74e0a6794ca2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 12 Dec 2013 11:33:48 +0100 Subject: [PATCH 11/40] Remove the Enum.reduce and Enumerable.reduce section Enum.reduce/3 will always be an abstraction around Enumerable.reduce/3. --- ...2-11-elixir-s-new-continuable-enumerators.markdown | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown b/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown index 7ba92b8a1..c28ca78b5 100644 --- a/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown +++ b/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown @@ -191,17 +191,6 @@ sometimes the accumulator value proper. It's a bit confusing, yes. This example shows that through clever combination of an outer function (`do_interleave`) and an inner function `step` two producers can be interleaved. -## `Enum.reduce` and `Enumerable.reduce` are now slightly different - -In the old system `Enum.reduce/3` simply called `Enumerable.reduce/3` with the -same arguments. In order to keep the `Enum.reduce/3` function simple to use this -is no longer the case in the new system. `Enum.reduce/3` now calls -`Enumerable.reduce/3` -with a very simple wrapper around the passed function: `fn x, acc -> { :cont, -f.(x, acc) } end`. Thus `Enum.reduce/3` works just as it has always done, it -calls the supplied function for every produced element without the possibility -of halting or suspending the producer. - ## Conclusion The new system of enumerators certainly makes things a bit more complicated but From 860111bb1ba5769a641f1b00239e3c7dfd7e5fbb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 12 Dec 2013 17:24:28 +0100 Subject: [PATCH 12/40] Ensure interleave is passing suspend, add an example at the end --- ...xir-s-new-continuable-enumerators.markdown | 55 ++++++++++++------- 1 file changed, 35 insertions(+), 20 deletions(-) diff --git a/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown b/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown index c28ca78b5..97b0f86de 100644 --- a/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown +++ b/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown @@ -150,29 +150,44 @@ Using the power of suspension it is now possible to create an interleave function. ```elixir -def interleave(a, b) do - step = fn x, acc -> [x|acc] end - af = &Enumerable.reduce(a, &1, step) - bf = &Enumerable.reduce(b, &1, step) - do_interleave(af, bf, []) |> :lists.reverse() -end +defmodule Interleave do + def interleave(a, b) do + step = fn x, acc -> { :suspend, [x|acc] } end + af = &Enumerable.reduce(a, &1, step) + bf = &Enumerable.reduce(b, &1, step) + do_interleave(af, bf, []) |> :lists.reverse() + end -defp do_interleave(a, b, acc) do - case a.({ :cont, acc }) do - { :suspended, acc, a } -> - case b.({ :cont, acc }) do - { :suspended, acc, b } -> - do_interleave(a, b, acc) - { :done, acc } -> - # Get remainder of a's entries - { :done, acc } = a.({ :cont, acc }, fn x, acc -> [x|acc] end) - acc - end - { :done, acc } -> - { :done, acc } = b.({ :cont, acc }, fn x, acc -> [x|acc] end) - acc + defp do_interleave(a, b, acc) do + case a.({ :cont, acc }) do + { :suspended, acc, a } -> + case b.({ :cont, acc }) do + { :suspended, acc, b } -> + do_interleave(a, b, acc) + { :halt, acc } -> + acc + { :done, acc } -> + finish_interleave(a, acc) + end + { :halt, acc } -> + acc + { :done, acc } -> + finish_interleave(b, acc) + end + end + + defp finish_interleave(a_or_b, acc) do + case a_or_b.({ :cont, acc }) do + { :suspended, acc, a_or_b } -> + finish_interleave(a_or_b, acc) + { _, acc } -> + acc + end end end + +Interleave.interleave([1,2], [:a, :b, :c, :d]) +#=> [1, :a, 2, :b, :c, :d] ``` Lets go through this step by step. The main `interleave` function first From fbe92d594fda5f768b4c229f107ec7e1abd4ac01 Mon Sep 17 00:00:00 2001 From: Takayuki Matsubara Date: Wed, 18 Dec 2013 21:47:34 +0900 Subject: [PATCH 13/40] remove `.git` suffix --- getting_started/mix/1.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getting_started/mix/1.markdown b/getting_started/mix/1.markdown index dcf4fb6fd..6652ffe5b 100644 --- a/getting_started/mix/1.markdown +++ b/getting_started/mix/1.markdown @@ -63,7 +63,7 @@ defmodule MyProject.Mixfile do # { :foobar, git: "https://github.com/elixir-lang/foobar.git", tag: "0.1" } # # To specify particular versions, regardless of the tag, do: - # { :barbat, "~> 0.1", github: "elixir-lang/barbat.git" } + # { :barbat, "~> 0.1", github: "elixir-lang/barbat" } defp deps do [] end From 28e6079f645d6fc584e09b9bb002898dd2f690c8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 19 Dec 2013 09:38:32 +0100 Subject: [PATCH 14/40] v0.12.0 blog post --- _includes/search.html | 2 +- ...013-12-15-elixir-v0-12-0-released.markdown | 52 +++++++++++++++++++ 2 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 _posts/2013-12-15-elixir-v0-12-0-released.markdown diff --git a/_includes/search.html b/_includes/search.html index 494a341ae..3bd4fe69d 100644 --- a/_includes/search.html +++ b/_includes/search.html @@ -1,6 +1,6 @@ diff --git a/_posts/2013-12-15-elixir-v0-12-0-released.markdown b/_posts/2013-12-15-elixir-v0-12-0-released.markdown new file mode 100644 index 000000000..403f27819 --- /dev/null +++ b/_posts/2013-12-15-elixir-v0-12-0-released.markdown @@ -0,0 +1,52 @@ +--- +layout: post +title: Elixir v0.12.0 released +author: José Valim +category: Releases +excerpt: Elixir v0.12.0 is out with improved enumerables, build patterns and welcoming a new member to our team +--- + +Elixir v0.12.0 has been released with improved enumerables, build patterns and welcoming a new member to our team. + +## Enumerables + +In previous versions, the Enumerable protocol was based on reduce/fold, and while it is very efficient for operations like `map`, `reduce` and `filter`, it was sub-optimal for operations that need to halt, like `take` and `take_while`, and it made it impossible for operations like `zip` to be implemented. + +In v0.12.0, Elixir's Enumerable protocol has been extended to allow suspension and halting mechanisms, making operations like `take` simpler and operations that require interleaving, like `zip`, possible. + +Although most users don't need to concern with the implementation of the Enumerable protocol, the side-effect is that both `Enum` and `Stream` modules have been considerably extended and improved in this release, with more than 15 new functions added to the `Stream` module. + +## Mix + +The tool that received most improvements in this release was Mix. The biggest change is that Mix no longer compiles projects in place but to the `_build` directory. For example, take the [Ecto project](https://github.com/elixir-lang/ecto) that [depends on `postgrex` and `poolboy`](https://github.com/elixir-lang/ecto/blob/master/mix.exs#L24-L25). When compiled, all the artifacts will be placed in the `_build` directory like this: + +``` +_build +└── shared + └── lib + ├── ecto + │   └── ebin + | └── priv + ├── poolboy + │   └── ebin + └── postgrex + └── ebin +``` + +For those familiar with Erlang's OTP, this is similar to the structure used by OTP when releasing your software. So this new structure makes our software one step close to production and guarantee it is designed correctly since day 1. + +This approach comes with the `:build_per_environment` option which, when set to true, creates a different build per environment (`dev`, `test`, `production` or more). Extremely useful when a project compile different artifacts depending on the compilation environment. + +Mix has also added support to optional dependencies and improved common patterns, like the usage of umbrella apps. + +## Welcome, Eric! + +With this release, we also want to welcome [Eric MJ](https://github.com/ericmj) to the Elixir Team. He has done a fantastic work on Elixir so far, helping us maintain the codebase and working on many of the important features from previous releases. + +Eric is also maintainer of both [Ecto](https://github.com/elixir-lang/ecto) and [Postgrex](https://github.com/ericmj/postgrex) projects. Which are proving to be very useful to the Elixir community too! + +## Tidying up + +There were other small changes, like additions to the `Float` module and improvements the to the typespec syntax. To see the full list, please [see the CHANGELOG](https://github.com/elixir-lang/elixir/blob/v0.12.0/CHANGELOG.md). + +Give Elixir a try! You can start with our [getting started guide](http://elixir-lang.org/getting_started/1.html), or check out our sidebar for other learning resources. From 4d23e0d77645e4f7f23db9187d26d4e5c9b46602 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Thu, 19 Dec 2013 19:44:34 +0100 Subject: [PATCH 15/40] Update 2013-12-15-elixir-v0-12-0-released.markdown --- _posts/2013-12-15-elixir-v0-12-0-released.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/_posts/2013-12-15-elixir-v0-12-0-released.markdown b/_posts/2013-12-15-elixir-v0-12-0-released.markdown index 403f27819..200a4a5cf 100644 --- a/_posts/2013-12-15-elixir-v0-12-0-released.markdown +++ b/_posts/2013-12-15-elixir-v0-12-0-released.markdown @@ -41,7 +41,7 @@ Mix has also added support to optional dependencies and improved common patterns ## Welcome, Eric! -With this release, we also want to welcome [Eric MJ](https://github.com/ericmj) to the Elixir Team. He has done a fantastic work on Elixir so far, helping us maintain the codebase and working on many of the important features from previous releases. +With this release, we also want to welcome [Eric MJ](https://github.com/ericmj) to the Elixir Team. He has done fantastic work on Elixir, helping us maintain the codebase and working on many of the important features from previous releases and now many more to come. Eric is also maintainer of both [Ecto](https://github.com/elixir-lang/ecto) and [Postgrex](https://github.com/ericmj/postgrex) projects. Which are proving to be very useful to the Elixir community too! From 6fa7ed1996779aac649078e5e36b1742043d0f7e Mon Sep 17 00:00:00 2001 From: Yuki Ito Date: Sun, 22 Dec 2013 18:09:47 +0900 Subject: [PATCH 16/40] Fix interleave example --- .../2013-12-11-elixir-s-new-continuable-enumerators.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown b/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown index 97b0f86de..970004c39 100644 --- a/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown +++ b/_posts/2013-12-11-elixir-s-new-continuable-enumerators.markdown @@ -164,12 +164,12 @@ defmodule Interleave do case b.({ :cont, acc }) do { :suspended, acc, b } -> do_interleave(a, b, acc) - { :halt, acc } -> + { :halted, acc } -> acc { :done, acc } -> finish_interleave(a, acc) end - { :halt, acc } -> + { :halted, acc } -> acc { :done, acc } -> finish_interleave(b, acc) From af8cf4c9350c961bcb99b8821da2389aec7843a7 Mon Sep 17 00:00:00 2001 From: Ryan Coppolo Date: Thu, 16 Jan 2014 14:38:56 -0800 Subject: [PATCH 17/40] Update crash course w/ send for messages instead of deprecated <- --- crash-course.markdown | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/crash-course.markdown b/crash-course.markdown index d9fc22a1b..ead267f96 100644 --- a/crash-course.markdown +++ b/crash-course.markdown @@ -101,7 +101,6 @@ Some operators are spelled differently. | =/= | !== | A negative match | | /= | != | Not equals | | =< | <= | Less than or equals | - | ! | <- | Send messages | ### Delimiters @@ -815,7 +814,7 @@ end. ```elixir pid = Kernel.self -pid <- { :hello } +send pid, { :hello } receive do { :hello } -> :ok From f95e1798534112f2e8a4e86a7ece518628e46918 Mon Sep 17 00:00:00 2001 From: Josh Adams Date: Fri, 27 Dec 2013 09:08:31 -0600 Subject: [PATCH 18/40] Add a post on XML Parsing with an ElixirSips episode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- ...013-12-27-parsing-xml-with-elixir.markdown | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 _posts/2013-12-27-parsing-xml-with-elixir.markdown diff --git a/_posts/2013-12-27-parsing-xml-with-elixir.markdown b/_posts/2013-12-27-parsing-xml-with-elixir.markdown new file mode 100644 index 000000000..61488ab3a --- /dev/null +++ b/_posts/2013-12-27-parsing-xml-with-elixir.markdown @@ -0,0 +1,24 @@ +--- +layout: post +title: Parsing XML With Elixir +author: Josh Adams +category: examples +excerpt: An example of interoperating with Erlang's built-in `xmerl` library to parse XML. +--- + +In the latest free video, [ElixirSips](http://www.elixirsips.com) [Episode +028](http://elixirsips.com/episodes/028_parsing_xml.html) provides an example of +parsing XML via the built in `xmerl` library in Erlang. + + + +[Here is the project built in this episode, for you to download.](http://elixirsips.com/downloads/028_parsing_xml.tar.gz) + +## Resources +- [xmerl user guide](http://www.erlang.org/doc/apps/xmerl/xmerl_ug.html) +- [xmerl manual](http://www.erlang.org/doc/man/xmerl_scan.html) +- [erlsom](https://github.com/willemdj/erlsom) +- [exml](https://github.com/paulgray/exml) +- [Differences between Erlang and Elixir records](http://elixir-lang.org/crash-course.html#notable_differences) - See the 'Records' section. +- [Dave Thomas on parsing XML in Erlang](http://pragdave.pragprog.com/pragdave/2007/04/a_first_erlang_.html) +- [`xmlElement` record](https://github.com/erlang/otp/blob/maint/lib/xmerl/include/xmerl.hrl#L73-L85) From d23cc15d00680c5ed2931d435e3387094ec486a2 Mon Sep 17 00:00:00 2001 From: Josh Adams Date: Tue, 7 Jan 2014 09:35:57 -0600 Subject: [PATCH 19/40] Add some code to the xml post, so it's not just a video embed MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: José Valim --- ...013-12-27-parsing-xml-with-elixir.markdown | 58 +++++++++++++++++++ 1 file changed, 58 insertions(+) diff --git a/_posts/2013-12-27-parsing-xml-with-elixir.markdown b/_posts/2013-12-27-parsing-xml-with-elixir.markdown index 61488ab3a..78643baed 100644 --- a/_posts/2013-12-27-parsing-xml-with-elixir.markdown +++ b/_posts/2013-12-27-parsing-xml-with-elixir.markdown @@ -14,6 +14,64 @@ parsing XML via the built in `xmerl` library in Erlang. [Here is the project built in this episode, for you to download.](http://elixirsips.com/downloads/028_parsing_xml.tar.gz) +You can watch the video for a complete rundown where we use tests to explore the +`xmerl` library and how we can use it from Elixir. If you just want to see the +results, here's the test file we ended up with, commented for clarity: + +```elixir +# If you want to pattern-match on a record defined in an erlang library, you +# need to use Record.extract to turn it into an Elixir record data structure. +# Here, we extract xmlElement and xmlText from xmerl. +defrecord :xmlElement, Record.extract(:xmlElement, from_lib: "xmerl/include/xmerl.hrl") +defrecord :xmlText, Record.extract(:xmlText, from_lib: "xmerl/include/xmerl.hrl") + +defmodule XmlParsingTest do + use ExUnit.Case + + # Here we define some simple XML that we'll work with in our tests. + def sample_xml do + """ + + + XML Parsing + + +

    Neato

    +
      +
    • First
    • +
    • Second
    • +
    + + + """ + end + + test "parsing the title out" do + { xml, _rest } = :xmerl_scan.string(bitstring_to_list(sample_xml)) + [ title_element ] = :xmerl_xpath.string('/html/head/title', xml) + [ title_text ] = title_element.content + title = title_text.value + + assert title == 'XML Parsing' + end + + test "parsing the p tag" do + { xml, _rest } = :xmerl_scan.string(bitstring_to_list(sample_xml)) + [ p_text ] = :xmerl_xpath.string('/html/body/p/text()', xml) + + assert p_text.value == 'Neato' + end + + test "parsing the li tags and mapping them" do + { xml, _rest } = :xmerl_scan.string(bitstring_to_list(sample_xml)) + li_texts = :xmerl_xpath.string('/html/body/ul/li/text()', xml) + texts = li_texts |> Enum.map(fn(x) -> x.value end) + + assert texts == ['First', 'Second'] + end +end +``` + ## Resources - [xmerl user guide](http://www.erlang.org/doc/apps/xmerl/xmerl_ug.html) - [xmerl manual](http://www.erlang.org/doc/man/xmerl_scan.html) From 8e527448d15985c2ed5096ffbfaccb280a9358cd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 20 Jan 2014 14:38:26 +0100 Subject: [PATCH 20/40] Tidy up episode's post --- ...013-12-27-parsing-xml-with-elixir.markdown | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/_posts/2013-12-27-parsing-xml-with-elixir.markdown b/_posts/2013-12-27-parsing-xml-with-elixir.markdown index 78643baed..c73d63867 100644 --- a/_posts/2013-12-27-parsing-xml-with-elixir.markdown +++ b/_posts/2013-12-27-parsing-xml-with-elixir.markdown @@ -6,17 +6,16 @@ category: examples excerpt: An example of interoperating with Erlang's built-in `xmerl` library to parse XML. --- -In the latest free video, [ElixirSips](http://www.elixirsips.com) [Episode -028](http://elixirsips.com/episodes/028_parsing_xml.html) provides an example of -parsing XML via the built in `xmerl` library in Erlang. +One of the latest episodes of [ElixirSips](http://elixirsips.com/episodes/028_parsing_xml.html) +provided an example of parsing XML via the built in `xmerl` library in Erlang: -[Here is the project built in this episode, for you to download.](http://elixirsips.com/downloads/028_parsing_xml.tar.gz) - -You can watch the video for a complete rundown where we use tests to explore the -`xmerl` library and how we can use it from Elixir. If you just want to see the -results, here's the test file we ended up with, commented for clarity: +Parsing XML is a common need to different applications. The example also show cases +how to integrate with existing Erlang libraries. You can watch the video for a complete +rundown where we use tests to explore the `xmerl` library and how we can use it from +Elixir. If you just want to see the results, here's the test file we ended up with, +commented for clarity: ```elixir # If you want to pattern-match on a record defined in an erlang library, you @@ -72,7 +71,11 @@ defmodule XmlParsingTest do end ``` +The project built in the episode is also +[available for download](http://elixirsips.com/downloads/028_parsing_xml.tar.gz). + ## Resources + - [xmerl user guide](http://www.erlang.org/doc/apps/xmerl/xmerl_ug.html) - [xmerl manual](http://www.erlang.org/doc/man/xmerl_scan.html) - [erlsom](https://github.com/willemdj/erlsom) From 90a5cbd2ad6a8f62c4a73aef228bb1735f64e0da Mon Sep 17 00:00:00 2001 From: sasa1977 Date: Mon, 20 Jan 2014 20:38:04 +0100 Subject: [PATCH 21/40] Elixir in Action link --- _includes/learning-resources.html | 1 + 1 file changed, 1 insertion(+) diff --git a/_includes/learning-resources.html b/_includes/learning-resources.html index 17e8d55f7..7471ced0c 100644 --- a/_includes/learning-resources.html +++ b/_includes/learning-resources.html @@ -4,5 +4,6 @@

    Learning resources

  • +
  • From 63edfcd2699fad738da414ea902f070e2170a8a1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Tue, 21 Jan 2014 12:26:07 +0100 Subject: [PATCH 22/40] Update learning resources --- _includes/learning-resources.html | 1 - 1 file changed, 1 deletion(-) diff --git a/_includes/learning-resources.html b/_includes/learning-resources.html index 7471ced0c..a30c82f1f 100644 --- a/_includes/learning-resources.html +++ b/_includes/learning-resources.html @@ -2,7 +2,6 @@

    Learning resources

    • -
    From 4264427ce1e42a66393dfd01b2ea80d3016c7999 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Sat, 25 Jan 2014 19:52:10 +0100 Subject: [PATCH 23/40] Fix remaining usage of <- --- getting_started/2.markdown | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/getting_started/2.markdown b/getting_started/2.markdown index fe02223aa..95590e948 100644 --- a/getting_started/2.markdown +++ b/getting_started/2.markdown @@ -512,7 +512,7 @@ x #=> 1 This next control-flow mechanism is essential to Elixir's actors. In Elixir, the code is run in separate processes that exchange messages between them. Those processes are not Operating System processes (they are actually quite light-weight) but are called so since they do not share state with each other. -In order to exchange messages, each process has a mailbox where the received messages are stored. The `receive` mechanism allows us to go through this mailbox searching for a message that matches the given pattern. Here is an example that uses the arrow operator `<-` to send a message to the current process and then collects this message from its mailbox: +In order to exchange messages, each process has a mailbox where the received messages are stored. The `receive` mechanism allows us to go through this mailbox searching for a message that matches the given pattern. Here is an example that uses the `send/2` function to send a message to the current process and then collects this message from its mailbox: ```iex # Get the current process id @@ -520,7 +520,7 @@ iex> current_pid = self # Spawn another process that will send a message to current_pid iex> spawn fn -> - current_pid <- { :hello, self } + send current_pid, { :hello, self } end <0.36.0> From fdbe84d445f6436883ca98d69fcea87c388e0f7c Mon Sep 17 00:00:00 2001 From: travishoyt Date: Mon, 27 Jan 2014 19:12:26 -0500 Subject: [PATCH 24/40] Update md to correct set_elem typo set_elem was written as setelem. --- crash-course.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/crash-course.markdown b/crash-course.markdown index ead267f96..2310d65ae 100644 --- a/crash-course.markdown +++ b/crash-course.markdown @@ -260,7 +260,7 @@ setelement(1, { a, b, c }, d) %=> { d, b, c } ```elixir elem({ :a, :b, :c }, 0) #=> :a -setelem({ :a, :b, :c }, 0, :d) #=> { :d, :b, :c } +set_elem({ :a, :b, :c }, 0, :d) #=> { :d, :b, :c } ``` ### Lists and Binaries From f6aa6e9317c200d5720ab1d530ce39e5be48652d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Mon, 3 Feb 2014 11:05:37 +0100 Subject: [PATCH 25/40] Link to Riak great tutorial for installing Erlang --- getting_started/1.markdown | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/getting_started/1.markdown b/getting_started/1.markdown index f4e711fca..e8a209ac7 100644 --- a/getting_started/1.markdown +++ b/getting_started/1.markdown @@ -17,9 +17,9 @@ Keep in mind that Elixir is still in development, so if at any point you receive ## 1.1 Installation -The only prerequisite for Elixir is Erlang, version R16B or later. You can find the source code for [Erlang here](http://www.erlang.org/download.html) or use one of the [precompiled packages](https://www.erlang-solutions.com/downloads/download-erlang-otp). +The only prerequisite for Elixir is Erlang, version R16B or later, which can be easily installed with [Precompiled packages](https://www.erlang-solutions.com/downloads/download-erlang-otp). In case you want to install it directly from source, it can be found on [the Erlang website](http://www.erlang.org/download.html) or by following the excellent tutorial available in the [Riak documentation](http://docs.basho.com/riak/1.3.0/tutorials/installation/Installing-Erlang/). -For Windows developers, we recommend the precompiled package. Those on a UNIX platform can probably get Erlang installed via one of the many package management tools. +For Windows developers, we recommend the precompiled packages. Those on a UNIX platform can probably get Erlang installed via one of the many package management tools. After Erlang is installed, you should be able to open up the command line (or command prompt) and check the Erlang version by typing `erl`. You will see some information as follows: @@ -50,9 +50,13 @@ This tutorial requires Elixir v0.10.2 or later and it may be available in some d If you don't use any of the distributions above, don't worry, we also provide a precompiled package! -### 1.1.2 Compiling from source (Unix and MinGW) +### 1.1.2 Precompiled package -You can download and compile Elixir in few steps. You can get the [latest stable release here](https://github.com/elixir-lang/elixir/tags), unpack it and then run `make` inside the unpacked directory. After that, you are ready to run the `elixir` and `iex` commands from the `bin` directory. It is recommended that you add Elixir's `bin` path to your PATH environment variable to ease development: +Elixir provides a [precompiled package for every release](https://github.com/elixir-lang/elixir/releases/). After downloading and unzip-ing the package, you are ready to run the `elixir` and `iex` commands from the `bin` directory. It is recommended that you also add Elixir's `bin` path to your PATH environment variable to ease development. + +### 1.1.3 Compiling from source (Unix and MinGW) + +You can download and compile Elixir in few steps. You can get the [latest stable release here](https://github.com/elixir-lang/elixir/releases/), unpack it and then run `make` inside the unpacked directory. After that, you are ready to run the `elixir` and `iex` commands from the `bin` directory. It is recommended that you add Elixir's `bin` path to your PATH environment variable to ease development: $ export PATH="$PATH:/path/to/elixir/bin" @@ -64,12 +68,6 @@ In case you are feeling a bit more adventurous, you can also compile from master If the tests pass, you are ready to go. Otherwise, feel free to open an issue [in the issues tracker on Github](https://github.com/elixir-lang/elixir). -### 1.1.3 Precompiled package - -Elixir provides a [precompiled package for every release](https://github.com/elixir-lang/elixir/releases/). Precompiled packages are the best option if you are developing on Windows. - -After downloading and unzip-ing the package, you are ready to run the `elixir` and `iex` commands from the `bin` directory. It is recommended that you also add Elixir's `bin` path to your PATH environment variable to ease development. - ## 1.2 Interactive mode When you install Elixir, you will have three new executables: `iex`, `elixir` and `elixirc`. If you compiled Elixir from source or are using a packaged version, you can find these inside the `bin` directory. From 0566314316686ce8195c3ee110e14dfa21597ca6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Meadows-J=C3=B6nsson?= Date: Fri, 7 Feb 2014 22:01:46 +0100 Subject: [PATCH 26/40] Remove `@only` section from guide Closes #189. --- getting_started/4.markdown | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/getting_started/4.markdown b/getting_started/4.markdown index 20c78876e..516fd57b3 100644 --- a/getting_started/4.markdown +++ b/getting_started/4.markdown @@ -87,7 +87,7 @@ For more information on records, [check out the documentation for the `defrecord ## 4.2 Protocols -Protocols are a mechanism to achieve polymorphism in Elixir. Dispatching a protocol is available to any data type as long as it implements the protocol. Let's consider a practical example. +Protocols are a mechanism to achieve polymorphism in Elixir. Dispatching on a protocol is available to any data type as long as it implements the protocol. Lets consider a practical example. In Elixir, only `false` and `nil` are treated as false. Everything else evaluates to true. Depending on the application, it may be important to specify a `blank?` protocol that returns a boolean for other data types that should be considered blank. For instance, an empty list or an empty binary could be considered blanks. @@ -174,7 +174,7 @@ Now all data types that we have not implemented the `Blank` protocol for will be ### 4.2.2 Using protocols with records -The power of Elixir extensibility comes when protocols and records are mixed. +The power of Elixir's extensibility comes when protocols and records are mixed. For instance, Elixir provides a `HashDict` implementation that is an efficient data structure to store many keys. Let's take a look at how it works: @@ -207,13 +207,7 @@ Blank.blank?(dict) #=> false Blank.blank?(HashDict.new) #=> true ``` -Excellent! The best of all is that we implemented the `Blank` protocol for an existing data structure (`HashDict`) without a need to wrap it or recompile it, which allows developers to easily extend previously defined protocols. Note this only worked because, when we defined the protocol, we have added `Record` to the list of types supported by the protocol: - -```elixir -@only [Atom, Record, Tuple, List, BitString, Any] -``` - -Keep in mind that `Record` needs to come before `Tuple`, since all records are tuples (but not all tuples are records). For this reason, in case a record does not implement a given protocol, Elixir will fall back to the tuple implementation of that protocol if one exists. So one can add a default protocol implementation for all records by simply defining a default implementation for tuples. +Excellent! The best of all is that we implemented the `Blank` protocol for an existing data structure (`HashDict`) without a need to wrap it or recompile it, which allows developers to easily extend previously defined protocols. ### 4.2.3 Built-in protocols From 819c5cefe4fd1651bdc128dfa4a56add9715c092 Mon Sep 17 00:00:00 2001 From: Peter Zsoldos Date: Fri, 7 Feb 2014 22:17:47 +0100 Subject: [PATCH 27/40] emphasize that Inspect.inspect return values starting with '#' are not enforced and that it's the responsibility of the data structure author to follow this convention --- getting_started/4.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getting_started/4.markdown b/getting_started/4.markdown index 516fd57b3..ba5cc69eb 100644 --- a/getting_started/4.markdown +++ b/getting_started/4.markdown @@ -242,7 +242,7 @@ iex> HashDict.new #HashDict<[]> ``` - Keep in mind that whenever the inspected value starts with `#`, it is representing a data structure in non-valid Elixir syntax. For those, the true representation can be retrieved by calling `inspect` directly and passing `raw` as an option: + Keep in mind that, by convention, whenever the inspected value starts with `#`, it is representing a data structure in non-valid Elixir syntax. For those, the true representation can be retrieved by calling `inspect` directly and passing `raw` as an option: ```iex iex> inspect HashDict.new, raw: true From 2a996b7666544c53b414166a0b9eb4ad6de2e7e5 Mon Sep 17 00:00:00 2001 From: Peter Zsoldos Date: Sat, 8 Feb 2014 14:52:29 +0100 Subject: [PATCH 28/40] generate linkable id attribtues for tags So that they can be linked to for easier sharing (as described in by @ericmj in #157 https://github.com/elixir-lang/elixir-lang.github.com/pull/157#issuecomment-24446351) This change only ensures that text-independent id attributes are generated in the HTML, the usability aspects (like the on-hover copyable link that github repo pages have) are not included. Tested on Xubuntu 13.04 with $ sudo apt-get install ruby1.9.3 $ sudo gem1.9.3 install github-pages $ cd ~/3rdparty/elixir-lang.github.com/ $ vim _config.yml $ git diff diff --git a/_config.yml b/_config.yml index 18d7dd5..78201b0 100644 --- a/_config.yml +++ b/_config.yml @@ -1,3 +1,5 @@ markdown: redcarpet pygments: true permalink: /blog/:year/:month/:day/:title +redcarpet: + extensions: ['with_toc_data'] $ jekyll serve --safe --- _config.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/_config.yml b/_config.yml index 18d7dd5ab..78201b070 100644 --- a/_config.yml +++ b/_config.yml @@ -1,3 +1,5 @@ markdown: redcarpet pygments: true permalink: /blog/:year/:month/:day/:title +redcarpet: + extensions: ['with_toc_data'] From 7cd4c1c4302e0d2ca9a96a086295ee8138b90251 Mon Sep 17 00:00:00 2001 From: John Warwick Date: Sat, 8 Feb 2014 21:33:14 -0500 Subject: [PATCH 29/40] Updating sigil marker from % -> ~. Didn't update 'whats new' posts. --- crash-course.markdown | 4 ++-- getting_started/6.markdown | 20 ++++++++++---------- index.html | 2 +- 3 files changed, 13 insertions(+), 13 deletions(-) diff --git a/crash-course.markdown b/crash-course.markdown index 2310d65ae..e716620cc 100644 --- a/crash-course.markdown +++ b/crash-course.markdown @@ -312,14 +312,14 @@ re:run("abc ", Pattern). **Elixir** ```elixir -Regex.run %r/abc\s/, "abc " +Regex.run ~r/abc\s/, "abc " #=> ["abc "] ``` Regexes are also supported in heredocs, which is convenient when defining multiline regexes: ```elixir -is_regex %r""" +is_regex ~r""" This is a regex spawning several lines. diff --git a/getting_started/6.markdown b/getting_started/6.markdown index f4a81ac00..7399c2b7f 100644 --- a/getting_started/6.markdown +++ b/getting_started/6.markdown @@ -11,27 +11,27 @@ This chapter contains different small topics that are part of Elixir's day to da ## 6.1 String sigils -Elixir provides string sigils via the token `%`: +Elixir provides string sigils via the token `~`: ```elixir -%s(String with escape codes \x26 interpolation) -%S(String without escape codes and without #{interpolation}) +~s(String with escape codes \x26 interpolation) +~S(String without escape codes and without #{interpolation}) ``` Sigils starting with an uppercase letter never escape characters or do interpolation. Notice the separators are not necessarily parenthesis, but any non-alphanumeric character: ```elixir -%s-another string- +~s-another string- ``` -Internally, `%s` is translated as a call to `sigil_s`. For instance, the docs for `%s` are available in the macro [`sigil_s/2`](/docs/stable/Kernel.html#sigil_s/2) defined in `Kernel` module. +Internally, `~s` is translated as a call to `sigil_s`. For instance, the docs for `~s` are available in the macro [`sigil_s/2`](/docs/stable/Kernel.html#sigil_s/2) defined in the `Kernel` module. The sigils defined in Elixir by default are: -* `%c` and `%C` - Returns a char list; -* `%r` and `%R` - Returns a regular expression; -* `%s` and `%S` - Returns a string; -* `%w` and `%W` - Returns a list of "words" split by whitespace; +* `~c` and `~C` - Returns a char list; +* `~r` and `~R` - Returns a regular expression; +* `~s` and `~S` - Returns a string; +* `~w` and `~W` - Returns a list of "words" split by whitespace; ## 6.2 Heredocs @@ -58,7 +58,7 @@ String heredocs in Elixir use """ Notice the sigils discussed in the previous section are also available as heredocs: ```elixir -%S""" +~S""" A heredoc without escaping or interpolation """ ``` diff --git a/index.html b/index.html index 40a89d256..da9c0aebe 100644 --- a/index.html +++ b/index.html @@ -82,7 +82,7 @@

    Polymorphism via protocols

    {% highlight elixir %} file = File.stream!("README.md") -lines = Enum.map(file, fn(line) -> Regex.replace(%r/"/, line, "'") end) +lines = Enum.map(file, fn(line) -> Regex.replace(~r/"/, line, "'") end) File.write("README.md", lines) {% endhighlight %} From 70e06e6b56d0bfedbbb90256c056d6aa51d85100 Mon Sep 17 00:00:00 2001 From: John Warwick Date: Sat, 8 Feb 2014 21:34:41 -0500 Subject: [PATCH 30/40] Removing references to __FILE__ --- getting_started/6.markdown | 1 - 1 file changed, 1 deletion(-) diff --git a/getting_started/6.markdown b/getting_started/6.markdown index 7399c2b7f..b9560b407 100644 --- a/getting_started/6.markdown +++ b/getting_started/6.markdown @@ -287,7 +287,6 @@ iex> bc <> inbits " hello world ", c != ?\s, do: <> Elixir provides a set of pseudo-variables. These variables can only be read and never assigned to. They are: * `__MODULE__` - Returns an atom representing the current module or nil; -* `__FILE__` - Returns a string representing the current file; * `__DIR__` - Returns a string representing the current directory; * `__ENV__` - Returns a [Macro.Env](/docs/stable/Macro.Env.html) record with information about the compilation environment. Here we can access the current module, function, line, file and others; * `__CALLER__` - Also returns a [Macro.Env](/docs/stable/Macro.Env.html) record but with information of the calling site. `__CALLER__` is available only inside macros; From 3706929e74f2b3a7f6a692a1bcb16c54171bfdb9 Mon Sep 17 00:00:00 2001 From: John Warwick Date: Sat, 8 Feb 2014 21:40:37 -0500 Subject: [PATCH 31/40] Updating default argument operator --- crash-course.markdown | 2 +- getting_started/3.markdown | 8 ++++---- getting_started/6.markdown | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/crash-course.markdown b/crash-course.markdown index e716620cc..340c2cf6a 100644 --- a/crash-course.markdown +++ b/crash-course.markdown @@ -565,7 +565,7 @@ sum "a", "b" In addition, Elixir allows for default values for arguments, whereas Erlang does not. ```elixir -def mul_by(x, n // 2) do +def mul_by(x, n \\ 2) do x * n end diff --git a/getting_started/3.markdown b/getting_started/3.markdown index 4a9a8b6f5..85ecaeb58 100644 --- a/getting_started/3.markdown +++ b/getting_started/3.markdown @@ -129,7 +129,7 @@ Named functions also support default arguments: ```elixir defmodule Concat do - def join(a, b, sep // " ") do + def join(a, b, sep \\ " ") do a <> sep <> b end end @@ -142,7 +142,7 @@ Any expression is allowed to serve as a default value, but it won't be evaluated ```elixir defmodule DefaultTest do - def dowork(x // IO.puts "hello") do + def dowork(x \\ IO.puts "hello") do x end end @@ -160,7 +160,7 @@ If a function with default values has multiple clauses, it is recommended to cre ```elixir defmodule Concat do - def join(a, b // nil, sep // " ") + def join(a, b \\ nil, sep \\ " ") def join(a, b, _sep) when nil?(b) do a @@ -185,7 +185,7 @@ defmodule Concat do a <> b end - def join(a, b, sep // " ") do + def join(a, b, sep \\ " ") do IO.puts "***Second join" a <> sep <> b end diff --git a/getting_started/6.markdown b/getting_started/6.markdown index b9560b407..d2525fef0 100644 --- a/getting_started/6.markdown +++ b/getting_started/6.markdown @@ -124,7 +124,7 @@ As you can see, invoking `h()` prints the documentation of `IEx.Helpers`. From t ```iex iex> h(c/2) -* def c(files, path // ".") +* def c(files, path \\ ".") ... :ok ``` From be3b262a63f064ad36544627c2538e19a14c9163 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Wed, 12 Feb 2014 10:48:59 +0100 Subject: [PATCH 32/40] Update Elixir dependency --- getting_started/1.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getting_started/1.markdown b/getting_started/1.markdown index e8a209ac7..f352e1ba3 100644 --- a/getting_started/1.markdown +++ b/getting_started/1.markdown @@ -31,7 +31,7 @@ After Erlang is up and running, it is time to install Elixir. You can do that vi ### 1.1.1 Distributions -This tutorial requires Elixir v0.10.2 or later and it may be available in some distributions: +This tutorial requires Elixir v0.12.4 or later and it may be available in some distributions: * Homebrew for Mac OS X * Update your homebrew to latest with `brew update` From 3bdea8cb3cea63e50ed037b5d8e5b07e406199ec Mon Sep 17 00:00:00 2001 From: Myers Carpenter Date: Wed, 12 Feb 2014 12:10:07 -0500 Subject: [PATCH 33/40] add title's for the docs page and the crash-course page. Link crash course in the getting started index. --- _layouts/getting_started.html | 6 ++++++ crash-course.markdown | 3 ++- docs.html | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/_layouts/getting_started.html b/_layouts/getting_started.html index 11647d40a..cfcb93ce3 100644 --- a/_layouts/getting_started.html +++ b/_layouts/getting_started.html @@ -33,6 +33,12 @@

    ExUnit - a unit test framework

  • Introduction to ExUnit
  • + {% include learning-resources.html %} {% include sponsors.html %} diff --git a/crash-course.markdown b/crash-course.markdown index 340c2cf6a..cbe62662b 100644 --- a/crash-course.markdown +++ b/crash-course.markdown @@ -1,9 +1,10 @@ --- +title: "Erlang/Elixir Syntax: A Crash Course" section: home layout: default --- -# Erlang/Elixir Syntax: A Crash Course +# {{ page.title }} This is a quick introduction to the Elixir syntax for Erlang developers and vice-versa. It is the absolute minimum amount of knowledge you need in order to understand Elixir/Erlang code, support interoperability, read the docs, sample code, etc. diff --git a/docs.html b/docs.html index 4c6afd2e5..73716c250 100644 --- a/docs.html +++ b/docs.html @@ -1,4 +1,5 @@ --- +title: Elixir Documentation section: docs layout: default --- From 31749fbb0d989236430408399b466e6e0a02e3ca Mon Sep 17 00:00:00 2001 From: Myers Carpenter Date: Wed, 12 Feb 2014 12:20:25 -0500 Subject: [PATCH 34/40] Make a link from the Mix OTP docs back to recieve --- getting_started/2.markdown | 2 +- getting_started/mix/2.markdown | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/getting_started/2.markdown b/getting_started/2.markdown index 95590e948..67175adbb 100644 --- a/getting_started/2.markdown +++ b/getting_started/2.markdown @@ -508,7 +508,7 @@ x = 1 x #=> 1 ``` -### 2.6.4 Receive +### 2.6.4 Receive This next control-flow mechanism is essential to Elixir's actors. In Elixir, the code is run in separate processes that exchange messages between them. Those processes are not Operating System processes (they are actually quite light-weight) but are called so since they do not share state with each other. diff --git a/getting_started/mix/2.markdown b/getting_started/mix/2.markdown index 0fbbce308..6976cba19 100644 --- a/getting_started/mix/2.markdown +++ b/getting_started/mix/2.markdown @@ -9,7 +9,7 @@ total_guides: 3 Where do we keep state in Elixir? -Our software needs to keep state, configuration values, data about the running system, etc. We have learned in previous sections how we can use processes/actors to keep state, receiving and responding to messages in a loop but this approach seems to be brittle. What happens if there is an error in our actor and it crashes? Even more, is it really required to create a new process when all we want to do is to keep simple configuration values? +Our software needs to keep state, configuration values, data about the running system, etc. We have learned in [previous sections](../2.html#receive) how we can use processes/actors to keep state, receiving and responding to messages in a loop but this approach seems to be brittle. What happens if there is an error in our actor and it crashes? Even more, is it really required to create a new process when all we want to do is to keep simple configuration values? In this chapter, we will answer those questions by building an OTP application. In practice, we don't need Mix in order to build such applications, however Mix provides some conveniences that we are going to explore throughout this chapter. From 9bb8de832740e6ab9a824d0114fef216e57937bd Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 21 Feb 2014 20:04:16 +0100 Subject: [PATCH 35/40] Remove background selection --- css/style.css | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/css/style.css b/css/style.css index a499b6dd0..925855b29 100644 --- a/css/style.css +++ b/css/style.css @@ -42,16 +42,6 @@ body { #container { background-color: #FFF; } -::-moz-selection { - background: #000; - color: #fff; - text-shadow: none; -} -::selection { - background: #000; - color: #fff; - text-shadow: none; -} a, a:visited { color: #4E2A8E; text-decoration: underline; From 8b5b197847e1e1d0e50a3b5dff3c752210dd078b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 21 Feb 2014 20:35:37 +0100 Subject: [PATCH 36/40] Cut the gibberish in the introduction --- index.html | 8 +------- 1 file changed, 1 insertion(+), 7 deletions(-) diff --git a/index.html b/index.html index da9c0aebe..27488467d 100644 --- a/index.html +++ b/index.html @@ -9,16 +9,10 @@

    Elixir is a functional, meta-programming aware language built on top of the Erlang VM. It is a dynamic language with flexible syntax and macro support that leverages Erlang's abilities to build concurrent, distributed and fault-tolerant applications with hot code upgrades.

    -

    Elixir also provides first-class support for pattern matching, polymorphism via protocols (similar to Clojure's), aliases and associative data structures (usually known as dicts or hashes in other programming languages).

    -

    Finally, Elixir and Erlang share the same bytecode and data types. This means you can invoke Erlang code from Elixir (and vice-versa) without any conversion or performance hit. This allows a developer to mix the expressiveness of Elixir with the robustness and performance of Erlang.

    -

    To install Elixir or learn more about it, check our getting started guide. We also have online documentation available and a Crash Course for Erlang developers.

    +

    To install Elixir or learn more about it, check our getting started guide. We also have online documentation available and a Crash Course for Erlang developers. Or you can just keep on reading for a few code samples!

    -
    -

    Highlights

    -
    -

    Everything is an expression

    From 617776a60a2544df4016798322464230384f25aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 21 Feb 2014 20:54:23 +0100 Subject: [PATCH 37/40] Let's talk about the tooling too --- index.html | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/index.html b/index.html index 27488467d..b1026cbee 100644 --- a/index.html +++ b/index.html @@ -142,6 +142,45 @@

    Pattern matching

    +
    +

    Tooling included

    + +
    +

    Elixir ships with a great set of tools to ease development. Mix allows you to easily create your new project, manage tasks and dependencies:

    + +{% highlight text %} +$ mix new my_app +$ cd my_app +$ mix test +. + +Finished in 0.04 seconds (0.04s on load, 0.00s on tests) +1 tests, 0 failures +{% endhighlight %} + +

    In the example above, we have created a new project and ran its initial test suite powered by the ExUnit test framework.

    + +

    Elixir also ships with an Interactive Shell, called IEx, which provides a great set of helpers for writing code, like easy access to documentation (shown above), code reloading and so on. It is also great companion for production, as it allows, for example, connecting to remote nodes. Here is a quick example you can try locally. In one terminal, do:

    + +{% highlight text %} +$ iex --name hello +iex(hello@machine)1> defmodule Hello do +...(hello@machine)1> def world, do: IO.puts "Distributed hello world" +...(hello@machine)1> end +{% endhighlight %} + +

    See the name in between parenthesis starting with hello? Copy that, open up another terminal and pass it to --remsh (short for remote shell):

    + +{% highlight text %} +$ iex --name world --remsh "hello@machine" +iex(hello@machine)1> Hello.world +"Distributed hello world" +{% endhighlight %} + +

    Notice we were able to invoke a function from a module defined in the other terminal! Even the node names are the same. This will work in between machines in the same network as long as they have the same value in the ~/.erlang.cookie file!

    +
    +
    +

    Erlang all the way down

    From b4c625cd1c54db5ac424509c722779eacf455bc4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 21 Feb 2014 21:08:59 +0100 Subject: [PATCH 38/40] Have a specific section for remote shells --- css/style.css | 2 +- index.html | 16 +++++++++++++--- 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/css/style.css b/css/style.css index 925855b29..62d7c699e 100644 --- a/css/style.css +++ b/css/style.css @@ -404,7 +404,6 @@ a:hover img, #slider-nav li a:hover img { opacity: 0.85; } border: 1px solid #e5e5e5; } .rss-button { margin-bottom: 25px; } -img.no-border { border: 0 }; /* Layout -------------------------------------------------------------- */ @@ -568,6 +567,7 @@ body.source div.menu li.source a { height: 150px; margin: 3px 25px 20px 0; } +.no-border { border: 0 }; /* Post titles -------------------------------------------------------------- */ diff --git a/index.html b/index.html index b1026cbee..439cbb969 100644 --- a/index.html +++ b/index.html @@ -4,7 +4,7 @@ ---
    -
    +
    Elixir Sample
    @@ -13,6 +13,10 @@
    +
    +

    Language highlights

    +
    +

    Everything is an expression

    @@ -159,8 +163,14 @@

    Tooling included

    {% endhighlight %}

    In the example above, we have created a new project and ran its initial test suite powered by the ExUnit test framework.

    +
    +
    + +
    +

    Interactive (and remote) shells

    -

    Elixir also ships with an Interactive Shell, called IEx, which provides a great set of helpers for writing code, like easy access to documentation (shown above), code reloading and so on. It is also great companion for production, as it allows, for example, connecting to remote nodes. Here is a quick example you can try locally. In one terminal, do:

    +
    +

    Elixir also ships with an Interactive Shell, called IEx, which provides a great set of helpers for writing code, like easy access to documentation (shown above), code reloading and so on. It is also a great companion for production, as it allows for example connecting to remote nodes. Here is a quick example you can try locally. In one terminal, do:

    {% highlight text %} $ iex --name hello @@ -185,7 +195,7 @@

    Tooling included

    Erlang all the way down

    -

    After all, Elixir is still Erlang. An Elixir programmer can invoke any Erlang function with no runtime cost:

    +

    After all, Elixir runs in the Erlang VM. An Elixir programmer can invoke any Erlang function with no runtime cost:

    {% highlight elixir %} :application.start(:crypto) From aee050da35afcd95bf5a44a0be833b43d8715647 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jos=C3=A9=20Valim?= Date: Fri, 21 Feb 2014 21:12:55 +0100 Subject: [PATCH 39/40] Add img.no-border back --- css/style.css | 1 + 1 file changed, 1 insertion(+) diff --git a/css/style.css b/css/style.css index 62d7c699e..b5013362f 100644 --- a/css/style.css +++ b/css/style.css @@ -404,6 +404,7 @@ a:hover img, #slider-nav li a:hover img { opacity: 0.85; } border: 1px solid #e5e5e5; } .rss-button { margin-bottom: 25px; } +img.no-border { border: 0 }; /* Layout -------------------------------------------------------------- */ From 9c03556a711748a5e6865ee91c5c44aa24930aae Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Meadows-J=C3=B6nsson?= Date: Sun, 9 Mar 2014 16:15:44 +0100 Subject: [PATCH 40/40] Document `:override` option in mix guide --- getting_started/mix/1.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/getting_started/mix/1.markdown b/getting_started/mix/1.markdown index 6652ffe5b..5ff834d59 100644 --- a/getting_started/mix/1.markdown +++ b/getting_started/mix/1.markdown @@ -235,7 +235,7 @@ Use `mix help` to get more information. ### 1.4.5 Dependencies of dependencies -If your dependency is another Mix or rebar project, Mix does the right thing: it will automatically fetch and handle all dependencies of your dependencies. However, if your project have two dependencies that share the same dependency and the SCM information for the shared dependency doesn't match between the parent dependencies, Mix will mark that dependency as diverged and emit a warning. To solve this issue you can declare the shared dependency in your project and Mix will use that SCM information to fetch the dependency. +If your dependency is another Mix or rebar project, Mix does the right thing: it will automatically fetch and handle all dependencies of your dependencies. However, if your project has two dependencies that share the same dependency and the SCM information for the shared dependency doesn't match between the parent dependencies, Mix will mark that dependency as diverged and emit a warning. To solve this issue you can declare the shared dependency in your project with the option `override: true` and Mix will use that SCM information to fetch the dependency. ## 1.5 Umbrella projects