Browse files

Merge branch 'master' of github.com:clojuredocs/cds

  • Loading branch information...
2 parents c7509b1 + 5d27e26 commit c08b252873e767f01861361bc3b70ad88492e104 @frenchy64 frenchy64 committed Mar 27, 2013
View
26 articles/ecosystem/libraries_directory.md
@@ -161,6 +161,8 @@ For more comprehensive overview of the Clojure library ecosystem, please see [Cl
### HTML Generation
* [hiccup](https://clojars.org/hiccup): Generates HTML from Clojure data structures.
+
+ * [Stencil](https://github.com/davidsantiago/stencil): Implements the Mustache templating language.
* [markdown-clj](https://clojars.org/markdown-clj): Clojure based Markdown parsers for both Clojure and ClojureScript.
@@ -235,9 +237,14 @@ For more comprehensive overview of the Clojure library ecosystem, please see [Cl
* [Neocons](https://clojureneo4j.info) ([at clojars](https://clojars.org/clojurewerkz/neocons)): Neocons is a feature rich idiomatic [Clojure client for the Neo4J REST API](http://clojureneo4j.info) with solid documentation
- * [Titanium](http://titanium.clojurewerkz.org): a Clojure graph library built on top of Titan
+ * [Titanium](http://titanium.clojurewerkz.org) ([at clojars](https://clojars.org/clojurewerkz/titanium)):
+ a Clojure graph library built on top of Titan
+
+ * [Archimedes](https://github.com/zmaril/archimedes) ([at clojars](https://clojars.org/zmaril/archimedes)):
+ a Clojure wrapper for Tinkerpop Blueprints
- * [Hermes](https://github.com/gameclosure/hermes): a Clojure wrapper for Titan
+ * [Ogre](https://github.com/zmaril/ogre) ([at clojars](https://clojars.org/zmaril/ogre)):
+ a Clojure library for querying Tinkerpop graphs
* [Borneo](https://github.com/wagjo/borneo) ([at clojars](https://clojars.org/borneo))
@@ -330,34 +337,40 @@ For more comprehensive overview of the Clojure library ecosystem, please see [Cl
* [jclouds](http://www.jclouds.org/): unified APIs for dozens of cloud (IaaS) providers
+ * [Amazonica](https://github.com/mcohen01/amazonica): comprehensive Clojure client for the entire AWS API
+
* [clj-ssh](https://github.com/hugoduncan/clj-ssh) ([at clojars](https://clojars.org/clj-ssh)): an SSH client
* [ssh-transport](https://github.com/pallet/ssh-transport): executes commands over SSH
## Monitoring, metrics
+ * [metrics-clojure](https://github.com/sjl/metrics-clojure) ([at clojars](https://clojars.org/metrics-clojure)):
+ Clojure library on top of Yammer's Metrics
+
* [clj-statsd](https://github.com/pyr/clj-statsd) ([at clojars](https://clojars.org/clj-statsd)): simple client library to interface with statsd
* [pulse](https://github.com/heroku/pulse): Real-time Heroku operations dashboard
- * [riemann](https://github.com/aphyr/riemann) ([at clojars](https://clojars.org/riemann)): A network event stream processing system, in Clojure.
+ * [riemann](http://riemann.io) ([at clojars](https://clojars.org/riemann)): A network event stream processing system, in Clojure.
## I/O
-### Files
+### Files, NIO, NIO2
File I/O is covered by the JDK and commonly used via `clojure.java.io` functions.
* [fs](https://clojars.org/fs): utilities for working with the file system
+ * [nio](https://github.com/pjstadig/nio): Clojure library for working with for Java NIO classes
### Standard Streams, Subprocesses
Standard streams I/O is covered by the JDK and commonly used via `clojure.java.io` functions.
- * clojure.java.shell: Conveniently launch a sub-process providing
+ * clojure.java.shell (part of Clojure distribution): Conveniently launch a sub-process providing
its stdin and collecting its stdout.
* [conch](https://clojars.org/conch): for shelling out to external programs.
@@ -388,8 +401,9 @@ Standard streams I/O is covered by the JDK and commonly used via `clojure.java.i
* [math.numeric-tower](https://github.com/clojure/math.numeric-tower): various utility math functions
- * [math.combinatorics](https://github.com/clojure/math.combinatorics) common combinatorial functions
+ * [math.combinatorics](https://github.com/clojure/math.combinatorics): common combinatorial functions
+ * [core.matrix](https://github.com/mikera/matrix-api): matrix operations
## Email
View
60 articles/ecosystem/web_development.md
@@ -53,6 +53,63 @@ libraries.
+## Templating Libraries
+
+Clojure has many options for building HTML.
+
+
+### Hiccup
+
+[Hiccup](https://github.com/weavejester/hiccup) represents HTML as
+Clojure data structures, allowing you to create and manipulate your
+HTML easily.
+
+[Tinsel](https://github.com/davidsantiago/tinsel) is a library that
+extends Hiccup with selectors and transformers, so that you can write
+a template separate from the insertion of your data into the template.
+
+
+### Mustache
+
+[Clostache](https://github.com/fhd/clostache) implements the
+[Mustache](http://mustache.github.com/) templating language for
+Clojure.
+
+[Stencil](https://github.com/davidsantiago/stencil) is another
+implementation of Mustache.
+
+
+### Fleet
+
+[Fleet](https://github.com/Flamefork/fleet) embeds Clojure inside HTML
+templates, much like Java's JSPs, or Ruby's ERb.
+
+
+### Clabango
+
+[Clabango](https://github.com/danlarkin/clabango) is modeled after the
+[Django templating system](https://docs.djangoproject.com/en/1.4/topics/templates/). It
+embeds special tags and filters inside HTML templates to insert and
+manipulate data.
+
+
+### Enlive and Laser
+
+[Enlive](https://github.com/cgrand/enlive) and
+[Laser](https://github.com/Raynes/laser) are similar libraries. They
+both manipulate plain HTML, and can be used for screen scraping as
+well as templating. They work with HTML templates with no special
+embedded tags or code. They use selector functions to find pieces of
+HTML and transformation function to change the HTML into the way you
+want.
+
+See the
+[Laser guide](https://github.com/Raynes/laser/blob/master/docs/guide.md)
+to see if this style of templating works for you. It is powerful, but
+different from most other languages' templating libraries.
+
+
+
## See Also
* the [web development section of the library
@@ -66,4 +123,5 @@ libraries.
## Contributors
-John Gabriele
+* John Gabriele
+* Clinton Dreisbach
View
267 articles/language/interop.md
@@ -542,7 +542,272 @@ CompilerException java.lang.IllegalArgumentException: More than one matching met
## gen-class and How to Implement Java Classes in Clojure
-TBD: [How to Contribute](https://github.com/clojuredocs/cds#how-to-contribute)
+### Overview
+
+`gen-class` is a Clojure feature for implementing Java classes in Clojure. It is relatively
+rarely used compared to `proxy` and `reify` but is needed to implement executable classes
+(that `java` runner and IDEs can as program entry points).
+
+Unlike `proxy` and `reify`, `gen-class` defines named classes. They can be passed to Java
+APIs that expect class references. Classes defined with `gen-class` can extend
+base classes, implement any number of Java interfaces, define any number of constructors
+and define both instance and static methods.
+
+### AOT
+
+`gen-class` requires *ahead-of-time* (AOT) compilation. It means that
+before using the classes defined with `gen-class`, the Clojure
+compiler needs to produce `.class` files from `gen-class` definitions.
+
+### Class Definition With clojure.core/gen-class
+
+`clojure.core/gen-class` is a macro that uses a DSL for defining class
+methods, base class, implemented interfaces and so on.
+
+It takes a number of options:
+
+ * `:name` (a symbol): defines generated class name
+ * `:extends` (a symbol): name of the base class
+ * `:implements` (a collection): interfaces the class implements
+ * `:constructors` (a map): constructor signatures
+ * `:methods` (a collection): lists methods that will be implemented
+ * `:init` (symbol): defines a function that will be invoked with constructor arguments
+ * `:post-init` (symbol): defines a function that will be called with a constructed instance as its first argument
+ * `:state` (symbol): if supplied, a public final instance field with the given name will be created. Only makes sense when
+ used with `:init`. State field value should be an atom or other ref type to allow state mutation.
+ * `:prefix` (string, default: `"-"`): methods will call functions named as `(str prefix method-name)`, e.g. `-getName` for `getName`.
+ * `:main` (boolean): if `true`, a public static main method will be generated for the class. It will delegate
+ to a function named main with the prefix (`(str prefix "main")`), `-main` by default
+ * `:exposes`: TBD
+ * `:exposes-methods`: TBD
+ * `:factory`: TBD
+ * `:load-impl-ns`: TBD
+ * `:impl-ns`: TBD
+
+#### The :name Option
+
+TBD
+
+#### The :extends Option
+
+TBD
+
+#### The :implements Option
+
+TBD
+
+#### The :constructors Option
+
+TBD
+
+#### The :methods Option
+
+TBD
+
+#### The :init Option
+
+TBD
+
+#### The :post-init Option
+
+TBD
+
+#### The :state Option
+
+TBD
+
+#### The :prefix Option
+
+TBD
+
+#### The :main Option
+
+TBD
+
+#### The :exposes Option
+
+TBD
+
+#### The :exposes-methods Option
+
+TBD
+
+#### The :factory Option
+
+TBD
+
+#### The :load-impl-ns Option
+
+TBD
+
+#### The :impl-ns Option
+
+TBD
+
+
+
+### gen-class In The ns Macro
+
+`gen-class` can be used with existing namespaces by adding `(:gen-class)` to the
+`ns` macro. Here is a "hello, world" example command line app that uses `gen-class`
+to generate a class that JVM launcher (`java`) can run:
+
+``` clojure
+(ns genclassy.core
+ (:gen-class))
+
+(defn -main
+ [& args]
+ (println "Hello, World!"))
+```
+
+This will use the name of the namespace for class name and use the namespace for method
+implementation (see the `:impl-ns` option above).
+
+
+### Examples
+
+A medium size example taken from an open source library:
+
+``` clojure
+(ns clojurewerkz.quartzite.listeners.amqp.PublishingSchedulerListener
+ (:gen-class :implements [org.quartz.SchedulerListener]
+ :init init
+ :state state
+ :constructors {[com.rabbitmq.client.Channel String String] []})
+ (:require [langohr.basic :as lhb]
+ [clojure.data.json :as json])
+ (:use [clojurewerkz.quartzite.conversion])
+ (:import [org.quartz SchedulerListener SchedulerException Trigger TriggerKey JobDetail JobKey]
+ [com.rabbitmq.client Channel]
+ [java.util Date]
+ [clojurewerkz.quartzite.listeners.amqp PublishingSchedulerListener]))
+
+
+
+(defn publish
+ [^PublishingSchedulerListener this payload ^String type]
+ (let [{ :keys [channel exchange routing-key] } @(.state this)
+ payload (json/json-str payload)]
+ (lhb/publish channel exchange routing-key payload :type type)))
+
+
+(defn -init
+ [^Channel ch ^String exchange ^String routing-key]
+ [[] (atom { :channel ch :exchange exchange :routing-key routing-key })])
+
+
+(defmacro payloadless-publisher
+ [method-name message-type]
+ `(defn ~method-name
+ [this#]
+ (publish this# (json/json-str {}) ~message-type)))
+
+(payloadless-publisher -schedulerStarted "quartz.scheduler.started")
+(payloadless-publisher -schedulerInStandbyMode "quartz.scheduler.standby")
+(payloadless-publisher -schedulingDataCleared "quartz.scheduler.cleared")
+(payloadless-publisher -schedulerShuttingDown "quartz.scheduler.shutdown")
+
+
+(defn -schedulerError
+ [this ^String msg ^SchedulerException cause]
+ (publish this (json/json-str { :message msg :cause (str cause) }) "quartz.scheduler.error"))
+
+
+(defn -jobScheduled
+ [this ^Trigger trigger]
+ (publish this (json/json-str { :group (-> trigger .getKey .getGroup) :key (-> trigger .getKey .getName) :description (.getDescription trigger) }) "quartz.scheduler.job-scheduled"))
+
+(defn -jobUnscheduled
+ [this ^TriggerKey key]
+ (publish this (json/json-str { :group (.getGroup key) :key (.getName key) }) "quartz.scheduler.job-unscheduled"))
+
+(defn -triggerFinalized
+ [this ^Trigger trigger]
+ (publish this (json/json-str { :group (-> trigger .getKey .getGroup) :key (-> trigger .getKey .getName) :description (.getDescription trigger) }) "quartz.scheduler.trigger-finalized"))
+
+(defn -triggerPaused
+ [this ^TriggerKey key]
+ (publish this (json/json-str { :group (.getGroup key) :key (.getName key) }) "quartz.scheduler.trigger-paused"))
+
+(defn -triggersPaused
+ [this ^String trigger-group]
+ (publish this (json/json-str { :group trigger-group }) "quartz.scheduler.triggers-paused"))
+
+(defn -triggerResumed
+ [this ^TriggerKey key]
+ (publish this (json/json-str { :group (.getGroup key) :key (.getName key) }) "quartz.scheduler.trigger-resumed"))
+
+(defn -triggersResumed
+ [this ^String trigger-group]
+ (publish this (json/json-str { :group trigger-group }) "quartz.scheduler.triggers-resumed"))
+
+
+
+(defn -jobAdded
+ [this ^JobDetail detail]
+ (publish this (json/json-str { :job-detail (from-job-data (.getJobDataMap detail)) :description (.getDescription detail) }) "quartz.scheduler.job-added"))
+
+(defn -jobDeleted
+ [this ^JobKey key]
+ (publish this (json/json-str { :group (.getGroup key) :key (.getName key) }) "quartz.scheduler.job-deleted"))
+
+(defn -jobPaused
+ [this ^JobKey key]
+ (publish this (json/json-str { :group (.getGroup key) :key (.getName key) }) "quartz.scheduler.job-paused"))
+
+(defn -jobsPaused
+ [this ^String job-group]
+ (publish this (json/json-str { :group job-group }) "quartz.scheduler.jobs-paused"))
+
+(defn -jobResumed
+ [this ^JobKey key]
+ (publish this (json/json-str { :group (.getGroup key) :key (.getName key) }) "quartz.scheduler.job-resumed"))
+
+(defn -jobsResumed
+ [this ^String job-group]
+ (publish this (json/json-str { :group job-group }) "quartz.scheduler.jobs-resumed"))
+```
+
+### Inspecting Class Signatures
+
+When using `gen-class` for interoperability purposes, sometimes it is necessary to inspect the API
+of the class generated by `gen-class`.
+
+It can be inspected
+using [javap](http://docs.oracle.com/javase/7/docs/technotes/tools/windows/javap.html). Given the
+following Clojure namespace:
+
+``` clojure
+(ns genclassy.core
+ (:gen-class))
+
+(defn -main
+ [& args]
+ (println "Hello, World!"))
+```
+
+We can inspect the produced class like so:
+
+```
+# from target/classes, default .class files location used by Leiningen
+javap genclassy.core
+```
+
+will output
+
+``` java
+public class genclassy.core {
+ public static {};
+ public genclassy.core();
+ public java.lang.Object clone();
+ public int hashCode();
+ public java.lang.String toString();
+ public boolean equals(java.lang.Object);
+ public static void main(java.lang.String[]);
+}
+```
+
## How To Extend Protocols to Java Classes
View
19 articles/language/macros.md
@@ -99,15 +99,20 @@ Such forms are called *special forms*. They are
* new
* set!
* def
+ * var
+ * fn
* if
+ * case
* do
- * let
+ * let (technically, `let*`)
+ * import
+ * letfn
* quote
- * var
- * fn
* loop, recur
- * throw, try, catch
- * monitor-enter
+ * throw, try, catch, finally
+ * deftype
+ * reify
+ * monitor-enter, monitor-exit
Other forms are implemented with macros on top of special forms. For example, `and` is
implemented on top of `if`:
@@ -163,7 +168,7 @@ To see what the macro expands to, we can use `clojure.core/macroexpand-1`:
``` clojure
(macroexpand-1 '(unless (= 1 2) true false))
-;= (if false (do true false))
+;= (if false true false)
```
This simplistic macro and the way we expanded it with `macroexpand-1`
@@ -224,7 +229,7 @@ of `(= 1 2)` (a list). We want `unless` to perform boolean evaluation on it,
and that's what unquote (`~`) does as can be seen from macroexpansion:
(macroexpand-1 '(unless (= 1 2) true false))
-;= (if false (do true false))
+;= (if false true false)
Compare this with what the macro expands to when the unquote is removed:
View
39 articles/tutorials/growing_a_dsl_with_clojure.md
@@ -63,12 +63,12 @@ Let’s define a function `emit-bash-form` that takes a Clojure form and returns
to its argument."
(cond
(= (class a) java.lang.String) a
- (= (class a) java.lang.Integer) (str a)
+ (= (class a) java.lang.Long) (str a)
(= (class a) java.lang.Double) (str a)
:else (throw (Exception. "Fell through"))))
```
-The `cond` expression handles cases for a `String`, `Integer`, or `Double` argument, or throws an exception.
+The `cond` expression handles cases for a `String`, `Long`, or `Double` argument, or throws an exception.
```clojure
user=> (emit-bash-form 1)
@@ -77,6 +77,17 @@ user=> (emit-bash-form "a")
"a"
```
+Now why did we chose to use a `Long` rather than an `Integer`? Under the hood, [Clojure uses the `Long` datatype for numbers. ](http://dev.clojure.org/display/doc/Documentation+for+1.3+Numerics)
+
+> Although it supports all primitives for the purposes of Java interoperability, pure Clojure uses only long and double. Clojure will seamlessly promote ints to longs and floats to doubles as needed.
+
+Quick and easy way to test this out.
+
+```clojure
+user=> (class 7)
+java.lang.Long
+```
+
Now if we want to add some more dispatches, we just need to add a new clause to our `cond` expression.
## Echo and Print
@@ -182,7 +193,7 @@ So let’s add a clause for `clojure.lang.PersistentList`.
"println" (str "echo " (second a)))
(= (class a) java.lang.String) a
- (= (class a) java.lang.Integer) (str a)
+ (= (class a) java.lang.Long) (str a)
(= (class a) java.lang.Double) (str a)
:else (throw (Exception. "Fell through"))))
```
@@ -214,16 +225,16 @@ Let’s define a multimethod called emit-bash. Here is the complete multimethod.
(defmethod emit-bash
clojure.lang.PersistentList
[form]
- (case (name (first a))
- "println" (str "echo " (second a))))
+ (case (name (first form))
+ "println" (str "echo " (second form))))
(defmethod emit-bash
java.lang.String
[form]
form)
(defmethod emit-bash
- java.lang.Integer
+ java.lang.Long
[form]
(str form))
@@ -274,15 +285,15 @@ Let’s say I’m happy with the Bash implementation. I feel like starting a new
(defmethod emit-batch clojure.lang.PersistentList
[form]
- (case (name (first a))
- "println" (str "ECHO " (second a))
+ (case (name (first form))
+ "println" (str "ECHO " (second form))
nil))
(defmethod emit-batch java.lang.String
[form]
form)
-(defmethod emit-batch java.lang.Integer
+(defmethod emit-batch java.lang.Long
[form]
(str form))
@@ -370,7 +381,7 @@ Remember the dispatch value is now a vector, notated with square brackets. In pa
[form]
form)
-(defmethod emit [::common java.lang.Integer]
+(defmethod emit [::common java.lang.Long]
[form]
(str form))
@@ -384,14 +395,14 @@ This should look familiar. The only methods that needs to be specialized are tho
```clojure
(defmethod emit [::bash clojure.lang.PersistentList]
[form]
- (case (name (first a))
- "println" (str "echo " (second a))
+ (case (name (first form))
+ "println" (str "echo " (second form))
nil))
(defmethod emit [::batch clojure.lang.PersistentList]
[form]
- (case (name (first a))
- "println" (str "ECHO " (second a))
+ (case (name (first form))
+ "println" (str "ECHO " (second form))
nil))
```

0 comments on commit c08b252

Please sign in to comment.