commit c30845575a6cadc768b449565b2ff45af6eeaa7d Author: Federico Pasqua (eisterman) Date: Tue Dec 24 17:45:52 2024 +0100 Initial Commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..4975c62 --- /dev/null +++ b/.gitignore @@ -0,0 +1,18 @@ +# Created by https://www.toptal.com/developers/gitignore/api/elixir +# Edit at https://www.toptal.com/developers/gitignore?templates=elixir + +### Elixir ### +/_build +/cover +/deps +/doc +/.fetch +erl_crash.dump +*.ez +*.beam +/config/*.secret.exs +.elixir_ls/ + +### Elixir Patch ### + +# End of https://www.toptal.com/developers/gitignore/api/elixir diff --git a/binary.exs b/binary.exs new file mode 100644 index 0000000..1207135 --- /dev/null +++ b/binary.exs @@ -0,0 +1,25 @@ +defmodule BinarySearch do + def binary_search(_numbers, _key, low, high) when low > high do + :not_found + end + + @spec binary_search(list, integer, integer, integer) :: integer | :not_found + def binary_search(numbers, key, low, high) do + md = low + Integer.floor_div(high-low, 2) + IO.inspect(md) + case elem(numbers, md) do + x when x > key -> binary_search(numbers, key, low, md-1) + x when x < key -> binary_search(numbers, key, md+1, high) + x when x == key -> md + end + end + + @spec search(tuple, integer) :: {:ok, integer} | :not_found + def search(numbers, key) do + case binary_search(numbers, key, 0, tuple_size(numbers)-1) do + :not_found -> :not_found + x -> {:ok, x} + end + end +end + diff --git a/fibo.exs b/fibo.exs new file mode 100644 index 0000000..5974df7 --- /dev/null +++ b/fibo.exs @@ -0,0 +1,19 @@ +defmodule Fibonacci do + def get(n) when n > 2 do + get(n-2) + get(n-1) + end + + def get(_n) do + 1 + end +end + +1..10 |> Enum.map(fn i -> IO.puts("Fib #{i} = #{Fibonacci.get(i)}") end) +1..10 |> Enum.map(&(IO.puts("Fib #{&1} = #{Fibonacci.get(&1)}"))) +for i <- 1..10 do + IO.puts("Fib #{i} = #{Fibonacci.get(i)}") +end +res = for x <- 1..10, reduce: 0 do + acc -> acc + Fibonacci.get(x) +end +IO.puts("Somma dei fibonacci da 1 a 10 #{res}") diff --git a/genserver.exs b/genserver.exs new file mode 100644 index 0000000..0e26797 --- /dev/null +++ b/genserver.exs @@ -0,0 +1,38 @@ +defmodule Stack do + use GenServer + + # Client + + def start_link(default) when is_binary(default) do + GenServer.start_link(__MODULE__, default) + end + + def push(pid, element) do + GenServer.cast(pid, {:push, element}) + end + + def pop(pid) do + GenServer.call(pid, :pop) + end + + # Server (callbacks) + + @impl true + def init(elements) do + initial_state = String.split(elements, ",", trim: true) + {:ok, initial_state} + end + + @impl true + def handle_call(:pop, _from, state) do + [to_caller | new_state] = state + {:reply, to_caller, new_state} + end + + @impl true + def handle_cast({:push, element}, state) do + new_state = [element | state] + {:noreply, new_state} + end +end + diff --git a/kv.exs b/kv.exs new file mode 100644 index 0000000..ab225e5 --- /dev/null +++ b/kv.exs @@ -0,0 +1,17 @@ +# Key-Value store +defmodule KV do + def start_link do + Task.start_link(fn -> loop(%{}) end) + end + + defp loop(map) do + receive do + {:get, key, caller} -> + send(caller, Map.get(map, key)) + loop(map) + {:put, key, value} -> + loop(Map.put(map, key, value)) + end + end +end + diff --git a/kv/.formatter.exs b/kv/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/kv/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/kv/.gitignore b/kv/.gitignore new file mode 100644 index 0000000..f911028 --- /dev/null +++ b/kv/.gitignore @@ -0,0 +1,26 @@ +# 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 third-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"). +kv-*.tar + +# Temporary files, for example, from tests. +/tmp/ diff --git a/kv/README.md b/kv/README.md new file mode 100644 index 0000000..0c3a917 --- /dev/null +++ b/kv/README.md @@ -0,0 +1,21 @@ +# KV + +**TODO: Add description** + +## Installation + +If [available in Hex](https://hex.pm/docs/publish), the package can be installed +by adding `kv` to your list of dependencies in `mix.exs`: + +```elixir +def deps do + [ + {:kv, "~> 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 . + diff --git a/kv/lib/kv.ex b/kv/lib/kv.ex new file mode 100644 index 0000000..2c20e7f --- /dev/null +++ b/kv/lib/kv.ex @@ -0,0 +1,10 @@ +defmodule KV do + use Application + + @impl true + def start(_type, _args) do + # Anche se non usiamo KV.Supervisor name direttamente, + # e' comodo per debug + KV.Supervisor.start_link(name: KV.Supervisor) + end +end diff --git a/kv/lib/kv/bucket.ex b/kv/lib/kv/bucket.ex new file mode 100644 index 0000000..71d59b2 --- /dev/null +++ b/kv/lib/kv/bucket.ex @@ -0,0 +1,33 @@ +defmodule KV.Bucket do + use Agent, restart: :temporary + + @doc """ + Starts a new bucket. + """ + def start_link(_opts) do + Agent.start_link(fn -> %{} end) + end + + @doc """ + Gets a value from the `bucket` by `key`. + """ + def get(bucket, key) do + Agent.get(bucket, &Map.get(&1, key)) + end + + @doc """ + Puts the `value` for the given `key` in the `bucket`. + """ + def put(bucket, key, value) do + Agent.update(bucket, &Map.put(&1, key, value)) + end + + @doc """ + Deletes `key` from `bucket`. + + Returns the current value of `key`, if `key` exists. + """ + def delete(bucket, key) do + Agent.get_and_update(bucket, &Map.pop(&1, key)) + end +end diff --git a/kv/lib/kv/registry.ex b/kv/lib/kv/registry.ex new file mode 100644 index 0000000..7eeb716 --- /dev/null +++ b/kv/lib/kv/registry.ex @@ -0,0 +1,69 @@ +defmodule KV.Registry do + use GenServer + + # Client API + @doc """ + Starts the registry. + """ + def start_link(opts) do + server = Keyword.fetch!(opts, :name) + GenServer.start_link(__MODULE__, server, opts) + end + + @doc """ + Looks up the bucket pid for `name` stored in `server`. + + Returns `{:ok, pid}` if the bucket exists, `:error` otherwise. + """ + def lookup(server, name) do + case :ets.lookup(server, name) do + [{^name, pid}] -> {:ok, pid} + [] -> :error + end + end + + @doc """ + Ensures there is a bucket associated with the given `name` in `server`. + """ + def create(server, name) do + GenServer.call(server, {:create, name}) + end + + # Server Callbacks + + @impl true + def init(table) do + # name -> bucket + names = :ets.new(table, [:named_table, read_concurrency: true]) + refs = %{} # ref -> name + {:ok, {names, refs}} + end + + @impl true + def handle_call({:create, name}, _from, {names, refs}) do + case lookup(names, name) do + {:ok, bucket} -> + {:reply, bucket, {names, refs}} + :error -> + {:ok, bucket} = DynamicSupervisor.start_child(KV.BucketSupervisor, KV.Bucket) + ref = Process.monitor(bucket) + refs = Map.put(refs, ref, name) + :ets.insert(names, {name, bucket}) + {:reply, bucket, {names, refs}} + end + end + + @impl true + def handle_info({:DOWN, ref, :process, _pid, _reason}, {names, refs}) do + {name, refs} = Map.pop(refs, ref) + :ets.delete(names, name) + {:noreply, {names, refs}} + end + + @impl true + def handle_info(msg, state) do + require Logger + Logger.debug("Unexpected message in KV.Registry: #{inspect(msg)}") + {:noreply, state} + end +end diff --git a/kv/lib/kv/supervisor.ex b/kv/lib/kv/supervisor.ex new file mode 100644 index 0000000..c42f17a --- /dev/null +++ b/kv/lib/kv/supervisor.ex @@ -0,0 +1,17 @@ +defmodule KV.Supervisor do + use Supervisor + + def start_link(opts) do + Supervisor.start_link(__MODULE__, :ok, opts) + end + + @impl true + def init(:ok) do + children = [ + {DynamicSupervisor, name: KV.BucketSupervisor, strategy: :one_for_one}, + {KV.Registry, name: KV.Registry}, + ] + + Supervisor.init(children, strategy: :one_for_all) + end +end diff --git a/kv/mix.exs b/kv/mix.exs new file mode 100644 index 0000000..081218e --- /dev/null +++ b/kv/mix.exs @@ -0,0 +1,29 @@ +defmodule KV.MixProject do + use Mix.Project + + def project do + [ + app: :kv, + version: "0.1.0", + elixir: "~> 1.17", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications. + def application do + [ + extra_applications: [:logger], + mod: {KV, []} + ] + end + + # Run "mix help deps" to learn about dependencies. + defp deps do + [ + # {: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/kv/test/kv/bucket_test.exs b/kv/test/kv/bucket_test.exs new file mode 100644 index 0000000..0cfa15f --- /dev/null +++ b/kv/test/kv/bucket_test.exs @@ -0,0 +1,15 @@ +defmodule KV.BucketTest do + use ExUnit.Case, async: true + + setup do + bucket = start_supervised!(KV.Bucket) + %{bucket: bucket} + end + + test "stores values by key", %{bucket: bucket} do + assert KV.Bucket.get(bucket, "milk") == nil + + KV.Bucket.put(bucket, "milk", 3) + assert KV.Bucket.get(bucket, "milk") == 3 + end +end diff --git a/kv/test/kv/registry_test.exs b/kv/test/kv/registry_test.exs new file mode 100644 index 0000000..e07bce0 --- /dev/null +++ b/kv/test/kv/registry_test.exs @@ -0,0 +1,42 @@ +defmodule KV.RegistryTest do + use ExUnit.Case, async: true + + setup context do + _ = start_supervised!({KV.Registry, name: context.test}) + %{registry: context.test} + end + + test "spawns buckets", %{registry: registry} do + assert KV.Registry.lookup(registry, "shopping") == :error + + KV.Registry.create(registry, "shopping") + assert {:ok, bucket} = KV.Registry.lookup(registry, "shopping") + + KV.Bucket.put(bucket, "milk", 1) + assert KV.Bucket.get(bucket, "milk") == 1 + end + + test "removes buckets on exit", %{registry: registry} do + KV.Registry.create(registry, "shopping") + {:ok, bucket} = KV.Registry.lookup(registry, "shopping") + Agent.stop(bucket) + # Do a call to ensure the registry processed the DOWN message + _ = KV.Registry.create(registry, "bogus") + assert KV.Registry.lookup(registry, "shopping") == :error + end + + test "removes bucket on crash", %{registry: registry} do + KV.Registry.create(registry, "shopping") + {:ok, bucket} = KV.Registry.lookup(registry, "shopping") + + # Stop the bucket with non-normal reason + # If a process terminates with a reason other than :normal, all linked processes + # receive an EXIT signal, causing the linked process to + # also terminate unless it is trapping exits. + Agent.stop(bucket, :shutdown) + + # Do a call to ensure the registry processed the DOWN message + _ = KV.Registry.create(registry, "bogus") + assert KV.Registry.lookup(registry, "shopping") == :error + end +end diff --git a/kv/test/test_helper.exs b/kv/test/test_helper.exs new file mode 100644 index 0000000..869559e --- /dev/null +++ b/kv/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start() diff --git a/kv_umbrella/.formatter.exs b/kv_umbrella/.formatter.exs new file mode 100644 index 0000000..90a0853 --- /dev/null +++ b/kv_umbrella/.formatter.exs @@ -0,0 +1,5 @@ +# Used by "mix format" +[ + inputs: ["mix.exs", "config/*.exs"], + subdirectories: ["apps/*"] +] diff --git a/kv_umbrella/.gitignore b/kv_umbrella/.gitignore new file mode 100644 index 0000000..013cd25 --- /dev/null +++ b/kv_umbrella/.gitignore @@ -0,0 +1,20 @@ +# 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 third-party dependencies like ExDoc output generated docs. +/doc/ + +# 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 + +# Temporary files, for example, from tests. +/tmp/ diff --git a/kv_umbrella/README.md b/kv_umbrella/README.md new file mode 100644 index 0000000..adc1f61 --- /dev/null +++ b/kv_umbrella/README.md @@ -0,0 +1,4 @@ +# KvUmbrella + +**TODO: Add description** + diff --git a/kv_umbrella/apps/kv/.formatter.exs b/kv_umbrella/apps/kv/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/kv_umbrella/apps/kv/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/kv_umbrella/apps/kv/.gitignore b/kv_umbrella/apps/kv/.gitignore new file mode 100644 index 0000000..f911028 --- /dev/null +++ b/kv_umbrella/apps/kv/.gitignore @@ -0,0 +1,26 @@ +# 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 third-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"). +kv-*.tar + +# Temporary files, for example, from tests. +/tmp/ diff --git a/kv_umbrella/apps/kv/README.md b/kv_umbrella/apps/kv/README.md new file mode 100644 index 0000000..0c3a917 --- /dev/null +++ b/kv_umbrella/apps/kv/README.md @@ -0,0 +1,21 @@ +# KV + +**TODO: Add description** + +## Installation + +If [available in Hex](https://hex.pm/docs/publish), the package can be installed +by adding `kv` to your list of dependencies in `mix.exs`: + +```elixir +def deps do + [ + {:kv, "~> 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 . + diff --git a/kv_umbrella/apps/kv/lib/kv.ex b/kv_umbrella/apps/kv/lib/kv.ex new file mode 100644 index 0000000..2c20e7f --- /dev/null +++ b/kv_umbrella/apps/kv/lib/kv.ex @@ -0,0 +1,10 @@ +defmodule KV do + use Application + + @impl true + def start(_type, _args) do + # Anche se non usiamo KV.Supervisor name direttamente, + # e' comodo per debug + KV.Supervisor.start_link(name: KV.Supervisor) + end +end diff --git a/kv_umbrella/apps/kv/lib/kv/bucket.ex b/kv_umbrella/apps/kv/lib/kv/bucket.ex new file mode 100644 index 0000000..71d59b2 --- /dev/null +++ b/kv_umbrella/apps/kv/lib/kv/bucket.ex @@ -0,0 +1,33 @@ +defmodule KV.Bucket do + use Agent, restart: :temporary + + @doc """ + Starts a new bucket. + """ + def start_link(_opts) do + Agent.start_link(fn -> %{} end) + end + + @doc """ + Gets a value from the `bucket` by `key`. + """ + def get(bucket, key) do + Agent.get(bucket, &Map.get(&1, key)) + end + + @doc """ + Puts the `value` for the given `key` in the `bucket`. + """ + def put(bucket, key, value) do + Agent.update(bucket, &Map.put(&1, key, value)) + end + + @doc """ + Deletes `key` from `bucket`. + + Returns the current value of `key`, if `key` exists. + """ + def delete(bucket, key) do + Agent.get_and_update(bucket, &Map.pop(&1, key)) + end +end diff --git a/kv_umbrella/apps/kv/lib/kv/registry.ex b/kv_umbrella/apps/kv/lib/kv/registry.ex new file mode 100644 index 0000000..7eeb716 --- /dev/null +++ b/kv_umbrella/apps/kv/lib/kv/registry.ex @@ -0,0 +1,69 @@ +defmodule KV.Registry do + use GenServer + + # Client API + @doc """ + Starts the registry. + """ + def start_link(opts) do + server = Keyword.fetch!(opts, :name) + GenServer.start_link(__MODULE__, server, opts) + end + + @doc """ + Looks up the bucket pid for `name` stored in `server`. + + Returns `{:ok, pid}` if the bucket exists, `:error` otherwise. + """ + def lookup(server, name) do + case :ets.lookup(server, name) do + [{^name, pid}] -> {:ok, pid} + [] -> :error + end + end + + @doc """ + Ensures there is a bucket associated with the given `name` in `server`. + """ + def create(server, name) do + GenServer.call(server, {:create, name}) + end + + # Server Callbacks + + @impl true + def init(table) do + # name -> bucket + names = :ets.new(table, [:named_table, read_concurrency: true]) + refs = %{} # ref -> name + {:ok, {names, refs}} + end + + @impl true + def handle_call({:create, name}, _from, {names, refs}) do + case lookup(names, name) do + {:ok, bucket} -> + {:reply, bucket, {names, refs}} + :error -> + {:ok, bucket} = DynamicSupervisor.start_child(KV.BucketSupervisor, KV.Bucket) + ref = Process.monitor(bucket) + refs = Map.put(refs, ref, name) + :ets.insert(names, {name, bucket}) + {:reply, bucket, {names, refs}} + end + end + + @impl true + def handle_info({:DOWN, ref, :process, _pid, _reason}, {names, refs}) do + {name, refs} = Map.pop(refs, ref) + :ets.delete(names, name) + {:noreply, {names, refs}} + end + + @impl true + def handle_info(msg, state) do + require Logger + Logger.debug("Unexpected message in KV.Registry: #{inspect(msg)}") + {:noreply, state} + end +end diff --git a/kv_umbrella/apps/kv/lib/kv/supervisor.ex b/kv_umbrella/apps/kv/lib/kv/supervisor.ex new file mode 100644 index 0000000..c42f17a --- /dev/null +++ b/kv_umbrella/apps/kv/lib/kv/supervisor.ex @@ -0,0 +1,17 @@ +defmodule KV.Supervisor do + use Supervisor + + def start_link(opts) do + Supervisor.start_link(__MODULE__, :ok, opts) + end + + @impl true + def init(:ok) do + children = [ + {DynamicSupervisor, name: KV.BucketSupervisor, strategy: :one_for_one}, + {KV.Registry, name: KV.Registry}, + ] + + Supervisor.init(children, strategy: :one_for_all) + end +end diff --git a/kv_umbrella/apps/kv/mix.exs b/kv_umbrella/apps/kv/mix.exs new file mode 100644 index 0000000..9c8bbe8 --- /dev/null +++ b/kv_umbrella/apps/kv/mix.exs @@ -0,0 +1,33 @@ +defmodule KV.MixProject do + use Mix.Project + + def project do + [ + app: :kv, + version: "0.1.0", + build_path: "../../_build", + config_path: "../../config/config.exs", + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.17", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications. + def application do + [ + extra_applications: [:logger], + mod: {KV, []} + ] + end + + # Run "mix help deps" to learn about dependencies. + defp deps do + [ + # {: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/kv_umbrella/apps/kv/test/kv/bucket_test.exs b/kv_umbrella/apps/kv/test/kv/bucket_test.exs new file mode 100644 index 0000000..0cfa15f --- /dev/null +++ b/kv_umbrella/apps/kv/test/kv/bucket_test.exs @@ -0,0 +1,15 @@ +defmodule KV.BucketTest do + use ExUnit.Case, async: true + + setup do + bucket = start_supervised!(KV.Bucket) + %{bucket: bucket} + end + + test "stores values by key", %{bucket: bucket} do + assert KV.Bucket.get(bucket, "milk") == nil + + KV.Bucket.put(bucket, "milk", 3) + assert KV.Bucket.get(bucket, "milk") == 3 + end +end diff --git a/kv_umbrella/apps/kv/test/kv/registry_test.exs b/kv_umbrella/apps/kv/test/kv/registry_test.exs new file mode 100644 index 0000000..e07bce0 --- /dev/null +++ b/kv_umbrella/apps/kv/test/kv/registry_test.exs @@ -0,0 +1,42 @@ +defmodule KV.RegistryTest do + use ExUnit.Case, async: true + + setup context do + _ = start_supervised!({KV.Registry, name: context.test}) + %{registry: context.test} + end + + test "spawns buckets", %{registry: registry} do + assert KV.Registry.lookup(registry, "shopping") == :error + + KV.Registry.create(registry, "shopping") + assert {:ok, bucket} = KV.Registry.lookup(registry, "shopping") + + KV.Bucket.put(bucket, "milk", 1) + assert KV.Bucket.get(bucket, "milk") == 1 + end + + test "removes buckets on exit", %{registry: registry} do + KV.Registry.create(registry, "shopping") + {:ok, bucket} = KV.Registry.lookup(registry, "shopping") + Agent.stop(bucket) + # Do a call to ensure the registry processed the DOWN message + _ = KV.Registry.create(registry, "bogus") + assert KV.Registry.lookup(registry, "shopping") == :error + end + + test "removes bucket on crash", %{registry: registry} do + KV.Registry.create(registry, "shopping") + {:ok, bucket} = KV.Registry.lookup(registry, "shopping") + + # Stop the bucket with non-normal reason + # If a process terminates with a reason other than :normal, all linked processes + # receive an EXIT signal, causing the linked process to + # also terminate unless it is trapping exits. + Agent.stop(bucket, :shutdown) + + # Do a call to ensure the registry processed the DOWN message + _ = KV.Registry.create(registry, "bogus") + assert KV.Registry.lookup(registry, "shopping") == :error + end +end diff --git a/kv_umbrella/apps/kv/test/test_helper.exs b/kv_umbrella/apps/kv/test/test_helper.exs new file mode 100644 index 0000000..869559e --- /dev/null +++ b/kv_umbrella/apps/kv/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start() diff --git a/kv_umbrella/apps/kv_server/.formatter.exs b/kv_umbrella/apps/kv_server/.formatter.exs new file mode 100644 index 0000000..d2cda26 --- /dev/null +++ b/kv_umbrella/apps/kv_server/.formatter.exs @@ -0,0 +1,4 @@ +# Used by "mix format" +[ + inputs: ["{mix,.formatter}.exs", "{config,lib,test}/**/*.{ex,exs}"] +] diff --git a/kv_umbrella/apps/kv_server/.gitignore b/kv_umbrella/apps/kv_server/.gitignore new file mode 100644 index 0000000..e545363 --- /dev/null +++ b/kv_umbrella/apps/kv_server/.gitignore @@ -0,0 +1,23 @@ +# 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 third-party dependencies like ExDoc output generated docs. +/doc/ + +# 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"). +kv_server-*.tar + +# Temporary files, for example, from tests. +/tmp/ diff --git a/kv_umbrella/apps/kv_server/README.md b/kv_umbrella/apps/kv_server/README.md new file mode 100644 index 0000000..fc5c772 --- /dev/null +++ b/kv_umbrella/apps/kv_server/README.md @@ -0,0 +1,21 @@ +# KVServer + +**TODO: Add description** + +## Installation + +If [available in Hex](https://hex.pm/docs/publish), the package can be installed +by adding `kv_server` to your list of dependencies in `mix.exs`: + +```elixir +def deps do + [ + {:kv_server, "~> 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 . + diff --git a/kv_umbrella/apps/kv_server/lib/kv_server.ex b/kv_umbrella/apps/kv_server/lib/kv_server.ex new file mode 100644 index 0000000..4a02a55 --- /dev/null +++ b/kv_umbrella/apps/kv_server/lib/kv_server.ex @@ -0,0 +1,18 @@ +defmodule KVServer do + @moduledoc """ + Documentation for `KVServer`. + """ + + @doc """ + Hello world. + + ## Examples + + iex> KVServer.hello() + :world + + """ + def hello do + :world + end +end diff --git a/kv_umbrella/apps/kv_server/lib/kv_server/application.ex b/kv_umbrella/apps/kv_server/lib/kv_server/application.ex new file mode 100644 index 0000000..09705d2 --- /dev/null +++ b/kv_umbrella/apps/kv_server/lib/kv_server/application.ex @@ -0,0 +1,20 @@ +defmodule KVServer.Application do + # See https://hexdocs.pm/elixir/Application.html + # for more information on OTP Applications + @moduledoc false + + use Application + + @impl true + def start(_type, _args) do + 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 diff --git a/kv_umbrella/apps/kv_server/mix.exs b/kv_umbrella/apps/kv_server/mix.exs new file mode 100644 index 0000000..7da6e79 --- /dev/null +++ b/kv_umbrella/apps/kv_server/mix.exs @@ -0,0 +1,35 @@ +defmodule KVServer.MixProject do + use Mix.Project + + def project do + [ + app: :kv_server, + version: "0.1.0", + build_path: "../../_build", + config_path: "../../config/config.exs", + deps_path: "../../deps", + lockfile: "../../mix.lock", + elixir: "~> 1.18", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Run "mix help compile.app" to learn about applications. + def application do + [ + extra_applications: [:logger], + mod: {KVServer.Application, []} + ] + end + + # Run "mix help deps" to learn about dependencies. + defp deps do + [ + {:kv, in_umbrella: true}, + # {:dep_from_hexpm, "~> 0.3.0"}, + # {:dep_from_git, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}, + # {:sibling_app_in_umbrella, in_umbrella: true} + ] + end +end diff --git a/kv_umbrella/apps/kv_server/test/kv_server_test.exs b/kv_umbrella/apps/kv_server/test/kv_server_test.exs new file mode 100644 index 0000000..d4b1d77 --- /dev/null +++ b/kv_umbrella/apps/kv_server/test/kv_server_test.exs @@ -0,0 +1,8 @@ +defmodule KVServerTest do + use ExUnit.Case + doctest KVServer + + test "greets the world" do + assert KVServer.hello() == :world + end +end diff --git a/kv_umbrella/apps/kv_server/test/test_helper.exs b/kv_umbrella/apps/kv_server/test/test_helper.exs new file mode 100644 index 0000000..869559e --- /dev/null +++ b/kv_umbrella/apps/kv_server/test/test_helper.exs @@ -0,0 +1 @@ +ExUnit.start() diff --git a/kv_umbrella/config/config.exs b/kv_umbrella/config/config.exs new file mode 100644 index 0000000..ab23e80 --- /dev/null +++ b/kv_umbrella/config/config.exs @@ -0,0 +1,18 @@ +# This file is responsible for configuring your umbrella +# and **all applications** and their dependencies with the +# help of the Config module. +# +# Note that all applications in your umbrella share the +# same configuration and dependencies, which is why they +# all use the same configuration file. If you want different +# configurations or dependencies per app, it is best to +# move said applications out of the umbrella. +import Config + +# Sample configuration: +# +# config :logger, :console, +# level: :info, +# format: "$date $time [$level] $metadata$message\n", +# metadata: [:user_id] +# diff --git a/kv_umbrella/mix.exs b/kv_umbrella/mix.exs new file mode 100644 index 0000000..15f1213 --- /dev/null +++ b/kv_umbrella/mix.exs @@ -0,0 +1,21 @@ +defmodule KvUmbrella.MixProject do + use Mix.Project + + def project do + [ + apps_path: "apps", + version: "0.1.0", + start_permanent: Mix.env() == :prod, + deps: deps() + ] + end + + # Dependencies listed here are available only for this + # project and cannot be accessed from applications inside + # the apps folder. + # + # Run "mix help deps" for examples and options. + defp deps do + [] + end +end diff --git a/macros.exs b/macros.exs new file mode 100644 index 0000000..f607170 --- /dev/null +++ b/macros.exs @@ -0,0 +1,10 @@ +defmodule Unless do + def fun_unless(clause, do: expression) do + if !clause, do: expression + end + defmacro macro_unless(clause, do: expression) do + quote do + if !unquote(clause), do: unquote(expression) + end + end +end diff --git a/math.exs b/math.exs new file mode 100644 index 0000000..dde8c63 --- /dev/null +++ b/math.exs @@ -0,0 +1,7 @@ +defmodule Math do + def sum(a, b) do + a + b + end +end + +IO.puts Math.sum(1, 2)