PageRenderTime 42ms CodeModel.GetById 16ms RepoModel.GetById 0ms app.codeStats 0ms

/repl-utils/src/ritz/repl_utils/namespaces.clj

http://github.com/pallet/ritz
Clojure | 158 lines | 131 code | 20 blank | 7 comment | 10 complexity | bc5ab99896a486e0bf6a421f8f7ad037 MD5 | raw file
  1. (ns ritz.repl-utils.namespaces
  2. "Namespace functions"
  3. (:use
  4. [clojure.set :only [difference union]])
  5. (:require
  6. ritz.repl-utils.core.defonce))
  7. ;;; Functions to flag and clear marked vars. Used to remove dead vars on
  8. ;;; load-file operations.
  9. (defn mark-vars-with-meta
  10. [ns]
  11. (when (find-ns ns)
  12. (doseq [[_ v] (ns-interns ns)
  13. :let [m (meta v)]
  14. :when (not (:defonce m))]
  15. (alter-meta! v assoc ::marked true))))
  16. (defn clear-marked-vars
  17. [ns]
  18. (doseq [[_ v] (ns-interns ns)
  19. :let [m (meta v)]
  20. :when (::marked m)]
  21. (ns-unmap (ns-name (:ns m)) (:name m))))
  22. (defmacro with-var-clearing
  23. "Marks all vars in a namespace, executes the body, then removes all vars that
  24. still have metadata."
  25. {:indent 1}
  26. [ns & body]
  27. `(let [ns# ~ns]
  28. (mark-vars-with-meta ns#)
  29. ~@body
  30. (clear-marked-vars ns#)))
  31. ;;; Namespace Dependencies
  32. (defn package-dependencies
  33. "Returns the packages on which the namespace depends."
  34. [ns]
  35. (->>
  36. (ns-imports ns)
  37. vals
  38. (map
  39. ;; can throw if mixed pre/post 1.2.1 types are on the classpath due to
  40. ;; changes in defrecord and deftype mangling
  41. #(try (symbol (.getName (.getPackage ^Class %))) (catch Exception _)))
  42. distinct
  43. (filter identity)))
  44. (defn refered-dependencies
  45. "Calculate the namespaces that are refered for a given namespace."
  46. [ns]
  47. (distinct (map (comp ns-name :ns meta val) (ns-refers ns))))
  48. (defn aliased-dependencies
  49. "Calculate the namespaces that are aliased for a given namespace."
  50. [ns]
  51. (->> (ns-aliases ns) vals (map ns-name) distinct))
  52. (defn namespace-dependencies
  53. "Calculate the namespaces that the given namespace depends on."
  54. [ns]
  55. (distinct
  56. (concat
  57. (refered-dependencies ns)
  58. (aliased-dependencies ns)
  59. (filter (set (map ns-name (all-ns))) (package-dependencies ns)))))
  60. (defn direct-dependencies
  61. "Calculate namespace dependencies based on namespace information.
  62. This reduces a map, from namespace symbol, to a set of symbols for the direct
  63. namespace dependencies of that namespace."
  64. []
  65. (reduce
  66. (fn [dependencies ns]
  67. (assoc dependencies (ns-name ns) (set (namespace-dependencies ns))))
  68. {}
  69. (all-ns)))
  70. (defn dependency-comparator
  71. "A comparator for dependencies in a dependency map"
  72. [dependency-map]
  73. (fn comparator [[ns-a deps-a] [ns-b deps-b]]
  74. (cond
  75. (when deps-a (deps-a ns-b)) 1
  76. (when deps-b (deps-b ns-a)) -1
  77. :else 0)))
  78. (defn sorted-dependencies
  79. "Sort a dependency map so that all namespaces appear after the namespaces that
  80. they depend on."
  81. [dependency-map]
  82. (sort-by identity (dependency-comparator dependency-map) dependency-map))
  83. (defn transitive-dependencies
  84. "Given a direct dependencies, returns transitive dependencies"
  85. [direct-dependencies]
  86. (letfn [(dependencies [deps namespaces]
  87. (reduce
  88. (fn [all-deps ns]
  89. (union all-deps (deps ns)))
  90. #{}
  91. namespaces))]
  92. (reduce
  93. (fn [deps [ns direct-deps]]
  94. (assoc deps ns (union direct-deps (dependencies deps direct-deps))))
  95. {}
  96. (sorted-dependencies direct-dependencies))))
  97. (defn dependent-on
  98. "Return the namespaces that are dependent on the given namespace symbol."
  99. [ns]
  100. (->>
  101. (transitive-dependencies (direct-dependencies))
  102. (filter #((val %) ns))
  103. (map key)))
  104. (defn dependencies
  105. "Return the namespaces the given namespace has as dependencies."
  106. [ns]
  107. (->
  108. (transitive-dependencies (direct-dependencies))
  109. (get ns)))
  110. ;;; # Namespace modifications
  111. (defn unuse
  112. "Remove all symbols from `from-ns` that have been refered from `ns`"
  113. ([ns from-ns]
  114. (doseq [[sym v] (ns-refers (ns-name from-ns))
  115. :let [m (meta v)]
  116. :when (and m (:ns m) (= ns (ns-name (:ns m))))]
  117. (ns-unmap from-ns sym)))
  118. ([ns] (unuse ns *ns*)))
  119. (defn ns-remove
  120. "Remove the specified namespace, ensuring removal from core too"
  121. [ns]
  122. (remove-ns ns)
  123. (dosync
  124. (commute @#'clojure.core/*loaded-libs* disj ns)))
  125. ;;; # All namespace tracking and reset
  126. (defn namespace-state
  127. "Returns namespace symbols for all loaded namespaces"
  128. []
  129. (map ns-name (all-ns)))
  130. (defn namespaces-since
  131. "Return the namespaces since the given namespace state"
  132. [state]
  133. (difference (set (namespace-state)) (set state)))
  134. (defn namespaces-reset
  135. "Reset the set of loaded namespaces to the given state."
  136. [state]
  137. (doseq [ns (namespaces-since state)]
  138. (ns-remove ns)))