milevy1 / koroibos

Elixir Phoenix API of 2016 Olympic athlete data
https://koroibos-elixir.herokuapp.com/api/v1/olympians
1 stars 0 forks source link

"Elixir School" - Basics #12

Closed milevy1 closed 5 years ago

milevy1 commented 5 years ago

Elixir School Basics - Notes

Complete all but DateTime, Custom mix tasks, and iex helpers

iex - interactive Elixir mode

(++/2)

Maps

syntax %{ }

map = %{:foo => "bar", "hello" => :world}
# %{:foo => "bar", "hello" => :world}

map[:foo]
# "bar"

map["hello"]
# :world

map.hello
# "world"

Enum

Enum.all?(["foo", "bar", "hello"], fn(s) -> String.length(s) == 3 end)
# false

Enum.all?(["foo", "bar", "hello"], fn(s) -> String.length(s) > 1 end)
# true

Patern Matching

# 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

Anonymous Functions

sum = fn (a, b) -> a + b end

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

"Elixir rocks" |> String.upcase() |> String.split()
# ["ELIXIR", "ROCKS"]

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 an iex inside our application, sorta like rails 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:

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

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

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.

Example test:

defmodule ExampleTest do
  use ExUnit.Case
  doctest Example

  test "greets the world" do
    assert Example.hello() == :a
  end
end

Test Setup

setup and setup_all macros

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

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

import Integer
iex> for x <- 1..100,
...>   is_even(x),
...>   rem(x, 3) == 0, do: x
[6, 12, 18, 24, 30, 36, 42, 48, 54, 60, 66, 72, 78, 84, 90, 96]

using :into

:into can be used to produce something other than a list

milevy1 commented 5 years ago

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:

milevy1 commented 5 years ago

Completed between 12pm - 1pm