event_source 0.0.2
event_source: ^0.0.2 copied to clipboard
Wrist friendly events for Dart
Event_source #
Event_source is a library for wrist friendly event implementation in Dart.
This is a very early version - expect bugs and breaking changes.
Overview #
At the moment, idiomatic implementation in Dart requires a bit of boilerplate code:
class Dog {
StreamController _barkController = new StreamController();
StreamController _wagController = new StreamController();
Stream _bark, _wag;
Dog() {
_bark = _barkController.stream.asBroadcastStream();
_wag = _wagController.stream.asBroadcastStream();
}
Stream<String> get onBark => _bark;
Stream get onWag => _wag;
void Bark(String sound) => _barkController.add(sound);
void Wag() => _wagController.add();
}
Now the client can attach as this:
var dog = new Dog();
dog.onBark.listen((data) => print('$data'));
dog.Bark('woof');
Event_source library removes the boilerplate from the implementation. It can be added to a class as mixin, removing the need for any extra fields:
class Dog extends Object with EventSource {
Stream<String> get onBark => events.BARK.stream;
Stream get onWag => events.WAG.stream;
void Bark(String sound) => events.BARK.signal(sound);
void Wag() => events.WAG.add();
}
If you don't like the idea of mixin poluting your class, just add an EventSource
instance as a field, everything else is exactly the same:
class Dog {
EventSource events = new EventSource();
Stream<String> get onBark => events.BARK.stream;
Stream get onWag => events.WAG.stream;
void Bark(String sound) => events.BARK.signal(sound);
void Wag() => events.WAG.add();
}
Usage #
Different ways to configure event identifiers #
The library dynamically checks the name (it overrides noSuchMethod
) to create the event identifier internally.
However, you don't have to rely on dynamic name dispatch if that's not your cup of tea.
Here are different ways to setup events:
class Dog extends Object with EventSource {
const int EVENT_WAG = 1;
Stream<String> get onBark => events.BARK.stream; // event name deduced
Stream get onWag => events[EVENT_WAG].stream; // numeric constant used as ID
Stream get onRun => events['RUN'].stream; // a string used as ID
Stream get onDrool => events[() => 1 + 2].stream; // runtime expression used as ID
void Bark(String sound) => events.BARK.signal(sound);
void Wag() => events[EVENT_WAG].add();
void Run() => events['RUN'].add();
void Drool() => events.[() => 1 + 2].add();
}
The difference between events['RUN']
and events.RUN
is that in latter case, a Symbol
instance is used as identifier instead of a string.
This means that you can't mix these approaches for same event. events['RUN']
is a different event than events.RUN
.
Differences between mixin and field approach + caveat #
I lied, there are differences between mixin and field approach.
Mixin approach allows following:
class Dog extends Object with EventSource {
Stream<String> get onBark => BARK.stream; // no need to prepend 'events.'
Stream get onWag => this[EVENT_WAG].stream; // 'this' instead of 'events'. 'events' returns 'this' anyway
}
If you use an EventSource
instance as a field, you don't have this choice, obviously.
WARNING:
However, there is a situatio n where mixin approach might bite you. The name of the getter must differ from event ID if you use dynamic names:
class Dog extends Object with EventSource {
Stream get onBark => events.onBark.stream; // <<< stack overflow
Stream get onWag => events['onWag'].stream; // this is fine
}
The reason is that Dog indeed has onBark
getter, and as events
point to the same object, it will again call the getter and so on.
Field approach doesn't exhibit this problem. Following works just fine:
class Dog {
EventSource events = new EventSource();
Stream get onBark => events.onBark.stream; // no problem here, delegated to EventSource instance
}
So feel free to pick what seems the best option to you.
Canceling subscription #
Canceling is done the same way as with any stream:
var dog = new Dog();
var sub = dog.onBark.listen((data) => print('$data'));
dog.bark('wooof');
sub.cancel();
Contributions #
Contributions are welcome, just send a pull request and if it fits into library I will gladly accept it.
Copyright and license #
Copyright 2013., Zdeslav Vojkovic.
Licensed under the MIT License, Version 2.0 (the "License");
You may not use this work except in compliance with the License. You may obtain a copy of the License in the LICENSE file, or at:
http://opensource.org/licenses/MIT
Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License.