Re: Curious behaviour when requiring clojure.tools.cli

2021-06-14 Thread Simon Brooke
Thank you, that was the right answer (and I would not have thought of it 
myself). Codox was on Clojure 1.7.0, but it was also on 
org.clojure/tools.namespace 0.2.11. Cloverage is on 1.10.1 and 1.0.0 
respectively, and if I bring the Codox versions into line with the 
Cloverage versions, it all works.

So I think I can get this working for me. I'm less confident of getting 
upstream to accept a pull request for such a major change.

On Monday, 14 June 2021 at 20:02:13 UTC+1 th.h...@gmail.com wrote:

> clojure.string/starts-with? was added in Clojure 1.8.0, I see 1.7.0 in the 
> project.clj?
>
> See 
> https://github.com/clojure/clojure/blob/b1b88dd25373a86e41310a525a21b497799dbbf2/src/clj/clojure/string.clj#L362
>
> What exactly else is going on I don't know but it all starts from the 
> wrong Clojure version.
>
> HTH
>
> On Monday, June 14, 2021 at 2:21:04 PM UTC+2 Simon Brooke wrote:
>
>>
>> I've discovered a weird behaviour which I don't understand and can't seem 
>> to fix - it's probably some obvious mistake of my own.
>>
>> Brief background, I'm trying to integrate cloverage with codox, so that I 
>> can show test coverage reports on my documentation pages. Both of these are 
>> established, solid, well written packages by respected members of the 
>> community.
>>
>> Cloverage (1.3.0-SNAPSHOT) depends on clojure.tools.cli version 0.4.2. 
>> When you start a repl within the cloverage/cloverage directory and attempt 
>> to use clojure.tools.cli, no problem:
>>
>> cloverage.coverage=> (use 'clojure.tools.cli)
>> nil
>>
>> Codox 0.10.7 does not depend on clojure.tools.cli, but my mildly 
>> modified version of codox does depend on cloverage 1.3.0-SNAPSHOT (that is 
>> literally the only change to the codox project.clj). When you start a repl 
>> within the codox/codox directory, and attempt to use clojure.tools.cli, you 
>> get:
>>
>> user=> (use 'clojure.tools.cli)
>> CompilerException java.lang.RuntimeException: No such var: 
>> s/starts-with?, compiling:(clojure/tools/cli.cljc:97:8) 
>>
>> OK, so, it's picking up clojure.tools.cli at all presumably via the 
>> dependency on cloverage, which is good. but clojure.tools.cli requires 
>> clojure.string as `s`, see
>>
>> https://github.com/clojure/tools.cli/blob/master/src/main/clojure/clojure/tools/cli.cljc#L12
>>  
>> so you would have thought this would all work fine.
>>
>> So what happens if I require clojure.string as `s` in the repl? Well, I 
>> get a different error:
>>
>> user=> (require '[clojure.string :as s])
>> nil
>> user=> (use 'clojure.tools.cli)
>> CompilerException java.lang.Exception: namespace 'clojure.tools.cli' 
>> not found, compiling:(/tmp/form-init1843820122884430414.clj:1:1) 
>>
>> So, can anyone explain what is going on here, and how I fix it? it 
>> matters to me, because it prevents my code from compiling:
>>
>> user=> (use 'codox.cloverage-integration.runner :reload)
>> CompilerException java.lang.RuntimeException: No such var: 
>> s/starts-with?, compiling:(clojure/tools/cli.cljc:97:8) 
>>
>> In case anyone's interested, my current diff with respect to 
>> weavejester's current codox is here: 
>> https://github.com/simon-brooke/codox/commit/ef4ba70659c768f1aab4bfbf32efdaa48e9c43a8
>>
>> Thanks in advance for any help or thoughts!
>>
>>
>>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/clojure/5e59dd16-9c5f-45ed-9f6e-db9469c1dda2n%40googlegroups.com.


Curious behaviour when requiring clojure.tools.cli

2021-06-14 Thread Simon Brooke

I've discovered a weird behaviour which I don't understand and can't seem 
to fix - it's probably some obvious mistake of my own.

Brief background, I'm trying to integrate cloverage with codox, so that I 
can show test coverage reports on my documentation pages. Both of these are 
established, solid, well written packages by respected members of the 
community.

Cloverage (1.3.0-SNAPSHOT) depends on clojure.tools.cli version 0.4.2. When 
you start a repl within the cloverage/cloverage directory and attempt to 
use clojure.tools.cli, no problem:

cloverage.coverage=> (use 'clojure.tools.cli)
nil

Codox 0.10.7 does not depend on clojure.tools.cli, but my mildly modified 
version of codox does depend on cloverage 1.3.0-SNAPSHOT (that is literally 
the only change to the codox project.clj). When you start a repl within the 
codox/codox directory, and attempt to use clojure.tools.cli, you get:

user=> (use 'clojure.tools.cli)
CompilerException java.lang.RuntimeException: No such var: 
s/starts-with?, compiling:(clojure/tools/cli.cljc:97:8) 

OK, so, it's picking up clojure.tools.cli at all presumably via the 
dependency on cloverage, which is good. but clojure.tools.cli requires 
clojure.string as `s`, see
https://github.com/clojure/tools.cli/blob/master/src/main/clojure/clojure/tools/cli.cljc#L12
 

so you would have thought this would all work fine.

So what happens if I require clojure.string as `s` in the repl? Well, I get 
a different error:

user=> (require '[clojure.string :as s])
nil
user=> (use 'clojure.tools.cli)
CompilerException java.lang.Exception: namespace 'clojure.tools.cli' 
not found, compiling:(/tmp/form-init1843820122884430414.clj:1:1) 

So, can anyone explain what is going on here, and how I fix it? it matters 
to me, because it prevents my code from compiling:

user=> (use 'codox.cloverage-integration.runner :reload)
CompilerException java.lang.RuntimeException: No such var: 
s/starts-with?, compiling:(clojure/tools/cli.cljc:97:8) 

In case anyone's interested, my current diff with respect to weavejester's 
current codox is here: 
https://github.com/simon-brooke/codox/commit/ef4ba70659c768f1aab4bfbf32efdaa48e9c43a8

Thanks in advance for any help or thoughts!


-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/clojure/cb99df18-b0e0-403d-979a-0572e27a4677n%40googlegroups.com.


Re: Bit rot and leiningen?

2020-02-06 Thread 'Simon Brooke' via Clojure


On Wednesday, 5 February 2020 22:34:42 UTC, Sean Corfield wrote:
>
> > because I still haven't found a development environment I like better 
> than LightTable
>
>  
>
> Have you looked at Atom/Chlorine recently? It has the same inline result 
> display that LightTable had, it has a built-in ClojureScript REPL, support 
> for Socket REPLs (in local and remote processes), and support for 
> shadow-cljs if you’re in the ClojureScript world.
>

Thanks for this; the answer is, no I haven't, but I shall.
 

>
>  
>
> -- 
> You received this message because you are subscribed to the Google
> Groups "Clojure" group.
> To post to this group, send email to clo...@googlegroups.com 
> Note that posts from new members are moderated - please be patient with 
> your first post.
> To unsubscribe from this group, send email to
> clo...@googlegroups.com 
> For more options, visit this group at
> http://groups.google.com/group/clojure?hl=en
> --- 
> You received this message because you are subscribed to the Google Groups 
> "Clojure" group.
> To unsubscribe from this group and stop receiving emails from it, send an 
> email to clo...@googlegroups.com .
> To view this discussion on the web visit 
> https://groups.google.com/d/msgid/clojure/4238247e-5ed7-474b-9905-b697c466b3e5%40googlegroups.com
>  
> 
> .
>
>  
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/clojure/cf5785d7-3c35-4e54-8e85-751294e6482b%40googlegroups.com.


Re: Bit rot and leiningen?

2020-02-05 Thread 'Simon Brooke' via Clojure

On Wednesday, 5 February 2020 09:59:25 UTC, Simon Brooke wrote:

>
> On Tuesday, 4 February 2020 15:56:47 UTC, James Reeves wrote:
>>
>> This may be due to the plugins overriding a dependency that Leiningen 
>> itself needs. There was an issue like this 
>> <https://github.com/weavejester/lein-ring/issues/203> logged with 
>> Lein-Ring, which I notice you're using. Try updating the Lein-Ring version 
>> to 0.12.5 and see if that fixes the issue.
>>
>
> Thanks for this suggestion. Sadly, it doesn't help.
>

OK, I beg your pardon. It seems you were right. Upgrading lein-ring to 
0.12.5 and immediately doing a build did not work, but after a bit of 
tinkering a build did work, and the differences were:

- [com.stuartsierra/component "0.3.2"]
+ [com.stuartsierra/component "0.4.0"]
-[lein-ring "0.8.13" :exclusions [org.clojure/clojure]]]
+[lein-ring "0.12.5" :exclusions [org.clojure/clojure]]]

As Alex Miller suggests, the problem is that something isn't conformant to 
spec, and it isn't something in my code since that runs under Clojure 1.8 
(because I still haven't found a development environment I like better than 
LightTable). So it must be something in a leiningen plugin, so the change 
that worked must have been your change.

Many thanks!

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/clojure/4238247e-5ed7-474b-9905-b697c466b3e5%40googlegroups.com.


Re: Bit rot and leiningen?

2020-02-05 Thread 'Simon Brooke' via Clojure


On Tuesday, 4 February 2020 15:56:47 UTC, James Reeves wrote:
>
> This may be due to the plugins overriding a dependency that Leiningen 
> itself needs. There was an issue like this 
>  logged with 
> Lein-Ring, which I notice you're using. Try updating the Lein-Ring version 
> to 0.12.5 and see if that fixes the issue.
>

Thanks for this suggestion. Sadly, it doesn't help.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
To view this discussion on the web visit 
https://groups.google.com/d/msgid/clojure/48255206-0547-4469-805c-6661083b4673%40googlegroups.com.


Bit rot and leiningen?

2020-02-04 Thread 'Simon Brooke' via Clojure
Hi all

I recently wanted to do some work on a project of mine I've not worked on 
for more than a year, and found to my great surprise that it will no longer 
build. Full details of the bug are here 
, but the core seems to 
be:

clojure.lang.Compiler$CompilerException: Syntax error macroexpanding 
clojure.core/fn at (clojure/core/unify.clj:83:18).
#:clojure.error{:phase :macro-syntax-check, :line 83, :column 18, :source 
"clojure/core/unify.clj", :symbol clojure.core/fn}
 at clojure.lang.Compiler.checkSpecs (Compiler.java:6971)

...

Caused by: clojure.lang.ExceptionInfo: Call to clojure.core/fn did not conform 
to spec.
#:clojure.spec.alpha{:problems ({:path [:fn-tail :arity-1 :params], :pred 
clojure.core/vector?, :val clojure.core.unify/var-unify, :via 
[:clojure.core.specs.alpha/params+body :clojure.core.specs.alpha/param-list 
:clojure.core.specs.alpha/param-list], :in [0]} {:path [:fn-tail :arity-n], 
:pred (clojure.core/fn [%] (clojure.core/or (clojure.core/nil? %) 
(clojure.core/sequential? %))), :val clojure.core.unify/var-unify, :via 
[:clojure.core.specs.alpha/params+body :clojure.core.specs.alpha/params+body], 
:in [0]}), :spec #object[clojure.spec.alpha$regex_spec_impl$reify__2509 
0x7c214cc0 "clojure.spec.alpha$regex_spec_impl$reify__2509@7c214cc0"], :value 
(clojure.core.unify/var-unify [G__813 G__814 G__815 G__816] 
(clojure.core/if-let [vb__806__auto__ (G__816 G__814)] 
(clojure.core.unify/garner-unifiers G__813 vb__806__auto__ G__815 G__816) 
(clojure.core/if-let [vexpr__807__auto__ (clojure.core/and (G__813 G__815) 
(G__816 G__815))] (clojure.core.unify/garner-unifiers G__813 G__814 
vexpr__807__auto__ G__816) (if (clojure.core.unify/occurs? G__813 G__814 G__815 
G__816) (throw (java.lang.IllegalStateException. (clojure.core/str "Cycle found 
in the path " G__815))) (clojure.core.unify/bind-phase G__816 G__814 
G__815), :args (clojure.core.unify/var-unify [G__813 G__814 G__815 G__816] 
(clojure.core/if-let [vb__806__auto__ (G__816 G__814)] 
(clojure.core.unify/garner-unifiers G__813 vb__806__auto__ G__815 G__816) 
(clojure.core/if-let [vexpr__807__auto__ (clojure.core/and (G__813 G__815) 
(G__816 G__815))] (clojure.core.unify/garner-unifiers G__813 G__814 
vexpr__807__auto__ G__816) (if (clojure.core.unify/occurs? G__813 G__814 G__815 
G__816) (throw (java.lang.IllegalStateException. (clojure.core/str "Cycle found 
in the path " G__815))) (clojure.core.unify/bind-phase G__816 G__814 
G__815)}
 at clojure.spec.alpha$macroexpand_check.invokeStatic (alpha.clj:705)

... 


No functions of mine occur anywhere in the stacktrace, but below all the 
clojure compiler functions I get to:

clojure.lang.RestFn.invoke (RestFn.java:408)
leiningen.core.utils$require_resolve.invokeStatic (utils.clj:102)
leiningen.core.utils$require_resolve.invoke (utils.clj:95)
leiningen.core.utils$require_resolve.invokeStatic (utils.clj:105)
leiningen.core.utils$require_resolve.invoke (utils.clj:95)
leiningen.core.main$lookup_task_var.invokeStatic (main.clj:69)
leiningen.core.main$lookup_task_var.invoke (main.clj:65)
leiningen.core.main$pass_through_help_QMARK_.invokeStatic (main.clj:79)
leiningen.core.main$pass_through_help_QMARK_.invoke (main.clj:73)
leiningen.core.main$task_args.invokeStatic (main.clj:82)
leiningen.core.main$task_args.invoke (main.clj:81)
leiningen.core.main$resolve_and_apply.invokeStatic (main.clj:339)
leiningen.core.main$resolve_and_apply.invoke (main.clj:336)
leiningen.core.main$_main$fn__6681.invoke (main.clj:452)
leiningen.core.main$_main.invokeStatic (main.clj:442)
leiningen.core.main$_main.doInvoke (main.clj:439)


The versions of Leiningen I am currently using are `Leiningen 2.9.1 on Java 
1.8.0_242 OpenJDK 64-Bit Server VM` and `Leiningen 2.9.1 on Java 11.0.6 
OpenJDK 64-Bit Server VM`; I don't recall the version I was using a year 
ago. None of the project dependencies have changed, I'm running with this 
project.clj 
, which 
certainly did build thirteen months ago.

My guess is that because my code has not changed, the version of Clojure 
used has not changed, and the dependencies have not changed, the only thing 
which is not controlled for is Leiningen. Has anyone else seen a problem 
like this, and if so how did you cure it?

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send 

Re: Re-frame - on-click handler doesn't work, and I can't understand why not

2018-08-28 Thread 'Simon Brooke' via Clojure
Thanks, yes, that was part of the problem. The other part was failing to 
deref the atom. D'oh!

On Tuesday, 28 August 2018 17:16:00 UTC+1, Matching Socks wrote:
>
> Did you intend to pass a function-that-returns-a-function instead of just 
> a function as the handler? Also, it is a bit odd (maybe it has to do with 
> context you have not shown) to use the big-link component function with () 
> as opposed to square brackets. 

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re-frame - on-click handler doesn't work, and I can't understand why not

2018-08-28 Thread 'Simon Brooke' via Clojure
Hi, I'm stuck...

Consider this function 
<https://github.com/simon-brooke/youyesyet/blob/feature/reflow-app/src/cljs/youyesyet/canvasser_app/ui_utils.cljs#L46>
:

(defn big-link
  [text & {:keys [target handler]}]
  (js/console.log (str "Big link with target '" target "'; handler '" handler 
"'"))
  [:div.big-link-container {:key (gensym "big-link")}
   [:a.big-link (merge {}
  (if target {:href target}{})
  (if handler {:on-click handler}{}))
text]])


You'd think that if you passed it a handler, it would generate an on-click 
attribute on the anchor. It's called (among other places) here 
<https://github.com/simon-brooke/youyesyet/blob/feature/reflow-app/src/cljs/youyesyet/canvasser_app/views/gdpr.cljs#L58>
:

(ui/big-link "I consent"
 :handler #(fn
 []
 (ui/log-and-dispatch
   [:set-consent-and-page
{:elector-id (:id elector)
 :page :elector
 :elector (merge
elector
:signature
(.toDataURL
  sig-pad
  "image/svg+xml")
)}])))


And sure enough, it prints in the console log:

Big link with target ''; handler 'function (){
return ((function (elector){
return (function (){
return youyesyet.canvasser_app.ui_utils.log_and_dispatch.call(null,new 
cljs.core.PersistentVector(null, 2, 5, 
cljs.core.PersistentVector.EMPTY_NODE, [new 
cljs.core.Keyword(null,"set-consent-and-page","set-consent-and-page",-160828440),new
 
cljs.core.PersistentArrayMap(null, 3, [new 
cljs.core.Keyword(null,"elector-id","elector-id",1904559247),new 
cljs.core.Keyword(null,"id","id",-1388402092).cljs$core$IFn$_invoke$arity$1(elector),new
 
cljs.core.Keyword(null,"page","page",849072397),new 
cljs.core.Keyword(null,"elector","elector",-948994537),new 
cljs.core.Keyword(null,"elector","elector",-948994537),cljs.core.merge.call(null,elector,new
 
cljs.core.Keyword(null,"signature","signature",1463754794),youyesyet.canvasser_app.views.gdpr.sig_pad.toDataURL("image/svg+xml"))],
 
null)], null));
});
;})(elector))
}'


But when you click the resulting link, nothing at all happens, and what you 
get when you inspect the generated element, it is:

I consent


So, what am I doing wrong? What do I need to do to get an 'on-click' 
handler working? And, if that's not possible, what's the workaround?

I can't extract the signature from the signature pad at page layout time, 
because the user hasn't yet signed it. It must be extracted when the link 
is selected.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Automatically upversioning a project in continuous integration?

2016-06-14 Thread 'Simon Brooke' via Clojure
Many thanks, googling 'leiningen release tasks' has certainly found me 
interesting things to read and digest.

On Tuesday, 14 June 2016 12:35:57 UTC+1, Alex Miller wrote:
>
>
>
> On Tuesday, June 14, 2016 at 5:21:04 AM UTC-5, Simon Brooke wrote:
>>
>> Apologies if this is a FAQ, I have done a number of searches and not 
>> found anything.
>>
>> I see that the Clojure project's internal Hudson CI server does automatic 
>> upversioning on release builds (see documentation here 
>> <http://dev.clojure.org/display/community/How+to+Make+Releases>). It 
>> doesn't, however, say in that page whether the project.clj file also gets 
>> automatically upversioned, or whether an upversioned SNAPSHOT number is 
>> automatically inserted into the develop branch project.clj. It also doesn't 
>> say how the magic is done (although it looks from the documentation as if 
>> it is just a Maven level, so not very hard to understand).
>>
>
> First note that Clojure contrib builds on Hudson use only Maven, not 
> Leiningen, so the project.clj files (if they exist) are not used. 
> Everything you see happening is standard Maven snapshot release stuff. The 
> version stays at x.y.z-SNAPSHOT (no change is committed to the repo on a 
> snapshot build). A SNAPSHOT version is effectively a "virtual" version 
> number. The release plugin will generate a SNAPSHOT release and set the 
> version number to include a timestamp and a build number and that's what 
> gets published to the maven snapshot repo (see here 
> <https://oss.sonatype.org/content/repositories/snapshots/org/clojure/clojure/1.9.0-master-SNAPSHOT/>
>  
> for example). When retrieving a SNAPSHOT, Maven knows how to find, 
> download, and use the newest version of a SNAPSHOT.
>
> There are additionally some plugins that automatically do version number 
> updating (for released versions), notably 
> http://www.mojohaus.org/versions-maven-plugin/.
>  
>
>> Has anyone made automatic upversioning in project.clj on master builds on 
>> a CI server work, and if so how did you do it? Does your recipe also 
>> upversion the SNAPSHOT number in project.clj in the develop branch?
>>
>
> For leiningen, I'm not quite as familiar. I would hope the Leiningen 
> support for publishing snapshots would follow the same process as expected 
> for Maven snapshot releases and thus would work the same way - generating 
> and publishing timestamped snapshot releases. Seems like Leiningen "release 
> tasks" is what you want to look at as well re automatic bumping for 
> releases.
>  
>
>>
>> Any help gratefully received!
>>
>

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Automatically upversioning a project in continuous integration?

2016-06-14 Thread 'Simon Brooke' via Clojure
Apologies if this is a FAQ, I have done a number of searches and not found 
anything.

I see that the Clojure project's internal Hudson CI server does automatic 
upversioning on release builds (see documentation here 
). It 
doesn't, however, say in that page whether the project.clj file also gets 
automatically upversioned, or whether an upversioned SNAPSHOT number is 
automatically inserted into the develop branch project.clj. It also doesn't 
say how the magic is done (although it looks from the documentation as if 
it is just a Maven level, so not very hard to understand).

Has anyone made automatic upversioning in project.clj on master builds on a 
CI server work, and if so how did you do it? Does your recipe also 
upversion the SNAPSHOT number in project.clj in the develop branch?

Any help gratefully received!

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Removing duplicates from a series

2016-05-17 Thread 'Simon Brooke' via Clojure
Thank you everyone who responded. After looking over the ideas I chose a 
variant on Thomas Mulvaney's suggestion:

(defn consolidate-events
  "Return a time series like this `series`, but without those events whose 
value is
   identical to the value of the preceding event."
  [series]
  (map last (partition-by get-value-for-event series)))


Note last instead of first because I needed the earliest event in each 
value group.

I also very much liked Fluid Dynamics response.

I'm really grateful to you all, this gets me out of a hole!

On Tuesday, 17 May 2016 10:47:06 UTC+1, Simon Brooke wrote:
>
> I'm having trouble with writing a function
>
>1. in idiomatic clojure
>2. which doesn't blow the stack
>
> The problem is I have a time series of events e.g.
>
> ({:idhistory 78758272, :timestamp #inst 
> "2016-03-31T19:34:27.31300-00:00", :nameid 5637, :stringvalue nil, 
> :value 8000.0} 
>  {:idhistory 78756591, :timestamp #inst 
> "2016-03-31T19:33:31.69700-00:00", :nameid 5637, :stringvalue nil, 
> :value 7368.0} 
>  {:idhistory 78754249, :timestamp #inst 
> "2016-03-31T19:32:17.1-00:00", :nameid 5637, :stringvalue nil, 
> :value 6316.0} 
>  {:idhistory 78753165, :timestamp #inst 
> "2016-03-31T19:31:41.84300-00:00", :nameid 5637, :stringvalue nil, 
> :value 5263.0} 
>  {:idhistory 78751187, :timestamp #inst 
> "2016-03-31T19:30:36.21300-00:00", :nameid 5637, :stringvalue nil, 
> :value 4211.0}
>  {:idhistory 78749476, :timestamp #inst 
> "2016-03-31T19:29:41.36300-00:00", :nameid 5637, :stringvalue nil, 
> :value 3158.0} ...)
>
> which is to say, each event is a map, and each event has two critical 
> keys, :timestamp and :value. The series is sorted in descending order by 
> timestamp, i.e. most recent event first. These series are of up to millions 
> of events; the average length of the series is about half a million events. 
> However, many contain successive events at which the value does not change, 
> and where the value doesn't change I want to retain only the first event.
>
> So far what I've got is:
>
> (defn consolidate-events
>   "Return a time series like this `series`, but without those events whose 
> value is
>identical to the value of the preceding event."
>   [series]
>   (let [[car cadr & cddr] series]
> (cond
>   (empty? series) series
>   (=
> (get-value-for-event car)
> (get-value-for-event cadr)) (consolidate-events (rest series))
>   true (cons car (consolidate-events (rest series))
>
>
> Obviously, with millions of events or even merely hundreds of thousands, a 
> recursive function blows the stack. Furthermore, this one isn't even tail 
> call optimisable. I tried creating an inner function which I naively 
> thought should be tail call optimisable, but it fails 'Can only recur from 
> tail position':
>
> (defn consolidate-events
>   "Return a time series like this `series`, but without those events whose 
> value is
>   identical to the value of the preceding event."
>   [series]
>   (remove
> nil?
> (let [inner (fn [series]
>   (let [[car cadr & cddr] series]
> (if
>   (not (empty? series))
>   ;; then
>   (cons
> (if
>   (= (get-value-for-event car)
>  (get-value-for-event cadr))
>   ;; then
>   nil
>   ;; else
>   car)
> (if
>   (not (empty? series))
>   (recur (rest series)))]
> (inner series
>
>
> Test for the function is as follows:
>
> (deftest consolidate-events-test
>   (testing "consolidate-events"
> (let [s1 [{:timestamp #inst "2016-03-31T19:34:27.31300-00:00", 
> :value 8000.0}
>   {:timestamp #inst "2016-03-31T19:33:31.69700-00:00", 
> :value 7368.0}
>   {:timestamp #inst "2016-03-31T19:32:17.1-00:00", 
> :value 6316.0}
>   {:timestamp #inst "2016-03-31T19:31:41.84300-00:00", 
> :value 5263.0}
>   {:timestamp #inst "2016-03-31T19:30:36.21300-00:00", 
> :value 4211.0}
>   {:timestamp #inst "2016-03-31T19:29:41.36300-00:00", 
> :value 3158.0}]
>   s2 [{:timestamp #inst "2016-03-31T19:34:27.31300-00:00", 
> :value 8000.0}
>   {:timestamp #inst "2016

Re: Removing duplicates from a series

2016-05-17 Thread 'Simon Brooke' via Clojure
Oooh, that one is neat.

On Tuesday, 17 May 2016 12:27:29 UTC+1, Thomas Mulvaney wrote:
>
> Rather than writing a new function you could always use something like 
> (map first (partition-by :value events)). partition-by will create lists of 
> events where consecutive values have not changed. You could also assemble a 
> transducer pipeline using the transducer arities of the functions: `(into 
> [] (comp (partition-by :value) (map first)) events)`.
>
> Hope that helps,
>
> Tom
>
> On Tue, May 17, 2016 at 10:47 AM, 'Simon Brooke' via Clojure <
> clo...@googlegroups.com > wrote:
>
>> I'm having trouble with writing a function
>>
>>1. in idiomatic clojure
>>2. which doesn't blow the stack
>>
>> The problem is I have a time series of events e.g.
>>
>> ({:idhistory 78758272, :timestamp #inst 
>> "2016-03-31T19:34:27.31300-00:00", :nameid 5637, :stringvalue nil, 
>> :value 8000.0} 
>>  {:idhistory 78756591, :timestamp #inst 
>> "2016-03-31T19:33:31.69700-00:00", :nameid 5637, :stringvalue nil, 
>> :value 7368.0} 
>>  {:idhistory 78754249, :timestamp #inst 
>> "2016-03-31T19:32:17.1-00:00", :nameid 5637, :stringvalue nil, 
>> :value 6316.0} 
>>  {:idhistory 78753165, :timestamp #inst 
>> "2016-03-31T19:31:41.84300-00:00", :nameid 5637, :stringvalue nil, 
>> :value 5263.0} 
>>  {:idhistory 78751187, :timestamp #inst 
>> "2016-03-31T19:30:36.21300-00:00", :nameid 5637, :stringvalue nil, 
>> :value 4211.0}
>>  {:idhistory 78749476, :timestamp #inst 
>> "2016-03-31T19:29:41.36300-00:00", :nameid 5637, :stringvalue nil, 
>> :value 3158.0} ...)
>>
>> which is to say, each event is a map, and each event has two critical 
>> keys, :timestamp and :value. The series is sorted in descending order by 
>> timestamp, i.e. most recent event first. These series are of up to millions 
>> of events; the average length of the series is about half a million events. 
>> However, many contain successive events at which the value does not change, 
>> and where the value doesn't change I want to retain only the first event.
>>
>> So far what I've got is:
>>
>> (defn consolidate-events
>>   "Return a time series like this `series`, but without those events 
>> whose value is
>>identical to the value of the preceding event."
>>   [series]
>>   (let [[car cadr & cddr] series]
>> (cond
>>   (empty? series) series
>>   (=
>> (get-value-for-event car)
>> (get-value-for-event cadr)) (consolidate-events (rest series))
>>   true (cons car (consolidate-events (rest series))
>>
>>
>> Obviously, with millions of events or even merely hundreds of thousands, 
>> a recursive function blows the stack. Furthermore, this one isn't even tail 
>> call optimisable. I tried creating an inner function which I naively 
>> thought should be tail call optimisable, but it fails 'Can only recur from 
>> tail position':
>>
>> (defn consolidate-events
>>   "Return a time series like this `series`, but without those events 
>> whose value is
>>   identical to the value of the preceding event."
>>   [series]
>>   (remove
>> nil?
>> (let [inner (fn [series]
>>   (let [[car cadr & cddr] series]
>> (if
>>   (not (empty? series))
>>   ;; then
>>   (cons
>> (if
>>   (= (get-value-for-event car)
>>  (get-value-for-event cadr))
>>   ;; then
>>   nil
>>   ;; else
>>   car)
>> (if
>>   (not (empty? series))
>>   (recur (rest series)))]
>> (inner series
>>
>>
>> Test for the function is as follows:
>>
>> (deftest consolidate-events-test
>>   (testing "consolidate-events"
>> (let [s1 [{:timestamp #inst "2016-03-31T19:34:27.31300-00:00", 
>> :value 8000.0}
>>   {:timestamp #inst "2016-03-31T19:33:31.69700-00:00", 
>> :value 7368.0}
>>   {:timestamp #inst "2016-03-31T19:32:17.1-00:00", 
>> :value 6316.0}
>>   {:timestamp #inst "2016-03-31T19:31:41.84300-00:00", 
>

Removing duplicates from a series

2016-05-17 Thread 'Simon Brooke' via Clojure
I'm having trouble with writing a function

   1. in idiomatic clojure
   2. which doesn't blow the stack

The problem is I have a time series of events e.g.

({:idhistory 78758272, :timestamp #inst 
"2016-03-31T19:34:27.31300-00:00", :nameid 5637, :stringvalue nil, 
:value 8000.0} 
 {:idhistory 78756591, :timestamp #inst 
"2016-03-31T19:33:31.69700-00:00", :nameid 5637, :stringvalue nil, 
:value 7368.0} 
 {:idhistory 78754249, :timestamp #inst 
"2016-03-31T19:32:17.1-00:00", :nameid 5637, :stringvalue nil, 
:value 6316.0} 
 {:idhistory 78753165, :timestamp #inst 
"2016-03-31T19:31:41.84300-00:00", :nameid 5637, :stringvalue nil, 
:value 5263.0} 
 {:idhistory 78751187, :timestamp #inst 
"2016-03-31T19:30:36.21300-00:00", :nameid 5637, :stringvalue nil, 
:value 4211.0}
 {:idhistory 78749476, :timestamp #inst 
"2016-03-31T19:29:41.36300-00:00", :nameid 5637, :stringvalue nil, 
:value 3158.0} ...)

which is to say, each event is a map, and each event has two critical keys, 
:timestamp and :value. The series is sorted in descending order by 
timestamp, i.e. most recent event first. These series are of up to millions 
of events; the average length of the series is about half a million events. 
However, many contain successive events at which the value does not change, 
and where the value doesn't change I want to retain only the first event.

So far what I've got is:

(defn consolidate-events
  "Return a time series like this `series`, but without those events whose 
value is
   identical to the value of the preceding event."
  [series]
  (let [[car cadr & cddr] series]
(cond
  (empty? series) series
  (=
(get-value-for-event car)
(get-value-for-event cadr)) (consolidate-events (rest series))
  true (cons car (consolidate-events (rest series))


Obviously, with millions of events or even merely hundreds of thousands, a 
recursive function blows the stack. Furthermore, this one isn't even tail 
call optimisable. I tried creating an inner function which I naively 
thought should be tail call optimisable, but it fails 'Can only recur from 
tail position':

(defn consolidate-events
  "Return a time series like this `series`, but without those events whose 
value is
  identical to the value of the preceding event."
  [series]
  (remove
nil?
(let [inner (fn [series]
  (let [[car cadr & cddr] series]
(if
  (not (empty? series))
  ;; then
  (cons
(if
  (= (get-value-for-event car)
 (get-value-for-event cadr))
  ;; then
  nil
  ;; else
  car)
(if
  (not (empty? series))
  (recur (rest series)))]
(inner series


Test for the function is as follows:

(deftest consolidate-events-test
  (testing "consolidate-events"
(let [s1 [{:timestamp #inst "2016-03-31T19:34:27.31300-00:00", 
:value 8000.0}
  {:timestamp #inst "2016-03-31T19:33:31.69700-00:00", 
:value 7368.0}
  {:timestamp #inst "2016-03-31T19:32:17.1-00:00", 
:value 6316.0}
  {:timestamp #inst "2016-03-31T19:31:41.84300-00:00", 
:value 5263.0}
  {:timestamp #inst "2016-03-31T19:30:36.21300-00:00", 
:value 4211.0}
  {:timestamp #inst "2016-03-31T19:29:41.36300-00:00", 
:value 3158.0}]
  s2 [{:timestamp #inst "2016-03-31T19:34:27.31300-00:00", 
:value 8000.0}
  {:timestamp #inst "2016-03-31T19:33:31.69700-00:00", 
:value 7368.0}
  {:timestamp #inst "2016-03-31T19:33:17.1-00:00", 
:value 6316.0}
  {:timestamp #inst "2016-03-31T19:32:27.1-00:00", 
:value 6316.0}
  {:timestamp #inst "2016-03-31T19:32:17.1-00:00", 
:value 6316.0}
  {:timestamp #inst "2016-03-31T19:31:41.84300-00:00", 
:value 5263.0}
  {:timestamp #inst "2016-03-31T19:30:36.21300-00:00", 
:value 4211.0}
  {:timestamp #inst "2016-03-31T19:29:41.36300-00:00", 
:value 3158.0}]]
  (is (= s1 (consolidate-events s1)) "There are no events in s1 that 
can be consolidated")
  (is (= s1 (consolidate-events s2)) "When consolidated, s2 = s1")
  (is (not (= s2 (consolidate-events s2))) "When consolidated, s2 no 
longer equals s2"


Any help gratefully accepted! 

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at

Re: Serialising/deserialising mixed Clojure and Java datastructures

2016-05-10 Thread 'Simon Brooke' via Clojure
On Tuesday, 10 May 2016 10:11:58 UTC+1, Simon Brooke wrote:
>
> On Monday, 9 May 2016 16:55:59 UTC+1, Alex Miller wrote:
>>
>> Clojure is designed with enough extensibility to modify the printer and 
>> reader to cover this case.
>>
>> You can define a custom print strategy for these types by extending the 
>> print-dup multimethod. If you print it as a tagged literal, you can also 
>> define a custom reader that can read it back as the appropriate type. Or 
>> you can just happen to write it as a form that constructs a Java object if 
>> that's possible. (I don't know the Joda classes well.)
>>
>> Print methods typically look like this:
>>
>> (defmethod print-dup org.joda.time.DateTime
>>   [date-time ^java.io.Writer w]
>>   (.write w (format "#org.joda.time.DateTime[%d]")))
>>
>> That particular format should produce a string like 
>> #org.joda.time.DateTime[1462809085214] which when read will call the 
>> DateTime constructor with the long value. 
>>
>> Or you could write your own custom tagged literal format and define and 
>> install a reader for that tag that refers to a function that does whatever 
>> you need.
>>
>> And I would recommend never using Java serialization in either Clojure or 
>> Java. :) 
>>
>
> Fair enough, thanks. I looked for printer macros in the documentation but 
> didn't find them; I didn't think of multimethods. 
>
> Thanks again.
>

Right. I investigated the nippy library but it too needs work to read and 
write joda time objects, and I didn't have anything to go on (and I'm under 
time pressure) so I left it.

Following Alex Miller's advice above and making use of an excellent blog at 
http://proofbyexample.com/print-and-read-in-clojure.html I solved the 
problem as follows:

(ns opsdata.persistence
  "Serialising/deserialsing mixed Clojure/JodaTime data.")

;; I made use of the advice at 
http://proofbyexample.com/print-and-read-in-clojure.html
;; in writing this file.

;; Make it possible to print joda DateTime instances in re-readable form, 
for persistence.
(defmethod print-dup org.joda.time.DateTime
  [dt out]
  (.write out (str "#=" `(org.joda.time.DateTime. ~(.getMillis dt) 
~org.joda.time.DateTimeZone/UTC


;; Make it possible to print joda Interval instances in re-readable form, 
for persistence.
(defmethod print-dup org.joda.time.Interval
  [value out]
  (.write out (str "#=" `(org.joda.time.Interval. ~(.getStartMillis value) 
~(.getEndMillis value) ~org.joda.time.DateTimeZone/UTC


;; Make it possible to print joda DateTimeZone instances in re-readable 
form, for persistence.
(defmethod print-dup org.joda.time.DateTimeZone
  [value out]
  (.write out (str "#=" `(org.joda.time.DateTimeZone/forID ~(.getID 
value)


(defn persist-to-file
  "Persist this `value` in the file at this `file-path`."
  [value file-path]
  (binding
[*print-dup* true]
(spit file-path (with-out-str (pr value)


(defn recover-from-file
  "Read a persisted value from this `file-path`."
  [file-path]
  (binding
[*read-eval* true]
(read-string (slurp file-path

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Serialising/deserialising mixed Clojure and Java datastructures

2016-05-10 Thread 'Simon Brooke' via Clojure
On Monday, 9 May 2016 16:55:59 UTC+1, Alex Miller wrote:
>
> Clojure is designed with enough extensibility to modify the printer and 
> reader to cover this case.
>
> You can define a custom print strategy for these types by extending the 
> print-dup multimethod. If you print it as a tagged literal, you can also 
> define a custom reader that can read it back as the appropriate type. Or 
> you can just happen to write it as a form that constructs a Java object if 
> that's possible. (I don't know the Joda classes well.)
>
> Print methods typically look like this:
>
> (defmethod print-dup org.joda.time.DateTime
>   [date-time ^java.io.Writer w]
>   (.write w (format "#org.joda.time.DateTime[%d]")))
>
> That particular format should produce a string like 
> #org.joda.time.DateTime[1462809085214] which when read will call the 
> DateTime constructor with the long value. 
>
> Or you could write your own custom tagged literal format and define and 
> install a reader for that tag that refers to a function that does whatever 
> you need.
>
> And I would recommend never using Java serialization in either Clojure or 
> Java. :) 
>

Fair enough, thanks. I looked for printer macros in the documentation but 
didn't find them; I didn't think of multimethods. 

Thanks again.

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Serialising/deserialising mixed Clojure and Java datastructures

2016-05-09 Thread 'Simon Brooke' via Clojure
I'm working on some complex analysis where it takes about twelve hours to 
construct the model to be analysed. Once it's constructed I'm doing various 
interactive things to explore it, but I can't currently persist it in a 
form in which it can be read back in, so that when the REPL session ends it 
is lost and I need to run the construction process again.

When I was creating the system I had thought, airily, 'well, Clojure is 
Lisp so all I need to do is spit the structure out to a file and slurp it 
back in again'. Unfortunately, of course, Clojure is only mostly Lisp.

My problem is clj-time objects, both date-time and interval. These are 
essentially Joda time objects, and when they are printed, what you get is a 
string representation of an object reference. When the reader reads it 
back, what you have is a string:

user=> (def foo (tc/now))

#'user/foo

user=> (spit "/tmp/saved-time" (with-out-str (pr foo)))

nil

user=> (def bar (slurp "/tmp/saved-time"))

#'user/bar

user=> (= foo bar)

false

user=> (type foo)

org.joda.time.DateTime

user=> (type bar)

java.lang.String


So, my question: in this particular case, what is the simplest means of 
writing my data structures (which, apart from the clj-time objects, 
comprises deeply nested maps of keywords, strings and numbers - all things 
which the Clojure reader and writer can cope with) to disk in a form in 
which they can subsequently be read back?


There are two obvious solutions: one is to have a function which walks the 
data structure and returns an equivalent data structure in which each 
clj-time object is replaced by a function invocation which when invoked 
creates an equivalent clj-time object; the other is to use Java 
serialisation to serialise the whole structure as in the answer to this 
stackoverflow question 

.


Which of these would people go for? Or is there some other solution I have 
not thought of?

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
"Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Can anyone recommend a tutorial or blog post on porting existing Clojure program to ClojureScript?

2015-08-06 Thread Simon Brooke
Hi

I have an existing Clojure program which is intended for use in classroom 
situations to teach kids about ecology and computer science. You can see it 
in action here http://www.journeyman.cc/microworld/ (but please don't use 
any but the basic map, since several users using bigger maps at once breaks 
my poor server); source code is here: engine 
https://github.com/simon-brooke/mw-engine, parser 
https://github.com/simon-brooke/mw-parser, user interface 
https://github.com/simon-brooke/mw-ui.

The problem with it is that it runs server side, and is fairly compute 
intensive - especially if many users connect at once. Furthermore, one user 
with a large map or a really complex rule can kill the performance of the 
server for everyone else. If I could move the engine client side it would 
enable one server to easily support a full classroom of users, which would 
make it far more practical; if I could move the parser client side as well 
one server could support very large numbers of users.

So I'm looking for something which gives me a 'how-to' on porting the code 
across. Any recommendations?

Thanks

Simon

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Can anyone recommend a tutorial or blog post on porting existing Clojure program to ClojureScript?

2015-08-06 Thread Simon Brooke
Thank you, that's very helpful.

On Thursday, 6 August 2015 08:50:01 UTC+1, Pedro Pereira Santos wrote:

 Hello,

 I did something similar, but my engine is pure clojure (no IO).

 https://medium.com/@donbonifacio/running-clojure-code-on-javascript-e1f37071e69e

 Best regards

 On Thu, Aug 6, 2015 at 8:01 AM, Simon Brooke stil...@googlemail.com 
 javascript: wrote:

 Hi

 I have an existing Clojure program which is intended for use in classroom 
 situations to teach kids about ecology and computer science. You can see it 
 in action here http://www.journeyman.cc/microworld/ (but please don't 
 use any but the basic map, since several users using bigger maps at once 
 breaks my poor server); source code is here: engine 
 https://github.com/simon-brooke/mw-engine, parser 
 https://github.com/simon-brooke/mw-parser, user interface 
 https://github.com/simon-brooke/mw-ui.

 The problem with it is that it runs server side, and is fairly compute 
 intensive - especially if many users connect at once. Furthermore, one user 
 with a large map or a really complex rule can kill the performance of the 
 server for everyone else. If I could move the engine client side it would 
 enable one server to easily support a full classroom of users, which would 
 make it far more practical; if I could move the parser client side as well 
 one server could support very large numbers of users.

 So I'm looking for something which gives me a 'how-to' on porting the 
 code across. Any recommendations?

 Thanks

 Simon

 -- 
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clo...@googlegroups.com 
 javascript:
 Note that posts from new members are moderated - please be patient with 
 your first post.
 To unsubscribe from this group, send email to
 clojure+u...@googlegroups.com javascript:
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 --- 
 You received this message because you are subscribed to the Google Groups 
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an 
 email to clojure+u...@googlegroups.com javascript:.
 For more options, visit https://groups.google.com/d/optout.




 -- 
 Pedro Santos
 Home - http://psantos.zi-yu.com


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Stack overflow while compiling...?

2015-04-14 Thread Simon Brooke
I'm persistently getting this. Annoyingly, it happens a long way through a 
very big computation:

CompilerException java.lang.StackOverflowError, 
compiling:(/tmp/form-init8817362891013362767.clj:1:1)

The content of file /tmp/form-init8817362891013362767.clj being compiled is 
this:

(.deleteOnExit (java.io.File. /tmp/form-init8817362891013362767.clj)) (do 
(set! *warn-on-reflection* nil) (require (quote gorilla-repl.core)) 
(gorilla-repl.core/run-gorilla-server {:ip 127.0.0.1, :port 0, 
:nrepl-port 0, :project mw-explore, :gorilla-options nil, :version 
0.3.4}))

I get the same error (although, obviously, not quite the same tmp file) 
when I run at the repl rather than with Gorilla. The stacktrace does not 
touch any file of mine.

The actual file of my own I'm evaluating is this:

https://github.com/simon-brooke/mw-explore/blob/master/src/mw_explore/mw_explore.clj

And it's calling into this library:

https://github.com/simon-brooke/mw-engine

And specifically, it's mainly exercising drainage:

https://github.com/simon-brooke/mw-engine/blob/master/src/mw_engine/drainage.clj

I acknowledge that this is a deep and nasty bit of algorithm, but the only 
thing I can think of that would cause a stack overflow while compiling 
would be an accidentally-recursive macro - and I'm not getting any of my 
own macros.

This problem started after I introduced three new functions:

(defn is-hollow
  Detects point hollows - that is, individual cells all of whose 
neighbours 
   are higher. Return true if this `cell` has an altitude lower than any of 
   its neighbours in this `world` 
  [world cell]
  ;; quicker to count the elements of the list and compare equality of 
numbers
  ;; than recursive equality check on members, I think. But worth 
benchmarking.
  (let [neighbours (get-neighbours world cell)
altitude (or (:altitude cell) 0)]
(= (count neighbours)
   (count (get-neighbours-with-property-value 
world (:x cell) (:y cell) 1 :altitude )

(defn flood-hollow
  Raise the altitude of a copy of this `cell` of this `world` to the 
altitude  
   of the lowest of its `neighbours`.
  ([world cell neighbours]
(let [lowest (get-least-cell neighbours :altitude)]
  (merge cell {:state :water :altitude (:altitude lowest)})))
  ([world cell]
(flood-hollow world cell (get-neighbours world cell

(defn flood-hollows 
  Flood all local hollows in this `world`. At this stage only floods single
   cell hollows.
  [world]
  (map-world world 
 #(if (is-hollow %1 %2) (flood-hollow %1 %2) %2)))

However at the stage the problem occurs, these functions have evaluated 
successfully, and am into the flow-world stage, which previously worked 
reliably.

Has anyone seen anything analogous? Any pointers as to what I might be 
doing wrong?


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Given a list of maps, produce a sublist having distinct values for one key

2015-04-06 Thread Simon Brooke
Sorry to be so slow getting back. Because they are maps, and a set can 
contain many maps which contain identical key value pairs - I assume 
because although they do indeed have identical key value pairs they are 
nevertheless not the same map.

On Tuesday, 24 March 2015 21:55:05 UTC, Ben wrote:

 why not just accumulate the interested customers in a set rather than a 
 seq in the first place?

 On Tue, Mar 24, 2015 at 2:50 PM, Simon Brooke stil...@googlemail.com 
 javascript: wrote:

 I'm rewriting a very odd e-commerce website I first wrote in 1996, for a 
 friend.

 The website features categories, which are supposed to be arranged into 
 an acyclic directed graph (actually there are currently cycles in the 
 graph, but there shouldn't be, and that is not the problem I'm trying to 
 solve here; assume there are not). Customers can register interest in a 
 category or in several categories. When an item is added to the site, we 
 want to email every customer who may be interested in that item; which is 
 to say 

 customers who are interested in the category to which the item has been 
 added, and
 customers who are interested in the parent of that category, and
 so on recursively to the root of the graph.

 Now, I can recurse up the graph asking each category in turn for the 
 customers interested in it; and by concatenating the lists, arrive at one 
 list of all the interested customers. The problem is that if one customer 
 has registered interest in both a category and its parent, he will appear 
 on the composite list twice. I need to construct from this a list of 
 records in which each customer appears only once, otherwise they'll receive 
 duplicate emails, which no-one likes.

 My solution, which I give below, is to recurse across the composite list 
 constructing a map whose keys are email addresses and whose values are the 
 customer records as maps; and then to take the values of that map. It 
 works, but it doesn't feel like idiomatic clojure:

 (defn map-by-key
   From this `list-of-maps`, produce a map keyed on the values for this 
 `key`
   [list-of-maps key]
   (if (empty? list-of-maps) {}
 (let [record (first list-of-maps)]
   (merge {(record key) record} (map-by-key (rest list-of-maps) 
 key)
 

 (defn interested-customers
   Return a list of the customers interested in the category with this
`category-id`. Recurses up the tree of categories; `path` is passed to
protect against cycles in the tree (which shouldn't be there by are
not impossible)
   ([category-id]
(vals (map-by-key (interested-customers category-id #{}) :email)))
   ([category-id path]
(if (contains? path category-id) ()   
 (let
   [id (if (integer? category-id) category-id
 (Integer/valueOf (str category-id)))
category (categories/fetch id)
parent (:parent category)
upstream (if (not (nil? parent)) (interested-customers parent 
 (conj path id)) ())
interested (select schema/customer
   (with schema/category
 (where {:id id})))]
   (concat interested upstream)

 Can anyone re-express that in a more idiomatic form?

 -- 
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to clo...@googlegroups.com 
 javascript:
 Note that posts from new members are moderated - please be patient with 
 your first post.
 To unsubscribe from this group, send email to
 clojure+u...@googlegroups.com javascript:
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 --- 
 You received this message because you are subscribed to the Google Groups 
 Clojure group.
 To unsubscribe from this group and stop receiving emails from it, send an 
 email to clojure+u...@googlegroups.com javascript:.
 For more options, visit https://groups.google.com/d/optout.




 -- 
 Ben Wolfson
 Human kind has used its intelligence to vary the flavour of drinks, which 
 may be sweet, aromatic, fermented or spirit-based. ... Family and social 
 life also offer numerous other occasions to consume drinks for pleasure. 
 [Larousse, Drink entry]

  

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Given a list of maps, produce a sublist having distinct values for one key

2015-03-24 Thread Simon Brooke
I'm rewriting a very odd e-commerce website I first wrote in 1996, for a 
friend.

The website features categories, which are supposed to be arranged into an 
acyclic directed graph (actually there are currently cycles in the graph, 
but there shouldn't be, and that is not the problem I'm trying to solve 
here; assume there are not). Customers can register interest in a category 
or in several categories. When an item is added to the site, we want to 
email every customer who may be interested in that item; which is to say 

customers who are interested in the category to which the item has been 
added, and
customers who are interested in the parent of that category, and
so on recursively to the root of the graph.

Now, I can recurse up the graph asking each category in turn for the 
customers interested in it; and by concatenating the lists, arrive at one 
list of all the interested customers. The problem is that if one customer 
has registered interest in both a category and its parent, he will appear 
on the composite list twice. I need to construct from this a list of 
records in which each customer appears only once, otherwise they'll receive 
duplicate emails, which no-one likes.

My solution, which I give below, is to recurse across the composite list 
constructing a map whose keys are email addresses and whose values are the 
customer records as maps; and then to take the values of that map. It 
works, but it doesn't feel like idiomatic clojure:

(defn map-by-key
  From this `list-of-maps`, produce a map keyed on the values for this 
`key`
  [list-of-maps key]
  (if (empty? list-of-maps) {}
(let [record (first list-of-maps)]
  (merge {(record key) record} (map-by-key (rest list-of-maps) key)


(defn interested-customers
  Return a list of the customers interested in the category with this
   `category-id`. Recurses up the tree of categories; `path` is passed to
   protect against cycles in the tree (which shouldn't be there by are
   not impossible)
  ([category-id]
   (vals (map-by-key (interested-customers category-id #{}) :email)))
  ([category-id path]
   (if (contains? path category-id) ()   
(let
  [id (if (integer? category-id) category-id
(Integer/valueOf (str category-id)))
   category (categories/fetch id)
   parent (:parent category)
   upstream (if (not (nil? parent)) (interested-customers parent (conj 
path id)) ())
   interested (select schema/customer
  (with schema/category
(where {:id id})))]
  (concat interested upstream)

Can anyone re-express that in a more idiomatic form?

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Odd bug, apparently in ring.middleware or clojure.core.memoize?

2014-11-14 Thread Simon Brooke
Thank you very much for the suggestion. I believe that your diagnosis is 
correct; unfortunately, your solution does not work. Furthermore, even if I 
remove the dependency on clj-jgit and all references to it from my code, do 
a 'lein clean', and rebuild, I still get the same error on startup 
(although my application does start and run, which it didn't before).

What does work is if I clone scm-jgit, update its dependency 
to [org.clojure/core.memoize 0.5.6] and its version to '0.8.2-SNAPSHOT', 
build it with 'lein install', and then build my own application, then 
everything works fine. I can't really, though, distribute a project based 
on an unsupported version on someone else's project.

I'll try sending a project.clj diff to the maintainers of clj-jgit, and see 
if they'll accept it.

This feels remarkably like DLL Hell :-(

On Thursday, 13 November 2014 22:56:17 UTC, James Reeves wrote:

 The problem is that your dependency tree pulls in core.memoize 0.5.3, but 
 other libraries have a dependency on 0.5.6. If you run lein deps :tree 
 you can see this for yourself:

 [clj-jgit 0.8.1] - [org.clojure/core.memoize 0.5.3]
  overrides
 [lib-noir 0.9.4] - [ring-middleware-format 0.4.0] - 
 [org.clojure/core.memoize 0.5.6]

 Maven dependency management is a little odd. Closer dependencies are 
 preferred, even if their version number is lower, so the memoize library 
 pulled in my clj-jgit is preferred over the one pulled in indirectly by 
 lib-noir.

 The reason it works on your laptop might be something to do with your 
 profiles.clj. Perhaps you have a plugin that pulls in the core.memoize 
 0.5.6 dependency, which causes everything to work.

 The solution to this is to add in an explicit dependency for core.memoize 
 0.5.6 in your project file. This will ensure you have the latest version. 
 You may also want to do something about all the other conflicts you have in 
 the dependency tree...

 - James


 On 13 November 2014 22:26, Simon Brooke stil...@googlemail.com 
 javascript: wrote:

 Hi everyone

 Yesterday I proudly announced my new Wiki engine; today I'm investigating 
 an odd bug which prevents it compiling on some Ubuntu machines, but not my 
 laptop (on which I did the development), and I'm really puzzled by it.

 Top level outline:

 When one clones the repository from 
 https://github.com/simon-brooke/smeagol.git and then invokes

 lein repl

 (or lein ring uberwar, lein ring server, and so on) one gets an odd bug.

 If one does simple 'lein repl', one gets an error message 
 '#CompilerException 
 java.lang.IllegalAccessError: lu does not exist, 
 compiling:(ring/middleware/format_response.clj:1:1)'; if one then does

 smeagol.repl= (ns smeagol.repl
   #_=   (:use smeagol.handler
   #_= ring.server.standalone
   #_= [ring.middleware file-info file]))

 one gets

 CompilerException java.lang.IllegalAccessError: lu does not exist, 
 compiling:(ring/middleware/format_response.clj:1:1) 

 If one instead does

 lein ring server

 one gets a full stacktrace, which I'll append at the end of this post. 
 However, the diagnosis as far as I've got goes like this:

 The file ring/middleware/format_response.clj 
 https://github.com/ngrunwald/ring-middleware-format/blob/master/src/ring/middleware/format_response.clj
  
 starts with this expression:

 (ns ring.middleware.format-response (:require [cheshire.core :as json] [
 ring.util.response :as res] [clojure.java.io :as io] [clj-yaml.core :as 
 yaml] [clojure.string :as s] [cognitect.transit :as transit]) (:use [
 clojure.core.memoize :only [lu]]) (:import [java.io File InputStream 
 BufferedInputStream ByteArrayOutputStream] [java.nio.charset Charset]))

 I've highlighted the sub-expression I'm suspicious of.

 Looking at clojure/core/memoize.clj 
 https://github.com/clojure/core.memoize/blob/master/src/main/clojure/clojure/core/memoize.clj,
  
 there is both '(def-deprecated lu ...)' (line 373) and '(defn lu ...)' 
 (line 384). I'm not sure what is going on there, and I'm even more 
 confused that the deprecation comment says

 (def-deprecated lu DEPRECATED: Please use clojure.core.memoize/lu 
 instead. 
 Given that this is in the namespace clojure.core.memoize, that comment 
 doesn't make sense to me - I'm obviously missing something. My guess that 
 the namespace clojure.core.memoize should be provided by the jar 
 clojure-1.6.0.jar seems to be correct:

 simon@fletcher:~/workspace/smeagol$ jar tvf 
 /home/simon/.m2/repository/org/clojure/clojure/1.6.0/clojure-1.6.0.jar | 
 grep memoize
 1055 Tue Mar 25 08:45:06 GMT 2014 clojure/core$memoize.class
 1708 Tue Mar 25 08:45:06 GMT 2014 clojure/core$memoize$fn__5097.class


 On both the machines on which Smeagol works, and on the machines on which 
 Smeagol does not work, the file size of clojure.1.0.jar is 3664472 bytes 
 and the MD5 sum is fdbad523e92cb53e61484106431d4489, so it's not the case 
 that I've got different versions

Re: If code is data why do we use text editors?

2014-11-14 Thread Simon Brooke
I wrote a couple of blog-posts on this topic - On Editing, and Clojure 
http://blog.journeyman.cc/2013/09/on-editing-and-clojure.html, and Editing 
and clojure revisited: this time, with structure! 
http://blog.journeyman.cc/2013/09/yesterday-i-blogged-on-editing-clojure.html 
I 
also wrote a bit of (very simple) code here 
https://github.com/simon-brooke/fedit.

The big lisp systems of the past often used in-core editors - the little 
toy editor I wrote is based on the editor in BBC Lisp, which in turn was 
based on the editor in Portable Standard Lisp. InterLisp had a much more 
powerful, graphical in-core editor called dedit.

You might also find this document 
http://www.ics.uci.edu/~andre/ics228s2006/teitelmanmasinter.pdf 
interesting.

On Friday, 14 November 2014 12:42:57 UTC, Thomas Huber wrote:

 Hi, here is an idea that has been in my mind for a while. I wonder what 
 you think about it.


 In Clojure code is data, right? But when we program we manipulate flat 
 text files, not the data directly.

 Imagine your source code where a data structure (in memory). And 
 programming is done by manipulating this data structure. No text editor and 
 text files involved. 

 Your editor directly manipulates the source data and later saves it on 
 disk (maybe as a text file). 


 These are the benefits I can think of:

  - It enables you to use any Clojure function to manipulate your source 
 „code“. Giving you hole new opportunities for refactoring.This functions 
 can be provides as library. 


 - Really nice auto complete. 


 - Visual programming. Source code can be represented in many different 
 ways (not just text) . The easiest example I can think of is color. It can 
 be represented as text of course (#23FF02)

 but that’s a quite bad interface for humans. Why not display the actual 
 color and provide a color picker? Or what about music notes? Or Math 
 formulars? Or what about a tree view to move and rename functions like 
 files? 

 This could all be implemented in a way that every library can ship there 
 own „views“. I think this „views“ are basically macros that are not limited 
 to text. 


 - You don’t have to worry that you text files are in the same state as 
 your JVM (when developing interactive). You only work on your sourcedata 
 and it gets loaded into the JVM automatically.


 - Answer questions about your source code. What is the most called 
 function? Who depends on this namespace? Where is this function used? What 
 is the biggest function? Thinks like that become easy. Again you can ship 
 this queries as a library.




 The drawback is you can’t simply program using any text editor. You need a 
 special tool. But we have that anyway (syntax highlighting, paredit etc.). 
 Nobody programs using a bare text editor. 


 Maybe this idea is not new? What do you think?


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: [ANN] Release 0.29.1 of Counterclockwise

2014-11-14 Thread Simon Brooke
Unfortunately your website at http://doc.ccw-ide.org/ 
http://doc.ccw-ide.org/documentation.html#_install_counterclockwise appears 
to be down.

On Thursday, 13 November 2014 15:00:52 UTC, Laurent PETIT wrote:

 Counterclockwise, the Eclipse Clojure development tool.

 Counterclockwise 0.29.1 has been released.

 Fixes bugs of the 0.29.0 version.


 ChangeLog
 =


 http://doc.ccw-ide.org/ChangeLog.html#_changes_between_counterclockwise_0_29_0_and_0_29_1

 Installation instructions
 ==

 http://doc.ccw-ide.org/documentation.html#_install_counterclockwise

 Cheers,


 -- 
 Laurent Petit
  

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Odd bug, apparently in ring.middleware or clojure.core.memoize?

2014-11-13 Thread Simon Brooke
Hi everyone

Yesterday I proudly announced my new Wiki engine; today I'm investigating 
an odd bug which prevents it compiling on some Ubuntu machines, but not my 
laptop (on which I did the development), and I'm really puzzled by it.

Top level outline:

When one clones the repository from 
https://github.com/simon-brooke/smeagol.git and then invokes

lein repl

(or lein ring uberwar, lein ring server, and so on) one gets an odd bug.

If one does simple 'lein repl', one gets an error message '#CompilerException 
java.lang.IllegalAccessError: lu does not exist, 
compiling:(ring/middleware/format_response.clj:1:1)'; if one then does

smeagol.repl= (ns smeagol.repl
  #_=   (:use smeagol.handler
  #_= ring.server.standalone
  #_= [ring.middleware file-info file]))

one gets

CompilerException java.lang.IllegalAccessError: lu does not exist, 
compiling:(ring/middleware/format_response.clj:1:1) 

If one instead does

lein ring server

one gets a full stacktrace, which I'll append at the end of this post. 
However, the diagnosis as far as I've got goes like this:

The file ring/middleware/format_response.clj 
https://github.com/ngrunwald/ring-middleware-format/blob/master/src/ring/middleware/format_response.clj
 
starts with this expression:

(ns ring.middleware.format-response (:require [cheshire.core :as json] [ring
.util.response :as res] [clojure.java.io :as io] [clj-yaml.core :as yaml] [
clojure.string :as s] [cognitect.transit :as transit]) (:use [clojure.core.
memoize :only [lu]]) (:import [java.io File InputStream BufferedInputStream 
ByteArrayOutputStream] [java.nio.charset Charset]))

I've highlighted the sub-expression I'm suspicious of.

Looking at clojure/core/memoize.clj 
https://github.com/clojure/core.memoize/blob/master/src/main/clojure/clojure/core/memoize.clj,
 
there is both '(def-deprecated lu ...)' (line 373) and '(defn lu ...)' 
(line 384). I'm not sure what is going on there, and I'm even more confused 
that the deprecation comment says

(def-deprecated lu DEPRECATED: Please use clojure.core.memoize/lu instead. 
Given that this is in the namespace clojure.core.memoize, that comment 
doesn't make sense to me - I'm obviously missing something. My guess that 
the namespace clojure.core.memoize should be provided by the jar 
clojure-1.6.0.jar seems to be correct:

simon@fletcher:~/workspace/smeagol$ jar tvf 
/home/simon/.m2/repository/org/clojure/clojure/1.6.0/clojure-1.6.0.jar | 
grep memoize
1055 Tue Mar 25 08:45:06 GMT 2014 clojure/core$memoize.class
1708 Tue Mar 25 08:45:06 GMT 2014 clojure/core$memoize$fn__5097.class


On both the machines on which Smeagol works, and on the machines on which 
Smeagol does not work, the file size of clojure.1.0.jar is 3664472 bytes 
and the MD5 sum is fdbad523e92cb53e61484106431d4489, so it's not the case 
that I've got different versions of Clojure. Likewise the filesize of 
/home/simon/.m2/repository/ring-middleware-format/ring-middleware-format/0.4.0/ring-middleware-format-0.4.0.jar
 
is 14366 bytes and the MD5 sum is 38b9850a38bd9ee5eb3321c73cada73c both on 
working and on non working installations.

I've pulled the source for ring-middleware-format from 
https://github.com/ngrunwald/ring-middleware-format.git 
- it compiles without complaint (but is a slightly later version than the 
0.4.0 build, it's 0.4.1-SNAPSHOT).

Oh, and (having made a backup, fortunately) I've done a 'lein clean; lein 
ring server' on my development machine and established that it now also has 
the bug. There is literally nothing that is not either in the git-ignore 
file or else in git.

In short, I'm stuck and puzzled. I don't think this is my bug, but I'm 
prepared to believe it could be. I don't understand why the bug appears in 
a clean checkout, but doesn't occur in my development directory. I'm not 
yet confident enough that it's someone else's bug to post an issue on their 
repository. Any help you can give would be extremely welcome!

My .git-ignore is as follows:

smeagol.log
pom.xml
pom.xml.asc
*jar
/lib/
/classes/
/target/
/checkouts/
/resources/public/content/.git
.lein-deps-sum
.lein-repl-history
.lein-plugins/
.lein-failures
.lein-env


My project.clj is as follows:

(defproject smeagol 0.2.0-SNAPSHOT
:description A simple Git-backed Wiki inspired by Gollum
:url http://example.com/FIXME;
:dependencies [[org.clojure/clojure 1.6.0]
[lib-noir 0.9.4 :exclusions [org.clojure/core.memoize 
org.clojure/tools.reader]]
[ring-server 0.3.1]
[selmer 0.7.2]
[com.taoensso/timbre 3.3.1 :exclusions [org.clojure/tools.reader]]
[com.taoensso/tower 3.0.2 :exclusions [com.taoensso/encore]]
[markdown-clj 0.9.55 :exclusions [com.keminglabs/cljx]]
[clj-jgit 0.8.1]
[environ 1.0.0]
[im.chit/cronj 1.4.2]
[noir-exception 0.2.2]
[prone 0.6.0]]
 :repl-options {:init-ns smeagol.repl}
:jvm-opts [-server]
:plugins [[lein-ring 0.8.13 :exclusions [org.clojure/clojure]]
[lein-environ 1.0.0]
[lein-ancient 0.5.5 :exclusions [org.clojure

Re: Announcing Smeagol, a very simple wiki engine inspired by Gollum

2014-11-13 Thread Simon Brooke
And... while it still works on my development machine, there's a bug if you 
check it out from gihub and try to build it. It fails with

#CompilerException java.lang.IllegalAccessError: lu does not exist, 
compiling:(ring/middleware/format_response.clj:1:1)


I know about this issue and am trying to fix it, but so far no joy. Any 
help or advice most welcome!

On Tuesday, 11 November 2014 21:55:00 UTC, Simon Brooke wrote:

 And now the Git integration does exist and does work. Clojure is such a 
 joy - a complete functional Wiki engine in less than eight hours actual 
 coding! Obviously it's alpha quality, and could definitely be improved, but 
 it works now.

 On Tuesday, 11 November 2014 18:00:18 UTC, Simon Brooke wrote:

 For a project recently I needed a wiki engine which was simple and easily 
 backed up, but which had authentication. I very much liked Gollum 
 https://github.com/gollum/gollum/wiki, but it does not have 
 authentication, and I thought it would be simpler for me to write a wiki 
 engine from scratch in Clojure than to modify Gollum. So here is Smeagol 
 https://github.com/simon-brooke/smeagol.

 It works now, but the security is pretty crude at this stage and the Git 
 integration which I plan does not yet exist. Feel free to fork or adapt, or 
 just use; any fixes or feedback welcome.



-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Announcing Smeagol, a very simple wiki engine inspired by Gollum

2014-11-11 Thread Simon Brooke
For a project recently I needed a wiki engine which was simple and easily 
backed up, but which had authentication. I very much liked Gollum 
https://github.com/gollum/gollum/wiki, but it does not have 
authentication, and I thought it would be simpler for me to write a wiki 
engine from scratch in Clojure than to modify Gollum. So here is Smeagol 
https://github.com/simon-brooke/smeagol.

It works now, but the security is pretty crude at this stage and the Git 
integration which I plan does not yet exist. Feel free to fork or adapt, or 
just use; any fixes or feedback welcome.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Announcing Smeagol, a very simple wiki engine inspired by Gollum

2014-11-11 Thread Simon Brooke
And now the Git integration does exist and does work. Clojure is such a joy 
- a complete functional Wiki engine in less than eight hours actual coding! 
Obviously it's alpha quality, and could definitely be improved, but it 
works now.

On Tuesday, 11 November 2014 18:00:18 UTC, Simon Brooke wrote:

 For a project recently I needed a wiki engine which was simple and easily 
 backed up, but which had authentication. I very much liked Gollum 
 https://github.com/gollum/gollum/wiki, but it does not have 
 authentication, and I thought it would be simpler for me to write a wiki 
 engine from scratch in Clojure than to modify Gollum. So here is Smeagol 
 https://github.com/simon-brooke/smeagol.

 It works now, but the security is pretty crude at this stage and the Git 
 integration which I plan does not yet exist. Feel free to fork or adapt, or 
 just use; any fixes or feedback welcome.


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Having a package visible in the environment in which generated code is compiled?

2014-07-07 Thread Simon Brooke
Answering myself, the solution has been to do a (use 'mw-engine.utils) in 
the immediate evaluation environment - just in the same file isn't enough. 
So I've written a function

(defn compile-rule 
  Parse this `rule-text`, a string conforming to the grammar of MicroWorld 
rules,
   into Clojure source, and then compile it into an anonymous
   function object, getting round the problem of binding mw-engine.utils in
   the compiling environment.
  [rule-text]
  (do
(use 'mw-engine.utils)
(eval (parse-rule rule-text  


This works!

On Saturday, 5 July 2014 14:10:33 UTC+1, Simon Brooke wrote:

 I am trying to write a domain-specific production rule language which is 
 compiled down at run-time into Clojure code. It's intended that the rule 
 language should be usable by primary school children with little help.

 So far it's going extremely well, except for one problem. If I run it in 
 the REPL, like this, it works:


 user= (use 'mw-parser.core :reload)
 nil
 user= (use 'mw-engine.utils)
 nil
 user= (parse-rule if state is forest and fertility is between 55 and 75 
 then state should be climax)
 (fn [cell world] (if (and (= (:state cell) :forest) (or ( 55 (get-int 
 cell :fertility) 75) ( 55 (get-int cell :fertility) 75))) (merge cell 
 {:state :climax})))
 user= (eval *1)
 #user$eval1839$fn__1840 user$eval1839$fn__1840@7a52b16b
 user= (apply *1 (list {:state :forest :fertility 60} nil))
 {:state :climax, :fertility 60}
 user= 


 However, I have a test as follows:

 ns mw-parser.core-test
   (:use mw-engine.utils)
   (:require [clojure.test :refer :all]
 [mw-parser.core :refer :all]))

 (deftest rules-tests
   (testing if altitude is less than 100 and state is forest then state 
 should be climax and deer should be 3
(is (parse-rule if altitude is less than 100 and state is 
 forest then state should be climax and deer should be 3))
(is (let [cell (apply (eval (parse-rule if altitude is less 
 than 100 and state is forest then state should be climax and deer should be 
 3))
  (list {:state :forest :altitude 99} nil))]
  (and (= (:state cell) :climax) (= (:deer cell) 3
))

 This fails as follows:

 simon@engraver:~/workspace/mw-parser$ lein test

 lein test mw-parser.core-test

 lein test :only mw-parser.core-test/rules-tests

 ERROR in (rules-tests) (Compiler.java:6380)
 if altitude is less than 100 and state is forest then state should be 
 climax and deer should be 3
 expected: (let [cell (apply (eval (parse-rule if altitude is less than 
 100 and state is forest then state should be climax and deer should be 3)) 
 (list {:state :forest, :altitude 99} nil))] (and (= (:state cell) :climax) 
 (= (:deer cell) 3)))
   actual: clojure.lang.Compiler$CompilerException: 
 java.lang.RuntimeException: Unable to resolve symbol: get-int in this 
 context, compiling:(/tmp/form-init4592216274934008360.clj:1:6384)


 The function get-int is in mw-engine.utils, and is:

 (defn get-int
   Get the value of a property expected to be an integer from a map; if 
 not present (or not an integer) return 0.
   
* `map` a map;
* `key` a symbol or keyword, presumed to be a key into the `map`.
   [map key]
   (cond map
 (let [v (map key)]
   (cond (and v (integer? v)) v
 true 0))

 true (throw (Exception. No map passed?

  
 I'm trying to understand why this function is not available in the test 
 environment when the anonymous function generated from the rule text is 
 compiled and applied. This matters, because I expect the users of the 
 system to add rules via a web form, so they won't have a REPL. 

 As you can see I've specified that mw-engine.utils is used by the test 
 file, but that does not apparently make the namespace available in eval. It 
 is the eval step, not the apply step, that fails, I've verified that by 
 trying:

 user= (use 'mw-parser.core :reload)
 nil
 user= (parse-rule if state is forest and fertility is between 55 and 75 
 then state should be climax)
 (fn [cell world] (if (and (= (:state cell) :forest) (or ( 55 (get-int 
 cell :fertility) 75) ( 55 (get-int cell :fertility) 75))) (merge cell 
 {:state :climax})))
 user= (eval *1)

 CompilerException java.lang.RuntimeException: Unable to resolve symbol: 
 get-int in this context, 
 compiling:(/tmp/form-init2345285067501587397.clj:1:1) 
 user= 


 (Note that on this occasion I didn't include the (use 'mw-engine.utils) 
 step)

 Any assistance gratefully received!



-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message

Having a package visible in the environment in which generated code is compiled?

2014-07-05 Thread Simon Brooke
I am trying to write a domain-specific production rule language which is 
compiled down at run-time into Clojure code. It's intended that the rule 
language should be usable by primary school children with little help.

So far it's going extremely well, except for one problem. If I run it in 
the REPL, like this, it works:


user= (use 'mw-parser.core :reload)
nil
user= (use 'mw-engine.utils)
nil
user= (parse-rule if state is forest and fertility is between 55 and 75 
then state should be climax)
(fn [cell world] (if (and (= (:state cell) :forest) (or ( 55 (get-int cell 
:fertility) 75) ( 55 (get-int cell :fertility) 75))) (merge cell {:state 
:climax})))
user= (eval *1)
#user$eval1839$fn__1840 user$eval1839$fn__1840@7a52b16b
user= (apply *1 (list {:state :forest :fertility 60} nil))
{:state :climax, :fertility 60}
user= 


However, I have a test as follows:

ns mw-parser.core-test
  (:use mw-engine.utils)
  (:require [clojure.test :refer :all]
[mw-parser.core :refer :all]))

(deftest rules-tests
  (testing if altitude is less than 100 and state is forest then state 
should be climax and deer should be 3
   (is (parse-rule if altitude is less than 100 and state is 
forest then state should be climax and deer should be 3))
   (is (let [cell (apply (eval (parse-rule if altitude is less 
than 100 and state is forest then state should be climax and deer should be 
3))
 (list {:state :forest :altitude 99} nil))]
 (and (= (:state cell) :climax) (= (:deer cell) 3
   ))

This fails as follows:

simon@engraver:~/workspace/mw-parser$ lein test

lein test mw-parser.core-test

lein test :only mw-parser.core-test/rules-tests

ERROR in (rules-tests) (Compiler.java:6380)
if altitude is less than 100 and state is forest then state should be 
climax and deer should be 3
expected: (let [cell (apply (eval (parse-rule if altitude is less than 100 
and state is forest then state should be climax and deer should be 3)) 
(list {:state :forest, :altitude 99} nil))] (and (= (:state cell) :climax) 
(= (:deer cell) 3)))
  actual: clojure.lang.Compiler$CompilerException: 
java.lang.RuntimeException: Unable to resolve symbol: get-int in this 
context, compiling:(/tmp/form-init4592216274934008360.clj:1:6384)


The function get-int is in mw-engine.utils, and is:

(defn get-int
  Get the value of a property expected to be an integer from a map; if not 
present (or not an integer) return 0.
  
   * `map` a map;
   * `key` a symbol or keyword, presumed to be a key into the `map`.
  [map key]
  (cond map
(let [v (map key)]
  (cond (and v (integer? v)) v
true 0))

true (throw (Exception. No map passed?

 
I'm trying to understand why this function is not available in the test 
environment when the anonymous function generated from the rule text is 
compiled and applied. This matters, because I expect the users of the 
system to add rules via a web form, so they won't have a REPL. 

As you can see I've specified that mw-engine.utils is used by the test 
file, but that does not apparently make the namespace available in eval. It 
is the eval step, not the apply step, that fails, I've verified that by 
trying:

user= (use 'mw-parser.core :reload)
nil
user= (parse-rule if state is forest and fertility is between 55 and 75 
then state should be climax)
(fn [cell world] (if (and (= (:state cell) :forest) (or ( 55 (get-int cell 
:fertility) 75) ( 55 (get-int cell :fertility) 75))) (merge cell {:state 
:climax})))
user= (eval *1)

CompilerException java.lang.RuntimeException: Unable to resolve symbol: 
get-int in this context, 
compiling:(/tmp/form-init2345285067501587397.clj:1:1) 
user= 


(Note that on this occasion I didn't include the (use 'mw-engine.utils) 
step)

Any assistance gratefully received!

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: every? expected behavior

2014-04-09 Thread Simon Brooke
On Tuesday, 8 April 2014 07:08:56 UTC+1, Jeff Mad wrote:

 Hi, 
 I am new to Clojure, so please forgive me if this does not make sense. 

 I was surprised to find out in the REPL that every? returns true if you 
 pass in an empty or nil collection. 

 user= (every? #(= 77 %) nil)

 true

 user= (every? #(= 77 %) '())

 true

Every item in the list () is equal to 77, so of course it returns true. 
There are no items in the list () that are not equal to 77.

Clojure is a bit muddled about nil. Nil, generally speaking, is the empty 
list - which is why (every? #(= 77 %) nil) is true. But in Clojure, it's 
not true that (= nil ()). There's no point in saying this is a mistake. But 
it does result in some very hard to explain design decisions.

 

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: Thoughts on a curly-infix reader macro?

2014-04-07 Thread Simon Brooke
I think this comes down to learning to speak Lisp.

Everyone's first few months of learning to speak Lisp are painful. And then 
quite suddenly it becomes natural. Yes, it's possible to write infix 
notation for Lisp - I first saw this in InterLisp's CLISP (I think) back in 
1985 or so, but it's older than that. Lots of people have implemented it, 
virtually no-one uses it. Because once you've learned enough Lisp to 
implement the macro, you've learned to speak Lisp; and once you've learned 
to speak Lisp, infix notation no longer seems natural.



On Friday, 4 April 2014 05:17:32 UTC+1, Joshua Brulé wrote:

 Proposal:

 For an *odd* number of forms a, x, b, ...

 {a x b x c ...} = (x a b c ...)
 {a x b y c ...} = (*nfx* a x b y c ...)

 Reasoning:

 Even after a lot of practice, prefix math is still harder (at least for 
 me...) to read than non-prefix math. The [], () and  matching delimiters 
 are already taken, but {} is only used for an even number of forms (and, in 
 fact, throws an exception on an odd number of forms.)

 ; trumped-up examples
 (defn harmonic-mean [x1 x2]
   {{2 * x1 * x2} / {x1 + x2}})

 (defn fib [n]
   (cond
 {n = 0} 1
 {n = 1} 1
 :else {(fib {n - 1}) + (fib {n - 2})}))

 Basically, I'm claiming a solid win on readability, and no risk of 
 breaking any existing code.

 I realize there's a certain risk of mistaking curly-infix for a map 
 literal when reading code, but I think it's minimal. To me, at least, {x + 
 y} just doesn't look like a map.

 Thoughts?


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


How do I detect the end of a file without catching an exception?

2014-04-07 Thread Simon Brooke
I've written a pair of functions which read a stream of Clojure source and 
identify the var[*] definitions. They work, but the way they work seems 
clumsy to me. Here they are:

(defn find-vars-in-reader [eddi]
Return a list of names of vars declared in the stream this reader 
reads
(try
(let [sexpr (read eddi)]
(cond
(nil? sexpr) nil
(= (first sexpr) 'def) (cons (first (rest 
sexpr)) (find-vars-in-reader eddi))
true (find-vars-in-reader eddi)))
(catch RuntimeException eof)))

(defn find-vars-in-file [filename]
Return a list of names of vars declared in the file at this path name
(with-open [eddi (java.io.PushbackReader. (reader filename))]
(find-vars-in-reader eddi)))

The thing that really offends me about this is using catching a runtime 
exception to stop reading. There must be a better way of detecting an 
end-of-file, but I've missed it.

The other thing, though, is I can't help feeling that it would be more 
idiomatic Clojure to write a wrapper around a source file which allowed 
functions to treat the file as a lazy sequence of S-expressions; and I can't 
help feeling someone must already have done this. Have they? Is there a library 
I should be looking at?

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: How do I detect the end of a file without catching an exception?

2014-04-07 Thread Simon Brooke
OK, the second question I've sort of answered for myself, by riffing on the 
source of line-seq:

(defn expr-seq
  Returns forms from src (assumed to be Clojure source) as a lazy sequence 
of expressions
  [^java.io.PushbackReader src]
  (when-let [expr (read src)]
(try
  (cons expr (lazy-seq (expr-seq src)))
  (catch RuntimeException eof

However, line-seq doesn't bother with catching an exception (presumably 
because it's not using a PushbackReader). So I come back to my first 
question: how do I detect the end of a file?

On Monday, 7 April 2014 18:45:44 UTC+1, Simon Brooke wrote:

 I've written a pair of functions which read a stream of Clojure source and 
 identify the var[*] definitions. They work, but the way they work seems 
 clumsy to me. Here they are:

 (defn find-vars-in-reader [eddi]
   Return a list of names of vars declared in the stream this reader 
 reads
   (try
   (let [sexpr (read eddi)]
   (cond
   (nil? sexpr) nil
   (= (first sexpr) 'def) (cons (first (rest 
 sexpr)) (find-vars-in-reader eddi))
   true (find-vars-in-reader eddi)))
   (catch RuntimeException eof)))

 (defn find-vars-in-file [filename]
   Return a list of names of vars declared in the file at this path name
   (with-open [eddi (java.io.PushbackReader. (reader filename))]
   (find-vars-in-reader eddi)))

 The thing that really offends me about this is using catching a runtime 
 exception to stop reading. There must be a better way of detecting an 
 end-of-file, but I've missed it.

 The other thing, though, is I can't help feeling that it would be more 
 idiomatic Clojure to write a wrapper around a source file which allowed 
 functions to treat the file as a lazy sequence of S-expressions; and I can't 
 help feeling someone must already have done this. Have they? Is there a 
 library I should be looking at?



-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Re: How do I detect the end of a file without catching an exception?

2014-04-07 Thread Simon Brooke
Thank you, that's neat!

On Monday, 7 April 2014 19:14:40 UTC+1, guns wrote:

 On Mon  7 Apr 2014 at 11:07:37AM -0700, Simon Brooke wrote: 
  OK, the second question I've sort of answered for myself, by riffing on 
 the 
  source of line-seq: 
  
  (defn expr-seq 
Returns forms from src (assumed to be Clojure source) as a lazy 
 sequence 
  of expressions 
[^java.io.PushbackReader src] 
(when-let [expr (read src)] 
  (try 
(cons expr (lazy-seq (expr-seq src))) 
(catch RuntimeException eof 
  
  However, line-seq doesn't bother with catching an exception (presumably 
  because it's not using a PushbackReader). So I come back to my first 
  question: how do I detect the end of a file? 

 Use clojure.core/read with three params: [stream eof-error? eof-value] 
 From the Slamhound source: 

 (take-while #(not= ::done %) (repeatedly #(read rdr false ::done))) 

 guns 


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Leiningen: referring to another project on local disc

2014-04-06 Thread Simon Brooke
I'm trying to reference one of my leiningen projects from another, and not 
succeeding. My error must be simple and obvious...

Essentially the projects 'poker' and 'testgen' are both in 
/home/simon/workspace, and both are standard leiningen projects using just 
the default project template. I've done 'lein uberjar' in testgen, so there 
are the following jars:

simon@engraver:~/workspace/poker$ ls -l 
/home/simon/workspace/testgen/target/
total 3588
drwxr-xr-x 2 simon simon4096 Apr  2 20:04 classes
-rw-r--r-- 1 simon simon   5 Apr  6 00:06 repl-port
drwxr-xr-x 2 simon simon4096 Apr  2 20:04 stale
-rw-r--r-- 1 simon simon   11226 Apr  6 00:10 testgen-0.1.0-SNAPSHOT.jar
-rw-r--r-- 1 simon simon 3646079 Apr  6 00:10 
testgen-0.1.0-SNAPSHOT-standalone.jar


In poker/project.clj I've done the following (added lines highlighted):

(defproject poker 0.1.0-SNAPSHOT
  :description Poker scoring kata
  :url http://example.com/FIXME;
  :license {:name Eclipse Public License
:url http://www.eclipse.org/legal/epl-v10.html}
:repositories [[testgen 
file:///home/simon/workspace/testgen/target]]
:dependencies [[org.clojure/clojure 1.5.1]
[testgen 0.1.0-SNAPSHOT]
])


When I try to run lein repl, I get the following:

simon@engraver:~/workspace/poker$ lein repl
Could not find artifact testgen:testgen:jar:0.1.0-SNAPSHOT in clojars 
(https://clojars.org/repo/)
Could not find artifact testgen:testgen:jar:0.1.0-SNAPSHOT in testgen 
(file:///home/simon/workspace/testgen/target)
This could be due to a typo in :dependencies or network issues.


So clearly lein is failing to recognise the jar file(s) as the artefact 
it's looking for. What do I need to do differently? Do I need a pom file, 
and if so what should be in it?

Cheers

Simon

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.


Referential integrity constraints using only clojure.java.jdbc?

2013-12-14 Thread Simon Brooke
First, yes, I now know I could build referential integrity constraints 
using Korma, and that's almost certainly what I shall do next time.

However, I'm quite a long way down building an app against a very tight 
deadline and I've declared my tables in clojure.java.jdbc, e.g.

(defn create-categories-table
  Reference data: award categories
  [db-spec]
  (sql/with-connection db-spec
(sql/create-table
 :categories
 [:id serial primary key]
 [:name varchar(48) not null])
(sql/do-commands insert into categories (name) values ('Best Use of 
Ecommerce (UK market)'))
(sql/do-commands insert into categories (name) values ('Best Use of 
Ecommerce (International market)'))
(sql/do-commands insert into categories (name) values ('Ecommerce 
Innovation of the Year'))
(sql/do-commands insert into categories (name) values ('Ecommerce 
Newcomer of the Year'))
(sql/do-commands insert into categories (name) values ('Ecommerce 
Digital Agency of the Year'))
(sql/do-commands insert into categories (name) values ('Ecommerce 
Specialist Supplier of the Year'))
))

(defn create-nominations-table
  Actual nominations
  [db-spec]
  (sql/with-connection db-spec
(sql/create-table
 :nominations
 [:id serial primary key]
 [:firstname varchar(64) not null]
 [:surname   varchar(64) not null]
 [:phone varchar(24) not null]
 [:email varchar(128) not null]
 [:business  varchar(64) not null]
 [:category  integer not null]
 [:url   varchar(256) not null]
 [:contact   varchar(128)]
 [:citation  :text]
  )))

Obviously, 'category' in the nominations table should reference categories. 
And obviously, I can hack that in the database, so the fact that Clojure 
doesn't automatically set it up doesn't (this time) matter. However, I'd 
like to know for the future whether Korma is just the best way to go, or 
whether there is some database-independent[*] way to set up referential 
integrity constraints at the clojure.java.jdbc.

[*] Yes, I know that the fact I'm using 'serial primary key' tells you 
already that I'm using Postgres, so this isn't database-independent!

-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Running Leiningen inside Jenkins CI server

2013-11-01 Thread Simon Brooke
I've installed Jenkins 1.537 on Debian 6, using Tomcat 6 as a servlet 
container; brief note about the installation here: 
http://blog.journeyman.cc/2013/11/getting-jenkins-ci-running-on-debian-6.html 
Now, 
I'm trying to get it to run Leiningen  and currently it isn't working. What 
I'm getting is as follows:

Started by user Simon Brooke https://www.journeyman.cc/jenkins/user/simon
Building in workspace /var/local/jenkins/workspace/et-clj
Cloning the remote Git repository
Cloning repository file:///srv/git/et-clj
git --version
git version 1.7.2.5
Checking out Revision 958f8466a11bef34143e43ba554b0d897942c2de (origin/master)
First time build. Skipping changelog.
FATAL: leiningen failed: leiningen jar path is 
emptyjava.lang.IllegalArgumentException 
http://stacktrace.jenkins-ci.org/search?query=java.lang.IllegalArgumentException:
 leiningen jar path is empty
at 
org.spootnik.LeiningenBuilder.getLeinCommand(LeiningenBuilder.java:111) 
http://stacktrace.jenkins-ci.org/search/?query=org.spootnik.LeiningenBuilder.getLeinCommandentity=method
at org.spootnik.LeiningenBuilder.perform(LeiningenBuilder.java:80) 
http://stacktrace.jenkins-ci.org/search/?query=org.spootnik.LeiningenBuilder.performentity=method
at hudson.tasks.BuildStepMonitor$1.perform(BuildStepMonitor.java:20) 
http://stacktrace.jenkins-ci.org/search/?query=hudson.tasks.BuildStepMonitor$1.performentity=method
at 
hudson.model.AbstractBuild$AbstractBuildExecution.perform(AbstractBuild.java:781)
 
http://stacktrace.jenkins-ci.org/search/?query=hudson.model.AbstractBuild$AbstractBuildExecution.performentity=method
at hudson.model.Build$BuildExecution.build(Build.java:199) 
http://stacktrace.jenkins-ci.org/search/?query=hudson.model.Build$BuildExecution.buildentity=method
at hudson.model.Build$BuildExecution.doRun(Build.java:160) 
http://stacktrace.jenkins-ci.org/search/?query=hudson.model.Build$BuildExecution.doRunentity=method
at 
hudson.model.AbstractBuild$AbstractBuildExecution.run(AbstractBuild.java:562) 
http://stacktrace.jenkins-ci.org/search/?query=hudson.model.AbstractBuild$AbstractBuildExecution.runentity=method
at hudson.model.Run.execute(Run.java:1665) 
http://stacktrace.jenkins-ci.org/search/?query=hudson.model.Run.executeentity=method
at hudson.model.FreeStyleBuild.run(FreeStyleBuild.java:46) 
http://stacktrace.jenkins-ci.org/search/?query=hudson.model.FreeStyleBuild.runentity=method
at hudson.model.ResourceController.execute(ResourceController.java:88) 
http://stacktrace.jenkins-ci.org/search/?query=hudson.model.ResourceController.executeentity=method
at hudson.model.Executor.run(Executor.java:230) 
http://stacktrace.jenkins-ci.org/search/?query=hudson.model.Executor.runentity=method
Build step 'Build project using leiningen' changed build result to FAILURE
Build step 'Build project using leiningen' marked build as failure
Finished: FAILURE


Can anyone suggest what I need to be looking at?


Many thanks

-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Running Leiningen inside Jenkins CI server

2013-11-01 Thread Simon Brooke
Thank you, that answer was correct and complete in every detail.

Very grateful!

On Friday, 1 November 2013, Jason Bennett wrote:

 Assuming you installed this plugin:
 https://wiki.jenkins-ci.org/display/JENKINS/leiningen+plugin you need to
 configure it.

 Make sure that lein is installed in a place that Jenkins can get to. You
 should probably log into the box, su to jenkins, and run the lein install
 procedure. Then, go to the Jenkins configuration page (/configure) and
 scroll down to the Leiningen Builder section. Enter the full path to the
 lein jar (very possibly
 /var/lib/jenkins/.lein/self-installs/leiningen-2.3.3-standalone.jar). You
 should be good to go.

 jason

 On Friday, November 1, 2013 1:15:40 PM UTC-7, Simon Brooke wrote:

 I've installed Jenkins 1.537 on Debian 6, using Tomcat 6 as a servlet
 container; brief note about the installation here:
 http://blog.journeyman.**cc/2013/11/getting-jenkins-ci-**
 running-on-debian-6.htmlhttp://blog.journeyman.cc/2013/11/getting-jenkins-ci-running-on-debian-6.html
  Now,
 I'm trying to get it to run Leiningen  and currently it isn't working. What
 I'm getting is as follows:

 Started by user Simon Brooke https://www.journeyman.cc/jenkins/user/simon
 Building in workspace /var/local/jenkins/workspace/**et-clj
 Cloning the remote Git repository
 Cloning repository file:///srv/git/et-clj
 git --version
 git version 1.7.2.5
 Checking out Revision 958f8466a11bef34143e43ba554b0d**897942c2de 
 (origin/master)
 First time build. Skipping changelog.
 FATAL: leiningen failed: leiningen jar path is 
 emptyjava.lang.**IllegalArgumentException 
 http://stacktrace.jenkins-ci.org/search?query=java.lang.IllegalArgumentException:
  leiningen jar path is empty
  at 
 org.spootnik.LeiningenBuilder.**getLeinCommand(**LeiningenBuilder.java:111) 
 http://stacktrace.jenkins-ci.org/search/?query=org.spootnik.LeiningenBuilder.getLeinCommandentity=method
  at org.spootnik.LeiningenBuilder.**perform(LeiningenBuilder.java:**80) 
 http://stacktrace.jenkins-ci.org/search/?query=org.spootnik.LeiningenBuilder.performentity=method
  at 
 hudson.tasks.BuildStepMonitor$**1.perform(BuildStepMonitor.**java:20) 
 http://stacktrace.jenkins-ci.org/search/?query=hudson.tasks.BuildStepMonitor$1.performentity=method
  at 
 hudson.model.AbstractBuild$**AbstractBuildExecution.**perform(AbstractBuild.java:**781)
  
 http://stacktrace.jenkins-ci.org/search/?query=hudson.model.AbstractBuild$AbstractBuildExecution.performentity=method
  at hudson.model.Build$**BuildExecution.build(Build.**java:199) 
 http://stacktrace.jenkins-ci.org/search/?query=hudson.model.Build$BuildExecution.buildentity=method
  at hudson.model.Build$**BuildExecution.doRun(Build.**java:160) 
 http://stacktrace.jenkins-ci.org/search/?query=hudson.model.Build$BuildExecution.doRunentity=method
  at 
 hudson.model.AbstractBuild$**AbstractBuildExecution.run(**AbstractBuild.java:562)
  
 http://stacktrace.jenkins-ci.org/search/?query=hudson.model.AbstractBuild$AbstractBuildExecution.runentity=method
  at hudson.model.Run.execute(Run.**java:1665) 
 http://stacktrace.jenkins-ci.org/search/?query=hudson.model.Run.executeentity=method
  at hudson.model.FreeStyleBuild.**run(FreeStyleBuild.java:46) 
 http://stacktrace.jenkins-ci.org/search/?query=hudson.model.FreeStyleBuild.runentity=method
  at 
 hudson.model.**ResourceController.execute(**ResourceController.java:88) 
 http://stacktrace.jenkins-ci.org/search/?query=hudson.model.ResourceController.executeentity=method
  at hudson.model.Executor.run(**Executor.java:230) 
 http://stacktrace.jenkins-ci.org/search/?query=hudson.model.Executor.runentity=method
 Build step 'Build project using leiningen' changed build result to FAILURE
 Build step 'Build project using leiningen' marked build as failure
 Finished: FAILURE


 Can anyone suggest what I need to be looking at?


 Many thanks

  --
 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to 
 clojure@googlegroups.comjavascript:_e({}, 'cvml', 
 'clojure@googlegroups.com');
 Note that posts from new members are moderated - please be patient with
 your first post.
 To unsubscribe from this group, send email to
 clojure+unsubscr...@googlegroups.com javascript:_e({}, 'cvml',
 'clojure%2bunsubscr...@googlegroups.com');
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to a topic in the
 Google Groups Clojure group.
 To unsubscribe from this topic, visit
 https://groups.google.com/d/topic/clojure/-81qyY-OmOQ/unsubscribe.
 To unsubscribe from this group and all its topics, send an email to
 clojure+unsubscr...@googlegroups.com javascript:_e({}, 'cvml',
 'clojure%2bunsubscr...@googlegroups.com');.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
You received this message because you are subscribed

Re: Reading single characters...?

2013-09-23 Thread Simon Brooke
OK, thank you very much chaps. I shall investigate!

On Monday, 23 September 2013, John Jacobsen wrote:

 The JLine story is indeed confusing.  I believe
 https://github.com/jline/jline2 is the current one you want ([jline
 2.11] in your project.clj deps).  See the forthcoming Clojure Cookbook
 recipehttps://github.com/clojure-cookbook/clojure-cookbook/blob/master/local-io/console/read-unbuffered-keystroke/read-unbuffered-keystroke.asciidoc.
  If that recipe (or its trivial extension to echo repeated
 characters) indeed does not work correctly for you, now would be an
 excellent time to let people know so there is a chance to correct it before
 it goes to print!

 John

 On Sunday, September 22, 2013 7:30:29 AM UTC-5, juan.facorro wrote:

 According to the JLine https://github.com/jline/jline's source code
 (v1.0) in 
 UnixTerminal.javahttps://github.com/jline/jline/blob/jline-1.0/src/main/java/jline/UnixTerminal.java#L355,
 echo is disabled with the command *stty -echo* which disables
 all echoing in the console (just tried it in a terminal since I wasn't
 familiar with this command).

 There are two projects for JLine in github https://github.com/jline, JLine
 and JLine2. The latter seems to be actively mantained, but after digging a
 little I found the same command is used when disabling echo in Unix
 terminals, see 
 herehttps://github.com/jline/jline2/blob/master/src/main/java/jline/UnixTerminal.java#L89and
 herehttps://github.com/jline/jline2/blob/master/src/main/java/jline/internal/TerminalLineSettings.java#L76
 .

 I don't know of a way you could go around that, but maybe someone can
 help or suggest an alternative.

 HTH,

 J

 On Saturday, September 21, 2013 12:49:29 AM UTC+8, Simon Brooke wrote:

 I've discovered some interesting behaviour - not necessarily a bug, and
 (if it is a bug) not necessarily a bug in Clojure.

 Essentially, to emulate a 1970s user interface, I want to read single
 key strokes from the console. I've found two recipes online, both using the
 JLine java package:

 http://stackoverflow.com/**questions/13435541/reading-**
 unbuffered-keyboard-input-in-**clojurehttp://stackoverflow.com/questions/13435541/reading-unbuffered-keyboard-input-in-clojure
 http://stackoverflow.com/**questions/3225025/single-**
 character-console-input-in-**java-clojurehttp://stackoverflow.com/questions/3225025/single-character-console-input-in-java-clojure

 One of these recipes uses Terminal.getTerminal(), the other uses new
 ConsoleReader(). What happens in my context (Debian on 64 bit Intel) is
 that as soon as an instance of either class is instantiated, echoing to the
 console ceases. If you do (obviously, with the jline jar on the classpath):

 (import 'jline.Terminal)
 (def term (Terminal/getTerminal))
 (.initializeTerminal term)
 (.enableEcho term)


 (or the equivalent things with a ConsoleReader), every keystroke is
 echoed twice. But if you do

 user= ((..ddiissaabblleeEEcchhoo  tteerrmm))
 ^Jnil

 one single further character gets echoed and then nothing more, unless
 you type (blindly) (.enableEcho term), when the double-echoing behaviour
 resumes. This is consistent - on my Debian box - with Clojure 1.2, Clojure
 1.3, and Clojure 1.5.1, all using jline 1.0. I haven't yet compiled up a
 little Java app to find out what happens without Clojure, and I haven't
 tried compiling a little command-line Clojure app, because I want to be
 able to read single characters in the context of the REPL, so if, as I
 hypothesise, jline is fighting with the REPL, proving whether it works
 outwith the context of the REPL doesn't really help me.

 Has anyone else seen this behaviour? Is there any solution?

  --
 --
 You received this message because you are subscribed to the Google
 Groups Clojure group.
 To post to this group, send email to 
 clojure@googlegroups.comjavascript:_e({}, 'cvml', 
 'clojure@googlegroups.com');
 Note that posts from new members are moderated - please be patient with
 your first post.
 To unsubscribe from this group, send email to
 clojure+unsubscr...@googlegroups.com javascript:_e({}, 'cvml',
 'clojure%2bunsubscr...@googlegroups.com');
 For more options, visit this group at
 http://groups.google.com/group/clojure?hl=en
 ---
 You received this message because you are subscribed to a topic in the
 Google Groups Clojure group.
 To unsubscribe from this topic, visit
 https://groups.google.com/d/topic/clojure/IDzqEQKkDD0/unsubscribe.
 To unsubscribe from this group and all its topics, send an email to
 clojure+unsubscr...@googlegroups.com javascript:_e({}, 'cvml',
 'clojure%2bunsubscr...@googlegroups.com');.
 For more options, visit https://groups.google.com/groups/opt_out.


-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure

ANN: Proof-of-concept structure editor for Clojure

2013-09-20 Thread Simon Brooke
I'd like to announce fedit, a structure editor for Clojure, is now 
available on GitHub:

https://github.com/simon-brooke/fedit

It is experimental, proof of concept code, and has bugs and infelicities. 
It emulates the Portable Standard Lisp/Cambridge Lisp fedit, a terminal 
oriented structure editor, not the InterLisp DEdit display editor, but it 
is preliminary code towards writing a display editor (I've now worked out 
more or less how I would approach that). If it is to be developed further, 
it will need a substantial (but backwards compatible) reworking of the 
Clojure package system, since that is predicated on the concept of 
out-of-core text editing.
Usage

Preliminary, incomplete, alpha quality code. This implements a structure 
editor in a terminal, not a display editor in the tradition of InterLisp's 
DEdit. I do intend to follow up with a display editor, but this is 
exploratory proof-of-concept code.

To edit an arbitrary s-expression:

(sedit sexpr)

This pretty much works now; it returns an edited copy of the s-expression. 
Vectors are not handled intelligently (but could be).

To edit a function definition

(fedit 'name-of-function)

This is still broken (it cannot rebind the function symbol), but shows 
promise.

-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Reading single characters...?

2013-09-20 Thread Simon Brooke
I've discovered some interesting behaviour - not necessarily a bug, and (if 
it is a bug) not necessarily a bug in Clojure.

Essentially, to emulate a 1970s user interface, I want to read single key 
strokes from the console. I've found two recipes online, both using the 
JLine java package:

http://stackoverflow.com/questions/13435541/reading-unbuffered-keyboard-input-in-clojure
http://stackoverflow.com/questions/3225025/single-character-console-input-in-java-clojure

One of these recipes uses Terminal.getTerminal(), the other uses new 
ConsoleReader(). What happens in my context (Debian on 64 bit Intel) is 
that as soon as an instance of either class is instantiated, echoing to the 
console ceases. If you do (obviously, with the jline jar on the classpath):

(import 'jline.Terminal)
(def term (Terminal/getTerminal))
(.initializeTerminal term)
(.enableEcho term)


(or the equivalent things with a ConsoleReader), every keystroke is echoed 
twice. But if you do

user= ((..ddiissaabblleeEEcchhoo  tteerrmm))
^Jnil

one single further character gets echoed and then nothing more, unless you 
type (blindly) (.enableEcho term), when the double-echoing behaviour 
resumes. This is consistent - on my Debian box - with Clojure 1.2, Clojure 
1.3, and Clojure 1.5.1, all using jline 1.0. I haven't yet compiled up a 
little Java app to find out what happens without Clojure, and I haven't 
tried compiling a little command-line Clojure app, because I want to be 
able to read single characters in the context of the REPL, so if, as I 
hypothesise, jline is fighting with the REPL, proving whether it works 
outwith the context of the REPL doesn't really help me.

Has anyone else seen this behaviour? Is there any solution?

-- 
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
--- 
You received this message because you are subscribed to the Google Groups 
Clojure group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to clojure+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.


Re: Current 'best practice' stack for CRUD website?

2013-01-21 Thread Simon Brooke
On Sunday, 20 January 2013 21:43:16 UTC, Sean Corfield wrote:

 On Sun, Jan 20, 2013 at 3:27 AM, Simon Brooke 
 stil...@googlemail.comjavascript: 
 wrote: 
  So I'm looking around at what is the right stack to use to build a CRUD 
 web 
  application in Compojure. 
  
  I really like Enlive, with its very clear separation of logic and 
  presentation. Are there any other libraries I should be looking at at 
 the 
  templating layer, or is Enlive currently the one to go for? 

 Since you like Enlive, you might like my web framework, ported from 
 CFML: FW/1 for Clojure - https://github.com/seancorfield/fw1-clj 

 It provides a convention-based approach to routes (with the ability to 
 override them), uses Enlive for (pure HTML) views, with automatically 
 cascading layouts (wrapping the views) and a standard MVC 
 organization of code. 

 Creating a basic FW/1 skeleton should be as simple as: 

 lein new fw1 myapp 
 cd myapp 
 lein run 

 (or PORT= lein run if you need to select a port other than 8080) 

 Documentation is a work-in-progress - I plan to port across all the 
 relevant parts from the original CFML version - 
 https://github.com/seancorfield/fw1 

 Feedback welcome! 


Thank you, that looks very interesting indeed. 

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Current 'best practice' stack for CRUD website?

2013-01-21 Thread Simon Brooke
On Sunday, 20 January 2013 14:55:07 UTC, Shantanu Kumar wrote:

  I really like Enlive, with its very clear separation of logic and 
  presentation. Are there any other libraries I should be looking at at 
 the 
  templating layer, or is Enlive currently the one to go for? 

 Enlive and Hiccup seem to be popular in the Clojure community. There 
 are also ClojureScript versions[1][2][3] of these templating libraries 
 that you may like to check out as Josh Kamau mentioned. There are also 
 Clojure implementations[4][5] of Mustache[6]. 

 [1] Enfocus: https://github.com/ckirkendall/enfocus 
 [2] Crate: https://github.com/ibdknox/crate 
 [3] Dommy: https://github.com/Prismatic/dommy 
 [4] Clostache: https://github.com/fhd/clostache 
 [5] Stencil: https://github.com/davidsantiago/stencil 
 [6] Mustache: http://mustache.github.com/ 

 Another Clojure templating library you may like to look at is Basil: 
 https://github.com/kumarshantanu/basil (Disclaimer: I am the author of 
 Basil.) It is a general purpose, conventional templating library for 
 Clojure(JVM) and ClojureScript. Though it's in early stage at the 
 moment and lacks features like nesting, template macros, realized 
 fragments etc, it may still be useful for some projects. 

  Again, I'm seeing a number of relational database abstraction libraries 
 for 
  Clojure. Clojureql looks a good one, but are there others I should 
  seriously consider? 

 SQL Korma is popular, though you can also use clojure.java.jdbc 
 directly. 

 [7] SQL Korma: http://sqlkorma.com/ 
 [8] clojure.java.jdbc: https://github.com/clojure/java.jdbc 

 For detailed discussion on Clojure web development you can post to 
 this group: https://groups.google.com/group/clojure-web-dev 


Thank you very much, that's all extremely helpful; I'll work through and 
try to evaluate that over the next few days. 

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Current 'best practice' stack for CRUD website?

2013-01-21 Thread Simon Brooke


On Sunday, 20 January 2013 11:27:58 UTC, Simon Brooke wrote:

 I've finally cleared other projects from my desk far enough that I'm about 
 to start trying to reimplement the CRUD part of http://sh.scenehere.info/ in 
 Clojure. I've been meaning to do this for a long time, but paying projects 
 have got in the way. However, it's now urgent because my old 
 Jacquardhttp://www.journeyman.cc/library/jacquard/build/documentation/library
  which I wrote back in 1997 is now broken by my attempts to drag it 
 kicking and screaming into the world of Java 7, and frankly it isn't work 
 putting masses of effort into maintaining such ancient code that no-one 
 else is using any longer anyway.

 Scythe/ 

Many thanks to everyone who replied. You've given me lots of useful 
homework to do!


-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Current 'best practice' stack for CRUD website?

2013-01-20 Thread Simon Brooke
I've finally cleared other projects from my desk far enough that I'm about 
to start trying to reimplement the CRUD part of http://sh.scenehere.info/ in 
Clojure. I've been meaning to do this for a long time, but paying projects 
have got in the way. However, it's now urgent because my old 
Jacquardhttp://www.journeyman.cc/library/jacquard/build/documentation/library 
which I wrote back in 1997 is now broken by my attempts to drag it 
kicking and screaming into the world of Java 7, and frankly it isn't work 
putting masses of effort into maintaining such ancient code that no-one 
else is using any longer anyway.

So I'm looking around at what is the right stack to use to build a CRUD web 
application in Compojure.

I really like Enlive, with its very clear separation of logic and 
presentation. Are there any other libraries I should be looking at at the 
templating layer, or is Enlive currently the one to go for?

I was looking eighteen months ago at Noir, but I gather this is now 
deprecated.

I've been looking at the Blocker https://github.com/rcampbell/blockerskeleton 
(which in turn is built on 
 [compojure 0.6.0]
 [enlive 1.0.0-SNAPSHOT]
 [clojureql 1.0.1]
 ), and it provides most of what I need, but I notice that 
it has not been updated since 2011.

The 
swanodette/enlive-tutorialhttps://github.com/swannodette/enlive-tutorialhas 
also not been updated for two years, but all works very sweetly; and 
the Getting Started https://github.com/cgrand/enlive/wiki/getting-startedpage 
of the Enlive wiki is equally old. Meantime, I see that there are very 
active commits to the master branch of Enlive, and the latest from Git is 
clearly different than the '1.0.0-SNAPSHOT' version that all the tutorial 
materials I've seen.

So, what is the current 'stable' Enlive? Is '1.0.0-SNAPSHOT' the version I 
should be using? I note that the Compojure front page on GitHub clearly 
says that the current stable is [compojure 1.1.5], which is helpful. I 
can't find a similar statement for Enlive?

Again, I'm seeing a number of relational database abstraction libraries for 
Clojure. Clojureql looks a good one, but are there others I should 
seriously consider?

Many thanks!

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Announcement: Vijual Graph Layout Library for Clojure Version 0.1

2010-01-25 Thread Simon Brooke
On 22 Jan, 22:06, Conrad drc...@gmail.com wrote:
 http://lisperati.com/vijual/

 Hope some of you find this library useful. Let me know if you have
 feature requests or want to help me improve this library.

Many thanks! I shall most certainly use this.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en


Re: Correct mapping from Lisp to Clojure?

2010-01-19 Thread Simon Brooke


On 19 Jan, 06:12, Sean Devlin francoisdev...@gmail.com wrote:
 Did you watch Rich's video Clojure for Lispers?  That might help

 (The only one I can answer for sure is that Clojure's let is CL's
 let*)

Ah! that's very handy, I too was wondering how to do a let*! It's
certainly expressively useful to have it as the default, and I presume
there isn't an excessive computational cost because if there were it
would not be the default.
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: Correct mapping from Lisp to Clojure?

2010-01-19 Thread Simon Brooke
On 19 Jan, 08:33, Laurent PETIT laurent.pe...@gmail.com wrote:
 Hello,

 Just one thought, since I also tried to convert some emacs lisp code
 to clojure recently ( paredit.el ).

 It seemed a good idea at first, something like :

 1. I write a one-to-on conversion, using the same idioms that are used
 in CL in clojure
 2. I write a bunch of non-regression tests
 3. I rewrite as much as is necessary so that it becomes idiomatic
 clojure and not CL in clojure. ( remember how some people coming
 from C world used to write C-in-java ? )

I know the feeling, because I am very much in the same place. Some
things about Clojure I'm just loving and believe I'm getting
idiomatically right (maps and keys as functions, orthogonal
collections, list comprehension), but other things I'm just not fully
groking yet (software transactional memory, for example)

It will come, I think!
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

[im]mutability, threads, state and idiom

2010-01-15 Thread Simon Brooke
Right, I'm trying to get my head around the consequences of
immutability for the sort of programming practices I'm used to, and
how I change the way I do things to fit in with it. Initially I
thought 'well, immutability just means you can't use rplaca and
rplacd, and I've very rarely used either so it doesn't affect me.' But
then I saw that it does. So I'm going right back to one of the first
programs I ever wrote in LISP, which was a multi-player text adventure
game.

To represent a player arriving in a room, you did something like

;; pseudo lisp - actual details unimportant
(defun move (player room)
  (let ((oldroom (get player 'location))(player-terminal (get player
'terminal)))
(put oldroom 'players (remove player (get oldroom 'players)))
(map (get oldroom 'players)
  '(lambda (other) (print (list (get player 'name) 'has 'left)
(get other 'terminal)))
(print (append '(you are in) (get room 'description)) player-
terminal)
(map (get room 'players)
  '(lambda (other) (print (list (get player 'name) 'has 'arrived)
(get other 'terminal))
(print (list (get other 'name) 'is 'here) player-terminal)))
(put player 'location room)
(put room 'players (cons player (get room 'players)

OK, not very functional or elegant. However, it operates mainly by
manipulating property lists, and property lists are  essentially maps,
so at first glance easy to translate... but if the maps are immutable,
then I can't do anything equivalent to

(put oldroom 'players (remove player (get oldroom 'players)))

I can create a new /copy/ of oldroom which is identical to oldroom
except that it has a different set of players, but I can't then set
all things that pointed to oldroom to point to the new copy. So that
way of working doesn't work. We cannot change state on either the
players or the rooms.

My next thought is that I need a new state-holding data structure
which maps players to rooms and vice-versa:

(def
#^{:doc A map which maps every player to his/her location, and
every
   location to the players who are present there}
*player-location-map* {})

(defn
#^{:doc Move player, assumed to be a struct of type player,
to location, assumed to be a struct of type location}
move [player location]
(let [old-location (player *player-location-map*)]
;; do things to announce move to others at new location, and
describe others to player
;; do this first because player is not there yet
(map #(announce-arrival player %) (location 
*player-location-map*))
(print-to-user player (format You are in %s (:description
location))
(map
#(print-to-user player (format %s is here (:name %)))
(location *player-location-map*))
(def *player-location-map*
(merge
{player location}
{location (cons player (location 
*player-location-map*)) }
{old-location (remove #(identical? player %) 
(old-location *player-
location-map*)) }
*player-location-map*))
;; do things to announce move to players at old location
(map #(announce-departure player %) (old-location 
*player-location-
map*)

This gives us just one global variable which holds state about who is
where; and, providing the implementation of a map is fairly efficient,
it does so without a huge amount of overhead. I'm always wary of
global variables... It seems (it isn't working yet, for the reason
that follows) that this approach would work. Is it a good one?

However, it raises the next issue. Suppose we want to construct the
old classic maze of twisty little passages, all alike. So we have,
notionally:

(def maze1 {:description a maze of twisty passages, all alike :north
maze2 :east maze3 :west maze4})
(def maze2 {:description a maze of twisty passages, all alike :north
maze1 :east maze4 :west maze3})

This doesn't work because at the time we try to create maze1, maze2
doesn't exist. If we created maze1 without the reference to maze2 (and
assuming maze3 and maze4 already existed), we could then create maze2.
But we couldn't subsequently fix up the pointer from maze1 to maze2,
because doing so would create a new copy of maze1 and maze2's :north
would still point to the old copy.

Of course we could invent six more magic global maps *north-of*, *east-
of*, *south-of*, *west-of*, *above*, *below*... but this is all
starting to look awfully clunky (yes, OK, we could have one global map
with keys :north-of, :east-of... each pointing to another map, but
that's just hiding the clunkiness behind a facade).

The adventure game's collection of rooms is just an example of the
general case of a cyclic directed graph. Surely there must be some
clean idiomatic way 

Re: mutability, threads, state and idiom

2010-01-15 Thread Simon Brooke
On 15 Jan, 17:40, Laurent PETIT laurent.pe...@gmail.com wrote:
 Simon,

 To be very clear, and incite you to watch all those videos and read
 all this material:

 One of the key motivations (if not the primary) of Rich writing
 clojure has been constructing a language which would offer built-in
 semantics to manage state change over time.

 So you're really in the right language regarding your concerns !

 This is what makes clojure so different from other pure functional
 languages or from pure non functional languages, as Rich stated in
 one of his videos:

 Clojure has a story for the parts of your program you cannot write
 purely functionally.


Thanks Laurent, atagart, Meikel. That's all extremely helpful. I'm
just now implementing the command parser, and having a lot of fun. I'm
thinking about how most efficiently to use the transactional memory to
hold state, but the command parser is pretty much pure functional and
so is easy.

-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Cond, and abusing or

2010-01-15 Thread Simon Brooke
There's an old programmers hack that works in many languages of
abusing the logical or operator to try a sequence of operations until
one returns something useful. It appears that this works in Clojure,
too.

The reason I tried it is that I'm unhappy with Clojure's
implementation of cond. Consider the following interaction:

You are in a shed.
There is a box here
There is a knife here
= open the box
You open the box.
There is a knife in the box
= Take the knife out of the box
You take the knife out of the box

Now, consider a recursive repertoire structure in which each element
is a tuple {token, before-action, sub-repertoire, after-action} a
subset of which is like this

((take
 ()
 ((the
(bind-target-and-continue player (cdr line) (caddr
repertoire) context)
((out () () (take-from-container player (cdr line)
(caddr repertoire) context))
))
(take-from-environment player (cdr line) (caddr repertoire)
context)))

The action parts may internally recurse into the interpreter; so for
example bind-target-and-continue puts the token that follows the
into the context as the target and then re-enters the interpreter with
the remainder of the line and the sub-repertoire

So given 'take the knife out of the box'

== at take there is no before action, so we interpret the sub-
repertoire
 at the there is a before action, so we bind knife as target,
and interpret the rest of the line with the sub-repertoire
== at out there is no before-action or sub-repertoire, so we
evaluate the after-action which tells us to treat what's left of the
line (of the box) as a container specifier, locate a container that
matches that description in the environment, and take the knife out of
it, rather than the knife in the environment

But given just 'take the knife'

== at take there is no before action, so we interpret the sub-
repertoire
 at the there is a before action, so we bind knife as target,
and interpret the rest of the line with the sub-repertoire
 but there is no rest-of-line, so interpreting it returns null
== so we interpret the post action on take, and take the knife from
the environment, not the one in the box.

You can build up remarkably convincing interpreters for a subset of
imperative English with this and a few Eliza style tricks. In portable
standard lisp one would write

(cond
  ((eval before-action))
  ((interpret player sub-repertoire context))
  ((eval after-action)))

This is because each clause of the cond statement was an implicit do
list, so

(let ((a 'foo)(b nil))
  (cond
(a)
(b)))

= foo

Each of a and b are evaluated at most once (as a has a non-nil binding
in this case b is not evaluated at all).

To achieve this with Clojure's cond I have to do either

(let [a 'foo b nil]
  (cond
a a
b b))

= foo

in which case a is evaluated twice; or

(let [a 'foo b nil]
  (let [value-of-a a value-of-b b]
(cond
  (not (= nil value-of-a))
  value-of-a
  (not (= nil value-of-b))
  value-of-b)))

= foo

which only evaluates a once but it always evaluates b whether it needs
to or not, /and/ it's fugly and hard to read, /and/ it's very likely
inefficient (but someone more fluent in Clojure could probably replace
my (not (= nil thing)) with something cleaner); or else

(let [a 'foo b nil]
  (or a b))

= foo

which is simple and easy to read, but is exploiting the left-to-right
evaluation strategy of the or operator. It isn't (or ought not to need
to be) part of the contract of the or operator that it evaluates left
to right. On a massively parallel machine, all branches of the or
might be explored simultaneously. So this sort of hack leaves me
feeling dirty.

Comments?

Is there (once again) something more elegant I've missed?
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: units.clj - unit conversion functions without repeating yourself

2010-01-14 Thread Simon Brooke
On 14 Jan, 15:49, Scott Jaderholm jaderh...@gmail.com wrote:
 Hi,

 I created a library that provides unit conversion functions[1] for
 several common units and allows you to define new units conversions
 with a single equation.

 The code is athttp://gist.github.com/276662#file_units.clj

 I'd love to receive feedback.

Speaking as a complete Clojure newbie, I'm well impressed! I
downloaded that, had a wee look, though, 'H'mmm... I wonder how you'd
extend this to handle things like celsius/fahrenheit where there isn't
just a simple linear equivalence', and dammit, you've got there
already.

I shall study it!
-- 
You received this message because you are subscribed to the Google
Groups Clojure group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Re: making code readable

2008-12-31 Thread Simon Brooke

On Dec 29, 3:15 am, Rich Hickey richhic...@gmail.com wrote:
 On Dec 28, 8:13 pm, Mark Volkmann r.mark.volkm...@gmail.com wrote:


 I'll not argue for making code harder to read, but I have to object to
 most of your example.

 Making something 4x longer does not make it easier to read.

 Redundant comments are useless.

This is the excuse continually trotted out by people too lazy to
comment, or who think themselves superior to merely mortal programmers
who have to work in teams and actually communicate with people.
Redundancy in communication is almost never redundant; think of it as
a checksum. When you listen to someone talking naturally and
explaining something, you'll almost always find they express the same
idea multiple times in different forms of words. Why? It makes certain
that it is clear.

I'm not denying there are occasions where comments add nothing to the
reader's understanding of the code. But they are usually not cases
where the comment repeats (in English or some other natural language)
what is being expressed in Lisp or Java or XSLT or whatever.
Repetition is not in itself bad. On the contrary, it can be explicitly
good, because places where what's written in the comment describes
something different from what's described in the code are probably
places for bugs.

I've never, in my life, worked with another programmer who commented
too much. I've once in my life worked with another programmer who
commented enough. In my experience, if you take over someone else's
code either to maintain it or to integrate it or to reuse components
from it, you're normally in for a huge learning process which would
have been obviated simply by adequate commenting.

'Redundant comments are useless' is the mantra of the dilettante, the
amateur, and the cowboy.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: In core structure editor, anyone?

2008-12-12 Thread Simon Brooke



On Dec 11, 6:39 pm, TNeste tomi.ne...@gmail.com wrote:
 On Dec 10, 2:15 pm, Simon Brooke still...@googlemail.com wrote:

  I note people seem mainly to be using Emacs as an editing/development
  environment for Clojure. But as people keep pointing out, Clojure is
  homoiconic; the canonical source of a function is not a stream of
  bytes read from a file, but is a structure in core.

  Now, in-core editing does raise some issues - there needs to be some
  means of associating the structure which is the canonical source of a
  function with the function itself, so that when the user invokes (edit
  froboz) (or (edit 'froboz), or whatever), the source structure for
  froboz is displayed in the editor. But in-core structure editors are
  extremely powerful and useful when editing homoiconic languages, so...
  is anyone working on an in-core editor for Clojure?

 Do you mean structured editing combined with image based development?
 I haven't really looked that closely at the old Interlisp documents
 but I suppose the source code is managed the same way it is in most
 Smalltalk systems but I have always been a bit puzzled about how that
 works with Lisp.

 In Smalltalk it is fairly straightforward since there is an obvious
 mapping from classes and methods to source code. With lisp it is not
 that simple as there is no limit to the syntactic forms that the user
 might want to query and edit in different forms. For example, if I
 have (define-foo my-foo ...) macro that is used to define some complex
 function named my-foo what happens when I do (edit 'my-foo)? Do I get
 the original define-foo form or the macroexpansion? What about when
 define-foo does something more complex like defines a bunch of methods
 and datastructures or binds my-foo to a closure? There needs to be
 mechanism that associates evaluated forms with the name(s) of the
 resulting object(s) and it probably couldn't, in general, be done
 automatically.

I am indeed looking back at structure editors such as DEdit on
InterLISP - which I rate as the best programmer's editor I've ever
used, superior even to its successor SEdit - but also to the editor in
the versions of Portable Standard LISP I was exposed to. I don't know
what the genesis of those was. I also wrote my own structure editors
for other variants of LISP I worked with - in a REPL on a TTY, a
primitive structure editor is pretty simple to write (you basically
only need a pretty printer). However, the DEdit style editor where you
can see the whole of the function or other data-structure you're
working on while operating on some small part of it is vastly
preferable, but rather more complex to write. Not /that/ difficult,
however, if you can pretty-print source into a Swing textbox.

Chouser, when you have some code you'd be willing to share I would be
extremely interested in poking at it.

And yes, Scott, this is a step towards Smalltalk-style (or old-
fashioned Lisp style) image based development. You may well be right
that this is a bad idea - but we won't know until we try... and in the
end we may disagree.

The next step, of course, it to write SYSOUT and its counterpart,
SYSIN ;-)
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to 
clojure+unsubscr...@googlegroups.com
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



In core structure editor, anyone?

2008-12-10 Thread Simon Brooke

I note people seem mainly to be using Emacs as an editing/development
environment for Clojure. But as people keep pointing out, Clojure is
homoiconic; the canonical source of a function is not a stream of
bytes read from a file, but is a structure in core.

Now, in-core editing does raise some issues - there needs to be some
means of associating the structure which is the canonical source of a
function with the function itself, so that when the user invokes (edit
froboz) (or (edit 'froboz), or whatever), the source structure for
froboz is displayed in the editor. But in-core structure editors are
extremely powerful and useful when editing homoiconic languages, so...
is anyone working on an in-core editor for Clojure?
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Macros and syntax-quote

2008-11-20 Thread Simon Brooke

On Nov 20, 12:19 pm, Jarkko Oranen [EMAIL PROTECTED] wrote:
 On Nov 20, 12:29 pm, Rock [EMAIL PROTECTED] wrote:

  Is there any chance of getting a more thourough explanation within
  Clojure? I'm convinced this is an important issue, especially for
  those coming from the likes of Java, Python, Ruby, etc...

 I'm not a macro expert myself, but I hope this will help you and
 others as well.
 It's good to spend some time simply writing macros and using
 'macroexpand to see what kind of code they produce. I don't think
 there is any other way to learn to write macros.

A point about using macroexpand which I stumbled badly on yesterday is
that macroexpand expands the macros your macro expands into. Well, of
course it does. But it's been so long since I was learning a new macro
syntax that I'd forgotten this. And when my rather simple macro
expanded into a mess of let* and ifs I found myself staring blankly at
it wondering what the heck I'd done wrong.
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Macros and namespaces

2008-11-20 Thread Simon Brooke

I sense already that I'm going to annoy people with this post, but
hear me out - I do have something significant to say.

I've been trying as a learning exercise to implement a subset of
Portable Standard Lisp in Clojure, enough to get some non-trivial
programs to run. I'm not talking about REDUCE here... This means, of
course, I'm going to have to redefine quite a lot of the language.

;; create a namespace
(create-ns 'psl)

;; and use it
(in-ns 'psl)

;; t is trivial, but useful to have it defined early
(def t true)

;; Need to map names which we will overwrite;
;; in some cases this is all that's needed
(clojure/refer 'clojure :rename
   '{
   ;; cdr and friends; just remap (trivial; car is mildly
   ;; more complex)
   rest cdr
   ffirst   caar
   frestcadr
   rfirst   cdar
   rrestcddr

   ;; note that macros that expand to things which we have
   ;; redefined are probably going to fail (e.g. cond,
   ;; which refers to itself)
   cond cljcond

   +plus
   -difference
   *times
   ;; can't implement PSL divide because Clojure doesn't
   ;; have dotted pairs.
   /quotient
})

;; In Clojure, 'nil?' looks as if it might be the same as 'null',
;; but it significantly isn't. (nil? ()) = false, because
;; (= nil ()) = false. 'empty?' is more like null, but it isn't
;; either, because it throws an exception if its arg is not a
;; collection.
(clojure/defn
  #^{:arglists '([any x])
  :doc true if x is an empty list or nil - in Clojure these are NOT
  the same - else false.}
  null [x]
  (if (= x nil) t
   (if (= x false) t
 (if (and (coll? x)(empty? x)) t
   nil)))
)

What's with all those untidy nested 'if's? Wouldn't a cond have been
more elegant? Well, I've moved the Clojure cond aside, and not yet
defined my own. But, the glory of namespaces is that I should have
been able to write

(clojure/cond
(= x nil) t
(= x false) t
(and (coll? x)(empty? x)) t
:else nil)

So why didn't I?

psl= (clojure/cond 'a 'b)
java.lang.Exception: Unable to resolve symbol: cond in this context

Hang on, I didn't type 'cond', I typed 'clojure/cond'. So where's the
unprotected 'cond' coming from?

psl= (macroexpand '(clojure/cond 'a 'b 'c 'd))
(if (quote a) (quote b) (cond (quote c) (quote d)))

And this in turn is because, in core.clj

(defmacro cond
  Takes a set of test/expr pairs. It evaluates each test one at a
  time.  If a test returns logical true, cond evaluates and returns
  the value of the corresponding expr and doesn't evaluate any of the
  other tests or exprs. (cond) returns nil.
  [ clauses]
(when clauses
  (list 'if (first clauses)
(second clauses)
(cons 'cond (rest (rest clauses))

Could I suggest that macros defined in the 'clojure' namespace, which
refer to other things in the clojure namespace, do so explicitly, so
that this should be:

(defmacro cond
  Takes a set of test/expr pairs. It evaluates each test one at a
  time.  If a test returns logical true, cond evaluates and returns
  the value of the corresponding expr and doesn't evaluate any of the
  other tests or exprs. (cond) returns nil.
  [ clauses]
(when clauses
  (list 'clojure/if (first clauses)
(second clauses)
(cons 'clojure/cond (rest (rest clauses))

In passing I note that 'cond' is actually defined in the namespace
'clojure.core' so that that should possibly be

(defmacro cond
  Takes a set of test/expr pairs. It evaluates each test one at a
  time.  If a test returns logical true, cond evaluates and returns
  the value of the corresponding expr and doesn't evaluate any of the
  other tests or exprs. (cond) returns nil.
  [ clauses]
(when clauses
  (list 'clojure/if (first clauses)
(second clauses)
(cons 'clojure/cond (rest (rest clauses))

But I think it's fair that anyone who modifies stuff in the clojure
namespace does so at their own risk. It ought, however, to be possible
to override stuff safely in private namespaces... or else, what's the
point of having namespaces?

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Namespaces and distinctness

2008-11-19 Thread Simon Brooke

Java has a simple and neat convention for achieving global namespace
distinctness without the overhead of a central registry - you just
reverse your domain name and append a bit. Is there a similar
convention for Clojure namespaces?
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Alioth binary-tree benchmark

2008-11-18 Thread Simon Brooke

As a learning exercise and also to continue to investigate Clojure
performance I've roughly translated the Alioth binary-tree benchmark
into Clojure. I chose the binary-tree simply because it's the first of
the Alioth benchmarks in alphabetical collation; I may do others
later.

I've based my implementation on Manuel Giraud's Common LISP
implementation 
http://shootout.alioth.debian.org/gp4/benchmark.php?test=binarytreeslang=sbclid=2
and followed his algorithm blindly. However Giraud uses the Common
LISP ASH (arithmetic shift) function, and, if there's a built-in
function in Clojure, I did not find it; consequently I implemented an
arithmetic-shift function of my own. As I'm as yet unfamiliar with
Clojure it's likely that my implementation is less than optimal.

;;; -*- mode: clojure -*-
;;;
;;; http://shootout.alioth.debian.org/
;;;
;;; From: Simon Brooke
;;; Based on Common LISP by: Manuel Giraud
;;; Node is either NIL (for leaf nodes) or an improper list (DATA
LEFT . RIGHT)

(defn build-btree [item depth]
  (if (zero? depth)
  (cons item
(cons nil nil))
  (let [item2 (* 2 item)
depth-1 (- depth 1)]
(cons item
  (cons (build-btree (- item2 1) depth-1)
(build-btree item2 depth-1))


(defn check-node [node]
  (if node
  (let [data (first node)
kids (rest node)]
(- (+ data (check-node (first kids)))
   (check-node (rest kids
  0))


;;; The Common LISP implementation used the ASH (arithmetic shift)
function.
;;; Whether this was optimisation or just showing off I'm not sure,
;;; but I'm going to blindly follow their implementation. This
function
;;; could almost certainly be improved upon
(defn arithmetic-shift [n i]
(cond
 (zero? i) n
 ( i 0) (loop [result n expt 0]
 (cond
(= expt i) result
true (recur (* result 
2) (+ expt 1
true (loop [result n expt 0]
 (cond
(= expt i) result
true (recur (/ result 2) (- 
expt 1))



(defn loop-depths [max-depth  others]
(let [min-depth (or (first others) 4)]
 (loop [d min-depth]
(let [iterations
(arithmetic-shift 1 (+ 
max-depth min-depth (- d)))]
(if ( d max-depth)
nil ;; 
return value
(do

(println (* iterations 2)

 \t trees of depth  d \t check: 

 (loop [i 1 sum 0]

 (if ( i iterations)

 sum

 (recur (+ i 1)


(+ sum


 (check-node (build-btree i d))


 (check-node (build-btree (- i) d)))

(recur

 (+ d 2


(defn main [n]
;;; ignore for now the issue of parsing a command-line variable
(println stretch trees of depth  (+ n 1) \t check: 
(check-node (build-btree 0 (+ n 1
(let [long-lived-tree (build-btree 0 n)]
 (loop-depths n)
 (println long lived tree of depth  n \t check: 
(check-node 
long-lived-tree


;;(main)

I get the following values (normalised to seconds) for (time (main
16)):

Armed

Re: Clojure for LISP programmers....

2008-11-17 Thread Simon Brooke

On Nov 16, 11:01 pm, Brian W [EMAIL PROTECTED] wrote:
 I'm going to assume this is serious and not a joke, but you do realize
 Clojure is already quite well documented at clojure.org?

I admit I started without reading the documentation, but having got
stuck I then read the documentation - both that at Clojure.org and
that in the Wikibook - carefully. It didn't help. I've been writing
LISP for half the history of the language, so I'm not exactly
unfamiliar with it.

 #t  t     =     true
 define  defun  =    defn
 car, cdr, caar, etc.   ~  first, rest, ffirst, rrest, frest, rfirst

 arglists are vectors because [ ] stand out better

This is very badly missing the point. The point about LISP is that
(ideally at least) it is completely regular and orthogonal, with no
artificial syntax. A list is a list is a list. Introducing
irregularity for the sake of has no benefit and only disbenefit. If
arglists are vectors for some efficiency reason connected to the need
to integrate with Java, that's a good reason, and worth putting up
with. But if it's syntax for the sake of syntax, then that's just
counterproductive.

--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Clojure for LISP programmers....

2008-11-17 Thread Simon Brooke

On Nov 17, 7:43 am, Howard Lewis Ship [EMAIL PROTECTED] wrote:
 I generally like that Clojure dispenses with parens that exist for the
 benefit of the evaluator rather than the developer; thus far fewer
 parens when using (cond).  Still, my old Lisp habits (20 years without
 use) succumbed as much as Simons.  See my earlier thread about
 exception reporting.

 Could Clojure display errors like seems like you're coding up some
 Common Lisp here?

C'mon, guys. There are no excess params in COND, COND is regular.

(COND
  (condition value)
  (condition value)
  ...
  (condition value))

It's like that for good reason, and it's been like that since LISP 1.5
[1]. A programming construct which has remained unchanged for fifty
years is almost certainly unchanged because it works. This is
different from changing 'CAR' and 'CDR' to 'first' and 'rest' - our
computers no longer have decrement registers, so calling an important
function 'contents of the decrement register' is at best a geeky joke,
at worst obscurantism. I'll continue to prefer CAR and CDR because I'm
of that generation and that's what I'm used to, but it's unimportant.
Replacing the word 'lambda' with 'fn' bothers me more. 'Lambda' isn't
a piece of obscure history like CAR or CDR. It's a reminder that we're
implementing - however imperfectly - the lambda calculus. The
regularity of the language, however, is very important. If you want a
separate macro called IF then I have no objection - I shan't use it so
it doesn't worry me. But don't mess with COND!

Having said that my initial performance tests this morning impress me.
Factorial 1000 is a pretty poor test of overall performance but it's
one I've used for twenty-five years and it's still always the first
one I try. So

Clojure: user= (time (fact 1000))
  Elapsed time: 25.418373 msecs
Armed Bear Common Lisp:  CL-USER(2): (time (fact 1000))
  0.093 seconds real time
  3998 cons cells
JScheme : fails to compute, fails to report an error!
CMUCL (non-JVM): * (time (fact 1000))
  ; Compiling LAMBDA NIL:
  ; Compiling Top-Level Form:

  ; Evaluation took:
  ;   0.02 seconds of real time
  ;   0.012 seconds of user run time
  ;   0.0 seconds of system run time
  ;   18,716,873 CPU cycles
  ;   0 page faults and
  ;   686,080 bytes consed.
Java [2] : 0.071 seconds elapsed

Now, this needs to be taken with a pinch of salt because I've timed
only a few runs with each system, and haven't formally averaged - the
above figures are typical figures for each system rather than strictly
averaged ones. GC could potentially throw the figures way out on any
of these systems. Nevertheless, what's interesting here is that
Clojure is nearly four times faster than Armed Bear, and three times
as fast as a (not exactly comparable) Java implementation. Clojure is
even reasonably competitive with CMUCL, which seems to me very
impressive.

It would be interesting (and in the next few days I may) code up some
of the benchmarks from http://shootout.alioth.debian.org/ in Clojure
and see how they compare against Java, ABCL and SBCL.


[1] Lisp 1.5 Programmers Manual, page 10, section 1.6; First published
1958.
[2] Java 6 in its default form can't compute factorial 1000
recursively because it runs out of stack, and clearly doesn't optimise
out the tail recursion - so you have to code it as iterative
explicitly. Java also can't move transparently between integers and
'BigIntegers', so you have to code that explicitly as well. The Java
implementation I used was:

public BigInteger bigFact( BigInteger n) {
BigInteger value = BigInteger.ONE;

for ( BigInteger i = BigInteger.ONE; i.compareTo(n)  0; i = 
i.add
(BigInteger.ONE)) {
value = value.multiply(i);
}
return value;
}


--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---



Re: Clojure for LISP programmers....

2008-11-17 Thread Simon Brooke

On Nov 17, 3:52 am, Luc Prefontaine [EMAIL PROTECTED]
wrote:
 Since it's existence, LISP has not gained a large acceptance in the
 commercial market compared to other conventional programming
 languages.

This is true; I think, though, it's largely a fashion thing. In the
days when you and I learned LISP, LISP was inherently too big (and
played with too big ideas) for the computers most people used. Now we
have computers - hell, we have cellphones - which can actually run big
LISP systems effectively, but LISP is still out of fashion because
managers in IT - people our age - still think of it as 'too big' and
'too strange' (and the successor generations see it as 'too old').

 I started to use it 28 years ago (UCI Lisp on a DEC10) and never crossed
 over it in my professional work except twice

I started with Portable Standard LISP (on 32016 and later on the first
generation ARM) in 1984 and went onto InterLISP-D on Xerox Dandelion
(1108) and Daybreak (1186) before the ubiquitous but unlovely Common
LISP took over. I still think PSL (which had some faults) was the best
LISP I've used from the programmers point of view - elegant,
orthogonal, simple to use and simple to build things in (as an aside
both PSL and InterLISP were designed for in-core development and the
use of structure editors, both of which I see as very important to
ease and speed of development).

 For a language that's been around for 50 years, it's at least annoying
 if not strange given the power of the language.

Could not agree more.

 Certainly, having t to represent the truth value instead of true,
 using defun instead of defn or making an indigestion of parenthesis
 are not essential LISP features.

I mostly agree with you about the names of functions. Willfully
changing things to make life difficult for people seems perverse, but
at the same time 't', 'car', 'cdr' and so on are historical accidents.
However, you're dead wrong about Lots of Irritating Stupid
Parentheses. They are the heart of the language: the fact that it does
not need any irregular syntax, because everything is regular. This
makes learning - after the initial 'where am I what the f*** is this'
phase - very simple and quick. Obviously, structure editors help...
which is why Common LISP makes them so bloody awkward to implement
(though Harlequin managed).

 Compromises at the syntax level are very small concessions to get LISP
 endorsed by a majority in the software community.

People have been saying that for fifty years, and those people have
been this: wrong. The SExpr notation was not LISP's original syntax -
it was adopted in preference to infix syntax because it works better.
InterLISP had an alternative 'conventional' syntax which looked like
an Algol family language - it was used so rarely I've forgotten what
it was called. Dylan was another LISP which used an Algol-like syntax
in an attempt to gain popularity. Where is Dylan now? And these are
only the best known of dozens - they've all failed, been lost in the
dustbins of history.. Arc is also following this path. I am convinced
it is a mistake.

Of course syntax is a sprinkling of sugar on the top of a language; of
course the same underlying semantics can be expressed in many
different syntaxes, and it is the semantics that matter. But SExprs
are the second most successful programming syntax after the Algol
family; and, as compared to Algol-derived languages (BCPL, Pascal, C,
Java, C#) the very regularity of SExprs and their lack of special
cases makes LISP relatively easy to learn.

 The post fix notation is already a challenge (look back at people using
 HP calculators in the 70s/80s), so lets make things a bit easier for
 the non LISP programmer used to left-right assignments...
 Clojure is not a second citizen LISP because it implements a simplified
 syntax.

But that is precisely my point. The syntax isn't simplified: it has
special cases /added/.

 You may need to start from a blank sheet if your Common Lisp knowledge
 interferes with your learning curve :)))
 Get Stuart's bookhttp://pragprog.com/titles/shcloj/programming-clojure
 and start from there.
 This should give you a clear vision of what Clojure is and is not.

I don't want to preserve Common LISP, heaven knows - Common LISP is a
perversely bad LISP variant. I was on the BSI LISP standardisation
committee at the time that Common LISP was going through and I was one
of several people who voted against, for a whole slew of reasons.
There is no reason to slavishly follow Common LISP.

 It's time for LISP to get a significant share of commercial success
 stories and the only way is to add some sex appeal to it to
 attract the masses. Considering that the software industry stagnates
 since the 1980s, it's a welcomed change.

Making a LISP which interoperates well with (and can leverage the
libraries of) Java or .Net is a big win. Some of the other stuff in
Clojure looks extremely interesting - I'm looking at concurrency in
particular. These are 

Clojure for LISP programmers....

2008-11-16 Thread Simon Brooke

Has anyone written a very simple introduction to Clojure for LISP
hackers? I've spend an evening playing with it pretty intensively, and
thus far I haven't got a thing to work. I've read
http://en.wikibooks.org/wiki/Clojure_Programming#Clojure_for_Common_Lisp_Programmers,
but it hasn't helped me.

In LISP:

* (defun fact (n) (cond ((= 1 n) 1)(t (* n (fact (- n 1))
FACT
* (fact 10)
3628800

that is Common LISP, but what the hell; in Portable Standard LISP it
would have been identical except 'de' instead of 'defun'; in Scheme
it's a little different:

 (define (fact n) (cond ((= n 1) 1)(#t (* n (fact (- n 1))
 (fact 10)
3628800

But the family resemblance is there... So, let's try it in Clojure:

user= (defun fact (n) (cond ((= n 1) 1) (t (* n (fact (- n 1))
java.lang.Exception: Unable to resolve symbol: defun in this context
user= (de fact (n) ( cond ((= n 1) 1) (t (* n (fact (- n 1))
java.lang.Exception: Unable to resolve symbol: de in this context
user= (def fact (n) ( cond ((= n 1) 1) (t (* n (fact (- n 1))
java.lang.Exception: Too many arguments to def
user= (defn fact [n] (cond ((= n 1) 1)(t (* n (fact (- n 1))
java.lang.Exception: Unable to resolve symbol: t in this context
user= (defn fact [n](cond ((= n 1) 1)(#t  (* n (fact (- n 1))
java.lang.Exception: No dispatch macro for: t
user= (defn fact [n](cond ((= n 1) 1)(#true (* n (fact (- n 1))
java.lang.Exception: No dispatch macro for: t
user= (defn fact [n] (cond ((= n 1) 1)(true (* n (fact (- n 1))
#'user/fact

OK, what's with the funny square brackets? A sequence of forms
enclosed in square brackets is a vector, not a list. Why is the
arglist for a function a vector? For now let's accept that it is, and
pass on.

user= (fact 10)
java.lang.ClassCastException: java.lang.Boolean cannot be cast to
clojure.lang.IFn

OK, so that doesn't work. As Zaphod memorably put it, 'hey, what is
truth, man?' Good question:

user= (true? 'true)
true
user= (true? true)
true
user= (true? t)
java.lang.Exception: Unable to resolve symbol: t in this context
user= (true? 't)
false
user= (def t 'true)
#'user/t
user= (true? t)
true

OK, now we know the truth, surely we can write a valid fact?

user= (defn fact [n] (cond ((= n 1) 1)('true (* n (fact (- n 1))
#'user/fact
user= (fact 10)
java.lang.ClassCastException: java.lang.Boolean cannot be cast to
clojure.lang.IFn
user= (defn fact [n] (cond ((= n 1) 1)((true? 'true) (* n (fact (- n
1))
#'user/fact
user= (fact 10)
java.lang.ClassCastException: java.lang.Boolean cannot be cast to
clojure.lang.IFn

OK, it looks like whatever's causing the break isn't the guard on the
second cond branch. Let's for a moment try something that's purely
boolean:

user= (defn band [l] (cond ((nil? l) true)((true? (car l))(band (cdr
l)
java.lang.Exception: Unable to resolve symbol: cdr in this context

No CDR? It's LISP, but it can't fetch the contents of the decrement
register? fifty years of LISP history tossed into the dirt. So if the
CDR isn't called the CDR, what is it called (and what's the CDADR
called)?

user= (defn band [l] (cond ((nil? l) true)((true? (first l))(band
(rest l)
#'user/band
user= (band '(true true true))
java.lang.ClassCastException: java.lang.Boolean cannot be cast to
clojure.lang.IFn

OK, can we write any function at all that works?

user= (defn square [n] (* n n))
#'user/square
user= (square 4)
16

Fine, so recurse up from that:

user= (defn power [n m] (cond ((= m 0) 1)(true (* n (power n (- m
1))
#'user/power
user= (power 2 2)
java.lang.ClassCastException: java.lang.Boolean cannot be cast to
clojure.lang.IFn

Aggghhh...

Getting LISP to work seamlessly inside a Java environment with easy
intercalling between LISP and Java is a very big win, and potentially
knocks things like JScheme and Armed Bear Common LISP into a cocked
hat...

But it would be nice to be able to get started!
--~--~-~--~~~---~--~~
You received this message because you are subscribed to the Google Groups 
Clojure group.
To post to this group, send email to clojure@googlegroups.com
To unsubscribe from this group, send email to [EMAIL PROTECTED]
For more options, visit this group at 
http://groups.google.com/group/clojure?hl=en
-~--~~~~--~~--~--~---