Skip to content

Commit aff605e

Browse files
committed
Preserve metadata on fn and action macros
Because they're macros, rx/fn and rx/action would lose metadata attached to them, in particular type hints which are slightly important to disambiguate overloaded Observable methods. Fixed.
1 parent 203973b commit aff605e

File tree

4 files changed

+106
-8
lines changed

4 files changed

+106
-8
lines changed

language-adaptors/rxjava-clojure/build.gradle

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ dependencies {
1313

1414
tasks.compileExamplesClojure.classpath = files(tasks.compileClojure.destinationDir) + tasks.compileClojure.classpath
1515

16+
clojureTest.dependsOn compileTestJava
1617
/*
1718
* Clojure
1819
*/

language-adaptors/rxjava-clojure/src/main/clojure/rx/lang/clojure/interop.clj

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -66,11 +66,13 @@
6666
6767
"
6868
[& fn-form]
69+
; preserve metadata so type hints work
6970
; have to qualify fn*. Otherwise bad things happen with the fn* special form in clojure
70-
`(rx.lang.clojure.interop/fn* (clojure.core/fn ~@fn-form)))
71+
(with-meta `(rx.lang.clojure.interop/fn* (clojure.core/fn ~@fn-form))
72+
(meta &form)))
7173

7274
(defn action*
73-
"Given function f, returns an object that implements rx.util.functions.Action0-9
75+
"Given function f, returns an object that implements rx.util.functions.Action0-3
7476
by delegating to the given function.
7577
7678
Example:
@@ -93,6 +95,8 @@
9395
9496
"
9597
[& fn-form]
96-
`(action* (clojure.core/fn ~@fn-form)))
98+
; preserve metadata so type hints work
99+
(with-meta `(action* (clojure.core/fn ~@fn-form))
100+
(meta &form)))
97101

98102
;################################################################################

language-adaptors/rxjava-clojure/src/test/clojure/rx/lang/clojure/interop_test.clj

Lines changed: 56 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33
[clojure.test :refer [deftest testing is]])
44
(:import [rx Observable]
55
[rx.observables BlockingObservable]
6-
))
6+
[rx.lang.clojure.interop DummyObservable]))
77

88
(deftest test-fn*
99
(testing "implements Func0-9"
@@ -27,12 +27,38 @@
2727
(is (= [1 2 3 4 5 6] (.call f 1 2 3 4 5 6)))
2828
(is (= [1 2 3 4 5 6 7] (.call f 1 2 3 4 5 6 7)))
2929
(is (= [1 2 3 4 5 6 7 8] (.call f 1 2 3 4 5 6 7 8)))
30-
(is (= [1 2 3 4 5 6 7 8 9] (.call f 1 2 3 4 5 6 7 8 9))))))
30+
(is (= [1 2 3 4 5 6 7 8 9] (.call f 1 2 3 4 5 6 7 8 9)))))
31+
32+
(let [dummy (DummyObservable.)]
33+
(testing "preserves metadata applied to form"
34+
; No type hint, picks Object overload
35+
(is (= "Object"
36+
(.call dummy (rx/fn* +))))
37+
(is (= "rx.util.functions.Func1"
38+
(.call dummy
39+
^rx.util.functions.Func1 (rx/fn* +))))
40+
(is (= "rx.util.functions.Func2"
41+
(.call dummy
42+
^rx.util.functions.Func2 (rx/fn* *)))))))
3143

3244
(deftest test-fn
3345
(testing "makes appropriate Func*"
3446
(let [f (rx/fn [a b c] (println "test-fn") (+ a b c))]
35-
(is (= 6 (.call f 1 2 3))))))
47+
(is (= 6 (.call f 1 2 3)))))
48+
49+
(let [dummy (DummyObservable.)]
50+
(testing "preserves metadata applied to form"
51+
; No type hint, picks Object overload
52+
(is (= "Object"
53+
(.call dummy
54+
(rx/fn [a] a))))
55+
(is (= "rx.util.functions.Func1"
56+
(.call dummy
57+
^rx.util.functions.Func1 (rx/fn [a] a))))
58+
(is (= "rx.util.functions.Func2"
59+
(.call dummy
60+
^rx.util.functions.Func2 (rx/fn [a b] (* a b))))))))
61+
3662

3763
(deftest test-fnN*
3864
(testing "implements FuncN"
@@ -51,14 +77,39 @@
5177
(.call a 1)
5278
(.call a 1 2)
5379
(.call a 1 2 3)
54-
(is (= [[] [1] [1 2] [1 2 3]])))))
80+
(is (= [[] [1] [1 2] [1 2 3]]))))
81+
(let [dummy (DummyObservable.)]
82+
(testing "preserves metadata applied to form"
83+
; no meta, picks Object overload
84+
(is (= "Object"
85+
(.call dummy
86+
(rx/action* println))))
87+
(is (= "rx.util.functions.Action1"
88+
(.call dummy
89+
^rx.util.functions.Action1 (rx/action* println))))
90+
(is (= "rx.util.functions.Action2"
91+
(.call dummy
92+
^rx.util.functions.Action2 (rx/action* prn)))))))
5593

5694
(deftest test-action
5795
(testing "makes appropriate Action*"
5896
(let [called (atom nil)
5997
a (rx/action [a b] (reset! called [a b]))]
6098
(.call a 9 10)
61-
(is (= [9 10] @called)))))
99+
(is (= [9 10] @called))))
100+
101+
(let [dummy (DummyObservable.)]
102+
(testing "preserves metadata applied to form"
103+
; no meta, picks Object overload
104+
(is (= "Object"
105+
(.call dummy
106+
(rx/action [a] a))))
107+
(is (= "rx.util.functions.Action1"
108+
(.call dummy
109+
^rx.util.functions.Action1 (rx/action [a] a))))
110+
(is (= "rx.util.functions.Action2"
111+
(.call dummy
112+
^rx.util.functions.Action2 (rx/action [a b] (* a b))))))))
62113

63114
(deftest test-basic-usage
64115

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
/**
2+
* Copyright 2013 Netflix, Inc.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
package rx.lang.clojure.interop;
17+
18+
// Dummy class with some overloads to make sure that type hinting works
19+
// correctly with the fn and action macros. Used only for testing.
20+
public class DummyObservable {
21+
22+
public String call(Object f) {
23+
return "Object";
24+
}
25+
26+
public String call(rx.util.functions.Func1 f) {
27+
return "rx.util.functions.Func1";
28+
}
29+
30+
public String call(rx.util.functions.Func2 f) {
31+
return "rx.util.functions.Func2";
32+
}
33+
34+
public String call(rx.util.functions.Action1 f) {
35+
return "rx.util.functions.Action1";
36+
}
37+
38+
public String call(rx.util.functions.Action2 f) {
39+
return "rx.util.functions.Action2";
40+
}
41+
42+
}

0 commit comments

Comments
 (0)