Reputation: 1266
I'm in the process of modifying an Emacs mode. https://github.com/bigos/git-auto-commit-mode
I am new to Emacs lisp and I can't find elegant solution to following problem.
I have this code fragment where function gac-raw-branches returns a string or nil and I can't find good solution to avoid errors where split expects a string. I use helper functions like gac-split-for-current shown in the following example. But, is there a better way to do it?
(defun gac-split-for-current-branch (raw-branches)
(split-string raw-branches "\n"))
(defun gac-current-branch (filename)
"Current git branch of FILENAME."
(let ((res)
(raw-branches (gac-raw-branches filename)))
(if raw-branches
(dolist (el
(gac-split-for-current-branch raw-branches)
res)
(if (string-match "^\\* .*" el)
(setq res (substring el 2))))
nil)))
Upvotes: 2
Views: 246
Reputation: 20342
Here's the good-looking (IMO) code:
(defun gac-current-branch (filename)
"Current git branch of FILENAME."
(let (res)
(dolist (el (ignore-errors
(split-string
(gac-raw-branches filename)
"\n" t)))
(when (string-match "^\\* +\\(.*\\)$" el)
(setq res (match-string 1 el))))
res))
I also kind of like functional style, although it's not recommended for Elisp:
(defun gac-current-branch (filename)
"Current git branch of FILENAME."
(cl-reduce
(lambda (res el)
(or (and (string-match "^\\* +\\(.*\\)$" el)
(match-string 1 el))
res))
(ignore-errors
(split-string (gac-raw-branches filename) "\n" t))))
Some points:
gac-split-for-current-branch
. It makes the code less clear.(ignore-errors (split-string x))
always returns a list, nil
at
worst. It's fine to iterate on nil
with either dolist
or
mapcar
or cl-reduce
.nil
in else clause of if
statement: it's automatic.Upvotes: 1
Reputation: 1586
If a function returns a string or nil, checking that the value is
non-nil (using if
, when
, or and
, depending on the context) is a
fine way to deal with that (at least I don't find it inelegant).
Here is one way to rewrite your function (assuming gac-raw-branches
is the output of git branch
).
(defun gac-current-branch (filename)
"Current git branch of FILENAME."
(let ((gb-output (gac-raw-branches filename)))
(when gb-output
(with-temp-buffer
(insert gb-output)
(goto-char (point-min))
(and (re-search-forward "^\\*\\s-+\\(.*\\)" nil t)
(match-string 1))))))
Note the when
in the fourth line that is used to make sure there is
a non-nil value. The and
in the eigth line serves the same purpose.
If you use dash, -if-let
and
-when-let
are nice for these situations.
(defun gac-current-branch (filename)
"Current git branch of FILENAME."
(-when-let (gb-output (gac-raw-branches filename))
(with-temp-buffer
(insert gb-output)
(goto-char (point-min))
(and (re-search-forward "^\\*\\s-+\\(.*\\)" nil t)
(match-string 1)))))
Unrelated to the question, but have you looked into using Magit for this? It has a backup mode, but even if that doesn't behave as you want, you could take advantage of its git interface.
Upvotes: 1