ghoetker
New to elixir, would appreciate a code review very much
I’m very new to Elixir and hoped someone might have a few moments to check over my first Elixir program. It’s a pretty direct translation of a Racket program I wrote, so I would especially value any feedback on more effective or Elixiry approaches.
The purpose of the program is to ingest a BibLaTeX file (@bibfile), which will be processed and written out to @outfile. Processing involves
- Regularizing the keywords (conveniently on lines starting "“Keywords = {”), so each keyword is separated by commas (rather than comma or semicolon) and capitalized
- Passing all of other lines unchanged
For example,
@book{Snoopy-Dark-01,
Author = {Snoopy},
Keywords = {fiction; Unfinished Books},
Booktitle = {It was a Dark and Stormy Night}}
should end up as
@book{Snoopy-Dark-01,
Author = {Snoopy},
Keywords = {Fiction, Unfinished books},
Booktitle = {It was a Dark and Stormy Night}}
Pretty basic, but a good learning experience.
Thank you very much in advance. I’m really enjoying both the Elixir language and community.
defmodule BibCleaner do
@bibfile "/Users/ghoetker/BibDeskPapers/masterbibliography.bib"
@outfile "test_out.bib"
@moduledoc """
Clean BibLaTeX files
"""
def clean do
{:ok, data} = File.read(@bibfile)
{:ok, file} = File.open(@outfile, [:write, :utf8])
data
|> String.split("\n")
|> Enum.map(&process(&1))
|> Enum.map(&IO.puts(file, &1))
File.close(file)
end
defp process(astring) do
cond do
String.contains?(astring, "\tKeywords = {") ->
astring
|> String.replace_leading("\tKeywords = {", "")
|> String.replace_trailing("},", "")
|> String.split([", ", "; "])
|> Enum.map(&String.capitalize/1)
|> Enum.join(", ")
|> (fn x -> "\tKeywords = {" <> "#{x}" <> "}," end).()
true ->
"#{astring}"
end
end
end
Most Liked
wmnnd
Instead of using cond, you could do this which seems a bit more Elixir-y to me:
defp process(astring) do
if String.contains?(astring, "\tKeywords = {"),
do: do_process(astring),
else: astring
end
defp do_process(astring)
astring
|> String.replace_leading("\tKeywords = {", "")
|> String.replace_trailing("},", "")
|> String.split([", ", "; "])
|> Enum.map(&String.capitalize/1)
|> Enum.join(", ")
|> (fn x -> "\tKeywords = {" <> "#{x}" <> "}," end).()
end
Was there any particular reason you were using "#{astring}"? It seems like this just creates a string that is identical to the previous string …
cdegroot
From a quick glance, lgtm. Having said that - and this has nothing to do with Elixir - if this is more than a one-off, I would parse that thing into some data structure, operate on the data structure, and then write it out to a string again. May be me, but I prefer to have the ugly string scanning stuff and the stuff I’m actually trying to accomplish separate ![]()
ghoetker
Thank you all very, very much.
Replacing cond makes a lot of sense. Not sure why I’d gone to "#{astring}", but just astring works just fine.
I agree that parsing into a data structure would make sense if I were doing anything more complex. Bib(La)TeX is infamous for being difficult to parse (in its defense, we’ve learned a lot in the 33 years since it was invented), so I’ve avoided that pain point for this simple task.
Very helpful and much appreciated. Thank you again.
Popular in Questions
Other popular topics
Categories:
Sub Categories:
Forums
Popular Tags
- #ecto
- #liveview
- #troubleshooting
- #learning-elixir
- #deployment
- #library
- #erlang
- #testing
- #genserver
- #mix
- #absinthe
- #remote-other
- #otp
- #plug
- #how-to-question
- #macros
- #postgres
- #channels
- #elixirconf
- #exunit
- #discussion
- #code-sync
- #javascript
- #podcasts
- #onsite
- #dialyzer
- #docker
- #authentication
- #umbrella
- #full-time-contract
- #podcasts-by-brainlid
- #ecto-query
- #elixir-ls
- #phoenix_html
- #iex
- #blog-post
- #graphql
- #genstage
- #ai
- #websockets
- #supervisor
- #elixirconf-us
- #advent-of-code
- #distillery
- #processes
- #forms
- #api
- #metaprogramming
- #security
- #hex









