4
\$\begingroup\$

I wanted to wrap the jkeymaster library in a Clojure wrapper (for my own use, but perhaps also to save others some time). I'm just learning Clojure so I'm still not quite sure what "idiomatic libraries/APIs" look like. In Ruby, I would have created an object with methods, but in one of the clojure books they recommended letting users manage state themselves, so I have function that creates a provider, and this provider must then be passed to the register function.

Here's first an example of usage:

(ns keymaster.core
 (:require [keymaster.keymaster :as km]))
(defn -main
 "I don't do a whole lot ... yet."
 [& args]
 (km/register (km/provider) "control shift 1" #(println "hi")))

And here is the full text of the "library".

(ns keymaster.keymaster
 (:gen-class)
 (:use (com.tulskiy.keymaster.common)))
(defn provider []
 "Gets and initiates a keymaster provider, which must be passed to register to register shortcuts"
 (let [provider (com.tulskiy.keymaster.common.Provider/getCurrentProvider true)]
 (.init provider)
 provider))
(defn- conv-keystroke [x]
 "Takes keystroke in the form \"control shift 1\" and returns a Keystroke class"
 (javax.swing.KeyStroke/getKeyStroke x))
(defn- conv-listener [f]
 "Takes a function with one argument, which will get passed the keycode, and creates a listener
 Todo: How to accept a function with or without a parameter to accept hotKey?"
 (proxy [com.tulskiy.keymaster.common.HotKeyListener] [] (onHotKey [hotKey] (f))))
(defn register
 [provider shortcut listener]
 "Registers a shortcut on provider, which will trigger listener (with one argument)"
 (let [k (conv-keystroke shortcut)
 l (conv-listener listener)]
 (.register provider k l)))

In addition to any general style feedback, both about the coding, and the design of the API, I'm also wondering if there is any way to have conv-listener accept either a 0 or 1-arity function. Right now I made the choice of accepting a 0-arity function, but if someone wanted to pass a 1-arity function, where the first argument would be the name of the keycode called (hotKey), which I would call with (f hotKey), I would have to rewrite... Possible to allow both? (1-arity is inconvenient for anonymous functions where we really don't need it - which I suspect is most of the time, since we can bind different hotkeys to different listeners).

Jamal
35.2k13 gold badges134 silver badges238 bronze badges
asked Apr 28, 2013 at 1:27
\$\endgroup\$
2
  • \$\begingroup\$ I rewrote slightly to have provider instead return a (partial register provider), which the user can then use to register a new key directly, thus exposing only one function to the user. github.com/houshuang/keymaster-clj - still interested in feedback \$\endgroup\$ Commented Apr 30, 2013 at 2:13
  • \$\begingroup\$ Got a nice GitHub pull request (another form of code review), and a substantially nicer function is now available - also as a Clojar. But still happy to receive feedback here. \$\endgroup\$ Commented May 2, 2013 at 2:53

1 Answer 1

2
\$\begingroup\$

As a wrapper goes I think this looks fine. The feedback I do have is that I wouldn't use let as often as you do and would use the treading macro (-> ...) instead.

For example:

(-> (com.tulskiy.keymaster.common.Provider/getCurrentProvider true)
 .init)

does the same as

(let [provider (com.tulskiy.keymaster.common.Provider/getCurrentProvider true)]
 (.init provider)
 provider)

and it's easier to read and shorter. You could also do it this way:

(.init (com.tulskiy.keymaster.common.Provider/getCurrentProvider true))
answered Jun 20, 2015 at 16:58
\$\endgroup\$

Your Answer

Draft saved
Draft discarded

Sign up or log in

Sign up using Google
Sign up using Email and Password

Post as a guest

Required, but never shown

Post as a guest

Required, but never shown

By clicking "Post Your Answer", you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.