Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Retain metadata on namespaces and function definitions #269

Closed
wilkerlucio opened this issue Feb 16, 2020 · 15 comments
Closed

Retain metadata on namespaces and function definitions #269

wilkerlucio opened this issue Feb 16, 2020 · 15 comments
Assignees

Comments

@wilkerlucio
Copy link
Contributor

wilkerlucio commented Feb 16, 2020

Is your feature request related to a problem? Please describe.
The problem is that I would like to make decisions based on the var metadata of namespaces and functions, currently, this information is not visible in the SCI environment.

Describe the solution you'd like
I like to have this information exposed in the symbol metadata present on the :namespace keys of the environment. So a code like this would work:

(let [env          (atom {})
      user-library (pr-str
                     '(do
                        (ns ^:user-ns some.new-ns)

                        (defn ^:user-fn my-custom-fn [x] (str x " augmented"))))]
  (sci/eval-string user-library {:env env :namespaces standard-lib-ns :bindings {'% {}}})
  (->> @env :namespaces keys (filter #{'some.new-ns}) first meta) ; => {:user-ns true}
  (-> @env :namespaces (get 'some.new-ns) first key meta) ; => {:user-fn true}
  )
@borkdude
Copy link
Collaborator

Namespaces currently don't keep metadata, I'll fix that.
Vars created by users however do retain metadata:

user=> (require '[sci.core :as sci])
nil
user=> (sci/eval-string "(defn ^:cool-fn foo [] :foo) (meta #'foo)")
{:ns #object[sci.impl.vars.SciNamespace 0x5f3f3d00 "user"], :name foo, :cool-fn true, :file nil, :end-column 29, :column 1, :line 1, :end-line 1, :arglists ([])}

@wilkerlucio
Copy link
Contributor Author

Thanks for the clarification, I was trying to get the meta from the symbol key, but as you mention its available on the var itself 👍

@borkdude borkdude self-assigned this Feb 16, 2020
@borkdude
Copy link
Collaborator

borkdude commented Feb 17, 2020

This now works in the namespace-meta branch:

$ lein run "(ns ^{:a 1} foo {:b 1}) (meta *ns*)"
{:line 1, :column 5, :end-line 1, :end-column 16, :a 1, :b 1}

TODO:

  • make namespace objects singletons

    lein run "(ns ^{:a 1} foo {:b 1}) (meta *ns*) (ns bar) (meta (the-ns 'foo))"
    

@wilkerlucio
Copy link
Contributor Author

wilkerlucio commented Feb 17, 2020

What's that about that map with {:b 1} after the namespace symbol, is that something supported by Clojure too?

@borkdude
Copy link
Collaborator

@wilkerlucio Yes, that's an attribute map (which is just another name for metadata).

@wilkerlucio
Copy link
Contributor Author

Cool, in this implementation, its also possible to get the meta from the :namespaces part of the SCI env?

@borkdude
Copy link
Collaborator

@wilkerlucio I don't recommend depending on the internal structure of the sci env atom. You can get the metadata like this (when this feature is done):

(def env (atom {}))
(sci/eval-string "(ns foo {:a 1})" {:env env})
(sci/eval-string "(meta (the-ns 'foo))" {:env env}) ;;=> {:a 1}

@wilkerlucio
Copy link
Contributor Author

Ok, makes sense, thanks for the clarification.

@wilkerlucio
Copy link
Contributor Author

I still want to use the :namespaces to iterate over all user defined namespaces, can I count on the :namespaces to stay consistent on the env? (as a map)

@borkdude
Copy link
Collaborator

@wilkerlucio You can get all namespaces with (all-ns) and all public vars with ns-publics:

 (sci/eval-string "(-> (all-ns) first ns-publics)")

@borkdude
Copy link
Collaborator

borkdude commented Feb 17, 2020

@wilkerlucioT his should now work in the namespace-meta branch:

$ lein run "(ns ^{:a 1} foo {:b 1}) (meta *ns*) (ns bar) (meta (the-ns 'foo))"
{:line 1, :column 5, :end-line 1, :end-column 16, :a 1, :b 1}

So I think combined with all-ns you can then fetch the metadata for all user-defined namespaces. Can you test a bit with this maybe?

@borkdude
Copy link
Collaborator

borkdude commented Feb 17, 2020

TODO

  • this should probably return the empty set:
(set/difference (sci/eval-string "(set (all-ns))") (sci/eval-string "(set (all-ns))"))

@borkdude
Copy link
Collaborator

@wilkerlucio I now fixed the above one. You can detect newly created namespaces like this now:

$ clojure -e "(require '[clojure.set :as set] '[sci.core :as sci]) (set/difference (sci/eval-string \"(ns foo) (set (all-ns))\") (sci/eval-string \"(set (all-ns))\"))"
#{#object[sci.impl.vars.SciNamespace 0x322b09da "foo"]}

@wilkerlucio
Copy link
Contributor Author

Cool, that sounds right! Thanks for iterating so quickly on this :)

borkdude added a commit that referenced this issue Feb 18, 2020
@borkdude
Copy link
Collaborator

@wilkerlucio This feature is now deploying as 0.0.13-alpha.11 on CI. Let me know if there are any issues, then I'll re-open the issue if needed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants