Skip to content

Commit

Permalink
Merge pull request #323 from mattrjacobs/static-core
Browse files Browse the repository at this point in the history
Static core
  • Loading branch information
benjchristensen committed Aug 30, 2013
2 parents df4121b + d2a00ff commit 84696e0
Show file tree
Hide file tree
Showing 56 changed files with 2,453 additions and 5,085 deletions.
51 changes: 46 additions & 5 deletions build.gradle
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
apply from: file('gradle/convention.gradle')
apply from: file('gradle/maven.gradle')
//apply from: file('gradle/check.gradle')
apply from: file('gradle/license.gradle')
apply from: file('gradle/release.gradle')

ext.githubProjectName = rootProject.name

buildscript {
Expand All @@ -9,20 +15,55 @@ allprojects {
repositories { mavenCentral() }
}

apply from: file('gradle/convention.gradle')
apply from: file('gradle/maven.gradle')
//apply from: file('gradle/check.gradle')
apply from: file('gradle/license.gradle')
apply from: file('gradle/release.gradle')

subprojects {
apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'

group = "com.netflix.${githubProjectName}"

// make 'examples' use the same classpath
configurations {
examplesCompile.extendsFrom compile
examplesRuntime.extendsFrom runtime
}

sourceSets.test.java.srcDir 'src/main/java'

tasks.withType(Javadoc).each {
it.classpath = sourceSets.main.compileClasspath
}

//include /src/examples folder
sourceSets {
examples
}

//include 'examples' in build task
tasks.build {
dependsOn(examplesClasses)
}

eclipse {
classpath {
// include 'provided' dependencies on the classpath
plusConfigurations += configurations.provided

downloadSources = true
downloadJavadoc = true
}
}

idea {
module {
// include 'provided' dependencies on the classpath
scopes.PROVIDED.plus += configurations.provided
}
}
}

project(':rxjava-core') {
sourceSets.test.java.srcDir 'src/test/java'
}

2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1 +1 @@
version=0.10.2
version=0.11.0-SNAPSHOT
2 changes: 1 addition & 1 deletion gradle/wrapper/gradle-wrapper.properties
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
distributionUrl=http\://services.gradle.org/distributions/gradle-1.3-bin.zip
distributionUrl=http\://services.gradle.org/distributions/gradle-1.6-bin.zip
52 changes: 44 additions & 8 deletions language-adaptors/rxjava-clojure/README.md
Original file line number Diff line number Diff line change
@@ -1,21 +1,57 @@
# Clojure Adaptor for RxJava

This adaptor provides functions and macros to ease Clojure/RxJava interop. In particular, there are functions and macros for turning Clojure functions and code into RxJava `Func*` and `Action*` interfaces without the tedium of manually reifying the interfaces.

This adaptor allows 'fn' functions to be used and RxJava will know how to invoke them.
# Basic Usage

This enables code such as:
## Requiring the interop namespace
The first thing to do is to require the namespace:

```clojure
(->
(Observable/toObservable ["one" "two" "three"])
(.take 2)
(.subscribe (fn [arg] (println arg))))
(ns my.namespace
(:require [rx.lang.clojure.interop :as rx])
(:import [rx Observable]))
```

This still dependes on Clojure using Java interop against the Java API.
or, at the REPL:

A future goal is a Clojure wrapper to expose the functions in a more idiomatic way.
```clojure
(require '[rx.lang.clojure.interop :as rx])
```

## Using rx/fn
Once the namespace is required, you can use the `rx/fn` macro anywhere RxJava wants a `rx.util.functions.Func` object. The syntax is exactly the same as `clojure.core/fn`:

```clojure
(-> my-observable
(.map (rx/fn [v] (* 2 v))))
```

If you already have a plain old Clojure function you'd like to use, you can pass it to the `rx/fn*` function to get a new object that implements `rx.util.functions.Func`:

```clojure
(-> my-numbers
(.reduce (rx/fn* +)))
```

## Using rx/action
The `rx/action` macro is identical to `rx/fn` except that the object returned implements `rx.util.functions.Action` interfaces. It's used in `subscribe` and other side-effect-y contexts:

```clojure
(-> my-observable
(.map (rx/fn* transform-data))
(.finallyDo (rx/action [] (println "Finished transform")))
(.subscribe (rx/action [v] (println "Got value" v))
(rx/action [e] (println "Get error" e))
(rx/action [] (println "Sequence complete"))))
```

# Gotchas
Here are a few things to keep in mind when using this interop:

* Keep in mind the (mostly empty) distinction between `Func` and `Action` and which is used in which contexts
* If there are multiple Java methods overloaded by `Func` arity, you'll need to use a type hint to let the compiler know which one to choose.
* Methods that take a predicate (like filter) expect the predicate to return a boolean value. A function that returns a non-boolean value will result in a `ClassCastException`.

# Binaries

Expand Down
53 changes: 9 additions & 44 deletions language-adaptors/rxjava-clojure/build.gradle
Original file line number Diff line number Diff line change
@@ -1,17 +1,12 @@
apply plugin: 'java'
apply plugin: 'clojure'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'osgi'

dependencies {
compile project(':rxjava-core')
provided 'org.clojure:clojure:1.4.+'
provided 'junit:junit-dep:4.10'
provided 'org.mockito:mockito-core:1.8.5'


// clojure
testCompile 'clj-http:clj-http:0.6.4' // https://clojars.org/clj-http
compile 'org.clojure:clojure:1.4.+'
//compile 'clj-http:clj-http:0.6.4' // https://clojars.org/clj-http
}

/*
Expand All @@ -22,11 +17,10 @@ warnOnReflection = true

buildscript {
repositories { maven { url "http://clojars.org/repo" } }
dependencies { classpath "clojuresque:clojuresque:1.5.4" }
dependencies { classpath "clojuresque:clojuresque:1.5.8" }
}

repositories {
mavenCentral()
clojarsRepo()
}

Expand All @@ -37,45 +31,16 @@ eclipse {
project {
natures "ccw.nature"
}
classpath {
plusConfigurations += configurations.provided
downloadSources = true
downloadJavadoc = true
}
}

idea {
module {
// include 'provided' dependencies on the classpath
scopes.PROVIDED.plus += configurations.provided
}
}


eclipse {
classpath {
// include 'provided' dependencies on the classpath
plusConfigurations += configurations.provided

downloadSources = true
downloadJavadoc = true
}
}

// include /src/examples folder
sourceSets {
examples
tasks.clojureTest {
classpath = classpath + configurations.provided
}

// make 'examples' use the same classpath
configurations {
examplesCompile.extendsFrom compile
examplesRuntime.extendsFrom runtime
tasks.compileExamplesClojure {
classpath = classpath + configurations.provided
}

// include 'examples' in build task
build.dependsOn examplesClasses

jar {
manifest {
name = 'rxjava-clojure'
Expand All @@ -84,4 +49,4 @@ jar {
instruction 'Import-Package', '!org.junit,!junit.framework,!org.mockito.*,*'
instruction 'Fragment-Host', 'com.netflix.rxjava.core'
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
(ns rx.lang.clojure.examples.http-examples
(:require [rx.lang.clojure.interop :as rx]
[clj-http.client :as http])
(:import rx.Observable rx.subscriptions.Subscriptions))

; NOTE on naming conventions. I'm using camelCase names (against clojure convention)
; in this file as I'm purposefully keeping functions and methods across
; different language implementations in-sync for easy comparison.

(defn fetchWikipediaArticleAsynchronously [wikipediaArticleNames]
"Fetch a list of Wikipedia articles asynchronously.

return Observable<String> of HTML"
(Observable/create
(rx/fn [observer]
(let [f (future
(doseq [articleName wikipediaArticleNames]
(-> observer (.onNext (http/get (str "http://en.wikipedia.org/wiki/" articleName)))))
; after sending response to onnext we complete the sequence
(-> observer .onCompleted))]
; a subscription that cancels the future if unsubscribed
(Subscriptions/create (rx/action [] (future-cancel f)))))))

; To see output
(comment
(-> (fetchWikipediaArticleAsynchronously ["Tiger" "Elephant"])
(.subscribe (rx/action [v] (println "--- Article ---\n" (subs (:body v) 0 125) "...")))))


; --------------------------------------------------
; Error Handling
; --------------------------------------------------

(defn fetchWikipediaArticleAsynchronouslyWithErrorHandling [wikipediaArticleNames]
"Fetch a list of Wikipedia articles asynchronously
with proper error handling.

return Observable<String> of HTML"
(Observable/create
(rx/fn [observer]
(let [f (future
(try
(doseq [articleName wikipediaArticleNames]
(-> observer (.onNext (http/get (str "http://en.wikipedia.org/wiki/" articleName)))))
;(catch Exception e (prn "exception")))
(catch Exception e (-> observer (.onError e))))
; after sending response to onNext we complete the sequence
(-> observer .onCompleted))]
; a subscription that cancels the future if unsubscribed
(Subscriptions/create (rx/action [] (future-cancel f)))))))

; To see output
(comment
(-> (fetchWikipediaArticleAsynchronouslyWithErrorHandling ["Tiger" "NonExistentTitle" "Elephant"])
(.subscribe (rx/action [v] (println "--- Article ---\n" (subs (:body v) 0 125) "..."))
(rx/action [e] (println "--- Error ---\n" (.getMessage e))))))


Loading

0 comments on commit 84696e0

Please sign in to comment.