diff --git a/lib/mix/tasks/simple_blog/new.ex b/lib/mix/tasks/simple_blog/new.ex new file mode 100644 index 0000000..77d320b --- /dev/null +++ b/lib/mix/tasks/simple_blog/new.ex @@ -0,0 +1,42 @@ +defmodule Mix.Tasks.SimpleBlog.New do + use Mix.Task + + @moduledoc """ + Module responsible for generate the skeleton of a new blog. + """ + + @doc """ + It generates a new project skeleton + + ## Examples + + iex> Mix.Tasks.SimpleBlog.New.run([]) + :ok + """ + @impl Mix.Task + def run([]), do: Mix.shell().info(usage()) + + def run([path]) do + source = Path.expand("static") + + destination = + Path.expand(path) + |> Path.join(["blog"]) + + case File.cp_r(source, destination) do + {:ok, _} -> + Mix.shell().info("Blog created with success!") + + {:error, _} -> + Mix.shell().error("Error while create the blog in the path: #{path}") + end + end + + def usage() do + """ + To generate a new blog you should pass a valid path: + + $ mix simple_blog.new . + """ + end +end diff --git a/lib/mix/tasks/simple_blog/post/new.ex b/lib/mix/tasks/simple_blog/post/new.ex new file mode 100644 index 0000000..5ab83e4 --- /dev/null +++ b/lib/mix/tasks/simple_blog/post/new.ex @@ -0,0 +1,47 @@ +defmodule Mix.Tasks.SimpleBlog.Post.New do + use Mix.Task + + @moduledoc """ + Module responsible for generate a new blog post. + """ + + @doc """ + It generates a new blog post + + ## Examples + + # iex> Mix.Tasks.SimpleBlog.Post.New.run(["My first blog post"]) + # :ok + """ + @impl Mix.Task + def run([]), do: Mix.shell().info(usage()) + + def run([title]) do + today = + Date.utc_today() + |> Date.to_string() + + filename = SimpleBlog.Post.generate_filename(%SimpleBlog.Post{title: title, date: today}) + + case File.open(filename, [:write]) do + {:ok, file} -> + IO.binwrite(file, "## " <> title) + File.close(file) + + {:error, :enoent} -> + Mix.shell().info(""" + There is a directory missing, please run the following command: + + $ mix simple_blog.new . + """) + end + end + + def usage() do + """ + To generate a new blog post you should pass a title as string: + + $ mix simple_blog.post.new "My first blog post" + """ + end +end diff --git a/lib/simple_blog/post.ex b/lib/simple_blog/post.ex new file mode 100644 index 0000000..28747b4 --- /dev/null +++ b/lib/simple_blog/post.ex @@ -0,0 +1,27 @@ +defmodule SimpleBlog.Post do + @moduledoc """ + Module responsible for Post + """ + + @extension "md" + + defstruct title: "", tags: [], body: "", date: "" + + @doc """ + Generate filename for blog post + + ## Examples + + iex> SimpleBlog.Post.generate_filename(%SimpleBlog.Post{ title: "My first blog post", date: ~D[2023-10-04] }) + "blog/_posts/2023-10-04-my-first-blog-post.md" + """ + def generate_filename(%SimpleBlog.Post{title: title, date: date}) do + normalized_title = + title + |> String.downcase() + |> String.replace(" ", "-", global: true) + + filename = "#{date}-#{normalized_title}.#{@extension}" + "blog/_posts/#{filename}" + end +end diff --git a/static/_posts/.gitkeep b/static/_posts/.gitkeep new file mode 100644 index 0000000..e69de29 diff --git a/static/index.html b/static/index.html new file mode 100644 index 0000000..7f2ad66 --- /dev/null +++ b/static/index.html @@ -0,0 +1,5 @@ + + + + + diff --git a/test/mix/tasks/simple_blog/new_test.exs b/test/mix/tasks/simple_blog/new_test.exs new file mode 100644 index 0000000..ed4ceff --- /dev/null +++ b/test/mix/tasks/simple_blog/new_test.exs @@ -0,0 +1,41 @@ +defmodule Mix.Tasks.SimpleBlog.NewTest do + use ExUnit.Case + import ExUnit.CaptureIO + doctest Mix.Tasks.SimpleBlog.New + + @instructions """ + To generate a new blog you should pass a valid path: + + $ mix simple_blog.new . + """ + + describe "run" do + setup do + on_exit(fn -> File.rm_rf("blog") end) + end + + test "returns instructions for no arguments" do + message = capture_io(fn -> Mix.Tasks.SimpleBlog.New.run([]) end) + + assert message == "#{@instructions}\n" + end + + test "show success message for created structure" do + message = capture_io(fn -> Mix.Tasks.SimpleBlog.New.run(["."]) end) + + assert message == "Blog created with success!\n" + end + + test "create folder structure for blog" do + Mix.Tasks.SimpleBlog.New.run(["."]) + + assert File.exists?("blog") + end + end + + describe "usage" do + test "returns instructions" do + assert Mix.Tasks.SimpleBlog.New.usage() == @instructions + end + end +end diff --git a/test/mix/tasks/simple_blog/post/new_test.exs b/test/mix/tasks/simple_blog/post/new_test.exs new file mode 100644 index 0000000..957615e --- /dev/null +++ b/test/mix/tasks/simple_blog/post/new_test.exs @@ -0,0 +1,50 @@ +defmodule Mix.Tasks.SimpleBlog.Post.NewTest do + use ExUnit.Case + import ExUnit.CaptureIO + doctest Mix.Tasks.SimpleBlog.Post.New + + @instructions """ + To generate a new blog post you should pass a title as string: + + $ mix simple_blog.post.new "My first blog post" + """ + + @error_instructions """ + There is a directory missing, please run the following command: + + $ mix simple_blog.new . + """ + + describe "run" do + setup do + on_exit(fn -> File.rm_rf("blog") end) + end + + test "returns instructions for no arguments" do + Mix.Tasks.SimpleBlog.New.run(["."]) + message = capture_io(fn -> Mix.Tasks.SimpleBlog.Post.New.run([]) end) + + assert message == "#{@instructions}\n" + end + + test "show success message for created blog post" do + Mix.Tasks.SimpleBlog.New.run(["."]) + Mix.Tasks.SimpleBlog.Post.New.run(["My First Blog Post"]) + + today = Date.utc_today() |> Date.to_string() + + assert File.exists?("blog/_posts/#{today}-my-first-blog-post.md") + end + + test "show error message when blog does not exist" do + message = capture_io(fn -> Mix.Tasks.SimpleBlog.Post.New.run(["My First Blog Post"]) end) + assert message == "#{@error_instructions}\n" + end + end + + describe "usage" do + test "returns instructions" do + assert Mix.Tasks.SimpleBlog.Post.New.usage() == @instructions + end + end +end diff --git a/test/simple_blog/post_test.exs b/test/simple_blog/post_test.exs new file mode 100644 index 0000000..2ada434 --- /dev/null +++ b/test/simple_blog/post_test.exs @@ -0,0 +1,13 @@ +defmodule SimpleBlog.PostTest do + use ExUnit.Case + doctest SimpleBlog.Post + + describe "generate_filename" do + test "generate filename with date" do + title = "Introduction to elixir" + date = ~D[2023-10-04] + filename = SimpleBlog.Post.generate_filename(%SimpleBlog.Post{title: title, date: date}) + assert "blog/_posts/2023-10-04-introduction-to-elixir.md" == filename + end + end +end