Skip to content

Commit 0b9d5de

Browse files
committed
[Fix #310,#311] clojure-expected-ns with src/cljc
When the source path is src/{clj,cljc,cljs} instead of just src/ clojure-expected ns would create namespaces like clj.my-project.my-ns whereas what's wanted is my-project.my-ns. Reading boot.clj or project.clj to find out the user's src dirs is out of scope for clojure-mode, so we use the simply heuristic that no namespace should start with clj, cljc or cljs because these are the idiomatic source directories in multi-source projects. When improving clojure-expected-ns I extracted out two utilities, clojure-project-dir and clojure-project-relative-path. These utilities already exist in clj-refactor so I opted to make them public rather than private, as they are generally useful.
1 parent ba273c5 commit 0b9d5de

File tree

2 files changed

+78
-12
lines changed

2 files changed

+78
-12
lines changed

clojure-mode.el

+25-12
Original file line numberDiff line numberDiff line change
@@ -979,18 +979,31 @@ nil."
979979

980980

981981

982-
(defun clojure-expected-ns ()
983-
"Return the namespace name that the file should have."
984-
(let* ((project-dir (file-truename
985-
(or (locate-dominating-file default-directory
986-
"project.clj")
987-
(locate-dominating-file default-directory
988-
"build.boot"))))
989-
(relative (substring (file-truename (buffer-file-name))
990-
(length project-dir)
991-
(- (length (file-name-extension (buffer-file-name) t))))))
992-
(replace-regexp-in-string
993-
"_" "-" (mapconcat 'identity (cdr (split-string relative "/")) "."))))
982+
(defun clojure-project-dir ()
983+
"Return the absolute path to the project's root directory."
984+
(file-truename
985+
(or (locate-dominating-file default-directory
986+
"project.clj")
987+
(locate-dominating-file default-directory
988+
"build.boot"))))
989+
990+
(defun clojure-project-relative-path (path)
991+
"Denormalize PATH by making it relative to the project root."
992+
(file-relative-name path (clojure-project-dir)))
993+
994+
(defun clojure-expected-ns (&optional path)
995+
"Return the namespace matching PATH.
996+
997+
PATH is expected to be an absolute file path.
998+
999+
If PATH is nil, use the path to the file backing the current buffer."
1000+
(let* ((relative (clojure-project-relative-path
1001+
(or path (file-truename (buffer-file-name)))))
1002+
(sans-file-type (substring relative 0 (- (length (file-name-extension path t)))))
1003+
(sans-file-sep (mapconcat 'identity (cdr (split-string sans-file-type "/")) "."))
1004+
(sans-underscores (replace-regexp-in-string "_" "-" sans-file-sep)))
1005+
;; Drop prefix from ns for projects with structure src/{clj,cljs,cljc}
1006+
(replace-regexp-in-string "\\`clj[scx]?." "" sans-underscores)))
9941007

9951008
(defun clojure-insert-ns-form-at-point ()
9961009
"Insert a namespace form at point."

test/clojure-mode-util-test.el

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
;;; clojure-mode-util-test.el --- Clojure Mode: util test suite -*- lexical-binding: t; -*-
2+
3+
;; Copyright (C) 2014-2015 Bozhidar Batsov <bozhidar@batsov.com>
4+
5+
;; This file is not part of GNU Emacs.
6+
7+
;; This program is free software; you can redistribute it and/or modify
8+
;; it under the terms of the GNU General Public License as published by
9+
;; the Free Software Foundation, either version 3 of the License, or
10+
;; (at your option) any later version.
11+
12+
;; This program is distributed in the hope that it will be useful,
13+
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
14+
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15+
;; GNU General Public License for more details.
16+
17+
;; You should have received a copy of the GNU General Public License
18+
;; along with this program. If not, see <http://www.gnu.org/licenses/>.
19+
20+
;;; Commentary:
21+
22+
;; The unit test suite of Clojure Mode
23+
24+
;;; Code:
25+
(require 'clojure-mode)
26+
(require 'cl-lib)
27+
(require 'ert)
28+
29+
(let ((project-dir "/home/user/projects/my-project/")
30+
(clj-file-path "/home/user/projects/my-project/src/clj/my_project/my_ns/my_file.clj")
31+
(project-relative-clj-file-path "src/clj/my_project/my_ns/my_file.clj")
32+
(clj-file-ns "my-project.my-ns.my-file"))
33+
34+
(ert-deftest project-relative-path ()
35+
:tags '(utils)
36+
(cl-letf (((symbol-function 'clojure-project-dir) (lambda () project-dir)))
37+
(should (string= (clojure-project-relative-path clj-file-path)
38+
project-relative-clj-file-path))))
39+
40+
(ert-deftest expected-ns ()
41+
:tags '(utils)
42+
(cl-letf (((symbol-function 'clojure-project-relative-path)
43+
(lambda (&optional current-buffer-file-name)
44+
project-relative-clj-file-path)))
45+
(should (string= (clojure-expected-ns clj-file-path) clj-file-ns)))))
46+
47+
(provide 'clojure-mode-util-test)
48+
49+
;; Local Variables:
50+
;; indent-tabs-mode: nil
51+
;; End:
52+
53+
;;; clojure-mode-util-test.el ends here

0 commit comments

Comments
 (0)