From e5b4e2b7cd86be9566b9479550ff17a78780ae8c Mon Sep 17 00:00:00 2001 From: Martin Sikora Date: Thu, 12 Jan 2017 11:04:45 +0100 Subject: [PATCH 1/4] output proper 0 and 1 for booleans --- demo/bootstrap.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/demo/bootstrap.php b/demo/bootstrap.php index 02f78e32..f337ac23 100644 --- a/demo/bootstrap.php +++ b/demo/bootstrap.php @@ -19,6 +19,8 @@ function asString($value) { if (is_array($value)) { return json_encode($value); + } elseif (is_bool($value)) { + return (string)(integer)$value; } return (string) $value; } From 9d553f6929544e4b1e17d266b40a73d7aa7df125 Mon Sep 17 00:00:00 2001 From: Martin Sikora Date: Wed, 11 Jan 2017 15:19:44 +0100 Subject: [PATCH 2/4] cherry-pick merge --- demo/isEmpty/isEmpty-false.php | 8 + demo/isEmpty/isEmpty-false.php.expect | 2 + demo/isEmpty/isEmpty.php | 8 + demo/isEmpty/isEmpty.php.expect | 2 + lib/Rx/Operator/IsEmptyOperator.php | 35 ++++ src/Observable.php | 18 +++ test/Rx/Functional/Operator/IsEmptyTest.php | 170 ++++++++++++++++++++ 7 files changed, 243 insertions(+) create mode 100644 demo/isEmpty/isEmpty-false.php create mode 100644 demo/isEmpty/isEmpty-false.php.expect create mode 100644 demo/isEmpty/isEmpty.php create mode 100644 demo/isEmpty/isEmpty.php.expect create mode 100644 lib/Rx/Operator/IsEmptyOperator.php create mode 100644 test/Rx/Functional/Operator/IsEmptyTest.php diff --git a/demo/isEmpty/isEmpty-false.php b/demo/isEmpty/isEmpty-false.php new file mode 100644 index 00000000..6af55102 --- /dev/null +++ b/demo/isEmpty/isEmpty-false.php @@ -0,0 +1,8 @@ +isEmpty(); + +$subscription = $source->subscribe($stdoutObserver); diff --git a/demo/isEmpty/isEmpty-false.php.expect b/demo/isEmpty/isEmpty-false.php.expect new file mode 100644 index 00000000..ee0f8aca --- /dev/null +++ b/demo/isEmpty/isEmpty-false.php.expect @@ -0,0 +1,2 @@ +Next value: +Complete! \ No newline at end of file diff --git a/demo/isEmpty/isEmpty.php b/demo/isEmpty/isEmpty.php new file mode 100644 index 00000000..2ab4b04d --- /dev/null +++ b/demo/isEmpty/isEmpty.php @@ -0,0 +1,8 @@ +isEmpty(); + +$subscription = $source->subscribe($stdoutObserver); diff --git a/demo/isEmpty/isEmpty.php.expect b/demo/isEmpty/isEmpty.php.expect new file mode 100644 index 00000000..07dda203 --- /dev/null +++ b/demo/isEmpty/isEmpty.php.expect @@ -0,0 +1,2 @@ +Next value: 1 +Complete! \ No newline at end of file diff --git a/lib/Rx/Operator/IsEmptyOperator.php b/lib/Rx/Operator/IsEmptyOperator.php new file mode 100644 index 00000000..3ad299b3 --- /dev/null +++ b/lib/Rx/Operator/IsEmptyOperator.php @@ -0,0 +1,35 @@ +subscribeCallback( + function() use ($observer) { + $observer->onNext(false); + $observer->onCompleted(); + }, + [$observer, 'onError'], + function() use ($observer) { + $observer->onNext(true); + $observer->onCompleted(); + }, + $scheduler + ); + } +} \ No newline at end of file diff --git a/src/Observable.php b/src/Observable.php index c169ed8e..1e5ac433 100644 --- a/src/Observable.php +++ b/src/Observable.php @@ -36,6 +36,7 @@ use Rx\Operator\DistinctUntilChangedOperator; use Rx\Operator\DoOnEachOperator; use Rx\Operator\GroupByUntilOperator; +use Rx\Operator\IsEmptyOperator; use Rx\Operator\MapOperator; use Rx\Operator\FilterOperator; use Rx\Operator\MinOperator; @@ -1922,6 +1923,23 @@ public function throttle(int $throttleDuration, SchedulerInterface $scheduler = }); } + /** + * If the source Observable is empty it returns an Observable that emits true, otherwise it emits false. + * + * @return Observable + * + * @demo isEmpty/isEmpty.php + * @demo isEmpty/isEmpty-false.php + * @operator + * @reactivex isEmpty + */ + public function isEmpty(): Observable + { + return $this->lift(function () { + return new IsEmptyOperator(); + }); + } + /** * @param Promise $promise * @param SchedulerInterface|null $scheduler diff --git a/test/Rx/Functional/Operator/IsEmptyTest.php b/test/Rx/Functional/Operator/IsEmptyTest.php new file mode 100644 index 00000000..b1c74293 --- /dev/null +++ b/test/Rx/Functional/Operator/IsEmptyTest.php @@ -0,0 +1,170 @@ +createHotObservable([ + onCompleted(300) + ]); + + $results = $this->scheduler->startWithCreate(function() use ($xs) { + return $xs->isEmpty(); + }); + + $this->assertMessages([ + onNext(300, true), + onCompleted(300), + ], $results->getMessages()); + + $this->assertSubscriptions([ + subscribe(200, 300), + ], $xs->getSubscriptions()); + } + + /** + * @test + */ + public function should_return_false_if_source_emits_element() + { + $xs = $this->createHotObservable([ + onNext(150, 'a'), + onNext(300, 'b'), + onCompleted(300) + ]); + + $results = $this->scheduler->startWithCreate(function() use ($xs) { + return $xs->isEmpty(); + }); + + $this->assertMessages([ + onNext(300, false), + onCompleted(300), + ], $results->getMessages()); + + $this->assertSubscriptions([ + subscribe(200, 300), + ], $xs->getSubscriptions()); + } + + /** + * @test + */ + public function should_raise_error_if_source_raise_error() + { + $e = new \Exception(); + + $xs = $this->createHotObservable([ + onError(300, $e), + ]); + + $results = $this->scheduler->startWithCreate(function() use ($xs) { + return $xs->isEmpty(); + }); + + $this->assertMessages([ + onError(300, $e), + ], $results->getMessages()); + + $this->assertSubscriptions([ + subscribe(200, 300), + ], $xs->getSubscriptions()); + } + + /** + * @test + */ + public function should_not_completes_if_source_never_emits() + { + $xs = $this->createHotObservable([]); + + $results = $this->scheduler->startWithCreate(function() use ($xs) { + return $xs->isEmpty(); + }); + + $this->assertMessages([], $results->getMessages()); + $this->assertSubscriptions([ + subscribe(200, 1000), + ], $xs->getSubscriptions()); + } + + /** + * @test + */ + public function should_return_true_if_source_completes_immediately() + { + $xs = $this->createHotObservable([ + onCompleted(201), + ]); + + $results = $this->scheduler->startWithCreate(function() use ($xs) { + return $xs->isEmpty(); + }); + + $this->assertMessages([ + onNext(201, true), + onCompleted(201), + ], $results->getMessages()); + $this->assertSubscriptions([ + subscribe(200, 201), + ], $xs->getSubscriptions()); + } + + /** + * @test + */ + public function should_allow_unsubscribing_explicitly_and_early() + { + $xs = $this->createHotObservable([ + onNext(600, 'a'), + onNext(700, 'b'), + ]); + + $results = $this->scheduler->startWithDispose(function() use ($xs) { + return $xs->isEmpty(); + }, 500); + + $this->assertMessages([], $results->getMessages()); + + $this->assertSubscriptions([ + subscribe(200, 500), + ], $xs->getSubscriptions()); + } + + /** + * @test + */ + public function should_not_break_unsubscription_chains_when_result_is_unsubscribed_explicitly() + { + $xs = $this->createHotObservable([ + onNext(600, 'a'), + onNext(700, 'b'), + ]); + + $results = $this->scheduler->startWithDispose(function() use ($xs) { + return $xs + ->flatMap(function($value) { + return \Rx\Observable::just($value); + }) + ->isEmpty() + ->flatMap(function($value) { + return \Rx\Observable::just($value); + }); + }, 500); + + $this->assertMessages([], $results->getMessages()); + + $this->assertSubscriptions([ + subscribe(200, 500), + ], $xs->getSubscriptions()); + } + +} \ No newline at end of file From bada6f5b19403aeb115ec10fa91599fae5f2f923 Mon Sep 17 00:00:00 2001 From: Martin Sikora Date: Thu, 12 Jan 2017 11:05:54 +0100 Subject: [PATCH 3/4] fixed demo and more tests --- demo/isEmpty/isEmpty-false.php | 2 +- demo/isEmpty/isEmpty-false.php.expect | 2 +- demo/isEmpty/isEmpty.php | 2 +- lib/Rx/Operator/IsEmptyOperator.php | 11 ++++----- src/Observable.php | 2 +- test/Rx/Functional/Operator/IsEmptyTest.php | 26 ++++++++++++++++++++- 6 files changed, 34 insertions(+), 11 deletions(-) diff --git a/demo/isEmpty/isEmpty-false.php b/demo/isEmpty/isEmpty-false.php index 6af55102..53359f88 100644 --- a/demo/isEmpty/isEmpty-false.php +++ b/demo/isEmpty/isEmpty-false.php @@ -5,4 +5,4 @@ $source = \Rx\Observable::just(1) ->isEmpty(); -$subscription = $source->subscribe($stdoutObserver); +$source->subscribe($stdoutObserver); diff --git a/demo/isEmpty/isEmpty-false.php.expect b/demo/isEmpty/isEmpty-false.php.expect index ee0f8aca..0dfe691c 100644 --- a/demo/isEmpty/isEmpty-false.php.expect +++ b/demo/isEmpty/isEmpty-false.php.expect @@ -1,2 +1,2 @@ -Next value: +Next value: 0 Complete! \ No newline at end of file diff --git a/demo/isEmpty/isEmpty.php b/demo/isEmpty/isEmpty.php index 2ab4b04d..bfe48a03 100644 --- a/demo/isEmpty/isEmpty.php +++ b/demo/isEmpty/isEmpty.php @@ -5,4 +5,4 @@ $source = \Rx\Observable::emptyObservable() ->isEmpty(); -$subscription = $source->subscribe($stdoutObserver); +$source->subscribe($stdoutObserver); diff --git a/lib/Rx/Operator/IsEmptyOperator.php b/lib/Rx/Operator/IsEmptyOperator.php index 3ad299b3..7367a67c 100644 --- a/lib/Rx/Operator/IsEmptyOperator.php +++ b/lib/Rx/Operator/IsEmptyOperator.php @@ -2,11 +2,9 @@ namespace Rx\Operator; -use Rx\Observer\CallbackObserver; -use Rx\Operator\OperatorInterface; use Rx\ObservableInterface; +use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; -use Rx\Scheduler\ImmediateScheduler; use Rx\SchedulerInterface; class IsEmptyOperator implements OperatorInterface @@ -19,7 +17,7 @@ class IsEmptyOperator implements OperatorInterface */ public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) { - return $observable->subscribeCallback( + $cbObserver = new CallbackObserver( function() use ($observer) { $observer->onNext(false); $observer->onCompleted(); @@ -28,8 +26,9 @@ function() use ($observer) { function() use ($observer) { $observer->onNext(true); $observer->onCompleted(); - }, - $scheduler + } ); + + return $observable->subscribe($cbObserver, $scheduler); } } \ No newline at end of file diff --git a/src/Observable.php b/src/Observable.php index 1e5ac433..f78eed12 100644 --- a/src/Observable.php +++ b/src/Observable.php @@ -1931,7 +1931,7 @@ public function throttle(int $throttleDuration, SchedulerInterface $scheduler = * @demo isEmpty/isEmpty.php * @demo isEmpty/isEmpty-false.php * @operator - * @reactivex isEmpty + * @reactivex contains */ public function isEmpty(): Observable { diff --git a/test/Rx/Functional/Operator/IsEmptyTest.php b/test/Rx/Functional/Operator/IsEmptyTest.php index b1c74293..f0c1f0a1 100644 --- a/test/Rx/Functional/Operator/IsEmptyTest.php +++ b/test/Rx/Functional/Operator/IsEmptyTest.php @@ -55,6 +55,30 @@ public function should_return_false_if_source_emits_element() ], $xs->getSubscriptions()); } + /** + * @test + */ + public function should_return_true_if_source_emits_before_subscription() + { + $xs = $this->createHotObservable([ + onNext(150, 'a'), + onCompleted(300) + ]); + + $results = $this->scheduler->startWithCreate(function() use ($xs) { + return $xs->isEmpty(); + }); + + $this->assertMessages([ + onNext(300, true), + onCompleted(300), + ], $results->getMessages()); + + $this->assertSubscriptions([ + subscribe(200, 300), + ], $xs->getSubscriptions()); + } + /** * @test */ @@ -82,7 +106,7 @@ public function should_raise_error_if_source_raise_error() /** * @test */ - public function should_not_completes_if_source_never_emits() + public function should_not_complete_if_source_never_emits() { $xs = $this->createHotObservable([]); From ca02d7245370f618c879bc4832cd709f50ee91bc Mon Sep 17 00:00:00 2001 From: Martin Sikora Date: Fri, 13 Jan 2017 12:27:42 +0100 Subject: [PATCH 4/4] transformed to 2.x --- {lib/Rx => src}/Operator/IsEmptyOperator.php | 19 ++++++------------- 1 file changed, 6 insertions(+), 13 deletions(-) rename {lib/Rx => src}/Operator/IsEmptyOperator.php (50%) diff --git a/lib/Rx/Operator/IsEmptyOperator.php b/src/Operator/IsEmptyOperator.php similarity index 50% rename from lib/Rx/Operator/IsEmptyOperator.php rename to src/Operator/IsEmptyOperator.php index 7367a67c..d8bf7ca8 100644 --- a/lib/Rx/Operator/IsEmptyOperator.php +++ b/src/Operator/IsEmptyOperator.php @@ -2,22 +2,16 @@ namespace Rx\Operator; +use Rx\DisposableInterface; use Rx\ObservableInterface; -use Rx\Observer\CallbackObserver; use Rx\ObserverInterface; -use Rx\SchedulerInterface; -class IsEmptyOperator implements OperatorInterface +final class IsEmptyOperator implements OperatorInterface { - /** - * @param \Rx\ObservableInterface $observable - * @param \Rx\ObserverInterface $observer - * @param \Rx\SchedulerInterface $scheduler - * @return \Rx\DisposableInterface - */ - public function __invoke(ObservableInterface $observable, ObserverInterface $observer, SchedulerInterface $scheduler = null) + + public function __invoke(ObservableInterface $observable, ObserverInterface $observer): DisposableInterface { - $cbObserver = new CallbackObserver( + return $observable->subscribe( function() use ($observer) { $observer->onNext(false); $observer->onCompleted(); @@ -28,7 +22,6 @@ function() use ($observer) { $observer->onCompleted(); } ); - - return $observable->subscribe($cbObserver, $scheduler); } + } \ No newline at end of file