From 470baf757029ae5cdfe752699d4ba864c296b129 Mon Sep 17 00:00:00 2001 From: Tajinder Chumber Date: Wed, 15 Aug 2018 14:22:07 +0100 Subject: [PATCH] chapter 3 --- chapter3/excersises.ex | 43 +++++++++++++++++++++ chapter3/metex/.formatter.exs | 4 ++ chapter3/metex/.gitignore | 25 ++++++++++++ chapter3/metex/README.md | 21 ++++++++++ chapter3/metex/config/config.exs | 30 +++++++++++++++ chapter3/metex/lib/coordinator.ex | 16 ++++++++ chapter3/metex/lib/metex.ex | 14 +++++++ chapter3/metex/lib/worker.ex | 59 +++++++++++++++++++++++++++++ chapter3/metex/mix.exs | 30 +++++++++++++++ chapter3/metex/mix.lock | 12 ++++++ chapter3/metex/test/metex_test.exs | 8 ++++ chapter3/metex/test/test_helper.exs | 1 + 12 files changed, 263 insertions(+) create mode 100644 chapter3/excersises.ex create mode 100644 chapter3/metex/.formatter.exs create mode 100644 chapter3/metex/.gitignore create mode 100644 chapter3/metex/README.md create mode 100644 chapter3/metex/config/config.exs create mode 100644 chapter3/metex/lib/coordinator.ex create mode 100644 chapter3/metex/lib/metex.ex create mode 100644 chapter3/metex/lib/worker.ex create mode 100644 chapter3/metex/mix.exs create mode 100644 chapter3/metex/mix.lock create mode 100644 chapter3/metex/test/metex_test.exs create mode 100644 chapter3/metex/test/test_helper.exs diff --git a/chapter3/excersises.ex b/chapter3/excersises.ex new file mode 100644 index 0000000..a92b69e --- /dev/null +++ b/chapter3/excersises.ex @@ -0,0 +1,43 @@ +defmodule Exercise do + def run() do + pboss = spawn(ProcessBoss, :loop, []) + pid1 = spawn(Process1, :loop, []) + pid2 = spawn(Process2, :loop, []) + + send pid1, {pboss, :ping} + send pid2, {pboss, :pong} + end +end + +defmodule ProcessBoss do + def loop do + receive do + {:ok, msg, from: from} -> IO.inspect("#{from} says #{msg}") + _ -> IO.puts "Unknow Message" + end + loop() + end +end + +defmodule Process1 do + def loop do + receive do + {sender_pid, :ping} -> + send(sender_pid, {:ok, :pong, from: :ping}) + _ -> + IO.puts "Unknow Message" + end + loop() + end +end + +defmodule Process2 do + def loop do + receive do + {sender_pid, :pong} -> + send(sender_pid, {:ok, :ping, from: :pong}) + _ -> IO.puts "Unknow Message" + end + loop() + end +end diff --git a/chapter3/metex/.formatter.exs b/chapter3/metex/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/chapter3/metex/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/chapter3/metex/.gitignore b/chapter3/metex/.gitignore new file mode 100644 index 0000000..80622fd --- /dev/null +++ b/chapter3/metex/.gitignore @@ -0,0 +1,25 @@ +# The directory Mix will write compiled artifacts to. +/_build/ + +# If you run "mix test --cover", coverage assets end up here. +/cover/ + +# The directory Mix downloads your dependencies sources to. +/deps/ + +# Where 3rd-party dependencies like ExDoc output generated docs. +/doc/ + +# Ignore .fetch files in case you like to edit your project deps locally. +/.fetch + +# If the VM crashes, it generates a dump, let's ignore it too. +erl_crash.dump + +# Also ignore archive artifacts (built via "mix archive.build"). +*.ez + +# Ignore package tarball (built via "mix hex.build"). +metex-*.tar + +.elixir_ls/ \ No newline at end of file diff --git a/chapter3/metex/README.md b/chapter3/metex/README.md new file mode 100644 index 0000000..0400196 --- /dev/null +++ b/chapter3/metex/README.md @@ -0,0 +1,21 @@ +# Metex + +**TODO: Add description** + +## Installation + +If [available in Hex](https://hex.pm/docs/publish), the package can be installed +by adding `metex` to your list of dependencies in `mix.exs`: + +```elixir +def deps do + [ + {:metex, "~> 0.1.0"} + ] +end +``` + +Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc) +and published on [HexDocs](https://hexdocs.pm). Once published, the docs can +be found at [https://hexdocs.pm/metex](https://hexdocs.pm/metex). + diff --git a/chapter3/metex/config/config.exs b/chapter3/metex/config/config.exs new file mode 100644 index 0000000..b3ba4d3 --- /dev/null +++ b/chapter3/metex/config/config.exs @@ -0,0 +1,30 @@ +# This file is responsible for configuring your application +# and its dependencies with the aid of the Mix.Config module. +use Mix.Config + +# This configuration is loaded before any dependency and is restricted +# to this project. If another project depends on this project, this +# file won't be loaded nor affect the parent project. For this reason, +# if you want to provide default values for your application for +# 3rd-party users, it should be done in your "mix.exs" file. + +# You can configure your application as: +# +# config :metex, key: :value +# +# and access this configuration in your application as: +# +# Application.get_env(:metex, :key) +# +# You can also configure a 3rd-party app: +# +# config :logger, level: :info +# + +# It is also possible to import configuration files, relative to this +# directory. For example, you can emulate configuration per environment +# by uncommenting the line below and defining dev.exs, test.exs and such. +# Configuration from the imported file will override the ones defined +# here (which is why it is important to import them last). +# +# import_config "#{Mix.env()}.exs" diff --git a/chapter3/metex/lib/coordinator.ex b/chapter3/metex/lib/coordinator.ex new file mode 100644 index 0000000..34a4a76 --- /dev/null +++ b/chapter3/metex/lib/coordinator.ex @@ -0,0 +1,16 @@ +defmodule Metex.Coordinator do + def loop(results \\ [], results_expected) do + receive do + {:ok, result} -> + new_results = [result | results] + if results_expected == Enum.count(new_results) do + send self(), :exit + end + loop(new_results, results_expected) + :exit -> + IO.puts(results |> Enum.sort |> Enum.join(", ")) + _ -> + loop(results, results_expected) + end + end +end diff --git a/chapter3/metex/lib/metex.ex b/chapter3/metex/lib/metex.ex new file mode 100644 index 0000000..df22e46 --- /dev/null +++ b/chapter3/metex/lib/metex.ex @@ -0,0 +1,14 @@ +defmodule Metex do + def temperature_of(cities) do + coordinator_pid = + spawn(Metex.Coordinator, :loop, [[], Enum.count(cities)]) + + cities |> Enum.each(fn city -> + worker_pid = spawn(Metex.Worker, :loop, []) + send worker_pid, {coordinator_pid, city} + end) + end +end + +# cities = ["Singapore", "Monaco", "Vatican City", "Hong Kong", "Macau"] +# Metex.temperature_of(cities) diff --git a/chapter3/metex/lib/worker.ex b/chapter3/metex/lib/worker.ex new file mode 100644 index 0000000..b2c122b --- /dev/null +++ b/chapter3/metex/lib/worker.ex @@ -0,0 +1,59 @@ +defmodule Metex.Worker do + def loop do + receive do + {sender_pid, location} -> + send(sender_pid, {:ok, temperature_of(location)}) + _ -> + IO.puts "don't know how to process this message" + end + loop() + end + + def temperature_of(location) do + result = url_for(location) |> HTTPoison.get |> parse_response + case result do + {:ok, temp} -> + "#{location}: #{temp}°C" + :error -> + "#{location}: not found" + end + end + + defp url_for(location) do + location = URI.encode(location) + "http://api.openweathermap.org/data/2.5/weather?q=#{location}&appid=#{apikey()}" + end + + defp parse_response({:ok, %HTTPoison.Response{body: body, status_code: 200}}) do + body |> JSON.decode! |> compute_temperature + end + + defp parse_response(_) do + :error + end + + defp compute_temperature(json) do + try do + temp = (json["main"]["temp"] - 273.15) |> Float.round(1) + {:ok, temp} + rescue + _ -> :error + end + end + + defp apikey do + "74148f1e51e4ac1feba5e0d04c2a1ec2" + end +end + +# cities = ["Singapore", "Monaco", "Vatican City", "Hong Kong", "Macau"] + +# Without Processes +# cities |> Enum.map(fn city -> Metex.Worker.temperature_of(city) end) + +# With Processes +# pid = spawn(Metex.Worker, :loop, []) +# cities |> Enum.each(fn city -> +# pid = spawn(Metex.Worker, :loop, []) +# send(pid, {self, city}) +# end) diff --git a/chapter3/metex/mix.exs b/chapter3/metex/mix.exs new file mode 100644 index 0000000..409b637 --- /dev/null +++ b/chapter3/metex/mix.exs @@ -0,0 +1,30 @@ +defmodule Metex.MixProject do + use Mix.Project + + def project do + [ + app: :metex, + version: "0.1.0", + elixir: "~> 1.7", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications. + def application do + [ + extra_applications: [:logger, :httpoison] + ] + end + + # Run "mix help deps" to learn about dependencies. + defp deps do + [ + {:httpoison, "~> 1.2.0"}, + {:json, "~> 1.2"} + # {:dep_from_hexpm, "~> 0.3.0"}, + # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}, + ] + end +end diff --git a/chapter3/metex/mix.lock b/chapter3/metex/mix.lock new file mode 100644 index 0000000..3306509 --- /dev/null +++ b/chapter3/metex/mix.lock @@ -0,0 +1,12 @@ +%{ + "certifi": {:hex, :certifi, "2.3.1", "d0f424232390bf47d82da8478022301c561cf6445b5b5fb6a84d49a9e76d2639", [:rebar3], [{:parse_trans, "3.2.0", [hex: :parse_trans, repo: "hexpm", optional: false]}], "hexpm"}, + "hackney": {:hex, :hackney, "1.13.0", "24edc8cd2b28e1c652593833862435c80661834f6c9344e84b6a2255e7aeef03", [:rebar3], [{:certifi, "2.3.1", [hex: :certifi, repo: "hexpm", optional: false]}, {:idna, "5.1.2", [hex: :idna, repo: "hexpm", optional: false]}, {:metrics, "1.0.1", [hex: :metrics, repo: "hexpm", optional: false]}, {:mimerl, "1.0.2", [hex: :mimerl, repo: "hexpm", optional: false]}, {:ssl_verify_fun, "1.1.1", [hex: :ssl_verify_fun, repo: "hexpm", optional: false]}], "hexpm"}, + "httpoison": {:hex, :httpoison, "1.2.0", "2702ed3da5fd7a8130fc34b11965c8cfa21ade2f232c00b42d96d4967c39a3a3", [:mix], [{:hackney, "~> 1.8", [hex: :hackney, repo: "hexpm", optional: false]}], "hexpm"}, + "idna": {:hex, :idna, "5.1.2", "e21cb58a09f0228a9e0b95eaa1217f1bcfc31a1aaa6e1fdf2f53a33f7dbd9494", [:rebar3], [{:unicode_util_compat, "0.3.1", [hex: :unicode_util_compat, repo: "hexpm", optional: false]}], "hexpm"}, + "json": {:hex, :json, "1.2.5", "3682c18c6b07480df2122d0daf5c05457b42c1990f197ce3de53884e8ba834c4", [:mix], [{:benchee, "~> 0.8", [hex: :benchee, repo: "hexpm", optional: true]}, {:benchee_html, "~> 0.1", [hex: :benchee_html, repo: "hexpm", optional: true]}, {:exjsx, "~> 4.0", [hex: :exjsx, repo: "hexpm", optional: true]}, {:jason, "~> 1.0", [hex: :jason, repo: "hexpm", optional: true]}, {:jsone, "~> 1.4", [hex: :jsone, repo: "hexpm", optional: true]}, {:poison, "~> 3.0", [hex: :poison, repo: "hexpm", optional: true]}, {:tiny, "~> 1.0", [hex: :tiny, repo: "hexpm", optional: true]}], "hexpm"}, + "metrics": {:hex, :metrics, "1.0.1", "25f094dea2cda98213cecc3aeff09e940299d950904393b2a29d191c346a8486", [:rebar3], [], "hexpm"}, + "mimerl": {:hex, :mimerl, "1.0.2", "993f9b0e084083405ed8252b99460c4f0563e41729ab42d9074fd5e52439be88", [:rebar3], [], "hexpm"}, + "parse_trans": {:hex, :parse_trans, "3.2.0", "2adfa4daf80c14dc36f522cf190eb5c4ee3e28008fc6394397c16f62a26258c2", [:rebar3], [], "hexpm"}, + "ssl_verify_fun": {:hex, :ssl_verify_fun, "1.1.1", "28a4d65b7f59893bc2c7de786dec1e1555bd742d336043fe644ae956c3497fbe", [:make, :rebar], [], "hexpm"}, + "unicode_util_compat": {:hex, :unicode_util_compat, "0.3.1", "a1f612a7b512638634a603c8f401892afbf99b8ce93a45041f8aaca99cadb85e", [:rebar3], [], "hexpm"}, +} diff --git a/chapter3/metex/test/metex_test.exs b/chapter3/metex/test/metex_test.exs new file mode 100644 index 0000000..27ff63c --- /dev/null +++ b/chapter3/metex/test/metex_test.exs @@ -0,0 +1,8 @@ +defmodule MetexTest do + use ExUnit.Case + doctest Metex + + test "greets the world" do + assert Metex.hello() == :world + end +end diff --git a/chapter3/metex/test/test_helper.exs b/chapter3/metex/test/test_helper.exs new file mode 100644 index 0000000..869559e --- /dev/null +++ b/chapter3/metex/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start()