Your Name bc14696f57 Static blog with front page summary
Goal: have a personal blog, and try out another point in the 'modular
app design with elixir' space.

Designing OTP systems with elixir had some interesting ideas.
2026-03-17 11:17:21 +00:00

101 lines
2.3 KiB
Elixir

defmodule Blogex.Test.FakeBlog do
@moduledoc """
A test double that implements the same interface as a `use Blogex.Blog`
module, but backed by an Agent so tests can control the post data.
## Usage in tests
setup do
posts = [PostBuilder.build(id: "hello"), PostBuilder.build(id: "world")]
Blogex.Test.FakeBlog.start(posts, blog_id: :engineering, title: "Eng Blog")
:ok
end
Then pass `Blogex.Test.FakeBlog` anywhere a blog module is expected.
"""
use Agent
@defaults [
blog_id: :test_blog,
title: "Test Blog",
description: "A blog for tests",
base_path: "/blog/test"
]
def start(posts \\ [], opts \\ []) do
opts = Keyword.merge(@defaults, opts)
state = %{
posts: posts,
blog_id: opts[:blog_id],
title: opts[:title],
description: opts[:description],
base_path: opts[:base_path]
}
case Agent.start(fn -> state end, name: __MODULE__) do
{:ok, pid} -> {:ok, pid}
{:error, {:already_started, pid}} ->
Agent.update(__MODULE__, fn _ -> state end)
{:ok, pid}
end
end
def stop, do: Agent.stop(__MODULE__)
defp get(key), do: Agent.get(__MODULE__, &Map.fetch!(&1, key))
def blog_id, do: get(:blog_id)
def title, do: get(:title)
def description, do: get(:description)
def base_path, do: get(:base_path)
def all_posts do
get(:posts)
|> Enum.filter(& &1.published)
|> Enum.sort_by(& &1.date, {:desc, Date})
end
def recent_posts(n \\ 5), do: Enum.take(all_posts(), n)
def all_tags do
all_posts()
|> Enum.flat_map(& &1.tags)
|> Enum.uniq()
|> Enum.sort()
end
def posts_by_tag(tag) do
Enum.filter(all_posts(), fn post -> tag in post.tags end)
end
def get_post!(id) do
Enum.find(all_posts(), &(&1.id == id)) ||
raise Blogex.NotFoundError, "post #{inspect(id)} not found"
end
def get_post(id) do
Enum.find(all_posts(), &(&1.id == id))
end
def paginate(page \\ 1, per_page \\ 10) do
posts = all_posts()
total = length(posts)
total_pages = max(ceil(total / per_page), 1)
entries =
posts
|> Enum.drop((page - 1) * per_page)
|> Enum.take(per_page)
%{
entries: entries,
page: page,
per_page: per_page,
total_entries: total,
total_pages: total_pages
}
end
end