Ecosyste.ms: Awesome
An open API service indexing awesome lists of open source software.
https://github.com/erikmueller/jelly_shot
Elixir blog engine based on Phoenix powered by markdown
https://github.com/erikmueller/jelly_shot
agent blog elixir elixir-flow elixir-phoenix genserver markdown
Last synced: about 1 month ago
JSON representation
Elixir blog engine based on Phoenix powered by markdown
- Host: GitHub
- URL: https://github.com/erikmueller/jelly_shot
- Owner: erikmueller
- Created: 2017-02-03T19:09:55.000Z (almost 8 years ago)
- Default Branch: master
- Last Pushed: 2022-12-09T08:14:24.000Z (almost 2 years ago)
- Last Synced: 2024-04-14T16:01:43.619Z (7 months ago)
- Topics: agent, blog, elixir, elixir-flow, elixir-phoenix, genserver, markdown
- Language: Elixir
- Homepage:
- Size: 4.31 MB
- Stars: 8
- Watchers: 2
- Forks: 4
- Open Issues: 33
-
Metadata Files:
- Readme: README.md
Awesome Lists containing this project
README
---
title: Jelly Shot
separator:
verticalSeparator:
theme: black
revealOptions:
controls: false
transition: 'slide'
---![CircleCI](https://circleci.com/gh/erikmueller/jelly_shot/tree/master.svg?style=svg) ![codecov](https://codecov.io/gh/erikmueller/jelly_shot/branch/master/graph/badge.svg)
# Jelly Shot
A semi static blog engine
## starting point
Static markdown blog by
[@seilund](http://www.sebastianseilund.com/static-markdown-blog-posts-with-elixir-phoenix)### A million static site generators...
### 💁 let's write another one* Phoenix
* No database
* No static file generation* Compiling [markdown](https://github.com/pragdave/earmark) into `%Post{}`s
* Have a [GenServer](https://hexdocs.pm/elixir/GenServer.html) deliver them### Let's take this further
* Generator __`->` markdown `|>` struct__
* Repository __`->` [Agent](https://hexdocs.pm/elixir/Agent.html) storing data__
* Watcher __`->` [GenServer](https://hexdocs.pm/elixir/GenServer.html) for auto update__#### Generator
```elixir
defp compile_file(file) do
with{:ok, matter, body} <- split_frontmatter(file),
{:ok, html, _} <- Earmark.as_html(body),
do: {:ok, into_post(file, matter, html)}
end
``````elixir
defp into_post(file, meta, html) do
data = %{
slug: file_to_slug(file),
content: html,
} |> Map.merge(meta)struct(JellyShot.Post, data)
end
```#### Repository
```elixir
def start_link do
Agent.start_link(&get_initial_state/0, name: __MODULE__)
end
``````elixir
posts = File.ls!("priv/posts")
|> Enum.filter(&(Path.extname(&1) == ".md"))
|> Enum.map(&compile_async/1)
|> Enum.map(&Task.await/1)
|> Enum.reduce([], &valid_into_list/2)
|> Enum.sort(&sort/2)
```#### Watcher
```elixir
def init(state) do
path = Path.expand("priv/posts"):fs.start_link(:fs_watcher, path)
:fs.subscribe(:fs_watcher){:ok, state}
end
``````elixir
def handle_info({_pid, {:fs, :file_event}, {path, ev}}, _) do
new_state = cond do
Enum.member?(ev, :modified) ->
path
|> JellyShot.Post.file_to_slug
|> JellyShot.Repo.upsert_by_slug
end
end
```### Integrating into Phoenix 🐣🔥
#### Listing posts
```elixir
def index(conn, params) do
{tmpl, headline, {:ok, posts}} = case params do
%{"author" => author} ->
{"list", "by author", Repo.get_by_author(author)}
%{"category" => category} ->
{"list", "by category", Repo.get_by_category(category)}
_ ->
{"index", "recent posts", Repo.list()}
endrender conn, "#{tmpl}.html", head: head, posts: posts
end
```![JellySHot](./jelly_shot.png)
## Limitations
### Filling the repository...
~ 250 sloc / file
* 12 posts in 406ms 🐰
* 384 posts in 3844ms 🐢
* ... 🐌We might hit a cap at some point
### Anyway, I Learned a lot
* __Pattern matching__
* `Agents`
* `GenServer`
* `with {:ok}`# Thanks
[https://github.com/erikmueller/jelly_shot](https://github.com/erikmueller/jelly_shot)
.reveal code {font-family: hasklig, monospace}