Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Static core #323

Merged
merged 26 commits into from
Aug 30, 2013
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6e1a1f7
Make rxjava-core typesafe
mattrjacobs Jul 3, 2013
ba768a9
Reworked Scala adaptor to use implicits in RxImplicits, rather than c…
mattrjacobs Jul 4, 2013
0188a7c
Removing JRuby adaptor (temporarily)
mattrjacobs Aug 27, 2013
6020f10
Removing Java ClojureAdaptor - will be replaced by an idiomatic Cloju…
mattrjacobs Aug 27, 2013
d2631ec
Removing Java GroovyAdaptor - will be replaced by Groovy idiomatic ve…
mattrjacobs Aug 27, 2013
e98ae37
Cleaning up rxjava-swing
mattrjacobs Aug 27, 2013
9fd3f3e
Remove FunctionLanguageAdaptor from rxjava-core
mattrjacobs Aug 27, 2013
ccf0d7d
Cleaning up rxjava-android build.gradle
mattrjacobs Aug 27, 2013
2721ead
Action interfacesAction Marker Interface
benjchristensen Aug 27, 2013
1531e21
Remove repetitive Scheduler overloads.
benjchristensen Aug 28, 2013
8c87c29
Groovy ExtensionModule to support groovy.lang.Closure
benjchristensen Aug 28, 2013
da4a8e5
0.11.0-SNAPSHOT
benjchristensen Aug 28, 2013
f91a2ea
Observable API reduction
benjchristensen Aug 28, 2013
8cb026a
Move Observable UnitTests
benjchristensen Aug 28, 2013
077b148
Fix RxJava Groovy Unit Tests after static method refactor
benjchristensen Aug 28, 2013
de66728
re-added combineLatest methods that got lost due to too optimistic su…
Aug 28, 2013
bd10365
Reactivated the rxjava-core tests
Aug 28, 2013
e3e148a
repaired rxjava-swing to work with new scheduler and observable api
Aug 28, 2013
64f433b
Merge pull request #2 from jmhofer/reactivate-core-tests
benjchristensen Aug 28, 2013
2dcbf1c
Added dummy Clojure class and stopped compiling Clojure examples to g…
mattrjacobs Aug 29, 2013
bb45652
Merge pull request #2 from benjchristensen/static-core
mattrjacobs Aug 29, 2013
885de91
Make Functions.from typesafe
benjchristensen Aug 29, 2013
f8bacd4
Remove subscribe(Map<String, Object>)
benjchristensen Aug 29, 2013
39239fa
Merge pull request #3 from benjchristensen/static-core
mattrjacobs Aug 29, 2013
4fa627d
Update rxjava-clojure adaptor.
daveray Aug 30, 2013
d2a00ff
Merge pull request #4 from daveray/static-core-clj
mattrjacobs Aug 30, 2013
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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