|
1 | 1 | (ns rx.lang.clojure.examples.rx-examples
|
2 |
| - (:import rx.Observable rx.subscriptions.Subscriptions) |
3 |
| - (:require [clj-http.client :as http])) |
| 2 | + (:require [rx.lang.clojure.interop :as rx]) |
| 3 | + (:import rx.Observable rx.subscriptions.Subscriptions)) |
4 | 4 |
|
5 | 5 | ; NOTE on naming conventions. I'm using camelCase names (against clojure convention)
|
6 | 6 | ; in this file as I'm purposefully keeping functions and methods across
|
|
12 | 12 |
|
13 | 13 | (defn hello
|
14 | 14 | [& args]
|
15 |
| - (-> (Observable/toObservable args) |
16 |
| - (.subscribe #(println (str "Hello " % "!"))))) |
| 15 | + (-> (Observable/from args) |
| 16 | + (.subscribe (rx/action [v] (println (str "Hello " v "!")))))) |
17 | 17 |
|
18 | 18 | ; To see output
|
19 | 19 | (comment
|
|
23 | 23 | ; Create Observable from Existing Data
|
24 | 24 | ; --------------------------------------------------
|
25 | 25 |
|
26 |
| -(defn existingDataFromNumbers [] |
27 |
| - (Observable/toObservable [1 2 3 4 5 6])) |
28 | 26 |
|
29 | 27 | (defn existingDataFromNumbersUsingFrom []
|
30 | 28 | (Observable/from [1 2 3 4 5 6]))
|
31 | 29 |
|
32 |
| -(defn existingDataFromObjects [] |
33 |
| - (Observable/toObservable ["a" "b" "c"])) |
34 |
| - |
35 | 30 | (defn existingDataFromObjectsUsingFrom []
|
36 | 31 | (Observable/from ["a" "b" "c"]))
|
37 | 32 |
|
38 |
| -(defn existingDataFromList [] |
39 |
| - (let [list [5, 6, 7, 8]] |
40 |
| - (Observable/toObservable list))) |
41 |
| - |
42 | 33 | (defn existingDataFromListUsingFrom []
|
43 | 34 | (let [list [5, 6, 7, 8]]
|
44 | 35 | (Observable/from list)))
|
|
56 | 47 |
|
57 | 48 | returns Observable<String>"
|
58 | 49 | (Observable/create
|
59 |
| - (fn [observer] |
| 50 | + (rx/fn [observer] |
60 | 51 | (doseq [x (range 50)] (-> observer (.onNext (str "value_" x))))
|
61 | 52 | ; after sending all values we complete the sequence
|
62 | 53 | (-> observer .onCompleted)
|
|
66 | 57 |
|
67 | 58 | ; To see output
|
68 | 59 | (comment
|
69 |
| - (.subscribe (customObservableBlocking) println)) |
| 60 | + (.subscribe (customObservableBlocking) (rx/action* println))) |
70 | 61 |
|
71 | 62 | (defn customObservableNonBlocking []
|
72 | 63 | "This example shows a custom Observable that does not block
|
73 | 64 | when subscribed to as it spawns a separate thread.
|
74 | 65 |
|
75 | 66 | returns Observable<String>"
|
76 | 67 | (Observable/create
|
77 |
| - (fn [observer] |
| 68 | + (rx/fn [observer] |
78 | 69 | (let [f (future
|
79 | 70 | (doseq [x (range 50)]
|
80 | 71 | (-> observer (.onNext (str "anotherValue_" x))))
|
81 | 72 | ; after sending all values we complete the sequence
|
82 | 73 | (-> observer .onCompleted))]
|
83 | 74 | ; return a subscription that cancels the future
|
84 |
| - (Subscriptions/create #(future-cancel f)))))) |
85 |
| - |
86 |
| -; To see output |
87 |
| -(comment |
88 |
| - (.subscribe (customObservableNonBlocking) println)) |
89 |
| - |
90 |
| - |
91 |
| -(defn fetchWikipediaArticleAsynchronously [wikipediaArticleNames] |
92 |
| - "Fetch a list of Wikipedia articles asynchronously. |
93 |
| - |
94 |
| - return Observable<String> of HTML" |
95 |
| - (Observable/create |
96 |
| - (fn [observer] |
97 |
| - (let [f (future |
98 |
| - (doseq [articleName wikipediaArticleNames] |
99 |
| - (-> observer (.onNext (http/get (str "http://en.wikipedia.org/wiki/" articleName))))) |
100 |
| - ; after sending response to onnext we complete the sequence |
101 |
| - (-> observer .onCompleted))] |
102 |
| - ; a subscription that cancels the future if unsubscribed |
103 |
| - (Subscriptions/create #(future-cancel f)))))) |
| 75 | + (Subscriptions/create (rx/action [] (future-cancel f))))))) |
104 | 76 |
|
105 | 77 | ; To see output
|
106 | 78 | (comment
|
107 |
| - (-> (fetchWikipediaArticleAsynchronously ["Tiger" "Elephant"]) |
108 |
| - (.subscribe #(println "--- Article ---\n" (subs (:body %) 0 125) "...")))) |
| 79 | + (.subscribe (customObservableNonBlocking) (rx/action* println))) |
109 | 80 |
|
110 | 81 |
|
111 | 82 | ; --------------------------------------------------
|
|
119 | 90 | (customObservableNonBlocking)
|
120 | 91 | (.skip 10)
|
121 | 92 | (.take 5)
|
122 |
| - (.map #(str % "_transformed")) |
123 |
| - (.subscribe #(println "onNext =>" %)))) |
| 93 | + (.map (rx/fn [v] (str v "_transformed"))) |
| 94 | + (.subscribe (rx/action [v] (println "onNext =>" v))))) |
124 | 95 |
|
125 | 96 | ; To see output
|
126 | 97 | (comment
|
|
136 | 107 |
|
137 | 108 | return Observable<Map>"
|
138 | 109 | (Observable/create
|
139 |
| - (fn [observer] |
| 110 | + (rx/fn [observer] |
140 | 111 | (let [f (future
|
141 | 112 | (try
|
142 | 113 | ; simulate fetching user data via network service call with latency
|
|
147 | 118 | (-> observer .onCompleted)
|
148 | 119 | (catch Exception e (-> observer (.onError e))))) ]
|
149 | 120 | ; a subscription that cancels the future if unsubscribed
|
150 |
| - (Subscriptions/create #(future-cancel f)))))) |
| 121 | + (Subscriptions/create (rx/action [] (future-cancel f))))))) |
151 | 122 |
|
152 | 123 | (defn getVideoBookmark [userId, videoId]
|
153 | 124 | "Asynchronously fetch bookmark for video
|
154 | 125 |
|
155 | 126 | return Observable<Integer>"
|
156 | 127 | (Observable/create
|
157 |
| - (fn [observer] |
| 128 | + (rx/fn [observer] |
158 | 129 | (let [f (future
|
159 | 130 | (try
|
160 | 131 | ; simulate fetching user data via network service call with latency
|
|
165 | 136 | (-> observer .onCompleted)
|
166 | 137 | (catch Exception e (-> observer (.onError e)))))]
|
167 | 138 | ; a subscription that cancels the future if unsubscribed
|
168 |
| - (Subscriptions/create #(future-cancel f)))))) |
| 139 | + (Subscriptions/create (rx/action [] (future-cancel f))))))) |
169 | 140 |
|
170 | 141 | (defn getVideoMetadata [videoId, preferredLanguage]
|
171 | 142 | "Asynchronously fetch movie metadata for a given language
|
172 | 143 | return Observable<Map>"
|
173 | 144 | (Observable/create
|
174 |
| - (fn [observer] |
| 145 | + (rx/fn [observer] |
175 | 146 | (let [f (future
|
176 | 147 | (try
|
177 | 148 | ; simulate fetching video data via network service call with latency
|
|
190 | 161 | (-> observer .onCompleted)
|
191 | 162 | (catch Exception e (-> observer (.onError e))))) ]
|
192 | 163 | ; a subscription that cancels the future if unsubscribed
|
193 |
| - (Subscriptions/create #(future-cancel f)))))) |
| 164 | + (Subscriptions/create (rx/action [] (future-cancel f))))))) |
194 | 165 |
|
195 | 166 |
|
196 | 167 | (defn getVideoForUser [userId videoId]
|
|
200 | 171 | - user data
|
201 | 172 | return Observable<Map>"
|
202 | 173 | (let [user-observable (-> (getUser userId)
|
203 |
| - (.map (fn [user] {:user-name (:name user) |
| 174 | + (.map (rx/fn [user] {:user-name (:name user) |
204 | 175 | :language (:preferred-language user)})))
|
205 | 176 | bookmark-observable (-> (getVideoBookmark userId videoId)
|
206 |
| - (.map (fn [bookmark] {:viewed-position (:position bookmark)}))) |
| 177 | + (.map (rx/fn [bookmark] {:viewed-position (:position bookmark)}))) |
207 | 178 | ; getVideoMetadata requires :language from user-observable so nest inside map function
|
208 | 179 | video-metadata-observable (-> user-observable
|
209 | 180 | (.mapMany
|
210 | 181 | ; fetch metadata after a response from user-observable is received
|
211 |
| - (fn [user-map] |
| 182 | + (rx/fn [user-map] |
212 | 183 | (getVideoMetadata videoId (:language user-map)))))]
|
213 | 184 | ; now combine 3 async sequences using zip
|
214 | 185 | (-> (Observable/zip bookmark-observable video-metadata-observable user-observable
|
215 |
| - (fn [bookmark-map metadata-map user-map] |
| 186 | + (rx/fn [bookmark-map metadata-map user-map] |
216 | 187 | {:bookmark-map bookmark-map
|
217 | 188 | :metadata-map metadata-map
|
218 | 189 | :user-map user-map}))
|
219 | 190 | ; and transform into a single response object
|
220 |
| - (.map (fn [data] |
| 191 | + (.map (rx/fn [data] |
221 | 192 | {:video-id videoId
|
222 | 193 | :video-metadata (:metadata-map data)
|
223 | 194 | :user-id userId
|
|
231 | 202 | (comment
|
232 | 203 | (-> (getVideoForUser 12345 78965)
|
233 | 204 | (.subscribe
|
234 |
| - (fn [x] (println "--- Object ---\n" x)) |
235 |
| - (fn [e] (println "--- Error ---\n" e)) |
236 |
| - (fn [] (println "--- Completed ---"))))) |
237 |
| - |
238 |
| - |
239 |
| -; -------------------------------------------------- |
240 |
| -; Error Handling |
241 |
| -; -------------------------------------------------- |
242 |
| - |
243 |
| -(defn fetchWikipediaArticleAsynchronouslyWithErrorHandling [wikipediaArticleNames] |
244 |
| - "Fetch a list of Wikipedia articles asynchronously |
245 |
| - with proper error handling. |
246 |
| - |
247 |
| - return Observable<String> of HTML" |
248 |
| - (Observable/create |
249 |
| - (fn [observer] |
250 |
| - (let [f (future |
251 |
| - (try |
252 |
| - (doseq [articleName wikipediaArticleNames] |
253 |
| - (-> observer (.onNext (http/get (str "http://en.wikipedia.org/wiki/" articleName))))) |
254 |
| - ;(catch Exception e (prn "exception"))) |
255 |
| - (catch Exception e (-> observer (.onError e)))) |
256 |
| - ; after sending response to onNext we complete the sequence |
257 |
| - (-> observer .onCompleted))] |
258 |
| - ; a subscription that cancels the future if unsubscribed |
259 |
| - (Subscriptions/create #(future-cancel f)))))) |
260 |
| - |
261 |
| -; To see output |
262 |
| -(comment |
263 |
| - (-> (fetchWikipediaArticleAsynchronouslyWithErrorHandling ["Tiger" "NonExistentTitle" "Elephant"]) |
264 |
| - (.subscribe #(println "--- Article ---\n" (subs (:body %) 0 125) "...") |
265 |
| - #(println "--- Error ---\n" (.getMessage %))))) |
266 |
| - |
| 205 | + (rx/action [x] (println "--- Object ---\n" x)) |
| 206 | + (rx/action [e] (println "--- Error ---\n" e)) |
| 207 | + (rx/action [] (println "--- Completed ---"))))) |
267 | 208 |
|
0 commit comments