You can assign variables through this matching with lists, maps, tuples
# Tuples
{:ok, value} = {:ok, "Successful!"}
# {:ok, "Successful!"}
value
# "Successful!"
{:ok, value} = {:error}
# ** (MatchError) no match of right hand side value: {:error}
Pin Operator
Used to prevent rebinding. Not sure on the use case of this. Will need to read more if encountered
Control Structures
if, else and unless behave similar to ruby
Other options are different... see:
case/2 - case switch statement but funky syntax
cond/1 - similar to elsif
with/1
Anonymous Functions
sum = fn (a, b) -> a + b end
Shorthand syntax for anonymous functions where &1, &2 are parameters
sum = &(&1 + &2)
sum.(2, 3)
# 5
Named Functions
Learn about defmodule later...
def ... do
end
defmodule Greeter do
def hello(name) do
"Hello, " <> name
end
end
Greeter.hello("Sean")
# "Hello, Sean"
Short 1 line function syntax:
defmodule Greeter do
def hello(name), do: "Hello, " <> name
end
Functions and Pattern Matching
Functions pattern match the arguments
defmodule Greeter1 do
def hello(%{name: person_name}) do
IO.puts "Hello, " <> person_name
end
end
fred = %{
name: "Fred",
age: "95",
"favorite_color: "Taupe"
}
Greeter1.hello(fred)
# "Hello, Fred"
Private functions
If you do not want other modules accessing a function, use defp instead of def
Guards
Two functions can run differently by using a guard. For example:
defmodule Greeter do
def hello(names) when is_list(names) do
names
|> Enum.join(", ")
|> hello
end
def hello(name) when is_binary(name) do
phrase() <> name
end
defp phrase, do: "Hello, "
end
Greeter.hello ["Sean", "Steve"]
# "Hello, Sean, Steve"
Default arguments
If we want a default value for an argument we use the argument \\ value syntax.
Pipe Operator
|>
Pipe takes the result of the left and passes it to the next function as an argument
def deps do
[
{:phoenix, "~> 1.1 or ~> 1.2"},
{:phoenix_html, "~> 2.3"},
{:cowboy, "~> 1.0", only: [:dev, :test]},
{:slime, "~> 0.14"}
]
end
Sigils
Alternative syntax for representing and working with literals. A sigil will start with a tilde ~ followed by a character
Examples...
~w/i love elixir school/
# ["i", "love", "elixir", "school"]
Documentation
Inline documentation same as Ruby: # add comments after hashtag
Documenting Modules... Add under defmodule
Documenting Functions... Add above function @doc
Example:
defmodule Greeter do
@moduledoc """
...
"""
@doc """
Prints a hello message
## Parameters
- name: String that represents the name of the person.
## Examples
iex> Greeter.hello("Sean")
"Hello, Sean"
iex> Greeter.hello("pete")
"Hello, pete"
"""
@spec hello(String.t()) :: String.t()
def hello(name) do
"Hello, " <> name
end
end
Could be a very simple way to document API endpoints and payloads
Testing with ExUnit
ExUnit is Elixir's built-in test framework.
Test filed are scripts and use .exs file extension
Before running tests, run ExUnit.start(), usually done in the test/test_helper.exs
Run tests by calling mix test
Example test:
defmodule ExampleTest do
use ExUnit.Case
doctest Example
test "greets the world" do
assert Example.hello() == :a
end
end
assert - similar to RSpec expect
refute - if you want to check if something is false
assert_raise - used to assert an error is raised
asser_received - used to assert if a message was received
capture_io / capture_log - Capture an apps output
Test Setup
setup and setup_all macros
setup - before each test
setup_all - runs once before the test suite
Example:
defmodule ExampleTest do
use ExUnit.Case
doctest Example
setup_all do
{:ok, recipient: :world}
end
test "greets", state do
assert Example.hello() == state[:recipient]
end
end
The gist is, that instead of mocking away dependencies for testing (mock as a verb), it has many advantages to explicitly define interfaces (behaviors) for code outside your application and using Mock (as a noun) implementations in your client code for testing.
Filters
Guard for comprehensions, if a filtered value returns false or nil, it is excluded from final list
Aliases are frequently used to define shortcuts. In fact, calling alias without an :as option sets the alias automatically to the last part of the module name, for example:
Elixir School Basics - Notes
Complete all but DateTime, Custom mix tasks, and iex helpers
iex
- interactive Elixir mode(++/2)
Maps
syntax
%{ }
Enum
Enum.
and then calling the enum you want.Patern Matching
=
operator is actually a matching operatorPin Operator
Used to prevent rebinding. Not sure on the use case of this. Will need to read more if encountered
Control Structures
Anonymous Functions
&1
,&2
are parametersNamed Functions
Learn about defmodule later...
def ... do end
Short 1 line function syntax:
Functions and Pattern Matching
Functions pattern match the arguments
Private functions
If you do not want other modules accessing a function, use
defp
instead ofdef
Guards
Two functions can run differently by using a guard. For example:
Default arguments
If we want a default value for an argument we use the
argument \\ value
syntax.Pipe Operator
|>
Pipe takes the result of the left and passes it to the next function as an argument
Structs & Composition
Mix
If you’re familiar with Ruby, Mix is Bundler, RubyGems, and Rake combined
Creating new project:
mix new name-of-app
iex -S mix
- If we want aniex
inside our application, sorta likerails console
Potentially useful template for Phoenix? https://github.com/slime-lang/phoenix_slime
Project details go in the root
mix.exs
file...deps - dependencies. Example of it in use:
Sigils
Alternative syntax for representing and working with literals. A sigil will start with a tilde ~ followed by a character
Examples...
Documentation
# add comments after hashtag
Example:
ExDoc
Official Elixir project: https://github.com/elixir-lang/ex_doc Produces HTML for online documentation of Elixir projects
Could be a very simple way to document API endpoints and payloads
Testing with ExUnit
ExUnit is Elixir's built-in test framework.
.exs
file extensionExUnit.start()
, usually done in thetest/test_helper.exs
mix test
Example test:
assert
- similar to RSpecexpect
refute
- if you want to check if something is falseassert_raise
- used to assert an error is raisedasser_received
- used to assert if a message was receivedcapture_io
/capture_log
- Capture an apps outputTest Setup
setup
andsetup_all
macrossetup
- before each testsetup_all
- runs once before the test suiteExample:
Mocking
Simple answer, DO NOT MOCK... Read this article for more about why: http://blog.plataformatec.com.br/2015/10/mocks-and-explicit-contracts/
The gist is, that instead of mocking away dependencies for testing (mock as a verb), it has many advantages to explicitly define interfaces (behaviors) for code outside your application and using Mock (as a noun) implementations in your client code for testing.
Filters
Guard for comprehensions, if a filtered value returns false or nil, it is excluded from final list
using :into
:into
can be used to produce something other than a list