Expose a smaller surface area for custom watchers (#92)
- Remove the function to unregister a custom watcher, we can add it
later when we have a specific use case for it.
- Remove the class `CustomFactoryWatcher` and take callbacks instead.
- Bump the version and add the changelog that was missed.
- Add missing copyright notice.
diff --git a/CHANGELOG.md b/CHANGELOG.md
index a65a6e3..a98ae20 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,7 @@
+# 0.9.8
+
+* Add the ability to create custom Watcher types for specific file paths.
+
# 0.9.7+15
* Fix a bug on Mac where modifying a directory with a path exactly matching a
diff --git a/lib/src/custom_watcher_factory.dart b/lib/src/custom_watcher_factory.dart
index b7f81fa..3dc1bea 100644
--- a/lib/src/custom_watcher_factory.dart
+++ b/lib/src/custom_watcher_factory.dart
@@ -1,35 +1,48 @@
+// Copyright (c) 2020, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
import '../watcher.dart';
-/// Defines a way to create a custom watcher instead of the default ones.
-///
-/// This will be used when a [DirectoryWatcher] or [FileWatcher] would be
-/// created and will take precedence over the default ones.
-abstract class CustomWatcherFactory {
- /// Uniquely identify this watcher.
- String get id;
+/// A factory to produce custom watchers for specific file paths.
+class _CustomWatcherFactory {
+ final String id;
+ final DirectoryWatcher Function(String path, {Duration pollingDelay})
+ createDirectoryWatcher;
+ final FileWatcher Function(String path, {Duration pollingDelay})
+ createFileWatcher;
- /// Tries to create a [DirectoryWatcher] for the provided path.
- ///
- /// Returns `null` if the path is not supported by this factory.
- DirectoryWatcher createDirectoryWatcher(String path, {Duration pollingDelay});
-
- /// Tries to create a [FileWatcher] for the provided path.
- ///
- /// Returns `null` if the path is not supported by this factory.
- FileWatcher createFileWatcher(String path, {Duration pollingDelay});
+ _CustomWatcherFactory(
+ this.id, this.createDirectoryWatcher, this.createFileWatcher);
}
/// Registers a custom watcher.
///
-/// It's only allowed to register a watcher factory once per [id] and at most
-/// one factory should apply to any given file (creating a [Watcher] will fail
-/// otherwise).
-void registerCustomWatcherFactory(CustomWatcherFactory customFactory) {
- if (_customWatcherFactories.containsKey(customFactory.id)) {
- throw ArgumentError('A custom watcher with id `${customFactory.id}` '
+/// Each custom watcher must have a unique [id] and the same watcher may not be
+/// registered more than once.
+/// [createDirectoryWatcher] and [createFileWatcher] should return watchers for
+/// the file paths they are able to handle. If the custom watcher is not able to
+/// handle the path it should reuturn null.
+/// The paths handled by each custom watch may not overlap, at most one custom
+/// matcher may return a non-null watcher for a given path.
+///
+/// When a file or directory watcher is created the path is checked against each
+/// registered custom watcher, and if exactly one custom watcher is available it
+/// will be used instead of the default.
+void registerCustomWatcher(
+ String id,
+ DirectoryWatcher Function(String path, {Duration pollingDelay})
+ createDirectoryWatcher,
+ FileWatcher Function(String path, {Duration pollingDelay}) createFileWatcher,
+) {
+ if (_customWatcherFactories.containsKey(id)) {
+ throw ArgumentError('A custom watcher with id `$id` '
'has already been registered');
}
- _customWatcherFactories[customFactory.id] = customFactory;
+ _customWatcherFactories[id] = _CustomWatcherFactory(
+ id,
+ createDirectoryWatcher ?? (_, {pollingDelay}) => null,
+ createFileWatcher ?? (_, {pollingDelay}) => null);
}
/// Tries to create a custom [DirectoryWatcher] and returns it.
@@ -40,7 +53,7 @@
{Duration pollingDelay}) {
DirectoryWatcher customWatcher;
String customFactoryId;
- for (var watcherFactory in customWatcherFactories) {
+ for (var watcherFactory in _customWatcherFactories.values) {
if (customWatcher != null) {
throw StateError('Two `CustomWatcherFactory`s applicable: '
'`$customFactoryId` and `${watcherFactory.id}` for `$path`');
@@ -59,7 +72,7 @@
FileWatcher createCustomFileWatcher(String path, {Duration pollingDelay}) {
FileWatcher customWatcher;
String customFactoryId;
- for (var watcherFactory in customWatcherFactories) {
+ for (var watcherFactory in _customWatcherFactories.values) {
if (customWatcher != null) {
throw StateError('Two `CustomWatcherFactory`s applicable: '
'`$customFactoryId` and `${watcherFactory.id}` for `$path`');
@@ -71,13 +84,4 @@
return customWatcher;
}
-/// Unregisters a custom watcher and returns it.
-///
-/// Returns `null` if the id was never registered.
-CustomWatcherFactory unregisterCustomWatcherFactory(String id) =>
- _customWatcherFactories.remove(id);
-
-Iterable<CustomWatcherFactory> get customWatcherFactories =>
- _customWatcherFactories.values;
-
-final _customWatcherFactories = <String, CustomWatcherFactory>{};
+final _customWatcherFactories = <String, _CustomWatcherFactory>{};
diff --git a/lib/watcher.dart b/lib/watcher.dart
index f5c7d3e..5ea8beb 100644
--- a/lib/watcher.dart
+++ b/lib/watcher.dart
@@ -9,11 +9,7 @@
import 'src/file_watcher.dart';
import 'src/watch_event.dart';
-export 'src/custom_watcher_factory.dart'
- show
- CustomWatcherFactory,
- registerCustomWatcherFactory,
- unregisterCustomWatcherFactory;
+export 'src/custom_watcher_factory.dart' show registerCustomWatcher;
export 'src/directory_watcher.dart';
export 'src/directory_watcher/polling.dart';
export 'src/file_watcher.dart';
diff --git a/test/custom_watcher_factory_test.dart b/test/custom_watcher_factory_test.dart
index 6c9ffd8..8210c06 100644
--- a/test/custom_watcher_factory_test.dart
+++ b/test/custom_watcher_factory_test.dart
@@ -3,19 +3,17 @@
import 'package:test/test.dart';
import 'package:watcher/watcher.dart';
-import 'utils.dart';
-
void main() {
_MemFs memFs;
final defaultFactoryId = 'MemFs';
- setUp(() {
+ setUpAll(() {
memFs = _MemFs();
- registerCustomWatcherFactory(_MemFsWatcherFactory(defaultFactoryId, memFs));
- });
-
- tearDown(() async {
- unregisterCustomWatcherFactory(defaultFactoryId);
+ var watcherFactory = _MemFsWatcherFactory(memFs);
+ registerCustomWatcher(
+ defaultFactoryId,
+ watcherFactory.createDirectoryWatcher,
+ watcherFactory.createFileWatcher);
});
test('notifes for files', () async {
@@ -44,34 +42,19 @@
expect(event.path, 'dir');
});
- test('unregister works', () async {
- unregisterCustomWatcherFactory(defaultFactoryId);
-
- watcherFactory = (path) => FileWatcher(path);
- try {
- // This uses standard files, so it wouldn't trigger an event in
- // _MemFsWatcher.
- writeFile('file.txt');
- await startWatcher(path: 'file.txt');
- deleteFile('file.txt');
- } finally {
- watcherFactory = null;
- }
-
- await expectRemoveEvent('file.txt');
- });
-
test('registering twice throws', () async {
expect(
- () => registerCustomWatcherFactory(
- _MemFsWatcherFactory(defaultFactoryId, memFs)),
+ () => registerCustomWatcher(defaultFactoryId,
+ (_, {pollingDelay}) => null, (_, {pollingDelay}) => null),
throwsA(isA<ArgumentError>()));
});
test('finding two applicable factories throws', () async {
// Note that _MemFsWatcherFactory always returns a watcher, so having two
// will always produce a conflict.
- registerCustomWatcherFactory(_MemFsWatcherFactory('Different id', memFs));
+ var watcherFactory = _MemFsWatcherFactory(memFs);
+ registerCustomWatcher('Different id', watcherFactory.createDirectoryWatcher,
+ watcherFactory.createFileWatcher);
expect(() => FileWatcher('file.txt'), throwsA(isA<StateError>()));
expect(() => DirectoryWatcher('dir'), throwsA(isA<StateError>()));
});
@@ -129,18 +112,14 @@
Future<void> get ready async {}
}
-class _MemFsWatcherFactory implements CustomWatcherFactory {
- @override
- final String id;
+class _MemFsWatcherFactory {
final _MemFs _memFs;
- _MemFsWatcherFactory(this.id, this._memFs);
+ _MemFsWatcherFactory(this._memFs);
- @override
DirectoryWatcher createDirectoryWatcher(String path,
{Duration pollingDelay}) =>
_MemFsWatcher(path, _memFs.watchStream(path));
- @override
FileWatcher createFileWatcher(String path, {Duration pollingDelay}) =>
_MemFsWatcher(path, _memFs.watchStream(path));
}