Skip to content
Permalink

Comparing changes

Choose two branches to see what’s changed or to start a new pull request. If you need to, you can also or learn more about diff comparisons.

Open a pull request

Create a new pull request by comparing changes across two branches. If you need to, you can also . Learn more about diff comparisons here.
base repository: marcojakob/dart-event-bus
Failed to load repositories. Confirm that selected base ref is valid, then try again.
Loading
base: v0.4.1
Choose a base ref
...
head repository: marcojakob/dart-event-bus
Failed to load repositories. Confirm that selected head ref is valid, then try again.
Loading
compare: master
Choose a head ref

Commits on May 13, 2015

  1. Copy the full SHA
    a425126 View commit details

Commits on Jul 6, 2018

  1. Migrate to Dart 2

    - BREAKING CHANGE: The `on` method now has a generic type. The type must be passed as a type argument instead of a method parameter. Change `myEventBus.on(MyEventType)` to `myEventBus.on<MyEventType>()`.
    - BREAKING CHANGE: Every `EventBus` is now hierarchical so that listeners will also receive events of subtypes of the specified type. This is exactly the way that `HierarchicalEventBus` worked. So `HierarchicalEventBus` has been removed. Use the normal `EventBus` instead.
    marcojakob committed Jul 6, 2018
    Copy the full SHA
    0d7b88c View commit details
  2. Sugar

    marcojakob committed Jul 6, 2018
    Copy the full SHA
    86664c4 View commit details

Commits on Jul 7, 2018

  1. Copy the full SHA
    c21526a View commit details

Commits on Feb 13, 2019

  1. Copy the full SHA
    35e89e3 View commit details
  2. Fix repo url

    marcojakob committed Feb 13, 2019
    Copy the full SHA
    e29b4a6 View commit details

Commits on Mar 26, 2019

  1. Update event_bus.dart

    Vadaski authored Mar 26, 2019
    Copy the full SHA
    d6e494a View commit details

Commits on Mar 27, 2019

  1. Update event_bus.dart

    Vadaski authored Mar 27, 2019
    Copy the full SHA
    fd4847b View commit details
  2. Rename to customController

    marcojakob committed Mar 27, 2019
    Copy the full SHA
    9dd8370 View commit details
  3. Remove new keyword

    marcojakob committed Mar 27, 2019
    Copy the full SHA
    8193be4 View commit details
  4. Getting ready for v1.1.0

    marcojakob committed Mar 27, 2019
    Copy the full SHA
    5ee947b View commit details

Commits on Dec 4, 2019

  1. Update Dart Pub urls

    marcojakob committed Dec 4, 2019
    Copy the full SHA
    df294a7 View commit details

Commits on Jan 23, 2020

  1. Fix homepage URL.

    marcojakob committed Jan 23, 2020
    Copy the full SHA
    0f64cd8 View commit details

Commits on Oct 29, 2020

  1. Upgrade to nnbd

    mnordine-gn committed Oct 29, 2020
    Copy the full SHA
    dd622c8 View commit details
  2. Cast to non-nullable

    mnordine-gn committed Oct 29, 2020
    Copy the full SHA
    350f87c View commit details

Commits on Mar 4, 2021

  1. Update dependencies

    marcojakob committed Mar 4, 2021
    Copy the full SHA
    3d7f52d View commit details
  2. 1
    Copy the full SHA
    0147330 View commit details
  3. Merge pull request #43 from mnordine/nnbd

    Migrate to null safety.
    marcojakob authored Mar 4, 2021
    Copy the full SHA
    ac8027b View commit details

Commits on Jan 16, 2024

  1. Copy the full SHA
    9f2a29e View commit details

Commits on Sep 23, 2024

  1. Copy the full SHA
    36a4f89 View commit details
  2. Copy the full SHA
    0f7af23 View commit details
  3. Copy the full SHA
    4b62747 View commit details
  4. Copy the full SHA
    4b0fcef View commit details
  5. Merge pull request #53 from plucenio/master

    fix: updating some dev_dependencies.
    marcojakob authored Sep 23, 2024
    Copy the full SHA
    a8178e3 View commit details
  6. Update changelog

    marcojakob committed Sep 23, 2024
    Copy the full SHA
    87fe3b8 View commit details
  7. Fix version

    marcojakob committed Sep 23, 2024
    Copy the full SHA
    28de171 View commit details
Showing with 367 additions and 457 deletions.
  1. +9 −4 .gitignore
  2. +58 −42 CHANGELOG.md
  3. +43 −45 README.md
  4. +3 −6 example/events.dart
  5. +49 −41 example/example.dart
  6. +31 −28 example/index.html
  7. +49 −48 lib/event_bus.dart
  8. +0 −50 lib/event_bus_hierarchical.dart
  9. +10 −7 pubspec.yaml
  10. +0 −14 test/all_tests.dart
  11. +0 −11 test/all_tests.html
  12. +30 −46 test/event_bus_hierarchical_test.dart
  13. +85 −80 test/event_bus_test.dart
  14. +0 −35 tool/drone_io.sh
13 changes: 9 additions & 4 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,7 +1,12 @@
.buildlog
.DS_Store
.idea
# Files and directories created by pub
.packages
.pub/
build/
packages
# Remove the following pattern if you wish to check in your lock file
pubspec.lock

# Files generated by dart tools
.dart_tool

# Directory created by dartdoc
doc/api/
100 changes: 58 additions & 42 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,91 +1,107 @@
# Changelog

## Version 0.4.1 (2015-05-13)
## Version 2.0.1 (2024-09-23)

- Update environment dependency to support up to Dart v3.

## Version 2.0.0 (2021-03-04)

- Migrate to null safety.

## Version 1.1.1 (2020-01-21)

- Fix homepage URL.


* Fix Issue #13: Improve on() stream when no type is specified
## Version 1.1.0 (2019-03-27)

- Add constructor for custom controllers like RxDart Subject (see #21).
- Remove `new` keyword.

## Version 1.0.3 (2019-02-14)

- Cleanup and update dependencies.

## Version 1.0.0 (2018-07-06)

- Migrate to Dart 2.
- BREAKING CHANGE: The `on` method now has a generic type. The type must be passed as a type argument instead of a method parameter. Change `myEventBus.on(MyEventType)` to `myEventBus.on<MyEventType>()`.
- BREAKING CHANGE: Every `EventBus` is now hierarchical so that listeners will also receive events of subtypes of the specified type. This is exactly the way that `HierarchicalEventBus` worked. So `HierarchicalEventBus` has been removed. Use the normal `EventBus` instead.

## Version 0.4.1 (2015-05-13)

- Fix Issue #13: Improve on() stream when no type is specified

## Version 0.4.0 (2015-05-03)

* BREAKING CHANGE: Moved the `HierarchicalEventBus` to a separate library to
be able to remove `dart:mirrors` from the normal `EventBus`.
- BREAKING CHANGE: Moved the `HierarchicalEventBus` to a separate library to
be able to remove `dart:mirrors` from the normal `EventBus`.
Users of the hierarchical event bus must import `event_bus_hierarchical.dart`
and replace the use of the factory constructor `EventBus.hierarchical()` with
the `HierarchicalEventBus` constructor.


## Version 0.3.0 (2014-09-08)

* BREAKING CHANGE: Changed and simplified the EventBus API. We can now dispatch
- BREAKING CHANGE: Changed and simplified the EventBus API. We can now dispatch
any Dart object as an event. Before, we had to create an EventType for every
type of event we wanted to fire. Now we can use any class as an event.
type of event we wanted to fire. Now we can use any class as an event.
Listeners can (optionally) filter events by that class.
* Added a way to create a **hierarchical event bus** that filters events by
class and their subclasses. This currently only works with classes
**extending** other classes and not with **implementing** an interface.
We might have to wait for
- Added a way to create a **hierarchical event bus** that filters events by
class and their subclasses. This currently only works with classes
**extending** other classes and not with **implementing** an interface.
We might have to wait for
https://code.google.com/p/dart/issues/detail?id=20756 to enable interfaces.
* BREAKING CHANGE: The EventBus constructor defaults to **async instead of
sync**!!. This matches the constructor of the Dart Streams and an async event
- BREAKING CHANGE: The EventBus constructor defaults to **async instead of
sync**!!. This matches the constructor of the Dart Streams and an async event
bus might also be the more common use case.
* BREAKING CHANGE: Removed LoggingEventBus. Reason is that logging can easily
- BREAKING CHANGE: Removed LoggingEventBus. Reason is that logging can easily
be implemented with a event listener that listens for all events and logs
them.


## Version 0.2.5 (2014-09-03)

* Update example.
* Update readme with new links.
* Update dependencies.

- Update example.
- Update readme with new links.
- Update dependencies.

## Version 0.2.4 (2013-11-11)

* Update to dart libraries 0.9.0.

- Update to dart libraries 0.9.0.

## Version 0.2.3 (2013-09-16)

* Fix issue #8: Add logging of events that flow through event bus

- Fix issue #8: Add logging of events that flow through event bus

## Version 0.2.2 (2013-09-16)

* Change default of SimpleEventBus to sync (same as factory in EventBus)

- Change default of SimpleEventBus to sync (same as factory in EventBus)

## Version 0.2.1 (2013-07-01)

* Fix issue #6: Fire should accept null as data

- Fix issue #6: Fire should accept null as data

## Version 0.2.0 (2013-06-06)

* Update to new Dart SDK v0.5.13.1_r23552.
* Using Darts new Stream.broadcast() factory.
* Provide option for synchronous broadcasting of events.
* Update unit tests and example.
* Create demo page.


## Version 0.1.3 (2013-05-19)
- Update to new Dart SDK v0.5.13.1_r23552.
- Using Darts new Stream.broadcast() factory.
- Provide option for synchronous broadcasting of events.
- Update unit tests and example.
- Create demo page.

* Removed all occurrences of @override
## Version 0.1.3 (2013-05-19)

- Removed all occurrences of @override

## Version 0.1.2 (2013-05-17)

* Change in README: contained wrong license (Apache instead of MIT).
* Remove import 'package:meta/meta.dart' in event_bus.dart as it is not needed
- Change in README: contained wrong license (Apache instead of MIT).
- Remove import 'package:meta/meta.dart' in event_bus.dart as it is not needed
and may cause an error if used as pub package.


## Version 0.1.1 (2013-04-29)

* Minor change in README to fix image links.

- Minor change in README to fix image links.

## Version 0.1.0 (2013-04-29)

* Initial Version.
- Initial Version.
88 changes: 43 additions & 45 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,29 +1,26 @@
# Event Bus

A simple Event Bus using Dart [Streams](https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:async.Stream)
A simple Event Bus using Dart [Streams](https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:async.Stream)
for decoupling applications.

[![Star this Repo](https://img.shields.io/github/stars/marcojakob/dart-event-bus.svg?style=flat-square)](https://github.com/marcojakob/dart-event-bus)
[![Pub Package](https://img.shields.io/pub/v/event_bus.svg?style=flat-square)](https://pub.dartlang.org/packages/event_bus)
[![Build Status](https://drone.io/github.com/marcojakob/dart-event-bus/status.png)](https://drone.io/github.com/marcojakob/dart-event-bus/latest)

[GitHub](https://github.com/marcojakob/dart-event-bus) |
[Pub](https://pub.dartlang.org/packages/event_bus) |
[Demos and Examples](http://code.makery.ch/library/dart-event-bus/)
[![Pub Package](https://img.shields.io/pub/v/event_bus.svg?style=flat-square)](https://pub.dev/packages/event_bus)

[GitHub](https://github.com/marcojakob/dart-event-bus) |
[Pub](https://pub.dev/packages/event_bus) |
[Demos and Examples](https://code.makery.ch/library/dart-event-bus/)

## Event Bus Pattern

An Event Bus follows the publish/subscribe pattern. It allows listeners to
An Event Bus follows the publish/subscribe pattern. It allows listeners to
subscribe for events and publishers to fire events. This enables objects to
interact without requiring to explicitly define listeners and keeping track of
them.


### Event Bus and MVC

The Event Bus pattern is especially helpful for decoupling [MVC](http://wikipedia.org/wiki/Model_View_Controller)
(or [MVP](http://wikipedia.org/wiki/Model_View_Presenter)) applications.
The Event Bus pattern is especially helpful for decoupling [MVC](https://wikipedia.org/wiki/Model_View_Controller)
(or [MVP](https://wikipedia.org/wiki/Model_View_Presenter)) applications.

**One group of MVC** is not a problem.

@@ -38,39 +35,23 @@ By communication through an **Event Bus**, the coupling is reduced.

![Event Bus](https://raw.githubusercontent.com/marcojakob/dart-event-bus/master/doc/event-bus.png)


## Usage


### 1. Create an Event Bus

Create an instance of `EventBus` and make it available to other classes.

Usually there is just one Event Bus per application, but more than one may be
Usually there is just one Event Bus per application, but more than one may be
set up to group a specific set of events.

```dart
import 'package:event_bus/event_bus.dart';
EventBus eventBus = new EventBus();
EventBus eventBus = EventBus();
```

You can alternatively use the `HierarchicalEventBus` that filters events by
event class **including** its subclasses.

*Note that the hierarchical event bus uses `dart:mirrors` which support in
dart2js is experimental.*

```dart
import 'package:event_bus/event_bus_hierarchical.dart';
EventBus eventBus = new HierarchicalEventBus();
```

**Note:** *The default constructor will create an asynchronous event bus. To
create a synchronous you must provide the optional `sync: true` attribute.*


**Note:** _The default constructor will create an asynchronous event bus. To
create a synchronous bus you must provide the optional `sync: true` attribute._

### 2. Define Events

@@ -79,24 +60,24 @@ Any Dart class can be used as an event.
```dart
class UserLoggedInEvent {
User user;
UserLoggedInEvent(this.user);
}
class NewOrderEvent {
Order order;
NewOrderEvent(this.order);
}
```


### 3. Register Listeners

Register listeners for a **specific events**:
Register listeners for **specific events**:

```dart
eventBus.on(UserLoggedInEvent).listen((UserLoggedInEvent event) {
eventBus.on<UserLoggedInEvent>().listen((event) {
// All events are of type UserLoggedInEvent (or subtypes of it).
print(event.user);
});
```
@@ -106,38 +87,55 @@ Register listeners for **all events**:
```dart
eventBus.on().listen((event) {
// Print the runtime type. Such a set up could be used for logging.
print(event.runtimeType);
print(event.runtimeType);
});
```


#### About Dart Streams

`EventBus` uses Dart [Streams](https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:async.Stream)
as its underlying mechanism to keep track of listeners. You may use all
as its underlying mechanism to keep track of listeners. You may use all
functionality available by the [Stream](https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:async.Stream)
API. One example is the use of [StreamSubscriptions](https://api.dartlang.org/apidocs/channels/stable/dartdoc-viewer/dart:async.StreamSubscription)
to later unsubscribe from the events.

```dart
StreamSubscription loginSubscription = eventBus.on(UserLoggedInEvent).listen((UserLoggedInEvent event) {
print(event.user);
StreamSubscription loginSubscription = eventBus.on<UserLoggedInEvent>().listen((event) {
print(event.user);
});
loginSubscription.cancel();
```


### 4. Fire Events

Finally, we need to fire an event.

```dart
User myUser = new User('Mickey');
eventBus.fire(new UserLoggedInEvent(myUser));
User myUser = User('Mickey');
eventBus.fire(UserLoggedInEvent(myUser));
```

## Using Custom Stream Controllers

Instead of using the default `StreamController` you can use the following constructor
to provide your own.

An example would be to use an [RxDart](https://pub.dev/packages/rxdart) Subject
as the controller.

```dart
import 'package:rxdart/rxdart.dart';
EventBus behaviorBus = EventBus.customController(BehaviorSubject());
```

## Running / Building / Testing

- Run from the terminal: `webdev serve`
- Build from the terminal: `webdev build`
- Testing: `pub run build_runner test -- -p chrome`

## License

The MIT License (MIT)
The MIT License (MIT)
9 changes: 3 additions & 6 deletions example/events.dart
Original file line number Diff line number Diff line change
@@ -1,24 +1,21 @@
/**
* This is an example of how to set up the [EventBus] and its events.
*/
library events;

import 'package:event_bus/event_bus.dart';

/// The global [EventBus] object.
EventBus eventBus = new EventBus();
EventBus eventBus = EventBus();

/// Event A.
class MyEventA {
String text;

MyEventA(this.text);
}

/// Event B.
class MyEventB {
String text;

MyEventB(this.text);
}

90 changes: 49 additions & 41 deletions example/example.dart
Original file line number Diff line number Diff line change
@@ -1,45 +1,47 @@
import 'dart:async';
import 'dart:html';

import 'dart:async';
import 'events.dart';
import 'package:logging/logging.dart';

import 'events.dart';

int counterA = 1;
int counterB = 1;

final _log = new Logger('event_bus_example');
final _log = Logger('event_bus_example');

void main() {
// Init logging.
initLogging();

// Log all events.
eventBus.on().listen((event) => _log.finest('event fired: ${event.runtimeType}'));


eventBus
.on()
.listen((event) => _log.finest('event fired: ${event.runtimeType}'));

// Initialize the listener boxes.
Listener listener1 = new Listener(querySelector('#listener-1'));
Listener listener2 = new Listener(querySelector('#listener-2'));
Listener(querySelector('#listener-1')!);
Listener(querySelector('#listener-2')!);

// Init Event fields.
LabelElement fireLabelA = querySelector('#fire-label-a');
LabelElement fireLabelB = querySelector('#fire-label-b');
ButtonElement fireButtonA = querySelector("#fire-button-a");
ButtonElement fireButtonB = querySelector("#fire-button-b");
LabelElement fireLabelA = querySelector('#fire-label-a') as LabelElement;
LabelElement fireLabelB = querySelector('#fire-label-b') as LabelElement;
ButtonElement fireButtonA = querySelector("#fire-button-a") as ButtonElement;
ButtonElement fireButtonB = querySelector("#fire-button-b") as ButtonElement;

fireButtonA.onClick.listen((_) {
// -------------------------------------------------
// Fire Event A
// -------------------------------------------------
eventBus.fire(new MyEventA('Received Event A [$counterA]'));
eventBus.fire(MyEventA('Received Event A [$counterA]'));
fireLabelA.text = '--> fired [$counterA]';
counterA++;
});
fireButtonB.onClick.listen((_) {
// -------------------------------------------------
// Fire Event B
// -------------------------------------------------
eventBus.fire(new MyEventB('Received Event B [$counterB]'));
eventBus.fire(MyEventB('Received Event B [$counterB]'));
fireLabelB.text = '--> fired [$counterB]';
counterB++;
});
@@ -50,90 +52,96 @@ initLogging() {
Logger.root.onRecord.listen((LogRecord r) {
print('${r.time}\t${r.loggerName}\t[${r.level.name}]:\t${r.message}');
});

// Root logger level.
Logger.root.level = Level.FINEST;
}

class Listener {
Element element;
TextAreaElement output;
StreamSubscription<String> subscription;

late final TextAreaElement output;

StreamSubscription? subscription;

Listener(this.element) {
output = element.querySelector('textarea');
output = element.querySelector('textarea') as TextAreaElement;
// Init buttons.
element.querySelector('.listen-a').onClick.listen((_) => listenForEventA());
element.querySelector('.listen-b').onClick.listen((_) => listenForEventB());
element.querySelector('.pause').onClick.listen((_) => pause());
element.querySelector('.resume').onClick.listen((_) => resume());
element.querySelector('.cancel').onClick.listen((_) => cancel());
element
.querySelector('.listen-a')!
.onClick
.listen((_) => listenForEventA());
element
.querySelector('.listen-b')!
.onClick
.listen((_) => listenForEventB());
element.querySelector('.pause')!.onClick.listen((_) => pause());
element.querySelector('.resume')!.onClick.listen((_) => resume());
element.querySelector('.cancel')!.onClick.listen((_) => cancel());
}

void listenForEventA() {
if (subscription != null) {
appendOuput('Already listening for an event.');
} else {
// -------------------------------------------------
// Listen for Event A
// -------------------------------------------------
subscription = eventBus.on(MyEventA).listen((event) {
subscription = eventBus.on<MyEventA>().listen((event) {
appendOuput(event.text);
});
appendOuput('---');
appendOuput('Listening for Event A');
appendOuput('---');
}
}

void listenForEventB() {
if (subscription != null) {
appendOuput('Already listening for an event.');
} else {
// -------------------------------------------------
// Listen for Event B
// -------------------------------------------------
subscription = eventBus.on(MyEventB).listen((MyEventB event) {
subscription = eventBus.on<MyEventB>().listen((MyEventB event) {
appendOuput(event.text);
});
appendOuput('---');
appendOuput('Listening for Event B');
appendOuput('---');
}
}

void pause() {
if (subscription != null) {
subscription.pause();
subscription!.pause();
appendOuput('Subscription paused.');
} else {
appendOuput('No subscription, cannot pause!');
}
}

void resume() {
if (subscription != null) {
subscription.resume();
subscription!.resume();
appendOuput('Subscription resumed.');
} else {
appendOuput('No subscription, cannot resume!');
}
}

void cancel() {
if (subscription != null) {
subscription.cancel();
subscription!.cancel();
subscription = null;
appendOuput('Subscription canceled.');
} else {
appendOuput('No subscription, cannot cancel!');
}
}

void appendOuput(String text) {
output.appendText('$text\n');
output.value = output.value! + '$text\n';
output.scrollTop = output.scrollHeight;
}
}
59 changes: 31 additions & 28 deletions example/index.html
Original file line number Diff line number Diff line change
@@ -1,52 +1,54 @@
<!DOCTYPE html>

<html>

<head>
<meta charset="utf-8">
<title>Event Bus</title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet" href="example.css">
<meta charset="utf-8">
<title>Event Bus</title>
<link rel="stylesheet"
href="https://maxcdn.bootstrapcdn.com/bootstrap/3.2.0/css/bootstrap.min.css">
<link rel="stylesheet"
href="example.css">

<script async type="application/dart" src="example.dart"></script>
<script async src="packages/browser/dart.js"></script>
<script defer
src="example.dart.js"></script>
</head>

<body>
<div id="example-container" class="container-fluid">
<div id="example-container"
class="container-fluid">

<a
href="https://github.com/marcojakob/dart-event-bus/tree/master/example"
target="_parent">Example Source on GitHub</a>
<a href="https://github.com/marcojakob/dart-event-bus/tree/master/example"
target="_parent">Example Source on GitHub</a>

<div class="row">
<div class="listener col-xs-6" id="listener-1">
<div class="listener col-xs-6"
id="listener-1">
<h4>Listener 1</h4>
<p>
<textarea class="form-control" rows="4"></textarea>
<textarea class="form-control"
rows="4"></textarea>
</p>
<p>
<button class="listen-a btn btn-primary btn-sm">Listen
for Event A</button>
<button class="listen-b btn btn-success btn-sm">Listen
for Event B</button>
<button class="listen-a btn btn-primary btn-sm">Listen for Event A</button>
<button class="listen-b btn btn-success btn-sm">Listen for Event B</button>
</p>
<p>
<button class="pause btn btn-default btn-sm">Pause</button>
<button class="resume btn btn-default btn-sm">Resume</button>
<button class="cancel btn btn-default btn-sm">Cancel</button>
</p>
</div>
<div class="listener col-xs-6" id="listener-2">
<div class="listener col-xs-6"
id="listener-2">
<h4>Listener 2</h4>
<p>
<textarea class="form-control" rows="4"></textarea>
<textarea class="form-control"
rows="4"></textarea>
</p>
<p>
<button class="listen-a btn btn-primary btn-sm">Listen
for Event A</button>
<button class="listen-b btn btn-success btn-sm">Listen
for Event B</button>
<button class="listen-a btn btn-primary btn-sm">Listen for Event A</button>
<button class="listen-b btn btn-success btn-sm">Listen for Event B</button>
</p>
<p>
<button class="pause btn btn-default btn-sm">Pause</button>
@@ -60,19 +62,20 @@ <h4>Fire Events</h4>
<div class="row">
<div class="event col-xs-12">
<p>
<button id="fire-button-a" class="btn btn-primary btn-sm">Fire
Event A</button>
<button id="fire-button-a"
class="btn btn-primary btn-sm">Fire Event A</button>
<label id="fire-label-a"></label>
</p>
</div>
<div class="event col-xs-12">
<p>
<button id="fire-button-b" class="btn btn-success btn-sm">Fire
Event B</button>
<button id="fire-button-b"
class="btn btn-success btn-sm">Fire Event B</button>
<label id="fire-label-b"></label>
</p>
</div>
</div>
</div>
</body>
</html>

</html>
97 changes: 49 additions & 48 deletions lib/event_bus.dart
Original file line number Diff line number Diff line change
@@ -1,68 +1,69 @@
library event_bus;

import 'dart:async';

/**
* Dispatches events to listeners using the Dart [Stream] API. The [EventBus]
* enables decoupled applications. It allows objects to interact without
* requiring to explicitly define listeners and keeping track of them.
*
* Not all events should be broadcasted through the [EventBus] but only those of
* general interest.
*
* Events are normal Dart objects. By specifying a class, listeners can
* filter events. Such a filter will return
* specifying a class.
*/
/// Dispatches events to listeners using the Dart [Stream] API. The [EventBus]
/// enables decoupled applications. It allows objects to interact without
/// requiring to explicitly define listeners and keeping track of them.
///
/// Not all events should be broadcasted through the [EventBus] but only those of
/// general interest.
///
/// Events are normal Dart objects. By specifying a class, listeners can
/// filter events.
///
class EventBus {

StreamController _streamController;

/// Controller for the event bus stream.
StreamController get streamController => _streamController;

/**
* Creates an [EventBus].
*
* If [sync] is true, events are passed directly to the stream's listeners
* during an [fire] call. If false (the default), the event will be passed to
* the listeners at a later time, after the code creating the event has
* completed.
*/
EventBus({bool sync: false}) {
_streamController = new StreamController.broadcast(sync: sync);
}
/// Creates an [EventBus].
///
/// If [sync] is true, events are passed directly to the stream's listeners
/// during a [fire] call. If false (the default), the event will be passed to
/// the listeners at a later time, after the code creating the event has
/// completed.
EventBus({bool sync = false})
: _streamController = StreamController.broadcast(sync: sync);

/// Instead of using the default [StreamController] you can use this constructor
/// to pass your own controller.
///
/// An example would be to use an RxDart Subject as the controller.
EventBus.customController(StreamController controller)
: _streamController = controller;

/**
* Listens for events of [eventType].
*
* The returned [Stream] is a broadcast stream so multiple subscriptions are
* allowed.
*
* Each listener is handled independently, and if they pause, only the pausing
* listener is affected. A paused listener will buffer events internally until
* unpaused or canceled. So it's usually better to just cancel and later
* subscribe again (avoids memory leak).
*/
Stream on([Type eventType]) {
if (eventType == null) {
return streamController.stream;
/// Listens for events of Type [T] and its subtypes.
///
/// The method is called like this: myEventBus.on<MyType>();
///
/// If the method is called without a type parameter, the [Stream] contains every
/// event of this [EventBus].
///
/// The returned [Stream] is a broadcast stream so multiple subscriptions are
/// allowed.
///
/// Each listener is handled independently, and if they pause, only the pausing
/// listener is affected. A paused listener will buffer events internally until
/// unpaused or canceled. So it's usually better to just cancel and later
/// subscribe again (avoids memory leak).
///
Stream<T> on<T>() {
if (T == dynamic) {
return streamController.stream as Stream<T>;
} else {
return streamController.stream.where((event) => event.runtimeType == eventType);
return streamController.stream.where((event) => event is T).cast<T>();
}
}

/**
* Fires a new event on the event bus with the specified [event].
*/
/// Fires a new event on the event bus with the specified [event].
///
void fire(event) {
streamController.add(event);
}

/**
* Destroy this [EventBus]. This is generally only in a testing context.
*/
/// Destroy this [EventBus]. This is generally only in a testing context.
///
void destroy() {
_streamController.close();
}
}
}
50 changes: 0 additions & 50 deletions lib/event_bus_hierarchical.dart

This file was deleted.

17 changes: 10 additions & 7 deletions pubspec.yaml
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
name: event_bus
version: 0.4.1
author: Marco Jakob <majakob@gmx.ch>
version: 2.0.1
description: A simple Event Bus using Dart Streams for decoupling applications
homepage: http://code.makery.ch/library/dart-event-bus
documentation: http://www.dartdocs.org/documentation/event_bus/latest/
repository: https://github.com/marcojakob/dart-event-bus
homepage: https://code.makery.ch/library/dart-event-bus/
environment:
sdk: '>=2.12.0 <4.0.0'
dev_dependencies:
browser: '>=0.10.0 <0.11.0'
logging: '>=0.10.0 <0.11.0'
unittest: '>=0.11.0 <0.12.0'
build_runner: ^2.4.8
build_web_compilers: ^4.0.9
build_test: ^2.0.0
logging: ^1.0.0
test: ^1.5.0
14 changes: 0 additions & 14 deletions test/all_tests.dart

This file was deleted.

11 changes: 0 additions & 11 deletions test/all_tests.html

This file was deleted.

76 changes: 30 additions & 46 deletions test/event_bus_hierarchical_test.dart
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
library hierarchical_event_bus_test;

import 'dart:async';
import 'package:unittest/unittest.dart';

import 'package:event_bus/event_bus_hierarchical.dart';
import 'package:event_bus/event_bus.dart';
import 'package:test/test.dart';

class EventA extends SuperEvent {
String text;
@@ -17,54 +15,40 @@ class EventB extends SuperEvent {
EventB(this.text);
}

class SuperEvent {
}
class SuperEvent {}

main() {

group('[HierarchicalEventBus]', () {

test('Listen on same class', () {
// given
EventBus eventBus = new HierarchicalEventBus();
Future f = eventBus.on(EventA).toList();

// when
eventBus.fire(new EventA('a1'));
eventBus.fire(new EventB('b1'));
eventBus.destroy();

// then
return f.then((List events) {
expect(events.length, 1);
group('[EventBus] (hierarchical)', () {
test('Listen on same class', () {
// given
EventBus eventBus = EventBus();
Future f = eventBus.on<EventA>().toList();

// when
eventBus.fire(EventA('a1'));
eventBus.fire(EventB('b1'));
eventBus.destroy();

// then
return f.then((events) {
expect(events.length, 1);
});
});
});

test('Listen on superclass', () {
// given
EventBus eventBus = new HierarchicalEventBus();
Future f = eventBus.on(SuperEvent).toList();
test('Listen on superclass', () {
// given
EventBus eventBus = EventBus();
Future f = eventBus.on<SuperEvent>().toList();

// when
eventBus.fire(new EventA('a1'));
eventBus.fire(new EventB('b1'));
eventBus.destroy();
// when
eventBus.fire(EventA('a1'));
eventBus.fire(EventB('b1'));
eventBus.destroy();

// then
return f.then((List events) {
expect(events.length, 2);
// then
return f.then((events) {
expect(events.length, 2);
});
});
});
});
}











165 changes: 85 additions & 80 deletions test/event_bus_test.dart
Original file line number Diff line number Diff line change
@@ -1,106 +1,111 @@
library event_bus_test;

import 'dart:async';
import 'package:unittest/unittest.dart';

import 'package:event_bus/event_bus.dart';
import 'package:test/test.dart';

class EventA {
String text;

EventA(this.text);
}

class EventB {
String text;

EventB(this.text);
}

main() {

group('[EventBus]', () {

test('Fire one event', () {
// given
EventBus eventBus = new EventBus();
Future f = eventBus.on(EventA).toList();

// when
eventBus.fire(new EventA('a1'));
eventBus.destroy();

// then
return f.then((List events) {
expect(events.length, 1);
});
});

test('Fire two events of same type', () {
// given
EventBus eventBus = new EventBus();
Future f = eventBus.on(EventA).toList();

// when
eventBus.fire(new EventA('a1'));
eventBus.fire(new EventA('a2'));
eventBus.destroy();

// then
return f.then((List events) {
expect(events.length, 2);
});
});

test('Fire events of different type', () {
// given
EventBus eventBus = new EventBus();
Future f1 = eventBus.on(EventA).toList();
Future f2 = eventBus.on(EventB).toList();

// when
eventBus.fire(new EventA('a1'));
eventBus.fire(new EventB('b1'));
eventBus.destroy();

// then
return Future.wait(
[
f1.then((List events) {
expect(events.length, 1);
}),
f2.then((List events) {
expect(events.length, 1);
})
]);
});

test('Fire events of different type, receive all types', () {
// given
EventBus eventBus = new EventBus();
Future f = eventBus.on().toList();

// when
eventBus.fire(new EventA('a1'));
eventBus.fire(new EventB('b1'));
eventBus.fire(new EventB('b2'));
eventBus.destroy();

// then
return f.then((List events) {
expect(events.length, 3);
});
});
});
class EventWithMap {
Map myMap;

EventWithMap(this.myMap);
}

main() {
group('[EventBus]', () {
test('Fire one event', () {
// given
EventBus eventBus = EventBus();
Future f = eventBus.on<EventA>().toList();

// when
eventBus.fire(EventA('a1'));
eventBus.destroy();

// then
return f.then((events) {
expect(events.length, 1);
});
});

test('Fire two events of same type', () {
// given
EventBus eventBus = EventBus();
Future f = eventBus.on<EventA>().toList();

// when
eventBus.fire(EventA('a1'));
eventBus.fire(EventA('a2'));
eventBus.destroy();

// then
return f.then((events) {
expect(events.length, 2);
});
});

test('Fire events of different type', () {
// given
EventBus eventBus = EventBus();
Future f1 = eventBus.on<EventA>().toList();
Future f2 = eventBus.on<EventB>().toList();

// when
eventBus.fire(EventA('a1'));
eventBus.fire(EventB('b1'));
eventBus.destroy();

// then
return Future.wait([
f1.then((events) {
expect(events.length, 1);
}),
f2.then((events) {
expect(events.length, 1);
})
]);
});

test('Fire events of different type, receive all types', () {
// given
EventBus eventBus = EventBus();
Future f = eventBus.on().toList();

// when
eventBus.fire(EventA('a1'));
eventBus.fire(EventB('b1'));
eventBus.fire(EventB('b2'));
eventBus.destroy();

// then
return f.then((events) {
expect(events.length, 3);
});
});

test('Fire event with a map type', () {
// given
EventBus eventBus = EventBus();
Future f = eventBus.on<EventWithMap>().toList();

// when
eventBus.fire(EventWithMap({'a': 'test'}));
eventBus.destroy();

// then
return f.then((events) {
expect(events.length, 1);
});
});
});
}
35 changes: 0 additions & 35 deletions tool/drone_io.sh

This file was deleted.