Skip to content

Commit b59ebe5

Browse files
martinsikdavidwdan
authored andcommitted
isEmpty operator 2.x branch (#128)
* output proper 0 and 1 for booleans * cherry-pick merge * fixed demo and more tests * transformed to 2.x
1 parent f93f7dd commit b59ebe5

File tree

8 files changed

+261
-0
lines changed

8 files changed

+261
-0
lines changed

demo/bootstrap.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@
1919
function asString($value) {
2020
if (is_array($value)) {
2121
return json_encode($value);
22+
} elseif (is_bool($value)) {
23+
return (string)(integer)$value;
2224
}
2325
return (string) $value;
2426
}

demo/isEmpty/isEmpty-false.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
require_once __DIR__ . '/../bootstrap.php';
4+
5+
$source = \Rx\Observable::just(1)
6+
->isEmpty();
7+
8+
$source->subscribe($stdoutObserver);
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Next value: 0
2+
Complete!

demo/isEmpty/isEmpty.php

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
<?php
2+
3+
require_once __DIR__ . '/../bootstrap.php';
4+
5+
$source = \Rx\Observable::emptyObservable()
6+
->isEmpty();
7+
8+
$source->subscribe($stdoutObserver);

demo/isEmpty/isEmpty.php.expect

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
Next value: 1
2+
Complete!

src/Observable.php

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@
3636
use Rx\Operator\DistinctUntilChangedOperator;
3737
use Rx\Operator\DoOnEachOperator;
3838
use Rx\Operator\GroupByUntilOperator;
39+
use Rx\Operator\IsEmptyOperator;
3940
use Rx\Operator\MapOperator;
4041
use Rx\Operator\FilterOperator;
4142
use Rx\Operator\MinOperator;
@@ -1922,6 +1923,23 @@ public function throttle(int $throttleDuration, SchedulerInterface $scheduler =
19221923
});
19231924
}
19241925

1926+
/**
1927+
* If the source Observable is empty it returns an Observable that emits true, otherwise it emits false.
1928+
*
1929+
* @return Observable
1930+
*
1931+
* @demo isEmpty/isEmpty.php
1932+
* @demo isEmpty/isEmpty-false.php
1933+
* @operator
1934+
* @reactivex contains
1935+
*/
1936+
public function isEmpty(): Observable
1937+
{
1938+
return $this->lift(function () {
1939+
return new IsEmptyOperator();
1940+
});
1941+
}
1942+
19251943
/**
19261944
* @param Promise $promise
19271945
* @param SchedulerInterface|null $scheduler

src/Operator/IsEmptyOperator.php

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
<?php
2+
3+
namespace Rx\Operator;
4+
5+
use Rx\DisposableInterface;
6+
use Rx\ObservableInterface;
7+
use Rx\ObserverInterface;
8+
9+
final class IsEmptyOperator implements OperatorInterface
10+
{
11+
12+
public function __invoke(ObservableInterface $observable, ObserverInterface $observer): DisposableInterface
13+
{
14+
return $observable->subscribe(
15+
function() use ($observer) {
16+
$observer->onNext(false);
17+
$observer->onCompleted();
18+
},
19+
[$observer, 'onError'],
20+
function() use ($observer) {
21+
$observer->onNext(true);
22+
$observer->onCompleted();
23+
}
24+
);
25+
}
26+
27+
}
Lines changed: 194 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
<?php
2+
3+
namespace Rx\Functional\Operator;
4+
5+
use Rx\Functional\FunctionalTestCase;
6+
7+
class IsEmptyTest extends FunctionalTestCase
8+
{
9+
10+
/**
11+
* @test
12+
*/
13+
public function should_return_true_if_source_is_empty()
14+
{
15+
$xs = $this->createHotObservable([
16+
onCompleted(300)
17+
]);
18+
19+
$results = $this->scheduler->startWithCreate(function() use ($xs) {
20+
return $xs->isEmpty();
21+
});
22+
23+
$this->assertMessages([
24+
onNext(300, true),
25+
onCompleted(300),
26+
], $results->getMessages());
27+
28+
$this->assertSubscriptions([
29+
subscribe(200, 300),
30+
], $xs->getSubscriptions());
31+
}
32+
33+
/**
34+
* @test
35+
*/
36+
public function should_return_false_if_source_emits_element()
37+
{
38+
$xs = $this->createHotObservable([
39+
onNext(150, 'a'),
40+
onNext(300, 'b'),
41+
onCompleted(300)
42+
]);
43+
44+
$results = $this->scheduler->startWithCreate(function() use ($xs) {
45+
return $xs->isEmpty();
46+
});
47+
48+
$this->assertMessages([
49+
onNext(300, false),
50+
onCompleted(300),
51+
], $results->getMessages());
52+
53+
$this->assertSubscriptions([
54+
subscribe(200, 300),
55+
], $xs->getSubscriptions());
56+
}
57+
58+
/**
59+
* @test
60+
*/
61+
public function should_return_true_if_source_emits_before_subscription()
62+
{
63+
$xs = $this->createHotObservable([
64+
onNext(150, 'a'),
65+
onCompleted(300)
66+
]);
67+
68+
$results = $this->scheduler->startWithCreate(function() use ($xs) {
69+
return $xs->isEmpty();
70+
});
71+
72+
$this->assertMessages([
73+
onNext(300, true),
74+
onCompleted(300),
75+
], $results->getMessages());
76+
77+
$this->assertSubscriptions([
78+
subscribe(200, 300),
79+
], $xs->getSubscriptions());
80+
}
81+
82+
/**
83+
* @test
84+
*/
85+
public function should_raise_error_if_source_raise_error()
86+
{
87+
$e = new \Exception();
88+
89+
$xs = $this->createHotObservable([
90+
onError(300, $e),
91+
]);
92+
93+
$results = $this->scheduler->startWithCreate(function() use ($xs) {
94+
return $xs->isEmpty();
95+
});
96+
97+
$this->assertMessages([
98+
onError(300, $e),
99+
], $results->getMessages());
100+
101+
$this->assertSubscriptions([
102+
subscribe(200, 300),
103+
], $xs->getSubscriptions());
104+
}
105+
106+
/**
107+
* @test
108+
*/
109+
public function should_not_complete_if_source_never_emits()
110+
{
111+
$xs = $this->createHotObservable([]);
112+
113+
$results = $this->scheduler->startWithCreate(function() use ($xs) {
114+
return $xs->isEmpty();
115+
});
116+
117+
$this->assertMessages([], $results->getMessages());
118+
$this->assertSubscriptions([
119+
subscribe(200, 1000),
120+
], $xs->getSubscriptions());
121+
}
122+
123+
/**
124+
* @test
125+
*/
126+
public function should_return_true_if_source_completes_immediately()
127+
{
128+
$xs = $this->createHotObservable([
129+
onCompleted(201),
130+
]);
131+
132+
$results = $this->scheduler->startWithCreate(function() use ($xs) {
133+
return $xs->isEmpty();
134+
});
135+
136+
$this->assertMessages([
137+
onNext(201, true),
138+
onCompleted(201),
139+
], $results->getMessages());
140+
$this->assertSubscriptions([
141+
subscribe(200, 201),
142+
], $xs->getSubscriptions());
143+
}
144+
145+
/**
146+
* @test
147+
*/
148+
public function should_allow_unsubscribing_explicitly_and_early()
149+
{
150+
$xs = $this->createHotObservable([
151+
onNext(600, 'a'),
152+
onNext(700, 'b'),
153+
]);
154+
155+
$results = $this->scheduler->startWithDispose(function() use ($xs) {
156+
return $xs->isEmpty();
157+
}, 500);
158+
159+
$this->assertMessages([], $results->getMessages());
160+
161+
$this->assertSubscriptions([
162+
subscribe(200, 500),
163+
], $xs->getSubscriptions());
164+
}
165+
166+
/**
167+
* @test
168+
*/
169+
public function should_not_break_unsubscription_chains_when_result_is_unsubscribed_explicitly()
170+
{
171+
$xs = $this->createHotObservable([
172+
onNext(600, 'a'),
173+
onNext(700, 'b'),
174+
]);
175+
176+
$results = $this->scheduler->startWithDispose(function() use ($xs) {
177+
return $xs
178+
->flatMap(function($value) {
179+
return \Rx\Observable::just($value);
180+
})
181+
->isEmpty()
182+
->flatMap(function($value) {
183+
return \Rx\Observable::just($value);
184+
});
185+
}, 500);
186+
187+
$this->assertMessages([], $results->getMessages());
188+
189+
$this->assertSubscriptions([
190+
subscribe(200, 500),
191+
], $xs->getSubscriptions());
192+
}
193+
194+
}

0 commit comments

Comments
 (0)