I'm using proxy in Clojure to extend a Java class. I need to set a field in the superclass, how can i do this? The code below doesn't work.
(proxy [BasicPlayer] []
(open [url]
(set! super/m_dataSource url)))
From the documentation for proxy:
Note that while method fns can
be provided to override protected methods, they have no other access
to protected members, nor to super, as these capabilities cannot be
proxied.
Sorry, but it sounds like you're out of luck. You can call protected superclass methods with proxy-super, but I think that's about it.
You might have better luck with gen-class. Something along the lines of:
(ns my.Player
(:gen-class
:extends BasicPlayer
:exposes {m_dataSource {:set -setDataSource}})
(defn -open [this url]
(-setDataSource this url))
Related
How can I define a new record that "inherits" the protocols from an existing type?
To make this question clear, I'll illustrate with extending Ubergraph, but Ubergraph is only an example; I'm looking for the general solution, not just a solution that works for Ubergraph. Suppose that I'd like to add a global attribute, graph-name, to Ubergraph. Ideally, I could do something like this:
(defrecord named-ubergraph [g graph-name])
(extend-type named-ubergraph
(all-the-protocols-supported-by ubergraph.core.Ubergraph)
(call-the-same-functions-replacing-first-argument-with '(this g))
Of course I could look at the Ubergraph source code and manually write all the forwarding functions, but as you can see here, Ubergraph satisfies many protocols and many protocol methods.
Writing so much boilerplate code doesn't sound very Clojurely, and it seems like a lot of work when all I want to do is add one eensy-weensy bit of data to an Ubergraph. What's a better way?
Please feel free to reconceptualize the question if you think I'm looking at this wrong.
extend-type extends existing types to given protocols.
If I understand you properly, you want to extend existing record to achieve some kind of inheritance.
AFAIK, there's no easy way to do this.
However, if all you want is to add another field, you can easily assoc additional field to an existing record instance:
(defprotocol Cost
(cost [this price-list]))
(defrecord Car [name speed]
Cost
(cost [this price-list] (price-list (:name this))))
(def my-car (->Car "bmw" 200))
(def price-list {"bmw" 100000})
(cost my-car price-list)
;;=> 100000
(-> my-car
(assoc :color "blue")
(cost price-list))
;;=> 100000
UPDATE:
I've also found this fantastic discussion on Clojure mailing list: defrecord with "inheritance": https://groups.google.com/forum/#!topic/clojure/mr-o9sRyiZ0
Let's say I'm doing a web app that exposes API to fetch and mutate data about cats.
I'm implementing my db layer using Korma, so there will be something like that:
(ns kittens.db
(:require [korma.core :refer :all]))
(defn fetch-cats [db]
(select cats-table ...))
(defn fetch-cat-by-id [db id]
(select cats-table
...
(where {:id id})))
(defn create-cat [db data]
(insert cats-table
...))
...
...
After I'm implementing API routes as follows:
(ns kittens.routes
(:require [compojure.core :refer [defroutes GET POST ...]]
[kittens.db :as db]))
(defroutes cats-routes
(GET "/cats" [...] (db/fetch-cats ...))
(GET "/cats/:id" [...] (db/fetch-cat-by-id ...))
(POST "/new-cat" [...] (db/create-cat ...)))
In such implementation routes module talks directly to db module, which seems kinda inflexible to me. Should there be something in between of them?
In my opinion you do not need anything else, this is good.
Such a setup is already plenty flexible.
Seeing as all looks good, here is some general advice as things grow:
Avoid putting logic route bodies.
If the body of a route starts to grow, consider extracting it to a function.
Routes are less fun to test.
Colocate your routes and handler middleware unless you have so many routes they need to be split out into contexts.
Make sure your handler references the routes var #' not the routes directly so that reloading routes will work.
How can I list all the routes on a handler function? I'm looking for behavior similar to rails' rake routes. For example:
(defroutes foo-routes
(GET "/foo/:foo-id"
[foo-id]
"bar response")
(GET "/bar/:bar-id"
[bar-id]
"foo response"))
Is it then possible to extract a map from foo-bar-routes containing the following?
{:GET "/foo/:foo-id"
:GET "/bar/:bar-id"}
I don't think it is possible. defroutes is a macro that returns a ring handler. GET is a macro that returns a route. Route is again just a function that calls related handler only if method and path are matching. So in the end your foo-routes is just a clojure function that is composed of other functions defined by your routes and it doesn't maintain such map. If you need to get such map, maybe you can maintain it in your code yourself and generate routes out of this map.
I know this thread is quite old but I had the same question and could resolve it by myself, here's what I've got:
Assuming you defined your API this way:
(def my-api (compojure.api.api/api ...))
Then you can easily list the routes you defined that way:
(->> (.-get-routes my-api {})
(map (juxt second first)))
I'm trying to add some functionality to an existing JavaScript system. To be then used from JavaScript again (as opposed to within the ClojureScript namespace). Perhaps this isn't possible?
Here's a simplification of what I want to do:
// JavaScript
String.prototype.foo = function() {
return "bar";
}
# CoffeeScript
String::foo = ->
"bar"
I want to be able to run my script above, and then call it from elsewhere in the code.
I've tried messing with extend-type and defprotocol, along with export, but nothing seemed to expose my foo function.
It's possible that this was a design decision and ClojureScript isn't going to work for me here, but I just wanted to make sure I wasn't overlooking something.
It can be done like so:
(set! (.-foo (.-prototype js/String)) (fn [] "bar"))
Or you can use .. sugar:
(set! (.. js/String -prototype -foo) (fn [] "bar"))
I'm developing a web application with Clojure, currently with Ring, Moustache, Sandbar and Hiccup. I have a resource named job, and a route to show a particular step in a multi-step form for a particular job defined like this (other routes omitted for simplicity):
(def web-app
(moustache/app
;; matches things like "/job/32/foo/bar"
:get [["job" id & step]
(fn [req] (web.controllers.job/show-job id step))]))
In the view my controller renders, there are links to other steps within the same job. At the moment, these urls are constructed by hand, e.g. (str "/job/" id step). I don't like that hard-coded "/job/" part of the url, because it repeats what I defined in the moustache route; if I change the route I need to change my controller, which is a tighter coupling than I care for.
I know that Rails' routing system has methods to generate urls from parameters, and I wish I had similar functionality, i.e. I wish I had a function url-for that I could call like this:
(url-for :job 32 "foo" "bar")
; => "/job/32/foo/bar"
Is there a Clojure web framework that makes this easy? If not, what are your thoughts on how this could be implemented?
Noir provides something similar. It's even called url-for.
The example function you have mentioned could be implemented as below. But I am not sure if this is exactly what you are looking for.
(defn url-for [& rest]
(reduce
#(str %1 "/" %2) "" (map #(if (keyword? %1) (name %1) (str %1)) rest)))