Elixir-Beispiele

Wesentliche Elixir-Programmierbeispiele für nebenläufige und verteilte Systeme

💻 Elixir Hello World elixir

🟢 simple ⭐⭐

Grundlegendes Hello World-Programm und fundamentale funktionale Programmierkonzepte

⏱️ 20 min 🏷️ elixir, functional programming, beginner, erlang
Prerequisites: Basic programming concepts, Understanding of functional programming
# Elixir Hello World Examples

# 1. Basic Hello World
IO.puts("Hello, World!")

# 2. Hello World with variable
message = "Hello, World!"
IO.puts(message)

# 3. Hello World with function
defmodule HelloWorld do
  def say_hello do
    "Hello, World!"
  end

  def print_hello do
    IO.puts(say_hello())
  end
end

HelloWorld.print_hello()

# 4. Hello World with function parameters
defmodule Greeting do
  def greet(name) do
    "Hello, #{name}!"
  end

  def print_greeting(name) do
    IO.puts(greet(name))
  end
end

Greeting.print_greeting("World")
Greeting.print_greeting("Elixir")

# 5. Hello World with pattern matching
defmodule PatternGreeting do
  def greet({:formal, name}) do
    "Good day, #{name}."
  end

  def greet({:informal, name}) do
    "Hey #{name}!"
  end

  def greet({:professional, name, title}) do
    "Hello #{title} #{name}."
  end

  def greet(name) when is_binary(name) do
    "Hello, #{name}!"
  end
end

IO.puts(PatternGreeting.greet("Alice"))
IO.puts(PatternGreeting.greet({:formal, "Bob"}))
IO.puts(PatternGreeting.greet({:informal, "Charlie"}))
IO.puts(PatternGreeting.greet({:professional, "Diana", "Dr."}))

# 6. Hello World multiple times
defmodule MultipleGreetings do
  def repeat_greeting(greeting, times) do
    1..times
    |> Enum.map(fn i -> "#{greeting} #{i}" end)
    |> Enum.each(&IO.puts/1)
  end
end

MultipleGreetings.repeat_greeting("Hello, World!", 5)

# 7. Hello World with list
defmodule ListGreetings do
  def greet_all(names) do
    names
    |> Enum.map(&"Hello, #{&1}!")
    |> Enum.each(&IO.puts/1)
  end

  def greet_in_different_languages do
    greetings = [
      "Hello", "Bonjour", "Hola", "Ciao", "こんにちは",
      "안녕하세요", "مرحبا", "Здравствуйте", "नमस्ते"
    ]

    greetings
    |> Enum.map(&"#{&1}, World!")
    |> Enum.each(&IO.puts/1)
  end
end

ListGreetings.greet_all(["Alice", "Bob", "Charlie"])
ListGreetings.greet_in_different_languages()

# 8. Hello World with map
defmodule MapGreetings do
  def greet_by_language do
    translations = %{
      "en" => "Hello",
      "es" => "Hola",
      "fr" => "Bonjour",
      "de" => "Hallo",
      "ja" => "こんにちは",
      "ko" => "안녕하세요"
    }

    translations
    |> Enum.map(fn {lang, greeting} -> "#{greeting}, World! (#{lang})" end)
    |> Enum.each(&IO.puts/1)
  end
end

MapGreetings.greet_by_language()

# 9. Hello World with recursion
defmodule RecursiveGreetings do
  def greet_countdown(0) do
    IO.puts("Liftoff! 🚀")
  end

  def greet_countdown(n) when n > 0 do
    IO.puts("Hello, World! #{n}")
    greet_countdown(n - 1)
  end

  def greet_list([]) do
    :ok
  end

  def greet_list([head | tail]) do
    IO.puts("Hello, #{head}!")
    greet_list(tail)
  end
end

RecursiveGreetings.greet_countdown(5)
RecursiveGreetings.greet_list(["Alice", "Bob", "Charlie"])

# 10. Hello World with pipe operator
defmodule PipeGreeting do
  def create_greeting(name, style) do
    name
    |> String.upcase()
    |> add_style(style)
    |> format_message()
  end

  defp add_style(name, :excited) do
    name <> "!"
  end

  defp add_style(name, :formal) do
    "Dear " <> name
  end

  defp add_style(name, :casual) do
    "Hey " <> name
  end

  defp format_message(message) do
    "Hello, #{message}"
  end
end

IO.puts(PipeGreeting.create_greeting("World", :excited))
IO.puts(PipeGreeting.create_greeting("World", :formal))
IO.puts(PipeGreeting.create_greeting("World", :casual))

# Basic data types and operations

# Numbers
integer = 42
float = 3.14

# Atoms (constants that start with colon)
atom = :hello
boolean_true = true
boolean_false = false
nil_value = nil

# Strings
string = "Hello, Elixir!"
string_with_interpolation = "The answer is #{integer}"

# Lists (linked lists)
list = [1, 2, 3, 4, 5]
string_list = ["apple", "banana", "cherry"]
mixed_list = [1, "two", :three, 4.0]

# Tuples
tuple = {:ok, "success"}
point = {10, 20}
person = {"Alice", 30, "Engineer"}

# Maps (key-value collections)
map = %{
  name: "Alice",
  age: 30,
  city: "New York"
}

map_with_string_keys = %{
  "name" => "Bob",
  "age" => 25,
  "skills" => ["Elixir", "Phoenix", "Ecto"]
}

# Ranges
range = 1..10
char_range = ?a..?z

# Keyword lists (special list of key-value tuples)
keyword_list = [name: "Alice", age: 30, city: "NYC"]

IO.puts("\n=== Data Types ===")
IO.inspect(integer, label: "Integer")
IO.inspect(float, label: "Float")
IO.inspect(atom, label: "Atom")
IO.inspect(string, label: "String")
IO.inspect(list, label: "List")
IO.inspect(tuple, label: "Tuple")
IO.inspect(map, label: "Map")
IO.inspect(range, label: "Range")
IO.inspect(keyword_list, label: "Keyword List")

# Pattern matching examples

# Variable binding
{a, b, c} = {1, 2, 3}
IO.puts("Pattern matching: a=#{a}, b=#{b}, c=#{c}")

# List pattern matching
[head | tail] = [1, 2, 3, 4, 5]
IO.puts("List pattern: head=#{head}, tail=#{inspect(tail)}")

# Map pattern matching
%{name: name, age: age} = %{name: "Alice", age: 30, city: "NYC"}
IO.puts("Map pattern: name=#{name}, age=#{age}")

# Function pattern matching
defmodule MathFunctions do
  def describe_number(0), do: "Zero"
  def describe_number(n) when n > 0, do: "Positive: #{n}"
  def describe_number(n) when n < 0, do: "Negative: #{n}"

  def max(a, b) when a > b, do: a
  def max(a, b), do: b

  def factorial(0), do: 1
  def factorial(n) when n > 0, do: n * factorial(n - 1)
end

IO.puts("\n=== Pattern Matching Functions ===")
IO.puts(MathFunctions.describe_number(5))
IO.puts(MathFunctions.describe_number(-3))
IO.puts(MathFunctions.describe_number(0))
IO.puts("Max of 5 and 3: #{MathFunctions.max(5, 3)}")
IO.puts("Factorial of 5: #{MathFunctions.factorial(5)}")

# Higher-order functions and Enum module
defmodule ListOperations do
  def process_numbers do
    numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]

    squared = Enum.map(numbers, &(&1 * &1))
    even_numbers = Enum.filter(numbers, &(rem(&1, 2) == 0))
    sum = Enum.reduce(numbers, 0, &+/2)

    IO.puts("Original: #{inspect(numbers)}")
    IO.puts("Squared: #{inspect(squared)}")
    IO.puts("Even: #{inspect(even_numbers)}")
    IO.puts("Sum: #{sum}")
  end

  def string_operations do
    words = ["hello", "world", "elixir", "functional", "programming"]

    upper_words = Enum.map(words, &String.upcase/1)
    long_words = Enum.filter(words, &(String.length(&1) > 5))
    word_lengths = Enum.map(words, &{&1, String.length(&1)})
    all_words = Enum.join(words, " ")

    IO.puts("Words: #{inspect(words)}")
    IO.puts("Upper: #{inspect(upper_words)}")
    IO.puts("Long words: #{inspect(long_words)}")
    IO.puts("Word lengths: #{inspect(word_lengths)}")
    IO.puts("Joined: #{all_words}")
  end
end

IO.puts("\n=== List Operations ===")
ListOperations.process_numbers()
IO.puts("\n=== String Operations ===")
ListOperations.string_operations()

# Control flow
defmodule ControlFlow do
  def check_grade(score) do
    cond do
      score >= 90 -> "A"
      score >= 80 -> "B"
      score >= 70 -> "C"
      score >= 60 -> "D"
      true -> "F"
    end
  end

  def case_example(value) do
    case value do
      :ok -> "Operation succeeded"
      :error -> "Operation failed"
      {:ok, result} -> "Operation succeeded with: #{result}"
      {:error, reason} -> "Operation failed because: #{reason}"
      _ -> "Unknown result"
    end
  end

  def unless_example(condition) do
    unless condition do
      "Condition is false"
    else
      "Condition is true"
    end
  end
end

IO.puts("\n=== Control Flow ===")
IO.puts("Grade for 85: #{ControlFlow.check_grade(85)}")
IO.puts("Case example ok: #{ControlFlow.case_example(:ok)}")
IO.puts("Case example error: #{ControlFlow.case_example({:error, "timeout"})}")
IO.puts("Unless example: #{ControlFlow.unless_example(false)}")

# Structs
defmodule Person do
  defstruct name: nil, age: nil, city: nil

  def greet(%Person{name: name}) do
    "Hello, #{name}!"
  end

  def birthday(%Person{age: age} = person) do
    %{person | age: age + 1}
  end

  def is_adult?(%Person{age: age}) when age >= 18, do: true
  def is_adult?(_), do: false
end

IO.puts("\n=== Structs ===")
person = %Person{name: "Alice", age: 30, city: "NYC"}
IO.inspect(person, label: "Person")
IO.puts(Person.greet(person))
older_person = Person.birthday(person)
IO.inspect(older_person, label: "After birthday")
IO.puts("Is adult?: #{Person.is_adult?(person)}")

# Protocols
defmodule Greeter do
  @doc "Greets any type that implements this protocol"
  @callback greet(any) :: String.t()
end

defmodule Human do
  defstruct [:name]

  defimpl Greeter do
    def greet(%Human{name: name}), do: "Hello, #{name}!"
  end
end

defmodule Robot do
  defstruct [:id]

  defimpl Greeter do
    def greet(%Robot{id: id}), do: "BEEP BOOP. I am robot #{id}."
  end
end

IO.puts("\n=== Protocols ===")
human = %Human{name: "Alice"}
robot = %Robot{id: 1234}

IO.puts(Greeter.greet(human))
IO.puts(Greeter.greet(robot))

# Module attributes and documentation
defmodule Calculator do
  @moduledoc """
  A simple calculator module that provides basic arithmetic operations.
  """

  @pi 3.14159
  @version "1.0.0"

  @doc """
  Adds two numbers together.

  ## Examples

      iex> Calculator.add(2, 3)
      5

      iex> Calculator.add(-1, 1)
      0
  """
  def add(a, b), do: a + b

  @doc "Multiplies two numbers together"
  def multiply(a, b), do: a * b

  @doc "Returns the value of pi"
  def pi, do: @pi

  @doc "Returns the version of this calculator"
  def version, do: @version
end

IO.puts("\n=== Module with Documentation ===")
IO.puts("2 + 3 = #{Calculator.add(2, 3)}")
IO.puts("5 * 4 = #{Calculator.multiply(5, 4)}")
IO.puts("Pi: #{Calculator.pi()}")
IO.puts("Version: #{Calculator.version()}")

# Error handling
defmodule SafeOperations do
  def safe_divide(_, 0), do: {:error, "Cannot divide by zero"}
  def safe_divide(a, b), do: {:ok, a / b}

  def process_result({:ok, result}), do: "Result: #{result}"
  def process_result({:error, reason}), do: "Error: #{reason}"

  def safe_divide_and_process(a, b) do
    a
    |> safe_divide(b)
    |> process_result()
  end
end

IO.puts("\n=== Error Handling ===")
IO.puts(SafeOperations.safe_divide_and_process(10, 2))
IO.puts(SafeOperations.safe_divide_and_process(10, 0))

# Comprehensions
defmodule Comprehensions do
  def matrix do
    for x <- 1..3, y <- 1..3 do
      {x, y, x * y}
    end
  end

  def pythagorean_triplets(limit) do
    for a <- 1..limit,
        b <- a..limit,
        c <- b..limit,
        a * a + b * b == c * c do
      {a, b, c}
    end
  end

  def word_lengths(words) do
    for word <- words,
        String.length(word) > 3,
        into: %{} do
      {word, String.length(word)}
    end
  end
end

IO.puts("\n=== Comprehensions ===")
IO.puts("Matrix products:")
Enum.each(Comprehensions.matrix(), &IO.puts/1)

IO.puts("\nPythagorean triplets up to 20:")
Enum.each(Comprehensions.pythagorean_triplets(20), &IO.inspect/1)

IO.puts("\nWord lengths:")
words = ["cat", "elephant", "dog", "programming", "hi"]
IO.inspect(Comprehensions.word_lengths(words))

# Working with files (basic examples)
defmodule FileOperations do
  def write_hello(filename) do
    content = "Hello from Elixir!\nThis is a test file.\nWritten at: #{DateTime.utc_now()}"

    case File.write(filename, content) do
      :ok -> IO.puts("Successfully wrote to #{filename}")
      {:error, reason} -> IO.puts("Failed to write: #{reason}")
    end
  end

  def read_hello(filename) do
    case File.read(filename) do
      {:ok, content} ->
        IO.puts("File content:")
        IO.puts(content)
      {:error, reason} ->
        IO.puts("Failed to read: #{reason}")
    end
  end
end

IO.puts("\n=== File Operations ===")
filename = "hello_elixir.txt"
FileOperations.write_hello(filename)
FileOperations.read_hello(filename)
File.rm(filename)  # Clean up

IO.puts("\n=== All Elixir Hello World Examples Complete! ===")

💻 Elixir-Nebenläufigkeit und OTP elixir

🟡 intermediate ⭐⭐⭐⭐

Fortgeschrittene Nebenläufigkeitsmuster mit GenServer, Supervisor und Agent

⏱️ 35 min 🏷️ elixir, concurrency, otp, distributed systems, fault tolerance
Prerequisites: Elixir basics, Understanding of concurrent programming, OTP concepts
# Elixir Concurrency and OTP Examples

# 1. Basic Processes and spawn
defmodule ProcessBasics do
  def start_greeter(name) do
    spawn(fn -> greeter_loop(name) end)
  end

  defp greeter_loop(name) do
    receive do
      {:greet, who} ->
        IO.puts("#{name}: Hello, #{who}!")
        greeter_loop(name)
      {:stop} ->
        IO.puts("#{name}: Goodbye!")
      :stop ->
        IO.puts("#{name}: Goodbye! (atom)")
    end
  end

  def send_message(pid, message) do
    send(pid, message)
  end
end

IO.puts("=== Basic Process Examples ===")
greeter1 = ProcessBasics.start_greeter("Alice")
greeter2 = ProcessBasics.start_greeter("Bob")

ProcessBasics.send_message(greeter1, {:greet, "World"})
ProcessBasics.send_message(greeter2, {:greet, "Everyone"})

# Give processes time to respond
:timer.sleep(100)
ProcessBasics.send_message(greeter1, :stop)
ProcessBasics.send_message(greeter2, :stop)

:timer.sleep(100)

# 2. Agent for State Management
defmodule Counter do
  def start_link(initial_value \ 0) do
    Agent.start_link(fn -> initial_value end, name: __MODULE__)
  end

  def increment do
    Agent.update(__MODULE__, &(&1 + 1))
  end

  def decrement do
    Agent.update(__MODULE__, &(&1 - 1))
  end

  def value do
    Agent.get(__MODULE__, &(&1))
  end

  def reset do
    Agent.update(__MODULE__, fn _ -> 0 end)
  end

  def stop do
    Agent.stop(__MODULE__)
  end
end

IO.puts("\n=== Agent Examples ===")
{:ok, _pid} = Counter.start_link(10)
IO.puts("Initial counter value: #{Counter.value()}")

Counter.increment()
Counter.increment()
Counter.decrement()
IO.puts("After operations: #{Counter.value()}")

Counter.reset()
IO.puts("After reset: #{Counter.value()}")

Counter.stop()

# 3. Task for Asynchronous Operations
defmodule AsyncOperations do
  def slow_operation(name, delay_ms) do
    :timer.sleep(delay_ms)
    {:ok, "#{name} completed after #{delay_ms}ms"}
  end

  def run_parallel_tasks do
    tasks = [
      Task.async(fn -> slow_operation("Task 1", 1000) end),
      Task.async(fn -> slow_operation("Task 2", 800) end),
      Task.async(fn -> slow_operation("Task 3", 1200) end)
    ]

    results = Task.await_many(tasks, 2000)
    Enum.each(results, fn result ->
      case result do
        {:ok, message} -> IO.puts("Success: #{message}")
        {:exit, reason} -> IO.puts("Task failed: #{reason}")
      end
    end)
  end

  def run_with_timeout do
    task = Task.async(fn ->
      :timer.sleep(3000)
      "Slow result"
    end)

    case Task.yield(task, 1000) do
      {:ok, result} -> IO.puts("Task completed: #{result}")
      nil ->
        IO.puts("Task didn't complete in time")
        Task.shutdown(task, :brutal_kill)
    end
  end
end

IO.puts("\n=== Task Examples ===")
IO.puts("Running parallel tasks...")
AsyncOperations.run_parallel_tasks()

IO.puts("\nRunning task with timeout...")
AsyncOperations.run_with_timeout()

# 4. GenServer for Stateful Processes
defmodule GameState do
  use GenServer

  # Client API
  def start_link(initial_state) do
    GenServer.start_link(__MODULE__, initial_state, name: __MODULE__)
  end

  def get_state do
    GenServer.call(__MODULE__, :get_state)
  end

  def make_move(player, move) do
    GenServer.call(__MODULE__, {:make_move, player, move})
  end

  def reset do
    GenServer.call(__MODULE__, :reset)
  end

  def get_history do
    GenServer.call(__MODULE__, :get_history)
  end

  # Server callbacks
  @impl true
  def init(initial_state) do
    state = %{
      board: initial_state[:board] || %{player1: nil, player2: nil},
      current_player: :player1,
      moves: [],
      winner: nil
    }
    {:ok, state}
  end

  @impl true
  def handle_call(:get_state, _from, state) do
    {:reply, state, state}
  end

  @impl true
  def handle_call({:make_move, player, move}, _from, state) do
    if state.current_player == player && state.winner == nil do
      new_board = put_in(state.board[player], move)
      new_moves = [{player, move} | state.moves]

      new_state = %{state |
        board: new_board,
        current_player: next_player(player),
        moves: new_moves,
        winner: check_winner(new_board)
      }

      {:reply, {:ok, move}, new_state}
    else
      {:reply, {:error, "Invalid move"}, state}
    end
  end

  @impl true
  def handle_call(:reset, _from, _state) do
    new_state = %{
      board: %{player1: nil, player2: nil},
      current_player: :player1,
      moves: [],
      winner: nil
    }
    {:reply, :ok, new_state}
  end

  @impl true
  def handle_call(:get_history, _from, state) do
    {:reply, Enum.reverse(state.moves), state}
  end

  @impl true
  def handle_info(:timeout, state) do
    IO.puts("Game timeout - resetting")
    {:noreply, reset_state()}
  end

  # Private helper functions
  defp next_player(:player1), do: :player2
  defp next_player(:player2), do: :player1

  defp check_winner(%{player1: move1, player2: move2}) when move1 != nil and move2 != nil do
    # Simple winner logic (for demonstration)
    cond do
      String.ends_with?(move1, "win") -> :player1
      String.ends_with?(move2, "win") -> :player2
      true -> nil
    end
  end

  defp check_winner(_), do: nil

  defp reset_state do
    %{
      board: %{player1: nil, player2: nil},
      current_player: :player1,
      moves: [],
      winner: nil
    }
  end
end

IO.puts("\n=== GenServer Examples ===")
{:ok, _pid} = GameState.start_link(%{board: %{player1: nil, player2: nil}})

IO.inspect(GameState.get_state(), label: "Initial state")

{:ok, _} = GameState.make_move(:player1, "rock")
IO.inspect(GameState.get_state(), label: "After player1 move")

{:ok, _} = GameState.make_move(:player2, "paper")
IO.inspect(GameState.get_state(), label: "After player2 move")

{:ok, _} = GameState.make_move(:player1, "win_move")
IO.inspect(GameState.get_state(), label: "After player1 winning move")

IO.puts("Move history:")
Enum.each(GameState.get_history(), &IO.inspect/1)

# 5. Supervisor for Process Management
defmodule GameSupervisor do
  use Supervisor

  def start_link(init_arg) do
    Supervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
  end

  @impl true
  def init(_init_arg) do
    children = [
      {GameState, %{board: %{player1: nil, player2: nil}}},
      {Counter, 0}
    ]

    Supervisor.init(children, strategy: :one_for_one)
  end
end

IO.puts("\n=== Supervisor Examples ===")
{:ok, _sup_pid} = GameSupervisor.start_link(%{})
IO.puts("Supervisor started with children")

# Check that our processes are running
IO.puts("Game state: #{inspect(GameState.get_state())}")

# 6. Dynamic Supervisor
defmodule DynamicGameSupervisor do
  use DynamicSupervisor

  def start_link(init_arg) do
    DynamicSupervisor.start_link(__MODULE__, init_arg, name: __MODULE__)
  end

  @impl true
  def init(_init_arg) do
    DynamicSupervisor.init(strategy: :one_for_one)
  end

  def start_game(name) do
    spec = %{
      id: GameState,
      start: {GameState, :start_link, [%{board: %{player1: nil, player2: nil}}]},
      restart: :temporary
    }

    DynamicSupervisor.start_child(__MODULE__, spec)
  end
end

IO.puts("\n=== Dynamic Supervisor Examples ===")
{:ok, _sup_pid} = DynamicGameSupervisor.start_link(%{})
{:ok, game1} = DynamicGameSupervisor.start_game("game1")
{:ok, game2} = DynamicGameSupervisor.start_game("game2")

IO.puts("Started dynamic games")
IO.puts("Children count: #{DynamicSupervisor.count_children(DynamicGameSupervisor)}")

# 7. Registry for Process Naming
defmodule GameRegistry do
  def start_link do
    Registry.start_link(keys: :unique, name: __MODULE__)
  end

  def register_game(name, pid) do
    Registry.register(__MODULE__, name, pid)
  end

  def lookup_game(name) do
    case Registry.lookup(__MODULE__, name) do
      [{pid, _}] -> {:ok, pid}
      [] -> {:error, :not_found}
    end
  end

  def list_games do
    Registry.select(__MODULE__, [{{:"$1", :"$2", :"$3"}, [], [:"$1"]}])
  end
end

IO.puts("\n=== Registry Examples ===")
{:ok, _reg_pid} = GameRegistry.start_link()

{:ok, game_pid} = GameState.start_link(%{board: %{player1: nil, player2: nil}})
GameRegistry.register_game("championship_game", game_pid)

{:ok, found_pid} = GameRegistry.lookup_game("championship_game")
IO.puts("Found game pid: #{inspect(found_pid)}")

IO.puts("All registered games: #{inspect(GameRegistry.list_games())}")

# 8. ETS (Erlang Term Storage) for In-Memory Database
defmodule GameCache do
  use GenServer

  # Client API
  def start_link do
    GenServer.start_link(__MODULE__, %{}, name: __MODULE__)
  end

  def store(key, value) do
    GenServer.call(__MODULE__, {:store, key, value})
  end

  def get(key) do
    GenServer.call(__MODULE__, {:get, key})
  end

  def delete(key) do
    GenServer.call(__MODULE__, {:delete, key})
  end

  def list_all do
    GenServer.call(__MODULE__, :list_all)
  end

  # Server callbacks
  @impl true
  def init(_) do
    table = :ets.new(:game_cache, [:set, :public, :named_table])
    {:ok, %{table: table}}
  end

  @impl true
  def handle_call({:store, key, value}, _from, %{table: table} = state) do
    :ets.insert(table, {key, value})
    {:reply, :ok, state}
  end

  @impl true
  def handle_call({:get, key}, _from, %{table: table} = state) do
    result = case :ets.lookup(table, key) do
      [{^key, value}] -> {:ok, value}
      [] -> {:error, :not_found}
    end
    {:reply, result, state}
  end

  @impl true
  def handle_call({:delete, key}, _from, %{table: table} = state) do
    :ets.delete(table, key)
    {:reply, :ok, state}
  end

  @impl true
  def handle_call(:list_all, _from, %{table: table} = state) do
    all = :ets.tab2list(table)
    {:reply, all, state}
  end
end

IO.puts("\n=== ETS Cache Examples ===")
{:ok, _cache_pid} = GameCache.start_link()

GameCache.store("player1_score", 100)
GameCache.store("player2_score", 150)
GameCache.store("game_status", "in_progress")

{:ok, score1} = GameCache.get("player1_score")
IO.puts("Player 1 score: #{score1}")

{:ok, status} = GameCache.get("game_status")
IO.puts("Game status: #{status}")

all_data = GameCache.list_all()
IO.puts("All cache data: #{inspect(all_data)}")

# 9. PubSub for Event Broadcasting
defmodule GameEvents do
  @name __MODULE__

  def start_link do
    Registry.start_link(keys: :duplicate, name: @name)
  end

  def subscribe(topic) do
    Registry.register(@name, topic, [])
  end

  def publish(topic, message) do
    Registry.dispatch(@name, topic, fn entries ->
      for {pid, _} <- entries do
        send(pid, {:broadcast, topic, message})
      end
    end)
  end

  def unsubscribe(topic) do
    Registry.unregister(@name, topic)
  end
end

defmodule GameSubscriber do
  def start_link(topic) do
    spawn(fn ->
      GameEvents.subscribe(topic)
      listen()
    end)
  end

  defp listen do
    receive do
      {:broadcast, topic, message} ->
        IO.puts("Subscriber received on #{topic}: #{message}")
        listen()
    end
  end
end

IO.puts("\n=== PubSub Examples ===")
{:ok, _pub_pid} = GameEvents.start_link()

subscriber1 = GameSubscriber.start_link("game_updates")
subscriber2 = GameSubscriber.start_link("game_updates")
subscriber3 = GameSubscriber.start_link("system_events")

GameEvents.publish("game_updates", "Player 1 scored!")
GameEvents.publish("game_updates", "Player 2 scored!")
GameEvents.publish("system_events", "Server maintenance scheduled")

:timer.sleep(100)

# 10. Poolboy for Connection Pooling (simplified example)
defmodule WorkerPool do
  def start_link(size) do
    workers = for i <- 1..size do
      spawn(fn -> worker_loop(i) end)
    end

    Agent.start_link(fn -> %{workers: workers, available: workers, busy: []} end, name: __MODULE__)
  end

  def checkout do
    Agent.get_and_update(__MODULE__, fn %{workers: workers, available: available, busy: busy} = state ->
      case available do
        [worker | rest] ->
          {{:ok, worker}, %{state | available: rest, busy: [worker | busy]}}
        [] ->
          {{:error, :no_workers}, state}
      end
    end)
  end

  def checkin(worker) do
    Agent.update(__MODULE__, fn %{workers: workers, available: available, busy: busy} ->
      case worker in busy do
        true ->
          %{workers: workers, available: [worker | available], busy: List.delete(busy, worker)}
        false ->
          %{workers: workers, available: available, busy: busy}
      end
    end)
  end

  defp worker_loop(id) do
    receive do
      {:work, from, task} ->
        result = perform_task(task, id)
        send(from, {:result, id, result})
        worker_loop(id)
      :stop ->
        :ok
    end
  end

  defp perform_task(task, worker_id) do
    :timer.sleep(:rand.uniform(1000))
    "#{task} (completed by worker #{worker_id})"
  end

  def execute_task(task) do
    case checkout() do
      {:ok, worker} ->
        send(worker, {:work, self(), task})
        receive do
          {:result, ^worker, result} ->
            checkin(worker)
            {:ok, result}
        after
          5000 ->
            checkin(worker)
            {:error, :timeout}
        end
      {:error, :no_workers} ->
        {:error, :no_workers}
    end
  end
end

IO.puts("\n=== Worker Pool Examples ===")
{:ok, _pool_pid} = WorkerPool.start_link(3)

tasks = ["Compute taxes", "Generate report", "Send emails", "Backup data"]
results = Enum.map(tasks, &WorkerPool.execute_task/1)

Enum.each(results, fn result ->
  case result do
    {:ok, message} -> IO.puts("✓ #{message}")
    {:error, reason} -> IO.puts("✗ Failed: #{reason}")
  end
end)

:timer.sleep(2000)

IO.puts("\n=== All Concurrency and OTP Examples Complete! ===")

💻 Elixir Phoenix Web-Entwicklung elixir

🟡 intermediate ⭐⭐⭐⭐

Web-Anwendungen mit Phoenix-Framework, Ecto und LiveView erstellen

⏱️ 40 min 🏷️ elixir, phoenix, web dev, full stack, real-time
Prerequisites: Elixir basics, Web development concepts, Understanding of MVC architecture
# Elixir Phoenix Web Development Examples

# Note: These examples demonstrate Phoenix patterns but can be run standalone
# In a real Phoenix application, these would be organized in different files

# 1. Phoenix Controller Patterns
defmodule WebAppWeb.PageController do
  use WebAppWeb, :controller

  def index(conn, _params) do
    render(conn, "index.html",
      message: "Welcome to Phoenix!",
      current_time: DateTime.utc_now(),
      features: [
        "LiveView for real-time UI",
        "Ecto for database operations",
        "Channels for WebSocket communication",
        "Plug pipeline for request handling"
      ]
    )
  end

  def about(conn, %{"team" => team_name}) do
    team_info = get_team_info(team_name)
    render(conn, "about.html", team: team_info)
  end

  def create_user(conn, %{"user" => user_params}) do
    case Accounts.create_user(user_params) do
      {:ok, user} ->
        conn
        |> put_flash(:info, "User created successfully.")
        |> redirect(to: Routes.user_path(conn, :show, user))

      {:error, %Ecto.Changeset{} = changeset} ->
        render(conn, "new.html", changeset: changeset)
    end
  end

  # API endpoint
  def api_stats(conn, _params) do
    stats = %{
      users_count: Accounts.count_users(),
      posts_count: Blog.count_posts(),
      server_uptime: get_server_uptime(),
      version: Application.spec(:web_app, :vsn)
    }

    json(conn, %{status: "success", data: stats})
  end

  # Streaming response
  def stream_data(conn, _params) do
    conn
    |> put_resp_content_type("text/plain")
    |> send_chunked(200)
    |> stream_lines()
  end

  defp stream_lines(conn) do
    Enum.each(1..10, fn i ->
      :timer.sleep(200)
      chunk(conn, "Line #{i}\n")
    end)
    conn
  end

  defp get_team_info("elixir") do
    %{
      name: "Elixir Team",
      members: ["José Valim", "Chris McCord", "Gary Bernhardt"],
      founded: 2011,
      language: "Elixir"
    }
  end

  defp get_team_info("phoenix") do
    %{
      name: "Phoenix Team",
      members: ["Chris McCord", "José Valim", "Eric Meadows-Jönsson"],
      founded: 2014,
      language: "Elixir"
    }
  end

  defp get_team_info(_) do
    %{name: "Unknown Team", error: "Team not found"}
  end

  defp get_server_uptime do
    {uptime_msec, _} = :erlang.statistics(:wall_clock)
    uptime_msec / 1000
  end
end

# 2. Ecto Schema and Models
defmodule WebApp.Accounts.User do
  use Ecto.Schema
  import Ecto.Changeset

  schema "users" do
    field :name, :string
    field :email, :string
    field :age, :integer
    field :bio, :string
    field :encrypted_password, :string
    field :is_active, :boolean, default: true
    field :role, :string, default: "user"

    has_many :posts, WebApp.Blog.Post
    has_many :comments, WebApp.Blog.Comment

    timestamps()
  end

  def changeset(user, attrs) do
    user
    |> cast(attrs, [:name, :email, :age, :bio, :role, :is_active])
    |> validate_required([:name, :email])
    |> validate_format(:email, ~r/@/)
    |> validate_length(:name, min: 2, max: 100)
    |> validate_inclusion(:role, ["user", "admin", "moderator"])
    |> validate_number(:age, greater_than: 0, less_than: 150)
    |> unique_constraint(:email)
  end

  def registration_changeset(user, attrs) do
    user
    |> changeset(attrs)
    |> cast(attrs, [:password])
    |> validate_required(:password)
    |> validate_length(:password, min: 8)
    |> put_password_hash()
  end

  defp put_password_hash(%Ecto.Changeset{valid?: true, changes: %{password: password}} = changeset) do
    change(changeset, Argon2.add_hash(password))
  end

  defp put_password_hash(changeset), do: changeset
end

defmodule WebApp.Blog.Post do
  use Ecto.Schema
  import Ecto.Changeset

  schema "posts" do
    field :title, :string
    field :content, :text
    field :published, :boolean, default: false
    field :published_at, :utc_datetime
    field :tags, {:array, :string}
    field :view_count, :integer, default: 0

    belongs_to :user, WebApp.Accounts.User
    has_many :comments, WebApp.Blog.Comment
    has_many :likes, WebApp.Social.Like

    timestamps()
  end

  def changeset(post, attrs) do
    post
    |> cast(attrs, [:title, :content, :published, :published_at, :tags])
    |> validate_required([:title, :content])
    |> validate_length(:title, min: 3, max: 200)
    |> validate_length(:content, min: 10)
    |> unique_constraint(:title)
    |> put_published_timestamp()
  end

  defp put_published_timestamp(%Ecto.Changeset{valid?: true} = changeset) do
    if get_field(changeset, :published) do
      put_change(changeset, :published_at, DateTime.utc_now())
    else
      changeset
    end
  end

  defp put_published_timestamp(changeset), do: changeset
end

# 3. Context Modules (Business Logic)
defmodule WebApp.Accounts do
  alias WebApp.Repo
  alias WebApp.Accounts.User

  import Ecto.Query

  def list_users(opts \\ []) do
    from(u in User)
    |> maybe_filter_by_role(opts[:role])
    |> maybe_filter_by_active(opts[:active])
    |> Repo.all()
  end

  def get_user!(id), do: Repo.get!(User, id)

  def get_user_by_email(email), do: Repo.get_by(User, email: email)

  def create_user(attrs \\ %{}) do
    %User{}
    |> User.changeset(attrs)
    |> Repo.insert()
  end

  def register_user(attrs \\ %{}) do
    %User{}
    |> User.registration_changeset(attrs)
    |> Repo.insert()
  end

  def update_user(%User{} = user, attrs) do
    user
    |> User.changeset(attrs)
    |> Repo.update()
  end

  def delete_user(%User{} = user) do
    Repo.delete(user)
  end

  def authenticate_user(email, password) do
    user = get_user_by_email(email)

    case user do
      nil ->
        Argon2.no_user_verify()
        {:error, :invalid_credentials}
      user ->
        if Argon2.verify_pass(password, user.encrypted_password) do
          {:ok, user}
        else
          {:error, :invalid_credentials}
        end
    end
  end

  def count_users do
    from(u in User, select: count(u.id))
    |> Repo.one()
  end

  def search_users(query) do
    from(u in User,
      where: ilike(u.name, ^"%#{query}%") or ilike(u.email, ^"%#{query}%")
    )
    |> Repo.all()
  end

  defp maybe_filter_by_role(query, nil), do: query
  defp maybe_filter_by_role(query, role), do: where(query, [u], u.role == ^role)

  defp maybe_filter_by_active(query, nil), do: query
  defp maybe_filter_by_active(query, active), do: where(query, [u], u.is_active == ^active)
end

defmodule WebApp.Blog do
  alias WebApp.Repo
  alias WebApp.Blog.{Post, Comment}

  import Ecto.Query

  def list_published_posts do
    from(p in Post,
      where: p.published == true,
      order_by: [desc: p.published_at],
      preload: [:user, :comments]
    )
    |> Repo.all()
  end

  def list_posts_by_user(user_id) do
    from(p in Post,
      where: p.user_id == ^user_id,
      order_by: [desc: p.inserted_at]
    )
    |> Repo.all()
  end

  def get_post!(id), do: Repo.get!(Post, id) |> Repo.preload([:user, :comments])

  def get_post_with_comments!(id) do
    from(p in Post,
      where: p.id == ^id,
      preload: [:user, comments: :user]
    )
    |> Repo.one!()
  end

  def create_post(%User{} = user, attrs \\ %{}) do
    %Post{}
    |> Post.changeset(attrs)
    |> Ecto.Changeset.put_assoc(:user, user)
    |> Repo.insert()
  end

  def update_post(%Post{} = post, attrs) do
    post
    |> Post.changeset(attrs)
    |> Repo.update()
  end

  def publish_post(%Post{} = post) do
    post
    |> Ecto.Changeset.change(%{published: true, published_at: DateTime.utc_now()})
    |> Repo.update()
  end

  def delete_post(%Post{} = post) do
    Repo.delete(post)
  end

  def increment_view_count(%Post{} = post) do
    from(p in Post, where: p.id == ^post.id)
    |> Repo.update_all(inc: [view_count: 1])
  end

  def search_posts(query) do
    from(p in Post,
      where: p.published == true and (ilike(p.title, ^"%#{query}%") or ilike(p.content, ^"%#{query}%")),
      order_by: [desc: p.published_at],
      preload: [:user]
    )
    |> Repo.all()
  end

  def get_popular_posts(limit \\ 10) do
    from(p in Post,
      where: p.published == true,
      order_by: [desc: p.view_count],
      limit: ^limit,
      preload: [:user]
    )
    |> Repo.all()
  end

  def count_posts do
    from(p in Post, select: count(p.id))
    |> Repo.one()
  end
end

# 4. Phoenix LiveView
defmodule WebAppWeb.UserLive.Index do
  use WebAppWeb, :live_view

  alias WebApp.Accounts
  alias WebApp.Accounts.User

  @impl true
  def mount(_params, _session, socket) do
    {:ok, stream(socket, :users, Accounts.list_users())}
  end

  @impl true
  def handle_params(params, _url, socket) do
    {:noreply, apply_action(socket, socket.assigns.live_action, params)}
  end

  defp apply_action(socket, :edit, %{"id" => id}) do
    socket
    |> assign(:page_title, "Edit User")
    |> assign(:user, Accounts.get_user!(id))
  end

  defp apply_action(socket, :new, _params) do
    socket
    |> assign(:page_title, "New User")
    |> assign(:user, %User{})
  end

  defp apply_action(socket, :index, _params) do
    socket
    |> assign(:page_title, "Listing Users")
    |> assign(:user, nil)
  end

  @impl true
  def handle_info({WebAppWeb.UserLive.FormComponent, {:saved, user}}, socket) do
    {:noreply, stream_insert(socket, :users, user)}
  end

  @impl true
  def handle_event("delete", %{"id" => id}, socket) do
    user = Accounts.get_user!(id)
    {:ok, _} = Accounts.delete_user(user)

    {:noreply, stream_delete(socket, :users, user)}
  end
end

defmodule WebAppWeb.UserLive.FormComponent do
  use WebAppWeb, :live_component

  alias WebApp.Accounts

  @impl true
  def render(assigns) do
    ~H"""
    <div>
      <.header>
        <%= @title %>
        <:subtitle>Manage user records in your database.</:subtitle>
      </.header>

      <.simple_form
        for={@form}
        id="user-form"
        phx-target={@myself}
        phx-change="validate"
        phx-submit="save"
      >
        <.input field={@form[:name]} type="text" label="Name" />
        <.input field={@form[:email]} type="email" label="Email" />
        <.input field={@form[:age]} type="number" label="Age" />
        <.input field={@form[:bio]} type="textarea" label="Bio" />
        <.input
          field={@form[:role]}
          type="select"
          label="Role"
          options={[{"User", "user"}, {"Admin", "admin"}, {"Moderator", "moderator"}]}
        />
        <:actions>
          <.button>Save User</.button>
        </:actions>
      </.simple_form>
    </div>
    """
  end

  @impl true
  def update(%{user: user} = assigns, socket) do
    changeset = Accounts.change_user(user)

    {:ok,
     socket
     |> assign(assigns)
     |> assign_form(changeset)}
  end

  defp assign_form(socket, %Ecto.Changeset{} = changeset) do
    assign(socket, :form, to_form(changeset))
  end

  @impl true
  def handle_event("validate", %{"user" => user_params}, socket) do
    changeset =
      socket.assigns.user
      |> Accounts.change_user(user_params)
      |> Map.put(:action, :validate)

    {:noreply, assign_form(socket, changeset)}
  end

  def handle_event("save", %{"user" => user_params}, socket) do
    save_user(socket, socket.assigns.action, user_params)
  end

  defp save_user(socket, :edit, user_params) do
    case Accounts.update_user(socket.assigns.user, user_params) do
      {:ok, user} ->
        notify_parent({:saved, user})

        {:noreply,
         socket
         |> put_flash(:info, "User updated successfully")
         |> push_patch(to: socket.assigns.patch)}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign_form(socket, changeset)}
    end
  end

  defp save_user(socket, :new, user_params) do
    case Accounts.create_user(user_params) do
      {:ok, user} ->
        notify_parent({:saved, user})

        {:noreply,
         socket
         |> put_flash(:info, "User created successfully")
         |> push_patch(to: socket.assigns.patch)}

      {:error, %Ecto.Changeset{} = changeset} ->
        {:noreply, assign_form(socket, changeset)}
    end
  end

  defp notify_parent(msg), do: send(self(), {__MODULE__, msg})
end

# 5. Phoenix Channels for Real-time Communication
defmodule WebAppWeb.Presence do
  use Phoenix.Presence,
    otp_app: :web_app,
    pubsub_server: WebApp.PubSub

  def fetch("chat:room:" <> _room_id, presences) do
    users =
      presences
      |> Enum.map(fn {user_id, %{metas: [meta]}} ->
        %{
          id: user_id,
          name: meta.name,
          online_at: meta.online_at
        }
      end)

    %{
      users: users,
      count: length(users)
    }
  end
end

defmodule WebAppWeb.ChatChannel do
  use WebAppWeb, :channel
  alias WebApp.Presence

  def join("chat:room:" <> room_id, %{"name" => name}, socket) do
    send(self(), :after_join)

    socket =
      socket
      |> assign(:room_id, room_id)
      |> assign(:name, name)
      |> assign(:user_id, socket.assigns.user_id || UUID.uuid4())

    {:ok, socket}
  end

  def handle_info(:after_join, socket) do
    {:ok, _} =
      Presence.track(socket, socket.assigns.user_id, %{
        name: socket.assigns.name,
        online_at: DateTime.utc_now()
      })

    push(socket, "presence_state", Presence.list(socket))
    {:noreply, socket}
  end

  def handle_in("new_message", %{"body" => body}, socket) do
    message = %{
      id: UUID.uuid4(),
      user_id: socket.assigns.user_id,
      name: socket.assigns.name,
      body: body,
      timestamp: DateTime.utc_now()
    }

    broadcast!(socket, "new_message", message)
    {:noreply, socket}
  end

  def handle_in("typing", _params, socket) do
    broadcast_from!(socket, "typing", %{
      user_id: socket.assigns.user_id,
      name: socket.assigns.name
    })
    {:noreply, socket}
  end
end

# 6. Plugs for Request Pipeline
defmodule WebAppWeb.Plugs.Auth do
  import Plug.Conn
  import Phoenix.Controller

  alias WebAppWeb.Router.Helpers
  alias WebApp.Accounts

  def init(opts), do: opts

  def call(conn, _opts) do
    user_id = get_session(conn, :user_id)

    cond do
      user = conn.assigns[:current_user] ->
        assign(conn, :current_user, user)

      user = user_id && Accounts.get_user(user_id) ->
        assign(conn, :current_user, user)

      true ->
        assign(conn, :current_user, nil)
    end
  end
end

defmodule WebAppWeb.Plugs.RequireAuth do
  import Phoenix.Controller
  import Plug.Conn

  alias WebAppWeb.Router.Helpers

  def init(opts), do: opts

  def call(conn, _opts) do
    if conn.assigns.current_user do
      conn
    else
      conn
      |> put_flash(:error, "You must be logged in to access this page.")
      |> redirect(to: Routes.session_path(conn, :new))
      |> halt()
    end
  end
end

# 7. LiveView Real-time Dashboard
defmodule WebAppWeb.DashboardLive do
  use WebAppWeb, :live_view

  @impl true
  def mount(_params, _session, socket) do
    if connected?(socket) do
      :timer.send_interval(1000, self(), :update_stats)
    end

    socket =
      socket
      |> assign(:user_count, get_user_count())
      |> assign(:post_count, get_post_count())
      |> assign(:active_users, get_active_users())
      |> assign(:recent_posts, get_recent_posts())
      |> assign(:system_info, get_system_info())

    {:ok, socket}
  end

  @impl true
  def handle_info(:update_stats, socket) do
    socket =
      socket
      |> assign(:user_count, get_user_count())
      |> assign(:post_count, get_post_count())
      |> assign(:active_users, get_active_users())
      |> assign(:system_info, get_system_info())

    {:noreply, socket}
  end

  @impl true
  def handle_info({:new_post, post}, socket) do
    recent_posts = [post | Enum.take(socket.assigns.recent_posts, 4)]
    {:noreply, assign(socket, :recent_posts, recent_posts)}
  end

  defp get_user_count do
    # Simulate database call
    :rand.uniform(1000)
  end

  defp get_post_count do
    # Simulate database call
    :rand.uniform(5000)
  end

  defp get_active_users do
    # Simulate getting active users from presence
    :rand.uniform(50)
  end

  defp get_recent_posts do
    # Simulate recent posts
    [
      %{title: "Elixir is awesome", author: "Alice"},
      %{title: "Phoenix LiveView guide", author: "Bob"},
      %{title: "Understanding OTP", author: "Charlie"},
      %{title: "Ecto best practices", author: "Diana"}
    ]
  end

  defp get_system_info do
    {uptime_msec, _} = :erlang.statistics(:wall_clock)
    memory_info = :erlang.memory()

    %{
      uptime: uptime_msec / 1000,
      memory_total: memory_info[:total],
      memory_processes: memory_info[:processes],
      process_count: length(:erlang.processes())
    }
  end
end

IO.puts("\n=== Phoenix Web Development Examples ===")
IO.puts("These examples demonstrate:")
IO.puts("- Phoenix controller patterns")
IO.puts("- Ecto schemas and contexts")
IO.puts("- LiveView components")
IO.puts("- Real-time channels")
IO.puts("- Authentication plugs")
IO.puts("- Dashboard with real-time updates")
IO.puts("\nIn a real Phoenix application, these would be:")
IO.puts("- Organized in separate files")
IO.puts("- Connected to actual databases")
IO.puts("- Served through the Phoenix web server")
IO.puts("\n=== Examples Complete! ===")