Skip to content

Commit 0b38d4f

Browse files
Merge pull request ReactiveX#134 from daveray/clj-video-example
Adapt Groovy VideoExample to Clojure
2 parents d25a017 + 5c28d6f commit 0b38d4f

File tree

1 file changed

+161
-0
lines changed
  • language-adaptors/rxjava-clojure/src/examples/clojure/rx/lang/clojure/examples

1 file changed

+161
-0
lines changed
Lines changed: 161 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,161 @@
1+
(ns rx.lang.clojure.examples.video-example
2+
(:import [rx Observable Observer Subscription]))
3+
4+
; Adapted from language-adaptors/rxjava-groovy/src/examples/groovy/rx/lang/groovy/examples/VideoExample.groovy
5+
6+
(declare get-video-grid-for-display)
7+
(declare get-list-of-lists)
8+
(declare video-list)
9+
(declare video-list->videos)
10+
(declare video->metadata)
11+
(declare video->bookmark)
12+
(declare video->rating)
13+
14+
; just use a simple lock to keep multi-threaded output fr beiom ng a interlea llved
15+
(def print-lock (Object.))
16+
17+
(defn example1
18+
[on-complete]
19+
(println "Starting example 1")
20+
; this will print the dictionary for each video and is a good representation of
21+
; how progressive rendering could work
22+
(println "---- sequence of video dictionaries ----")
23+
(-> (get-video-grid-for-display 1)
24+
(.subscribe #(locking print-lock (println %))
25+
#(locking print-lock (println "Error: " %))
26+
#(do
27+
(println "Finished example 1")
28+
(on-complete)))))
29+
30+
(defn example2
31+
[on-complete]
32+
(println "Starting example 2")
33+
; onNext will be called once with a list and demonstrates how a sequence can be combined
34+
; for document style responses (most webservices)
35+
(-> (get-video-grid-for-display 1)
36+
.toList
37+
(.subscribe #(println "\n ---- single list of video dictionaries ----\n" %)
38+
#(println "Error: " %)
39+
#(do
40+
(println "Finished Example 2")
41+
(println "Exiting")
42+
(on-complete)))))
43+
44+
(defn -main
45+
[& args]
46+
; Run example1 followed by example2, then exit
47+
(example1 (fn [] (example2 #(System/exit 0)))))
48+
49+
(defn ^Observable get-video-grid-for-display
50+
"
51+
Demonstrate how Rx is used to compose Observables together such as
52+
how a web service would to generate a JSON response.
53+
54+
The simulated methods for the metadata represent different services
55+
that are often backed by network calls.
56+
57+
This will return a sequence of maps like this:
58+
59+
{:id 1000, :title video-1000-title, :length 5428, :bookmark 0,
60+
:rating {:actual 4 :average 3 :predicted 0}}
61+
"
62+
[user-id]
63+
(-> (get-list-of-lists user-id)
64+
(.mapMany (fn [list]
65+
; for each VideoList we want to fetch the videos
66+
(-> (video-list->videos list)
67+
(.take 10) ; we only want the first 10 of each list
68+
(.mapMany (fn [video]
69+
; for each video we want to fetch metadata
70+
(let [m (-> (video->metadata video)
71+
(.map (fn [md]
72+
; transform to the data and format we want
73+
{:title (:title md)
74+
:length (:duration md) })))
75+
b (-> (video->bookmark video user-id)
76+
(.map (fn [position]
77+
{:bookmark position})))
78+
r (-> (video->rating video user-id)
79+
(.map (fn [rating]
80+
{:rating {:actual (:actual-star-rating rating)
81+
:average (:average-star-rating rating)
82+
:predicted (:predicted-star-rating rating) }})))]
83+
; join these together into a single, merged map for each video
84+
(Observable/zip m b r (fn [m b r]
85+
(merge {:id video} m b r)))))))))))
86+
87+
88+
; A little helper to make the future-based observables a little less verbose
89+
; this has possibilities ...
90+
(defn- ^Observable future-observable
91+
"Returns an observable that executes (f observer) in a future, returning a
92+
subscription that will cancel the future."
93+
[f]
94+
(Observable/create (fn [^Observer observer]
95+
(let [f (future (f observer))]
96+
(Observable/createSubscription #(future-cancel f))))))
97+
98+
(defn ^Observable get-list-of-lists
99+
"
100+
Retrieve a list of lists of videos (grid).
101+
102+
Observable<VideoList> is the \"push\" equivalent to List<VideoList>
103+
"
104+
[user-id]
105+
(future-observable (fn [^Observer observer]
106+
(Thread/sleep 180)
107+
(dotimes [i 15]
108+
(.onNext observer (video-list i)))
109+
(.onCompleted observer))))
110+
111+
112+
(comment (.subscribe (get-list-of-lists 7777) println))
113+
114+
(defn video-list
115+
[position]
116+
{:position position
117+
:name (str "ListName-" position) })
118+
119+
(defn ^Observable video-list->videos
120+
[{:keys [position] :as video-list}]
121+
(Observable/create (fn [^Observer observer]
122+
(dotimes [i 50]
123+
(.onNext observer (+ (* position 1000) i)))
124+
(.onCompleted observer)
125+
(Observable/noOpSubscription))))
126+
127+
(comment (.subscribe (video-list->videos (video-list 2)) println))
128+
129+
(defn ^Observable video->metadata
130+
[video-id]
131+
(Observable/create (fn [^Observer observer]
132+
(.onNext observer {:title (str "video-" video-id "-title")
133+
:actors ["actor1" "actor2"]
134+
:duration 5428 })
135+
(.onCompleted observer)
136+
(Observable/noOpSubscription))))
137+
138+
(comment (.subscribe (video->metadata 10) println))
139+
140+
(defn ^Observable video->bookmark
141+
[video-id user-id]
142+
(future-observable (fn [^Observer observer]
143+
(Thread/sleep 4)
144+
(.onNext observer (if (> (rand-int 6) 1) 0 (rand-int 4000)))
145+
(.onCompleted observer))))
146+
147+
(comment (.subscribe (video->bookmark 112345 99999) println))
148+
149+
(defn ^Observable video->rating
150+
[video-id user-id]
151+
(future-observable (fn [^Observer observer]
152+
(Thread/sleep 10)
153+
(.onNext observer {:video-id video-id
154+
:user-id user-id
155+
:predicted-star-rating (rand-int 5)
156+
:average-star-rating (rand-int 5)
157+
:actual-star-rating (rand-int 5) })
158+
(.onCompleted observer))))
159+
160+
(comment (.subscribe (video->rating 234345 8888) println))
161+

0 commit comments

Comments
 (0)