alecStewart1

alecStewart1

Hello there!

So I’ve been wanting to jump in Phoenix and I thought I’d try making it more difficult for myself with introducing Earmark into the equation.

I would say setting up like a blog, however I would find the CRUD way of doing things to be somewhat silly for me because…well it’s only me creating posts with Markdown.

I do have a few questions:

  1. Should I bother with Ecto?

    I’m more wondering what the best way to store everything. I think I should store both the Markdown itself and the generated HTML, in separate tables with a shared key like ID or something. Though I’m not the most experience with databases.

  2. Potentially extending Earmark?

    The two things I’d like to do is:

    1. Have frontmatter in Markdown for posts

    2. Components of sorts

      Mainly just for use with things like code blocks and such.

    Though maybe, for now, it would just be worth..somehow using remark? Though that sounds like it be a bit more of a headache.

  3. ElixirLS to ignore certain folders.

    I like that ElixirLS exists, however I wish I could tell it to not look in every directory in my project, slowing itself down and Emacs. Is it possible to have ElixirLS ignore some folders, or is that yet to be added in it’s functionality? Potentially specifying a .gitignore?

Thank you for any answers you give!

Showing Posts 1 to 10

kokolegorille

kokolegorille

Hello and welcome,

This post might give You some idea…

alecStewart1

alecStewart1 OP

Oh I like that so far!

Thank you!

I feel like

defp parse_attr(:title, value),
  do: String.trim(value)

defp parse_attr(:author, value),
  do: String.trim(value)

defp parse_attr(:description, value),
  do: String.trim(value)

defp parse_attr(:body, value),
  do: value

defp parse_attr(:tags, value),
  do: value |> String.split(",") |> Enum.map(&String.trim/1) |> Enum.sort()

Could maybe be abstracted better in some way, though. As opposed to this…mutlimethod(?) of sorts. Maybe.

kokolegorille

kokolegorille

Ouch, this is typical Elixir code… and it’s hard to be more descriptive than this.

Maybe later You’ll enjoy this kind of code, when You’ll start to like pattern matching in function header :slight_smile:

alecStewart1

alecStewart1 OP

Is there not some kind of metaprogramming facility that allows to us to abstract this away? Or simply pattern matching with case or with?

Like…oh

case a do  # we'd have to test if `a' is of type atom, maybe with a guard
  :tags -> value |> String.split(",") |> Enum.map(&String.trim/1) |> Enum.sort()
  _ -> String.trim(value)
  :error -> "Oops!"
end

Or something?

kokolegorille

kokolegorille

Using abstraction and multi methods suggests You are still thinking in OOP, but in FP You don’t have methods, just Module, Function and Arguments…

Of course You can simplify this, but using metaprogramming add complexity, or use a case.

defp parse_attr(type, value) do
  case type do
    type when type in ~w(title author description)a ->
      String.trim(value)
    etc
  end
end

But most will try to avoid this case, and use multiple header function.

In the end, it’s only one function :slight_smile:

alecStewart1

alecStewart1 OP

Oh, I kind of get it. Because there’s functions like fun/1 and fun/2. The functions defined are based on their name and arity, right?

kokolegorille

kokolegorille

Yes, if You mean Elixir will treat them as 2 distincts functions. But what You described is just one.

Compare with this code…

defp parse_attr(:title, value), do: String.trim(value)
defp parse_attr(:author, value), do: String.trim(value)
defp parse_attr(:description, value), do: String.trim(value)

It’s repetitive, but descriptive too.

srowley

srowley

You could be a little more terse with:

defp parse_attr(:body, value),
  do: value

defp parse_attr(:tags, value),
  do: value |> String.split(",") |> Enum.map(&String.trim/1) |> Enum.sort()

defp parse_attr(_, value),
  do: String.trim(value)

That does the same thing as your first example except that it will not throw an error if something other than :title, :author, :description, :body or :tags is passed as the first argument to that function. In that case it just returns String.trim(value). You could make it throw an error by using a guard (see the example below), and not defining a function clause that matches the first argument on anything.

The code below is what I think you intended to do with your second example, but there are two differences between this and that example:

  1. It returns value if the first argument is :body (the second example would return String.trim(value))
  2. It returns “Oops!” if the first argument wasn’t one of the expected ones (the second example returns String.trim(value) if the first argument is anything other than :tags).

The third clause in that case block will never match because :error would match on the second clause.

defp parse_attr(:body, value),
  do: value

defp parse_attr(:tags, value),
  do: value |> String.split(",") |> Enum.map(&String.trim/1) |> Enum.sort()

defp parse_attr(trimmed, value) when trimmed in [:title, :author, :description] do
  String.trim(value)
end

# If you leave this out, calls to this function will raise an error if the first 
# value is not one of the expected ones above.
defp parse_attr(_, value),
 do: "Oops!"

As the other poster said, this is pretty idiomatic Elixir code. I felt like it would be confusing when I started learning Elixir, but now I find it much easier to read and reason about than one or more control flow blocks.

kokolegorille

kokolegorille

You can do it with macros, but first rule is… don’t use macros.

It’s just harder to read.

iex(1)> defmodule Koko do                                                
...(1)> for type <- ~w(title author description)a do                     
...(1)>     defp parse_attr(unquote(type), value), do: String.trim(value)
...(1)> end
...(1)> end
{:module, Koko,
 <<70, 79, 82, 49, 0, 0, 4, 92, 66, 69, 65, 77, 65, 116, 85, 56, 0, 0, 0, 130,
   0, 0, 0, 13, 11, 69, 108, 105, 120, 105, 114, 46, 75, 111, 107, 111, 8, 95,
   95, 105, 110, 102, 111, 95, 95, 10, 97, ...>>,
 [parse_attr: 2, parse_attr: 2, parse_attr: 2]}
RobertDober

RobertDober

… and easy to change!

Where Next? Top

Trending in Questions Top

RSP87
I’m working on a project that simulates the bumbl example in the programming phoenix book. It acts almost like an email client. We have a...
New
nseaSeb
Hello, I know there is an approach for handling lists that allows for optimized traversal, but I can’t recall the specific method (somet...
New
RemyXRenard
I’m seeing that a list inside a Kino.DataTable will be interpreted as a charlist, even if the Kino.configure() is set to charlists: :as_l...
New
brecabral
Documentation While reading the Scoped Routes section, I noticed that the documentation currently refers to a problem without explainin...
New
velrest
So my question is quite simple and i have found no conclusive answer on forum, google or AI. Should we use :erlang.float for Integer to ...
New
samoloth
Hi, I’ve just set up an application with ash_authentication. There is only magic link strategy for now, so there is no confirmation add o...
New
FlyingNoodle
If a change or preparation module uses Ash.Changeset.get_argument/2 or Ash.Query.get_argument/2 (or any of the other get_argument functio...
New

Other Trending Topics Top

mudasobwa
I am happy to introduce the very α version of the new programming language compiled to BEAM. Welcome Cure. It has literally three kille...
New
marciok
Hi there! We created Gust: A task orchestrator inspired by Airflow. For those who have never heard about Aiflow, it’s a Python-based wor...
New
jimsynz
Beam Bots (or just BB for short) is a framework for building fault-tolerant robotics applications in Elixir using familiar OTP patterns. ...
New
Dmk
Xamal is a deployment tool for Elixir apps that deploys native releases to bare metal servers over SSH. It’s a port of GitHub - basecamp/...
New
netoum
Corex is an accessible, unstyled UI component library for Phoenix that integrates Zag.js state machines using Vanilla JavaScript and Live...
New
webofbits
With AI doing more of the implementation work, I’ve been wondering how much coding I should deliberately keep doing myself. My main conc...
#ai
New

We're in Beta

About us Mission Statement

Options

Thread Display Mode




Thread Preview

Skip Thread Previews