Brute Wrap
Brute force wrapping of Java methods with Clojure functions.
Install
Bwrap is available in Clojars, add [bwrap "0.1.0"] to your Leiningen dependencies to pull it in to your project.
Usage
In a namespace,
(ns wrapper.string
(:require [bwrap.wrapper :refer [defclassfns]]))
(defclassfns java.lang.String)In the REPL,
user> (ns wrapper.string)
nil
wrapper.string> (use 'bwrap.wrapper)
nil
wrapper.string> (defclassfns java.lang.String)
WARNING: concat already refers to: #'clojure.core/concat in namespace: wrapper.string, being replaced by: #'wrapper.string/concat
WARNING: intern already refers to: #'clojure.core/intern in namespace: wrapper.string, being replaced by: #'wrapper.string/intern
WARNING: replace already refers to: #'clojure.core/replace in namespace: wrapper.string, being replaced by: #'wrapper.string/replace
#'wrapper.string/starts-with
wrapper.string> (keys (ns-publics *ns*))
(hash-code to-string trim get-chars split code-point-at sub-sequence concat starts-with ends-with offset-by-code-points content-equals intern compare-to-ignore-case char-at to-upper-case to-char-array last-index-of to-lower-case replace get-bytes compare-to replace-all length code-point-before equals-ignore-case region-matches matches code-point-count equals index-of hash32 is-empty replace-first substring contains)It's a wise move to run this in a dedicated namespace. It will happily blat over existing function definitions.
The created functions have a first argument of self, this is the instance that the function should operate on. The remaining arguments will be passed into the function call.
wrapper.string> (length "123")
3
wrapper.string> (equals "aaa" "bbb")
false
wrapper.string> (equals "aaa" "aaa")
trueFunction documentation
There is nothing useful. The function parameter names are constructed based on the type and the parameter index. Without a programmatic way to acquire sensible names of documentation there is not much that can be done here.
user> (doc length)
-------------------------
user/length
([self])
nil
user> (doc equals)
-------------------------
user/equals
([self object0])
nil
user> (doc index-of)
-------------------------
user/index-of
([self string0] [self int0 int1])
nilOverloaded methods and multiple arity functions
Bwrap handles overloaded methods and will create multi arity functions. However, it does this in a fairly crude way.
Clojure cannot have multiple function definitions with the same number of arguments* so all overloaded Java methods with the same number of arguments will be rolled into a single Clojure function definition.
For example, something like String#indexOf has four implementations, two with one argument and two with two arguments.
int indexOf(int ch)
Returns the index within this string of the first occurrence of the specified character.
int indexOf(int ch, int fromIndex)
Returns the index within this string of the first occurrence of the specified character, starting the search at the specified index.
int indexOf(String str)
Returns the index within this string of the first occurrence of the specified substring.
int indexOf(String str, int fromIndex)
Returns the index within this string of the first occurrence of the specified substring, starting at the specified index.Bwrap cannot differentiate based on type* and create four different functions, so only two come into existence,
user> (doc index-of)
-------------------------
user/index-of
([self string0] [self int0 int1])
nilThe argument names are picked from the first implementation that bwrap finds.
Fortunately, (or not) we can still dispatch on reflection. Here's an example of reflection dispatch on the single argument methods.
user> (index-of "abcdefg" 100)
3
user> (index-of "abcdefg" "d")
3*actually, with multimethods it can. But I'll ignore that for now.
TODO
- Replace reflection dispatch with multimethods and type hints
- Investigate creating macros instead of functions
- Add question mark suffix to boolean functions
- Return self on void functions (or, perhaps create a return self alternative of each function)
License
Copyright © 2014 Dan Midwood
Distributed under the Eclipse Public License either version 1.0 or (at your option) any later version.