nelsonic / practice

Practice makes ...
11 stars 4 forks source link

Moar Elixir (Official "Getting Started" Guide) #11

Open nelsonic opened 7 years ago

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/introduction.html image

https://elixir-lang.org/getting-started/introduction.html#interactive-mode image

https://elixir-lang.org/getting-started/introduction.html#running-scripts image

https://elixir-lang.org/getting-started/basic-types.html image

https://elixir-lang.org/getting-started/basic-types.html#basic-arithmetic image image

https://elixir-lang.org/getting-started/basic-types.html#booleans image

https://elixir-lang.org/getting-started/basic-types.html#atoms image Took a detour to read: https://www.quora.com/What-are-atoms-in-Erlang-programming-language but got sucked into reading: https://www.quora.com/What-is-something-that-needs-to-be-said (don't fall into the same trap! you will waste a whole pomodoro before you realise it...!)

https://elixir-lang.org/getting-started/basic-types.html#strings image

byte_size vs. String.length: image

https://elixir-lang.org/getting-started/basic-types.html#anonymous-functions image image

https://elixir-lang.org/getting-started/basic-types.html#linked-lists image image

https://elixir-lang.org/getting-started/basic-types.html#tuples image

https://elixir-lang.org/getting-started/basic-types.html#lists-or-tuples image

Tuples as return values from built-in functions: image

good insight at the end of this "chapter" about size vs length operations. size (_e.g: byte_size/1 and tuple_size/1 are pre-computed values and are thus "cheap" operations_) whereas length has a linear (proportional to the length of the list/string etc.) time because String.length/1 needs to "traverse" the entire string to determine it's length. πŸ‘

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/basic-operators.html image image

image

Elixir sorting order (data types):

number < atom < reference < function < port < pid < tuple < map < list < bitstring

image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/pattern-matching.html image image

https://elixir-lang.org/getting-started/pattern-matching.html#pattern-matching-1 image

https://elixir-lang.org/getting-started/pattern-matching.html#the-pin-operator image image

No function calls on the left-hand side of a pattern matching statement: image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/case-cond-and-if.html https://elixir-lang.org/getting-started/case-cond-and-if.html#cond image

https://elixir-lang.org/getting-started/case-cond-and-if.html#if-and-unless image

https://elixir-lang.org/getting-started/case-cond-and-if.html#doend-blocks image image

https://elixir-lang.org/getting-started/binaries-strings-and-char-lists.html image

image

https://elixir-lang.org/getting-started/binaries-strings-and-char-lists.html#binaries-and-bitstrings image image

https://elixir-lang.org/getting-started/binaries-strings-and-char-lists.html#char-lists image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/keywords-and-maps.html image image

https://elixir-lang.org/getting-started/keywords-and-maps.html#maps image Map update syntax only for existing keys: image

Accessing (atom) keys using dot notation: image

https://elixir-lang.org/getting-started/keywords-and-maps.html#nested-data-structures image

nested map put_in update syntax: image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/modules-and-functions.html image

https://elixir-lang.org/getting-started/modules-and-functions.html#compilation image

https://elixir-lang.org/getting-started/modules-and-functions.html#scripted-mode image

https://elixir-lang.org/getting-started/modules-and-functions.html#named-functions image image

Using do: syntax: image You may use do: for one-liners but always use do/end for functions spanning multiple lines.

https://elixir-lang.org/getting-started/modules-and-functions.html#function-capturing image image

https://elixir-lang.org/getting-started/modules-and-functions.html#default-arguments image

Any expression is allowed to serve as a default value, but it won’t be evaluated during the function definition. Every time the function is invoked and any of its default values have to be used, the expression for that default value will be evaluated: image

Concat with various clauses: image

Second Clause unreachable because first clause Always matches: image

image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/recursion.html https://elixir-lang.org/getting-started/recursion.html#loops-through-recursion image

https://elixir-lang.org/getting-started/recursion.html#reduce-and-map-algorithms image

Inline each clause: image

Math.double_each: image

Enum.map & Enum.reduce: image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/enumerables-and-streams.html image

https://elixir-lang.org/getting-started/enumerables-and-streams.html#enumerables image

https://elixir-lang.org/getting-started/enumerables-and-streams.html#eager-vs-lazy image

https://elixir-lang.org/getting-started/enumerables-and-streams.html#the-pipe-operator image

https://elixir-lang.org/getting-started/enumerables-and-streams.html#streams "Streams are lazy, composable enumerables." image

More stream goodness: image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/processes.html image

https://elixir-lang.org/getting-started/processes.html#spawn image

https://elixir-lang.org/getting-started/processes.html#send-and-receive image image

https://elixir-lang.org/getting-started/processes.html#links image

https://elixir-lang.org/getting-started/processes.html#tasks image

https://elixir-lang.org/getting-started/processes.html#state image

image

Using Agent for maintaining state: image

image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/io-and-the-file-system.html image

https://elixir-lang.org/getting-started/io-and-the-file-system.html#the-io-module image

https://elixir-lang.org/getting-started/io-and-the-file-system.html#the-file-module image

image

https://elixir-lang.org/getting-started/io-and-the-file-system.html#the-path-module image

https://elixir-lang.org/getting-started/io-and-the-file-system.html#processes-and-group-leaders image

Of all IO devices, there is one that is special to each process: the group leader ... image

https://elixir-lang.org/getting-started/io-and-the-file-system.html#iodata-and-chardata image image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/alias-require-and-import.html image

https://elixir-lang.org/getting-started/alias-require-and-import.html#alias image

image

https://elixir-lang.org/getting-started/alias-require-and-import.html#require image

https://elixir-lang.org/getting-started/alias-require-and-import.html#import image image

https://elixir-lang.org/getting-started/alias-require-and-import.html#use image

https://elixir-lang.org/getting-started/alias-require-and-import.html#understanding-aliases image

https://elixir-lang.org/getting-started/alias-require-and-import.html#module-nesting image

https://elixir-lang.org/getting-started/alias-require-and-import.html#multi-aliasimportrequireuse image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/module-attributes.html image

https://elixir-lang.org/getting-started/module-attributes.html#as-annotations image

image image

https://elixir-lang.org/getting-started/module-attributes.html#as-constants image

image

https://elixir-lang.org/getting-started/module-attributes.html#as-temporary-storage image image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/structs.html image

https://elixir-lang.org/getting-started/structs.html#defining-structs image

https://elixir-lang.org/getting-started/structs.html#accessing-and-updating-structs image

https://elixir-lang.org/getting-started/structs.html#structs-are-bare-maps-underneath image

https://elixir-lang.org/getting-started/structs.html#default-values-and-required-keys image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/protocols.html image

image

Passing a data type that doesn’t implement the protocol raises an error: image

https://elixir-lang.org/getting-started/protocols.html#protocols-and-structs image

Implement Size.size for a Struct: image

https://elixir-lang.org/getting-started/protocols.html#implementing-any image

Note: we set it to 0 (zero) in the implementation...)

https://elixir-lang.org/getting-started/protocols.html#fallback-to-any image

https://elixir-lang.org/getting-started/protocols.html#built-in-protocols image image

https://elixir-lang.org/getting-started/protocols.html#protocol-consolidation image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/comprehensions.html image

https://elixir-lang.org/getting-started/comprehensions.html#generators-and-filters image

Show size of each image in "Pictures" directory:

dirs = ['/Users/Admin/Pictures']
for dir  <- dirs,
    file <- File.ls!(dir),
    path = Path.join(dir, file),
    File.regular?(path) do
      IO.puts File.stat!(path).size
end

image

Simplification: image

https://elixir-lang.org/getting-started/comprehensions.html#bitstring-generators image

https://elixir-lang.org/getting-started/comprehensions.html#the-into-option image image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/sigils.html image

https://elixir-lang.org/getting-started/sigils.html#regular-expressions image image

https://elixir-lang.org/getting-started/sigils.html#strings-char-lists-and-word-lists-sigils image image

https://elixir-lang.org/getting-started/sigils.html#interpolation-and-escaping-in-sigils image

Heredoc sigils: image

https://elixir-lang.org/getting-started/sigils.html#custom-sigils image image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/try-catch-and-rescue.html image

https://elixir-lang.org/getting-started/try-catch-and-rescue.html#errors image

image

image

image

https://elixir-lang.org/getting-started/try-catch-and-rescue.html#throws image

https://elixir-lang.org/getting-started/try-catch-and-rescue.html#exits image

https://elixir-lang.org/getting-started/try-catch-and-rescue.html#after image image

https://elixir-lang.org/getting-started/try-catch-and-rescue.html#else image

https://elixir-lang.org/getting-started/try-catch-and-rescue.html#variables-scope image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/typespecs-and-behaviours.html image

https://elixir-lang.org/getting-started/typespecs-and-behaviours.html#defining-custom-types image image

custom @type is available outside the module definition, to make it private use @typep: image

https://elixir-lang.org/getting-started/typespecs-and-behaviours.html#behaviours image

https://elixir-lang.org/getting-started/typespecs-and-behaviours.html#defining-behaviours image

https://elixir-lang.org/getting-started/typespecs-and-behaviours.html#adopting-behaviours image

Ok. I get this. I'll need to use it in a project to remember it tho... πŸ˜‰

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/erlang-libraries.html image

https://elixir-lang.org/getting-started/erlang-libraries.html#the-binary-module image

https://elixir-lang.org/getting-started/erlang-libraries.html#formatted-text-output image

https://elixir-lang.org/getting-started/erlang-libraries.html#the-crypto-module image

https://elixir-lang.org/getting-started/erlang-libraries.html#the-digraph-module image

https://elixir-lang.org/getting-started/erlang-libraries.html#erlang-term-storage image

https://elixir-lang.org/getting-started/erlang-libraries.html#the-math-module image

https://elixir-lang.org/getting-started/erlang-libraries.html#the-queue-module image

https://elixir-lang.org/getting-started/erlang-libraries.html#the-rand-module image

https://elixir-lang.org/getting-started/erlang-libraries.html#the-zip-and-zlib-modules didn't work, but when I zipped the contents of the CWD as file.zip:

zip -r ../file.zip ./*

got: image and finally: image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/where-to-go-next.html

nelsonic commented 7 years ago

https://elixir-lang.org/learning.html

nelsonic commented 7 years ago

https://elixir-lang.org/crash-course.html image

https://elixir-lang.org/crash-course.html#running-code image

https://elixir-lang.org/crash-course.html#elixir image

https://elixir-lang.org/crash-course.html#notable-differences image

https://elixir-lang.org/crash-course.html#variable-names image

https://elixir-lang.org/crash-course.html#calling-functions image

https://elixir-lang.org/crash-course.html#data-types image image

https://elixir-lang.org/crash-course.html#tuples image

https://elixir-lang.org/crash-course.html#lists-and-binaries image

https://elixir-lang.org/crash-course.html#keyword-list image

https://elixir-lang.org/crash-course.html#maps image

https://elixir-lang.org/crash-course.html#regular-expressions image

https://elixir-lang.org/crash-course.html#modules image

image image

https://elixir-lang.org/crash-course.html#function-syntax image

see: http://learnyousomeerlang.com/syntax-in-functions

https://elixir-lang.org/crash-course.html#identifying-functions image

https://elixir-lang.org/crash-course.html#default-values image

https://elixir-lang.org/crash-course.html#anonymous-functions image

I prefer the Erlang syntax for anon functions...

https://elixir-lang.org/crash-course.html#first-class-functions image

https://elixir-lang.org/crash-course.html#partials-and-function-captures-in-elixir image

https://elixir-lang.org/crash-course.html#control-flow image

https://elixir-lang.org/crash-course.html#if image

https://elixir-lang.org/crash-course.html#sending-and-receiving-messages image

https://elixir-lang.org/crash-course.html#adding-elixir-to-existing-erlang-programs image

image

Done. βœ…

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html image

image

https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html#our-first-project image

https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html#project-compilation image image

image

https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html#running-tests image

(deliberately) Make tests fail: image

https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html#environments image

https://elixir-lang.org/getting-started/mix-otp/introduction-to-mix.html#exploring image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/mix-otp/agent.html image

https://elixir-lang.org/getting-started/mix-otp/agent.html#the-trouble-with-state image

https://elixir-lang.org/getting-started/mix-otp/agent.html#agents image

Tests first: image

Test fails (functionality not yet implemented): image

image

image

Tests pass: image

https://elixir-lang.org/getting-started/mix-otp/agent.html#test-setup-with-exunit-callbacks image

using test context with %{bucket: bucket} image

https://elixir-lang.org/getting-started/mix-otp/agent.html#other-agent-actions

Delete key TEST First: image

delete implemented (test passing): image

https://elixir-lang.org/getting-started/mix-otp/agent.html#clientserver-in-agents image

(just info. no code to write...)

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/mix-otp/genserver.html image

image

Never convert user input into atoms as this can exhaust system memory ... 😞 image

https://elixir-lang.org/getting-started/mix-otp/genserver.html#our-first-genserver image

https://elixir-lang.org/getting-started/mix-otp/genserver.html#testing-a-genserver image

https://elixir-lang.org/getting-started/mix-otp/genserver.html#the-need-for-monitoring image

image

image

https://elixir-lang.org/getting-started/mix-otp/genserver.html#call-cast-or-info Just reading. no code. image

https://elixir-lang.org/getting-started/mix-otp/genserver.html#monitors-or-links image

Onto the next one. πŸ‘

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html image

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html#our-first-supervisor image

image

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html#naming-processes image

image

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html#understanding-applications image

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html#starting-applications image image

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html#the-application-callback image

image image

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html#projects-or-applications image

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html#simple-one-for-one-supervisors image

Failing Test: image

image

BEFORE:

  def handle_cast({:create, name}, {names, refs}) do
    if Map.has_key?(names, name) do
      {:noreply, {names, refs}}
    else
      {:ok, pid} = KV.Bucket.start_link([])
      ref = Process.monitor(pid)
      refs = Map.put(refs, ref, name)
      names = Map.put(names, name, pid)
      {:noreply, {names, refs}}
    end
  end

AFTER:

  def handle_cast({:create, name}, {names, refs}) do
    if Map.has_key?(names, name) do
      {:noreply, {names, refs}}
    else
      {:ok, pid} = KV.BucketSupervisor.start_bucket()
      ref = Process.monitor(pid)
      refs = Map.put(refs, ref, name)
      names = Map.put(names, name, pid)
      {:noreply, {names, refs}}
    end
  end

image

Tests pass: image

Temporary: image

Test: image

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html#supervision-trees image

image

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html#observer image

Applications: image

create "shopping": image

image

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html#shared-state-in-tests image

So far so good ... πŸ‘

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/mix-otp/supervisor-and-application.html#shared-state-in-tests image

https://elixir-lang.org/getting-started/mix-otp/ets.html#ets-as-a-cache image

image image

image

Run tests with --trace: image (passing intermittently!!)

One failure: image

Add "bogus" bucket: image Tests pass as expected.

Conclusion: Use "Registry" module: image

see: https://hexdocs.pm/elixir/Registry.html

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-apps.html image

https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-apps.html#external-dependencies image

image

got: image

changed the deps to:

 defp deps do
    [
      {:plug, "~> 1.0"}
    ]
  end

See: https://github.com/elixir-lang/elixir-lang.github.com/issues/1019

https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-apps.html#internal-dependencies image image

https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-apps.html#umbrella-projects

image image image

run the tests in the umbrella project: image

https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-apps.html#in-umbrella-dependencies image

image

https://elixir-lang.org/getting-started/mix-otp/dependencies-and-umbrella-apps.html#summing-up image image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/mix-otp/task-and-gen-tcp.html image

https://elixir-lang.org/getting-started/mix-otp/task-and-gen-tcp.html#echo-server image

explanation of code ... image

Telnet session: image

https://elixir-lang.org/getting-started/mix-otp/task-and-gen-tcp.html#tasks

apps/kv_server/lib/kv_server/application.ex BEFORE

defmodule KVServer.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    # List all child processes to be supervised
    children = [
      # Starts a worker by calling: KVServer.Worker.start_link(arg)
      # {KVServer.Worker, arg},
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: KVServer.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

AFTER:

defmodule KVServer.Application do
  # See https://hexdocs.pm/elixir/Application.html
  # for more information on OTP Applications
  @moduledoc false

  use Application

  def start(_type, _args) do
    # List all child processes to be supervised
    children = [
      {Task, fn -> KVServer.accept(4040) end}
    ]

    # See https://hexdocs.pm/elixir/Supervisor.html
    # for other strategies and supported options
    opts = [strategy: :one_for_one, name: KVServer.Supervisor]
    Supervisor.start_link(children, opts)
  end
end

Dual Telnet Connections: image

Doesn't work because we need a new process to respond ...

https://elixir-lang.org/getting-started/mix-otp/task-and-gen-tcp.html#task-supervisor image

  :ok = :gen_tcp.controlling_process(client, pid)

image

run: PORT=4040 mix run --no-halt image

image

image

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/mix-otp/docs-tests-and-with.html image

https://elixir-lang.org/getting-started/mix-otp/docs-tests-and-with.html#doctests image

Failing test: image

Make it pass: image

image

image

https://elixir-lang.org/getting-started/mix-otp/docs-tests-and-with.html#with image

Start server, connect using Telnet and issue commands: image

Re-write serve to use with: image

BEFORE:

  defp serve(socket) do
    msg =
      case read_line(socket) do
        {:ok, data} ->
          case KVServer.Command.parse(data) do
            {:ok, command} ->
              KVServer.Command.run(command)
            {:error, _} = err ->
              err
          end
        {:error, _} = err ->
          err
      end

    write_line(socket, msg)
    serve(socket)
  end

AFTER:

  defp serve(socket) do
    msg =
      with {:ok, data} <- read_line(socket),
           {:ok, command} <- KVServer.Command.parse(data),
           do: KVServer.Command.run(command)

    write_line(socket, msg)
    serve(socket)
  end

https://elixir-lang.org/getting-started/mix-otp/docs-tests-and-with.html#running-commands image

image

Implement integration tests: image

image

image

This tutorial ends with failing tests ... πŸ˜•

nelsonic commented 7 years ago

https://elixir-lang.org/getting-started/mix-otp/distributed-tasks-and-configuration.html image

https://elixir-lang.org/getting-started/mix-otp/distributed-tasks-and-configuration.html#our-first-distributed-code image

Got error:

Protocol 'inet_tcp': invalid node name:  foo@nelson@local

I suspect it has something to do with the two @ symbols ... πŸ˜• When I tried:

iex --sname foo@localhost

It appears to work: image

Second instance of iex: image

Spawn process in original instance of iex: image

Ping the process: image

We are going to use Tasks: image

https://elixir-lang.org/getting-started/mix-otp/distributed-tasks-and-configuration.html#asyncawait image

https://elixir-lang.org/getting-started/mix-otp/distributed-tasks-and-configuration.html#distributed-tasks image

iex --sname foo@computer-name -S mix
iex --sname bar@computer-name -S mix

Fails ... image

Tests still fail after following the instructions: image

However the ==> kv_server Excluding tags: [distributed: true] is working: image

At this point nothing is going to work ...

image

I think I'm going to have to take a few steps back ...