Skip to content

Commit

Permalink
[Fix clojure-emacs#310,clojure-emacs#311] clojure-expected-ns with sr…
Browse files Browse the repository at this point in the history
…c/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.
  • Loading branch information
expez committed Jul 29, 2015
1 parent ba273c5 commit 0b9d5de
Show file tree
Hide file tree
Showing 2 changed files with 78 additions and 12 deletions.
37 changes: 25 additions & 12 deletions clojure-mode.el
Original file line number Diff line number Diff line change
Expand Up @@ -979,18 +979,31 @@ nil."



(defun clojure-expected-ns ()
"Return the namespace name that the file should have."
(let* ((project-dir (file-truename
(or (locate-dominating-file default-directory
"project.clj")
(locate-dominating-file default-directory
"build.boot"))))
(relative (substring (file-truename (buffer-file-name))
(length project-dir)
(- (length (file-name-extension (buffer-file-name) t))))))
(replace-regexp-in-string
"_" "-" (mapconcat 'identity (cdr (split-string relative "/")) "."))))
(defun clojure-project-dir ()
"Return the absolute path to the project's root directory."
(file-truename
(or (locate-dominating-file default-directory
"project.clj")
(locate-dominating-file default-directory
"build.boot"))))

(defun clojure-project-relative-path (path)
"Denormalize PATH by making it relative to the project root."
(file-relative-name path (clojure-project-dir)))

(defun clojure-expected-ns (&optional path)
"Return the namespace matching PATH.
PATH is expected to be an absolute file path.
If PATH is nil, use the path to the file backing the current buffer."
(let* ((relative (clojure-project-relative-path
(or path (file-truename (buffer-file-name)))))
(sans-file-type (substring relative 0 (- (length (file-name-extension path t)))))
(sans-file-sep (mapconcat 'identity (cdr (split-string sans-file-type "/")) "."))
(sans-underscores (replace-regexp-in-string "_" "-" sans-file-sep)))
;; Drop prefix from ns for projects with structure src/{clj,cljs,cljc}
(replace-regexp-in-string "\\`clj[scx]?." "" sans-underscores)))

(defun clojure-insert-ns-form-at-point ()
"Insert a namespace form at point."
Expand Down
53 changes: 53 additions & 0 deletions test/clojure-mode-util-test.el
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
;;; clojure-mode-util-test.el --- Clojure Mode: util test suite -*- lexical-binding: t; -*-

;; Copyright (C) 2014-2015 Bozhidar Batsov <bozhidar@batsov.com>

;; This file is not part of GNU Emacs.

;; This program is free software; you can redistribute it and/or modify
;; it under the terms of the GNU General Public License as published by
;; the Free Software Foundation, either version 3 of the License, or
;; (at your option) any later version.

;; This program is distributed in the hope that it will be useful,
;; but WITHOUT ANY WARRANTY; without even the implied warranty of
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
;; GNU General Public License for more details.

;; You should have received a copy of the GNU General Public License
;; along with this program. If not, see <http://www.gnu.org/licenses/>.

;;; Commentary:

;; The unit test suite of Clojure Mode

;;; Code:
(require 'clojure-mode)
(require 'cl-lib)
(require 'ert)

(let ((project-dir "/home/user/projects/my-project/")
(clj-file-path "/home/user/projects/my-project/src/clj/my_project/my_ns/my_file.clj")
(project-relative-clj-file-path "src/clj/my_project/my_ns/my_file.clj")
(clj-file-ns "my-project.my-ns.my-file"))

(ert-deftest project-relative-path ()
:tags '(utils)
(cl-letf (((symbol-function 'clojure-project-dir) (lambda () project-dir)))
(should (string= (clojure-project-relative-path clj-file-path)
project-relative-clj-file-path))))

(ert-deftest expected-ns ()
:tags '(utils)
(cl-letf (((symbol-function 'clojure-project-relative-path)
(lambda (&optional current-buffer-file-name)
project-relative-clj-file-path)))
(should (string= (clojure-expected-ns clj-file-path) clj-file-ns)))))

(provide 'clojure-mode-util-test)

;; Local Variables:
;; indent-tabs-mode: nil
;; End:

;;; clojure-mode-util-test.el ends here

0 comments on commit 0b9d5de

Please sign in to comment.