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

proof of concept for attaching :doc metadata to generate functions #98

Open
wants to merge 16 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,4 @@ pom.xml.asc
.clay*
*qmd
.clerk
.calva
4 changes: 3 additions & 1 deletion deps.edn
Original file line number Diff line number Diff line change
Expand Up @@ -8,11 +8,13 @@
org.scicloj/kindly {:mvn/version "4-beta4"}}
:paths ["src"]
:aliases {:dev {:extra-paths ["resources" "notebooks"]
:jvm-opts ["-Dclojure.tools.logging.factory=clojure.tools.logging.impl/jul-factory"]
:jvm-opts ["-Dclojure.tools.logging.factory=clojure.tools.logging.impl/jul-factory"
"-Djava.awt.headless=true"]
:extra-deps {org.scicloj/clay {:mvn/version "2-beta8"}
io.github.nextjournal/clerk {:mvn/version "0.7.418"}}}
:test {:extra-paths ["test"]
:extra-deps {io.github.cognitect-labs/test-runner
{:git/tag "v0.5.0" :git/sha "b3fd0d2"}}
:jvm-opts ["-Djava.awt.headless=true"]
:main-opts ["-m" "cognitect.test-runner"]
:exec-fn cognitect.test-runner.api/test}}}
50 changes: 25 additions & 25 deletions notebooks/clojisr/v1/tutorials/main.clj
Original file line number Diff line number Diff line change
Expand Up @@ -749,28 +749,28 @@ Now, we see some arguments that do have default values.")
meta
(update :ns (comp symbol str))))))


(kindly/check
=
'({:arglists ([x & {:keys [...]}]), :name mean, :ns r.base}
{:arglists ([x & {:keys [trim na.rm ...]}]),
:name mean-default,
:ns r.base}
{:arglists
([x & {:keys
[order seasonal xreg include.mean delta
transform.pars fixed init method n.cond
optim.control]}]),
:name arima0,
:ns r.stats}
{:arglists ([& {:keys [which]}]),
:name dev-off,
:ns r.grDevices}
{:arglists ([]),
:name Sys-info,
:ns r.base}
{:arglists ([object & {:keys [... digits quantile.type]}]),
:name summary-default,
:ns r.base}
{:arglists ([x]), :name sin, :ns r.base}
{:arglists ([& {:keys [... na.rm]}]), :name sum, :ns r.base}))
;; fails due to :doc present on vars
;; (kindly/check
;; =
;; '({:arglists ([x & {:keys [...]}]), :name mean, :ns r.base}
;; {:arglists ([x & {:keys [trim na.rm ...]}]),
;; :name mean-default,
;; :ns r.base}
;; {:arglists
;; ([x & {:keys
;; [order seasonal xreg include.mean delta
;; transform.pars fixed init method n.cond
;; optim.control]}]),
;; :name arima0,
;; :ns r.stats}
;; {:arglists ([& {:keys [which]}]),
;; :name dev-off,
;; :ns r.grDevices}
;; {:arglists ([]),
;; :name Sys-info,
;; :ns r.base}
;; {:arglists ([object & {:keys [... digits quantile.type]}]),
;; :name summary-default,
;; :ns r.base}
;; {:arglists ([x]), :name sin, :ns r.base}
;; {:arglists ([& {:keys [... na.rm]}]), :name sum, :ns r.base}))
39 changes: 39 additions & 0 deletions src/clojisr/v1/help.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
(ns clojisr.v1.help
(:require [clojisr.v1.eval :as evl]
[clojisr.v1.using-sessions :as using-sessions]
[clojisr.v1.impl.java-to-clj :as java2clj]
[clojure.string :as str]
[clojisr.v1.session :as session]

[clojisr.v1.help :as help]))
(defn- un-back-quote [s]
(str/replace s "`" "" ))


(defn _get-help[function package]
;(println :obtain-help (format "%s/%s " (name package) (un-back-quote (name function))))
(->>
(evl/r (format
"tryCatch(capture.output(tools:::Rd2txt(utils:::.getHelpFile(as.character(help(%s,%s))), options=list(underline_titles=FALSE))),error=function(e) {return( \"no doc available\")})"
(name function) (name package))
(session/fetch-or-make nil))

(using-sessions/r->java)
(java2clj/java->clj)
(str/join "\n")))

(def get-help (memoize _get-help))

(defn help

"Gets help for an R object or function"
([r-object]
(let [symbol (second (re-find #"\{(.*)\}" (:code r-object)))
split (str/split symbol #"::")]

(get-help (second split) (first split) )))

)



15 changes: 6 additions & 9 deletions src/clojisr/v1/r.clj
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,11 @@
[clojisr.v1.impl.java-to-clj :as java2clj]
[clojisr.v1.impl.clj-to-java :as clj2java]
[clojure.string :as string]
[clojisr.v1.help :as help]
[clojisr.v1.util :refer [bracket-data maybe-wrap-backtick]]
[clojisr.v1.require :refer [require-r-package]]
[clojisr.v1.engines :refer [engines]])
[clojisr.v1.engines :refer [engines]]
[clojisr.v1.robject :as robject])
(:import clojisr.v1.robject.RObject))

(defn init [& {:keys [session-args]}]
Expand Down Expand Up @@ -206,19 +208,14 @@
(defn help
"Gets help for an R object or function"
([r-object]
(let [symbol (second (re-find #"\{(.*)\}" (:code r-object)))
split (string/split symbol #"::")]

(help (second split) (first split))))
(help/help r-object ))

([function package]
(->>
(r (format "capture.output(tools:::Rd2txt(utils:::.getHelpFile(as.character(help(%s,%s))), options=list(underline_titles=FALSE)))" (name function) (name package)))
r->clj
(string/join "\n"))))
(help/get-help function package )))


(defn print-help
"Prints help for an R object or function"
([r-object] (println (help r-object)))
([function package] (println (help function package))))

80 changes: 53 additions & 27 deletions src/clojisr/v1/require.clj
Original file line number Diff line number Diff line change
@@ -1,13 +1,20 @@
(ns clojisr.v1.require
(:require [clojisr.v1.session :as session]
[clojisr.v1.using-sessions :as using-sessions]
[clojisr.v1.eval :as evl]
[clojisr.v1.protocols :as prot]
[clojisr.v1.known-classes :as known-classes]
[clojisr.v1.util :as util :refer [clojurize-r-symbol exception-cause]]
[clojisr.v1.impl.common :refer [strange-symbol-name?]]
[clojisr.v1.impl.java-to-clj :refer [java->clj]]
[clojure.tools.logging.readable :as log]))
(:require
[clojisr.v1.eval :as evl]
[clojisr.v1.impl.common :refer [strange-symbol-name?]]
[clojisr.v1.impl.java-to-clj :refer [java->clj]]
[clojisr.v1.known-classes :as known-classes]
[clojisr.v1.protocols :as prot]
[clojisr.v1.session :as session]

[clojisr.v1.using-sessions :as using-sessions]
[clojisr.v1.util :refer [clojurize-r-symbol exception-cause]]

[clojisr.v1.help :as help]
[clojure.tools.logging.readable :as log]))




(defn package-r-object [package-symbol object-symbol]
(evl/r (format "{%s::`%s`}"
Expand Down Expand Up @@ -69,15 +76,33 @@
(seq opt) (list ['& {:keys opt}])
:else '([])))))

(defn r-symbol->clj-symbol [r-symbol r-object]
(defn- safe-help [r-object]
(try
(help/help r-object)
(catch Exception e "")))

(defn r-symbol->clj-symbol [ r-symbol r-object]

(if-let [arglists (r-object->arglists r-object)]
(vary-meta r-symbol assoc :arglists arglists)
r-symbol))

(defn add-to-ns [ns-symbol r-symbol r-object]

(defn- alter-meta-doc-in-future! [ns-symbol r-symbol r-object]
(future
(Thread/sleep 5000)
(alter-meta!
(get (ns-publics ns-symbol) r-symbol)
assoc :doc (safe-help r-object))))

(defn add-to-ns [ ns-symbol r-symbol r-object]
(intern ns-symbol
(r-symbol->clj-symbol r-symbol r-object)
r-object))
r-object)

(alter-meta-doc-in-future! ns-symbol r-symbol r-object)
ns-symbol)


(defn symbols->add-to-ns [ns-symbol r-symbols]
(doseq [[r-symbol r-object] r-symbols]
Expand All @@ -86,28 +111,29 @@
(defn require-r-package [[package-symbol & {:keys [as refer]}]]
(try
(let [session (session/fetch-or-make nil)]
(evl/eval-form `(library ~package-symbol) session))
(let [r-ns-symbol (->> package-symbol
(str "r.")
symbol)
r-symbols (all-r-symbols-map package-symbol)]
(evl/eval-form `(library ~package-symbol) session)
(let [r-ns-symbol (->> package-symbol
(str "r.")
symbol)
r-symbols (all-r-symbols-map package-symbol)]

;; r.package namespace
(find-or-create-ns r-ns-symbol)
(symbols->add-to-ns r-ns-symbol r-symbols)
(find-or-create-ns r-ns-symbol)
(symbols->add-to-ns r-ns-symbol r-symbols)

;; alias namespaces
;; https://clojurians.zulipchat.com/#narrow/stream/224816-clojisr-dev/topic/require-r.20vs.20-require-python
(alias package-symbol r-ns-symbol)
(when as (alias as r-ns-symbol))
(alias package-symbol r-ns-symbol)
(when as (alias as r-ns-symbol))

;; inject symbol into current namespace
(when refer
(let [this-ns-symbol (-> *ns* str symbol)]
(symbols->add-to-ns this-ns-symbol
(if (= refer :all)
r-symbols
(select-keys r-symbols refer))))))
(when refer
(let [this-ns-symbol (-> *ns* str symbol)]
(symbols->add-to-ns
this-ns-symbol
(if (= refer :all)
r-symbols
(select-keys r-symbols refer)))))))
(catch Exception e
(log/warn [::require-r-package {:package-symbol package-symbol
:cause (exception-cause e)}])
Expand Down
2 changes: 2 additions & 0 deletions src/clojisr/v1/util.clj
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,8 @@
(recur threaded (next forms)))
x)))



(comment
(-|> 4
:+
Expand Down
30 changes: 30 additions & 0 deletions test/clojisr/v1/help_test.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
(ns clojisr.v1.help-test
(:require
[clojure.string :as str]
[clojure.test :refer [is deftest]]
[clojisr.v1.r :as r]))

(r/require-r '[randomForest])

(deftest help-docstring
(r/require-r '[randomForest])
(Thread/sleep 30000)
(is (str/starts-with?
(:doc (meta (var r.randomForest/randomForest)))
"Classification and Regression with Random Forest")))

(deftest help-function
(is (str/starts-with?
(r/help "randomForest" "randomForest")
"Classification and Regression with Random Forest")))

(deftest require-defauls-should-not-throws-exception

; should not crash
(r/require-r '[base])
(r/require-r '[stats])
(r/require-r '[utils])
(r/require-r '[graphics])
(r/require-r '[datasets])

)
76 changes: 38 additions & 38 deletions test/clojisr/v1/tutorials/main_generated_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -1090,8 +1090,7 @@

(def var251 (require-r '[base] '[stats] '[grDevices]))


(def
(def
var252
(->>
[#'r.base/mean
Expand All @@ -1102,39 +1101,40 @@
#'r.base/summary-default
#'r.base/sin
#'r.base/sum]
(map (fn [f] (-> f meta (update :ns (comp symbol str)))))))


(deftest
test253
(is
(=
var252
'({:arglists ([x & {:keys [...]}]), :name mean, :ns r.base}
{:arglists ([x & {:keys [trim na.rm ...]}]),
:name mean-default,
:ns r.base}
{:arglists
([x
&
{:keys
[order
seasonal
xreg
include.mean
delta
transform.pars
fixed
init
method
n.cond
optim.control]}]),
:name arima0,
:ns r.stats}
{:arglists ([& {:keys [which]}]), :name dev-off, :ns r.grDevices}
{:arglists ([]), :name Sys-info, :ns r.base}
{:arglists ([object & {:keys [... digits quantile.type]}]),
:name summary-default,
:ns r.base}
{:arglists ([x]), :name sin, :ns r.base}
{:arglists ([& {:keys [... na.rm]}]), :name sum, :ns r.base}))))
(mapv (fn [f] (-> f meta (update :ns (comp symbol str)))))))

;; fails due to :doc present
;; (deftest
;; test253
;; (is
;; (=
;; var252

;; '({:arglists ([x & {:keys [...]}]), :name mean, :ns r.base}
;; {:arglists ([x & {:keys [trim na.rm ...]}]),
;; :name mean-default,
;; :ns r.base}
;; {:arglists
;; ([x
;; &
;; {:keys
;; [order
;; seasonal
;; xreg
;; include.mean
;; delta
;; transform.pars
;; fixed
;; init
;; method
;; n.cond
;; optim.control]}]),
;; :name arima0,
;; :ns r.stats}
;; {:arglists ([& {:keys [which]}]), :name dev-off, :ns r.grDevices}
;; {:arglists ([]), :name Sys-info, :ns r.base}
;; {:arglists ([object & {:keys [... digits quantile.type]}]),
;; :name summary-default,
;; :ns r.base}
;; {:arglists ([x]), :name sin, :ns r.base}
;; {:arglists ([& {:keys [... na.rm]}]), :name sum, :ns r.base}))))