Elixir - Ngôn ngữ được viết bằng macros
Macro không những là một trong những viên gạch giúp bạn meta-program với Elixir, mà nó còn là công cụ giúp Elixir meta-program … chính nó nữa.
Nabo is a simple, extendable and fast blog engine written in Elixir. She is designed to be integrate-able into any component of your application like Phoenix or Plug.
To start using Nabo, add nabo
to your mix.exs
.
def deps do
[{:nabo, "~> 0.2.0"}]
end
After mix deps.get
, you can generate a repo for your posts with nabo.gen.repo
task.
mix nabo.gen.repo MyBlog.PostRepo
Nabo assumes your posts located in priv/posts
, but if they are not, feel free to change the path using root
option in your repo.
defmodule MyBlog.PostRepo do
use Nabo.Repo, root: "path/to/posts"
end
Nabo comes with nabo.gen.post
Mix task with which you can generate post.
mix nabo.gen.post say-hello
Note that Nabo post will be in this format: a JSON front-matter, an post excerpt and a post body.
{
"title": "Say Hello",
"slug": "say-hello",
"published_at": "2017-01-01T00:00:00Z"
}
---
This is the excerpt of the post in markdown.
---
This is the *body* of the post in markdown.
And that’s everything you need to set up Nabo.
Now you’ve got everything up for Nabo, we move on with Phoenix.
In your Phoenix app, let’s create a new controller for posts.
defmodule MyBlogWeb.PostController do
use MyBlogWeb, :controller
def index(conn, _params) do
posts = MyBlog.PostRepo.all()
render conn, "index.html", posts: posts
end
def show(conn, %{"id" => id}) do
case MyBlog.PostRepo.get(id) do
{:ok, posts} -> render conn, "show.html", post: post
{:error, _} -> render conn, "404.html"
end
end
end
And of course, don’t forget to add your routes to router.
scope "/", MyBlogWeb do
pipe_through :browser # Use the default browser stack
get "/", PageController, :index
resources "/posts", PostController, only: [:index, :show]
end
And also view and templates.
defmodule MyBlogWeb.PostView do
use MyBlogWeb, :view
end
# lib/my_blog_web/templates/post/index.eex
<div class="row posts--listing">
<div class="col-lg-12">
<%= for post <- @posts do %>
<div class="post">
<h1 class="post__title">
<a href="<%= post_path(@conn, :show, post.slug) %>">
<%= post.title %>
</a>
</h1>
<div class="post__intro"><%= post.excerpt %></div>
</div>
<% end %>
</div>
</div>
# lib/my_blog_web/templates/post/show.eex
<div class="row posts--single">
<div class="col-lg-12">
<div class="post">
<h1 class="post__title">
<%= @post.title %>
</h1>
<div class="post__content"><%= raw @post.body_html %></div>
</div>
</div>
</div>
Now run your application with iex -S mix phx.server
and access the website at http://localhost:4000/posts
.
For more information, you can check out the documentation or the example app.
As I mentioned, Nabo is designed to be extendable.
By default Nabo uses its own Markdown compiler, Nabo.Compilers.Markdown
powered by Earmark. To pass your customized Earmark options you can configure the compiler
option in your repo.
defmodule MyBlog.PostRepo do
use Nabo.Repo,
root: "priv/posts",
compiler: {
Nabo.Compilers.Markdown,
markdown: %Earmark.Options{code_class_prefix: "lang-"}
}
end
Or if you’re feeling hardcore and would love to write your own compiler, you are more than welcomed to. (and send a pull request maybe?)
defmodule MyAwesomeCompiler do
@behaviour Nabo.Compiler
def compile(content, options) do
post = AwesomeParser.parse(content)
compiled = Macro.escape(post)
# return a two-element tuple of post slug and compiled post
{post.slug, compiled}
end
end
Then set it up in your repo.
defmodule MyBlog.PostRepo do
use Nabo.Repo,
root: "priv/posts",
compiler: {MyAwesomeCompiler, the_options_above}
end
That’s it, enjoy Nabo-ing!
Macro không những là một trong những viên gạch giúp bạn meta-program với Elixir, mà nó còn là công cụ giúp Elixir meta-program … chính nó nữa.
Bài viết giới thiệu về IO data, Vectored I/O và tối ưu hóa hệ thống dùng Elixir bằng cách tận dụng Vectored I/O.
g