|
4944 | 4944 | Basilisp will attempt to load a corresponding namespace starting with 'basilisp.'
|
4945 | 4945 | automatically, aliasing the imported namespace as the requested namespace name.
|
4946 | 4946 | This should allow for automatically importing Clojure's included core libraries such
|
4947 |
| - as ``clojure.string``" |
| 4947 | + as ``clojure.string``." |
4948 | 4948 | [req]
|
4949 | 4949 | (rewrite-clojure-libspec
|
4950 | 4950 | (cond
|
|
4955 | 4955 | (ex-info "Invalid libspec for require"
|
4956 | 4956 | {:value req})))))
|
4957 | 4957 |
|
| 4958 | +(def ^:private require-flags #{:reload :reload-all}) |
| 4959 | + |
| 4960 | +(defn ^:private libspecs-and-flags |
| 4961 | + "Return a vector of ``[libspecs flags]``." |
| 4962 | + [req] |
| 4963 | + (let [groups (group-by #(if (contains? require-flags %) |
| 4964 | + :flags |
| 4965 | + :libspecs) |
| 4966 | + req)] |
| 4967 | + [(:libspecs groups) (set (:flags groups))])) |
| 4968 | + |
4958 | 4969 | (defn ^:private require-lib
|
4959 |
| - "Require the library described by ``libspec`` into the Namespace ``requiring-ns``\\." |
4960 |
| - [requiring-ns libspec] |
4961 |
| - (let [required-ns-sym (:namespace libspec)] |
4962 |
| - ;; In order to enable direct linking of Vars as Python variables, required |
4963 |
| - ;; namespaces must be `require*`ed into the namespace. That's not possible |
4964 |
| - ;; to do without a macro, so we're using this hacky approach to eval the |
4965 |
| - ;; code directly (which will effectively add it to the root namespace module). |
4966 |
| - (eval (list 'require* |
4967 |
| - (if-let [ns-alias (:as libspec)] |
4968 |
| - [required-ns-sym :as ns-alias] |
4969 |
| - required-ns-sym)) |
4970 |
| - requiring-ns) |
4971 |
| - ;; Add a special alias for the original namespace (e.g. `clojure.*`), if we |
4972 |
| - ;; rewrote the namespace on require. |
4973 |
| - (when-let [original-ns (:original-namespace libspec)] |
4974 |
| - (.add-alias requiring-ns (the-ns required-ns-sym) original-ns)) |
4975 |
| - ;; If an `:as-alias` is requested, apply that as well. |
4976 |
| - (when-let [as-alias (:as-alias libspec)] |
4977 |
| - (.add-alias requiring-ns (the-ns required-ns-sym) as-alias)) |
| 4970 | + "Require the library described by ``libspec`` into the Namespace ``requiring-ns``\\ |
| 4971 | + subject to the provided ``flags``." |
| 4972 | + [requiring-ns libspec flags] |
| 4973 | + (let [required-ns-sym (:namespace libspec) |
| 4974 | + existing-ns (find-ns required-ns-sym)] |
| 4975 | + (cond |
| 4976 | + #?@(:lpy39+ |
| 4977 | + [(and existing-ns (contains? flags :reload-all)) |
| 4978 | + (.reload-all (the-ns required-ns-sym))]) |
| 4979 | + |
| 4980 | + (and existing-ns (contains? flags :reload)) |
| 4981 | + (.reload (the-ns required-ns-sym)) |
| 4982 | + |
| 4983 | + :else |
| 4984 | + (do |
| 4985 | + ;; In order to enable direct linking of Vars as Python variables, required |
| 4986 | + ;; namespaces must be `require*`ed into the namespace. That's not possible |
| 4987 | + ;; to do without a macro, so we're using this hacky approach to eval the |
| 4988 | + ;; code directly (which will effectively add it to the root namespace module). |
| 4989 | + (eval (list 'require* |
| 4990 | + (if-let [ns-alias (:as libspec)] |
| 4991 | + [required-ns-sym :as ns-alias] |
| 4992 | + required-ns-sym)) |
| 4993 | + requiring-ns) |
| 4994 | + ;; Add a special alias for the original namespace (e.g. `clojure.*`), if we |
| 4995 | + ;; rewrote the namespace on require. |
| 4996 | + (when-let [original-ns (:original-namespace libspec)] |
| 4997 | + (.add-alias requiring-ns (the-ns required-ns-sym) original-ns)) |
| 4998 | + ;; If an `:as-alias` is requested, apply that as well. |
| 4999 | + (when-let [as-alias (:as-alias libspec)] |
| 5000 | + (.add-alias requiring-ns (the-ns required-ns-sym) as-alias)))) |
4978 | 5001 | ;; Reset the namespace to the requiring namespace, since it was likely changed
|
4979 | 5002 | ;; during the require process
|
4980 | 5003 | (set! *ns* requiring-ns)))
|
|
5032 | 5055 | - ``:refer [& syms]`` which will refer syms in the local namespace directly
|
5033 | 5056 | - ``:refer :all`` which will refer all symbols from the namespace directly
|
5034 | 5057 |
|
| 5058 | + Arguments may also be flags, which are optional. Flags are keywords. The following |
| 5059 | + flags are supported: |
| 5060 | + |
| 5061 | + - ``:reload`` if provided, attempt to reload the namespace |
| 5062 | + - ``:reload-all`` if provided, attempt to reload all named namespaces and the |
| 5063 | + namespaces loaded by those namespaces as a directed graph |
| 5064 | + |
5035 | 5065 | Use of ``require`` directly is discouraged in favor of the ``:require`` directive in
|
5036 |
| - the :lpy:fn:`ns` macro." |
| 5066 | + the :lpy:fn:`ns` macro. |
| 5067 | + |
| 5068 | + .. warning:: |
| 5069 | + |
| 5070 | + Reloading namespaces has many of the same limitations described for |
| 5071 | + :external:py:func:`importlib.reload_module`. Below is a non-exhaustive set of |
| 5072 | + limitations of reloading Basilisp namespace: |
| 5073 | + |
| 5074 | + - Vars will be re-``def``'ed based on the current definition of the underlying |
| 5075 | + file. If the file has not changed, then the namespace file will be reloaded |
| 5076 | + according to the current :ref:`namespace_caching` settings. If a Var is |
| 5077 | + removed from the source file, it will not be removed or updated by a reload. |
| 5078 | + - References to objects from previous versions of modules (particularly those |
| 5079 | + external to the namespace) are not rebound by reloading. In Basilisp code, |
| 5080 | + this problem can be limited by disabling :ref:`inlining` and |
| 5081 | + :ref:`direct_linking`. |
| 5082 | + - Updates to type or record definitions will not be reflected to previously |
| 5083 | + instantiated objects of those types." |
5037 | 5084 | [& args]
|
5038 |
| - (let [current-ns *ns*] |
5039 |
| - (doseq [libspec (map require-libspec args)] |
| 5085 | + (let [current-ns *ns* |
| 5086 | + groups (libspecs-and-flags args) |
| 5087 | + libspecs (first groups) |
| 5088 | + flags (second groups)] |
| 5089 | + (doseq [libspec (map require-libspec libspecs)] |
5040 | 5090 | (if (and (:as-alias libspec) (not (:as libspec)))
|
5041 | 5091 | (let [alias-target (or (find-ns (:namespace libspec))
|
5042 | 5092 | (create-ns (:namespace libspec)))]
|
5043 | 5093 | (.add-alias current-ns alias-target (:as-alias libspec)))
|
5044 | 5094 | (do
|
5045 |
| - (require-lib current-ns libspec) |
| 5095 | + (require-lib current-ns libspec flags) |
5046 | 5096 |
|
5047 | 5097 | ;; Add refers
|
5048 | 5098 | (let [new-ns (the-ns (:namespace libspec))
|
|
5075 | 5125 | ``:require`` directive of the :lpy:fn:`ns` macro or the ``:use`` directive of the
|
5076 | 5126 | ``ns`` macro."
|
5077 | 5127 | [ns-sym & filters]
|
5078 |
| - (let [current-ns *ns*] |
| 5128 | + (let [current-ns *ns* |
| 5129 | + groups (group-by #(if (contains? require-flags %) |
| 5130 | + :flags |
| 5131 | + :filters) |
| 5132 | + filters)] |
5079 | 5133 | ;; It is necessary to first require the Namespace directly, otherwise
|
5080 | 5134 | ;; when refer attempts to load the Namespace later, it will fail.
|
5081 |
| - (->> (require-libspec ns-sym) |
5082 |
| - (require-lib current-ns)) |
5083 |
| - (->> (apply vector ns-sym filters) |
| 5135 | + (require-lib current-ns |
| 5136 | + (require-libspec ns-sym) |
| 5137 | + (set (:flags groups))) |
| 5138 | + (->> (:filters groups) |
| 5139 | + (apply vector ns-sym) |
5084 | 5140 | (require-libspec)
|
5085 | 5141 | (refer-lib current-ns))))
|
5086 | 5142 |
|
|
5113 | 5169 | Use of ``use`` directly is discouraged in favor of the ``:use`` directive in the
|
5114 | 5170 | :lpy:fn:`ns` macro."
|
5115 | 5171 | [& args]
|
5116 |
| - (let [current-ns *ns*] |
5117 |
| - (doseq [libspec (map require-libspec args)] |
| 5172 | + (let [current-ns *ns* |
| 5173 | + groups (libspecs-and-flags args) |
| 5174 | + libspecs (first groups) |
| 5175 | + flags (second groups)] |
| 5176 | + (doseq [libspec (map require-libspec libspecs)] |
5118 | 5177 | ;; Remove the :refer key to avoid having require-lib
|
5119 | 5178 | ;; perform a full :refer, instead we'll use refer-lib
|
5120 |
| - (->> (dissoc libspec :refer) |
5121 |
| - (require-lib current-ns)) |
| 5179 | + (require-lib current-ns |
| 5180 | + (dissoc libspec :refer) |
| 5181 | + flags) |
5122 | 5182 | (refer-lib current-ns libspec))
|
5123 | 5183 | nil))
|
5124 | 5184 |
|
|
0 commit comments