Refactor using reflection support (#110)
This commit is contained in:
parent
a9347c7753
commit
a0fa854969
9 changed files with 130 additions and 262 deletions
39
README.md
39
README.md
|
|
@ -162,24 +162,26 @@ namespaces. If not all vars are available, they are enumerated explicitly.
|
|||
- [`clojure.tools.cli`](https://github.com/clojure/tools.cli) aliased as `tools.cli`
|
||||
- [`clojure.data.csv`](https://github.com/clojure/data.csv) aliased as `csv`
|
||||
|
||||
From Java the following is available:
|
||||
The following Java classes are available:
|
||||
|
||||
- `Integer`:
|
||||
- static methods: `parseInt`
|
||||
- `File`:
|
||||
- static methods: `createTempFile`
|
||||
- instance methods: `.canRead`, `.canWrite`, `.delete`,
|
||||
`.deleteOnExit`, `.exists`, `.getAbsoluteFile`, `.getCanonicalFile`,
|
||||
`.getCanonicalPath`, `.getName`, `.getParent`, `.getParentFile`,
|
||||
`.getPath`, `.isAbsolute`, `.isDirectory`, `.isFile`, `.isHidden`,
|
||||
`.lastModified`, `.length`, `.list`, `.listFiles`, `.mkdir`,
|
||||
`.mkdirs`, `.renameTo`, `.setLastModified`, `.setReadOnly`,
|
||||
`.setReadable`, `.toPath`, `.toURI`.
|
||||
- `System`:
|
||||
- static methods: `exit`, `getProperty`, `setProperty`, `getProperties`, `getenv`
|
||||
- `Thread`:
|
||||
- static methods: `sleep`
|
||||
- `java.util.regex.Pattern` (all static and instance methods and constants)
|
||||
```
|
||||
ArithmeticException
|
||||
AssertionError
|
||||
Boolean
|
||||
Class
|
||||
Double
|
||||
Exception
|
||||
clojure.lang.ExceptionInfo
|
||||
java.io.File
|
||||
Integer
|
||||
java.io.File
|
||||
java.util.regex.Pattern
|
||||
String
|
||||
System
|
||||
Thread
|
||||
```
|
||||
|
||||
More classes can be added by request.
|
||||
|
||||
Special vars:
|
||||
|
||||
|
|
@ -442,8 +444,7 @@ Differences with Clojure:
|
|||
- No first class vars. Note that you can define and redefine global values with
|
||||
`def` / `defn`, but there is no `var` indirection.
|
||||
|
||||
- Java classes and interop are not available. For a selection of classes we mimic constructors and interop by having
|
||||
functions like `Exception.` and `.getCanonicalPath`.
|
||||
- A subset of Java classes are supported.
|
||||
|
||||
- Only the `clojure.core`, `clojure.set` and `clojure.string` namespaces are
|
||||
available from Clojure.
|
||||
|
|
|
|||
|
|
@ -1,4 +1,26 @@
|
|||
[
|
||||
{
|
||||
"name":"java.lang.ArithmeticException",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.AssertionError",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Boolean",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.io.BufferedReader",
|
||||
"allPublicMethods":true
|
||||
},
|
||||
{
|
||||
"name": "java.lang.Class",
|
||||
"allDeclaredConstructors": true,
|
||||
|
|
@ -7,9 +29,45 @@
|
|||
"allPublicMethods": true
|
||||
},
|
||||
{
|
||||
"name":"java.io.BufferedReader",
|
||||
"name":"java.lang.Double",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Exception",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name": "clojure.lang.ExceptionInfo",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Integer",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.io.File",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.LinkedBlockingQueue",
|
||||
"allPublicMethods":true
|
||||
},
|
||||
{
|
||||
"name":"java.util.regex.Pattern",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Process",
|
||||
"allPublicMethods":true
|
||||
|
|
@ -20,14 +78,25 @@
|
|||
},
|
||||
{
|
||||
"name":"java.lang.String",
|
||||
"allPublicMethods":true
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
}
|
||||
,
|
||||
{
|
||||
"name":"java.lang.System",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.Thread",
|
||||
"allPublicMethods":true,
|
||||
"allPublicFields": true,
|
||||
"allPublicConstructors": true
|
||||
},
|
||||
{
|
||||
"name":"java.lang.UNIXProcess",
|
||||
"allPublicMethods":true
|
||||
},
|
||||
{
|
||||
"name":"java.util.concurrent.LinkedBlockingQueue",
|
||||
"allPublicMethods":true
|
||||
}
|
||||
]
|
||||
|
|
|
|||
2
sci
2
sci
|
|
@ -1 +1 @@
|
|||
Subproject commit cb1dc3139a53c680b2bdc1038d2c6e26b975ee8e
|
||||
Subproject commit 419d39d24f9e3676d9922218e747fc277a921a72
|
||||
|
|
@ -1,87 +0,0 @@
|
|||
(ns babashka.impl.File
|
||||
{:no-doc true}
|
||||
(:refer-clojure :exclude [list])
|
||||
(:require [clojure.java.io :as io]
|
||||
[clojure.string :as str]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
;; also see https://gist.github.com/plexus/68594ba9b5e3f0d63fe84dcae31c4a53
|
||||
|
||||
(defmacro gen-wrapper-fn [method-name]
|
||||
`(defn ~method-name {:bb/export true}
|
||||
[~(with-meta 'x {:tag 'java.io.File})]
|
||||
(~(symbol (str "." method-name)) ~'x)))
|
||||
|
||||
(defmacro gen-wrapper-fn-2 [method-name]
|
||||
`(defn ~method-name {:bb/export true}
|
||||
[~(with-meta 'x {:tag 'java.io.File}) ~'y]
|
||||
(~(symbol (str "." method-name)) ~'x ~'y)))
|
||||
|
||||
(gen-wrapper-fn canExecute)
|
||||
(gen-wrapper-fn canRead)
|
||||
(gen-wrapper-fn canWrite)
|
||||
(defn createTempFile
|
||||
([^String prefix ^String suffix]
|
||||
(java.io.File/createTempFile prefix suffix))
|
||||
([^String prefix ^String suffix ^java.io.File dir]
|
||||
(java.io.File/createTempFile prefix suffix dir)))
|
||||
(gen-wrapper-fn delete)
|
||||
(gen-wrapper-fn deleteOnExit)
|
||||
(gen-wrapper-fn exists)
|
||||
(gen-wrapper-fn getAbsoluteFile)
|
||||
(gen-wrapper-fn getCanonicalFile)
|
||||
(gen-wrapper-fn getCanonicalPath)
|
||||
(gen-wrapper-fn getName)
|
||||
(gen-wrapper-fn getParent)
|
||||
(gen-wrapper-fn getParentFile)
|
||||
(gen-wrapper-fn getPath)
|
||||
(gen-wrapper-fn isAbsolute)
|
||||
(gen-wrapper-fn isDirectory)
|
||||
(gen-wrapper-fn isFile)
|
||||
(gen-wrapper-fn isHidden)
|
||||
(gen-wrapper-fn lastModified)
|
||||
(gen-wrapper-fn length)
|
||||
(gen-wrapper-fn list)
|
||||
(gen-wrapper-fn listFiles)
|
||||
(gen-wrapper-fn mkdir)
|
||||
(gen-wrapper-fn mkdirs)
|
||||
(gen-wrapper-fn-2 renameTo)
|
||||
(defn ^:bb/export setExecutable
|
||||
([^java.io.File f b]
|
||||
(.setExecutable f b))
|
||||
([^java.io.File f b ownerOnly]
|
||||
(.setExecutable f b ownerOnly)))
|
||||
(gen-wrapper-fn-2 setLastModified)
|
||||
(gen-wrapper-fn-2 setReadable)
|
||||
(gen-wrapper-fn setReadOnly)
|
||||
(defn ^:bb/export setWritable
|
||||
([^java.io.File f b]
|
||||
(.setWritable f b))
|
||||
([^java.io.File f b ownerOnly]
|
||||
(.setWritable f b ownerOnly)))
|
||||
(gen-wrapper-fn toPath)
|
||||
(gen-wrapper-fn toURI)
|
||||
|
||||
(def file-bindings
|
||||
(-> (reduce (fn [acc [k v]]
|
||||
(if (-> v meta :bb/export)
|
||||
(assoc acc (symbol (str "." k))
|
||||
@v)
|
||||
acc))
|
||||
{}
|
||||
(ns-publics *ns*))
|
||||
;; static methods
|
||||
(assoc (symbol "File/createTempFile") createTempFile)
|
||||
(assoc (symbol "java.io.File/createTempFile") createTempFile)))
|
||||
|
||||
(comment
|
||||
(canRead (clojure.java.io/file "README.md"))
|
||||
(canWrite (clojure.java.io/file "README.md"))
|
||||
(exists (clojure.java.io/file "README.md"))
|
||||
(renameTo (io/file "/tmp/script2.clj") (io/file "/tmp/script.clj"))
|
||||
(.setWritable (io/file "/tmp/script.clj") true true)
|
||||
(meta #'toURI)
|
||||
(meta #'canWrite)
|
||||
;; for README.md:
|
||||
(str/join ", " (map #(format "`%s`" %) (sort (keys file-bindings))))
|
||||
)
|
||||
|
|
@ -1,17 +0,0 @@
|
|||
(ns babashka.impl.Integer
|
||||
{:no-doc true}
|
||||
(:refer-clojure :exclude [list]))
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
(defn parseInt
|
||||
([^String x] (Integer/parseInt x))
|
||||
([^String x ^long radix]
|
||||
(Integer/parseInt x radix)))
|
||||
|
||||
(def integer-bindings
|
||||
{'Integer/parseInt parseInt})
|
||||
|
||||
(comment
|
||||
|
||||
)
|
||||
|
|
@ -1,72 +0,0 @@
|
|||
(ns babashka.impl.Pattern
|
||||
{:no-doc true})
|
||||
|
||||
(set! *warn-on-reflection* true)
|
||||
|
||||
(defmacro gen-wrapper-fn [method-name]
|
||||
`(defn ~method-name {:bb/export true}
|
||||
[~(with-meta 'x {:tag 'java.util.regex.Pattern})]
|
||||
(~(symbol (str "." method-name)) ~'x)))
|
||||
|
||||
(defmacro gen-wrapper-fn-2 [method-name]
|
||||
`(defn ~method-name {:bb/export true}
|
||||
[~(with-meta 'x {:tag 'java.util.regex.Pattern}) ~'y]
|
||||
(~(symbol (str "." method-name)) ~'x ~'y)))
|
||||
|
||||
(defmacro gen-constants [& constant-names]
|
||||
(let [defs (for [constant-name constant-names
|
||||
:let [full-name (symbol (str "java.util.regex.Pattern/" constant-name))
|
||||
meta {:bb/export-constant true
|
||||
:bb/full-name (list 'quote full-name)}
|
||||
constant-name (with-meta constant-name meta)]]
|
||||
`(def ~constant-name
|
||||
~full-name))]
|
||||
`(do ~@defs)))
|
||||
|
||||
(gen-constants CANON_EQ CASE_INSENSITIVE COMMENTS DOTALL LITERAL MULTILINE
|
||||
UNICODE_CASE UNICODE_CHARACTER_CLASS UNIX_LINES)
|
||||
|
||||
(gen-wrapper-fn asPredicate)
|
||||
|
||||
(defn compile*
|
||||
([^String s]
|
||||
(java.util.regex.Pattern/compile s))
|
||||
([^String s ^long flags]
|
||||
(java.util.regex.Pattern/compile s flags)))
|
||||
|
||||
(gen-wrapper-fn flags)
|
||||
|
||||
(gen-wrapper-fn-2 matcher)
|
||||
|
||||
(defn matches [^String regex ^CharSequence input]
|
||||
(java.util.regex.Pattern/matches regex input))
|
||||
|
||||
(gen-wrapper-fn pattern)
|
||||
|
||||
(defn pattern-quote [s]
|
||||
(java.util.regex.Pattern/quote s))
|
||||
|
||||
(defn ^:bb/export split
|
||||
([^java.util.regex.Pattern p ^CharSequence input]
|
||||
(.split p input))
|
||||
([^java.util.regex.Pattern p ^CharSequence input ^long limit]
|
||||
(.split p input limit)))
|
||||
|
||||
(gen-wrapper-fn-2 splitAsStream)
|
||||
|
||||
(def pattern-bindings
|
||||
(-> (reduce (fn [acc [k v]]
|
||||
(let [m (meta v)]
|
||||
(cond (:bb/export m)
|
||||
(assoc acc (symbol (str "." k))
|
||||
@v),
|
||||
(:bb/export-constant m)
|
||||
(assoc acc (symbol (:bb/full-name m))
|
||||
@v)
|
||||
:else acc)))
|
||||
{}
|
||||
(ns-publics *ns*))
|
||||
;; static method
|
||||
(assoc (symbol "java.util.regex.Pattern/compile") compile*)
|
||||
(assoc (symbol "java.util.regex.Pattern/quote") pattern-quote)
|
||||
(assoc (symbol "java.util.regex.Pattern/matches") matches)))
|
||||
|
|
@ -1,28 +0,0 @@
|
|||
(ns babashka.impl.System
|
||||
{:no-doc true})
|
||||
|
||||
(defn get-env
|
||||
([] (System/getenv))
|
||||
([s] (System/getenv s)))
|
||||
|
||||
(defn get-property
|
||||
([s]
|
||||
(System/getProperty s))
|
||||
([s d]
|
||||
(System/getProperty s d)))
|
||||
|
||||
(defn set-property [k v]
|
||||
(System/setProperty k v))
|
||||
|
||||
(defn get-properties []
|
||||
(System/getProperties))
|
||||
|
||||
(defn exit [n]
|
||||
(throw (ex-info "" {:bb/exit-code n})))
|
||||
|
||||
(def system-bindings
|
||||
{'System/getenv get-env
|
||||
'System/getProperty get-property
|
||||
'System/setProperty set-property
|
||||
'System/getProperties get-properties
|
||||
'System/exit exit})
|
||||
|
|
@ -1,9 +0,0 @@
|
|||
(ns babashka.impl.Thread
|
||||
{:no-doc true})
|
||||
|
||||
(defn sleep
|
||||
([millis] (Thread/sleep millis))
|
||||
([millis nanos] (Thread/sleep millis nanos)))
|
||||
|
||||
(def thread-bindings
|
||||
{'Thread/sleep sleep})
|
||||
|
|
@ -1,20 +1,12 @@
|
|||
(ns babashka.main
|
||||
{:no-doc true}
|
||||
(:require
|
||||
[babashka.impl.File :refer [file-bindings]]
|
||||
[babashka.impl.Integer :refer [integer-bindings]]
|
||||
[babashka.impl.Double :refer [double-bindings]]
|
||||
[babashka.impl.Boolean :refer [boolean-bindings]]
|
||||
[babashka.impl.Pattern :refer [pattern-bindings]]
|
||||
[babashka.impl.System :refer [system-bindings]]
|
||||
[babashka.impl.Thread :refer [thread-bindings]]
|
||||
[babashka.impl.async :refer [async-namespace]]
|
||||
[babashka.impl.clojure.core :refer [core-extras]]
|
||||
[babashka.impl.clojure.java.io :refer [io-namespace]]
|
||||
[babashka.impl.clojure.stacktrace :refer [print-stack-trace]]
|
||||
[babashka.impl.conch :refer [conch-namespace]]
|
||||
[babashka.impl.csv :as csv]
|
||||
[babashka.impl.exceptions :refer [exception-bindings]]
|
||||
[babashka.impl.pipe-signal-handler :refer [handle-pipe! pipe-signal-received?]]
|
||||
[babashka.impl.socket-repl :as socket-repl]
|
||||
[babashka.impl.tools.cli :refer [tools-cli-namespace]]
|
||||
|
|
@ -150,16 +142,6 @@ Everything after that is bound to *command-line-args*."))
|
|||
(str/replace x #"^#!.*" ""))
|
||||
(throw (Exception. (str "File does not exist: " file))))))
|
||||
|
||||
(def bindings
|
||||
(merge system-bindings
|
||||
file-bindings
|
||||
thread-bindings
|
||||
integer-bindings
|
||||
double-bindings
|
||||
boolean-bindings
|
||||
exception-bindings
|
||||
pattern-bindings))
|
||||
|
||||
(defn read-edn []
|
||||
(edn/read {;;:readers *data-readers*
|
||||
:eof ::EOF} *in*))
|
||||
|
|
@ -180,6 +162,9 @@ Everything after that is bound to *command-line-args*."))
|
|||
;; hang until SIGINT
|
||||
@(promise)))
|
||||
|
||||
(defn exit [n]
|
||||
(throw (ex-info "" {:bb/exit-code n})))
|
||||
|
||||
(defn main
|
||||
[& args]
|
||||
(handle-pipe!)
|
||||
|
|
@ -223,9 +208,35 @@ Everything after that is bound to *command-line-args*."))
|
|||
'me.raynes.conch.low-level conch-namespace
|
||||
'clojure.core.async async-namespace
|
||||
'clojure.data.csv csv/csv-namespace}
|
||||
:bindings (assoc bindings '*command-line-args* command-line-args)
|
||||
:bindings {'*command-line-args* command-line-args
|
||||
'java.lang.System/exit exit ;; override exit, so we have more control
|
||||
'System/exit exit}
|
||||
:env env
|
||||
:features #{:bb}}
|
||||
:features #{:bb}
|
||||
:classes {'java.lang.ArithmeticException ArithmeticException
|
||||
'java.lang.AssertionError AssertionError
|
||||
'java.lang.Boolean Boolean
|
||||
'java.lang.Class Class
|
||||
'java.lang.Double Double
|
||||
'java.lang.Exception Exception
|
||||
'clojure.lang.ExceptionInfo clojure.lang.ExceptionInfo
|
||||
'java.lang.Integer Integer
|
||||
'java.io.File java.io.File
|
||||
'java.util.regex.Pattern java.util.regex.Pattern
|
||||
'java.lang.String String
|
||||
'java.lang.System System
|
||||
'java.lang.Thread Thread}
|
||||
:imports '{ArithmeticException java.lang.ArithmeticException
|
||||
AssertionError java.lang.AssertionError
|
||||
Boolean java.lang.Boolean
|
||||
Class java.lang.Class
|
||||
Double java.lang.Double
|
||||
Exception java.lang.Exception
|
||||
Integer java.lang.Integer
|
||||
File java.io.File
|
||||
String java.lang.String
|
||||
System java.lang.System
|
||||
Thread java.lang.Thread}}
|
||||
ctx (update ctx :bindings assoc 'eval #(eval* ctx %)
|
||||
'load-file #(load-file* ctx %))
|
||||
_preloads (some-> (System/getenv "BABASHKA_PRELOADS") (str/trim) (sci/eval-string ctx))
|
||||
|
|
|
|||
Loading…
Reference in a new issue