From f7076c21a1f2a449718f261719772d5e27bb5e1c Mon Sep 17 00:00:00 2001 From: Matan Lurey Date: Mon, 21 Nov 2016 10:52:46 -0800 Subject: [PATCH] Update to pkg/observable 0.17.0 (#92) * Revert "Revert "Update to pkg/observable 0.17.0"" This reverts commit 77f5f61154c21aecf16fbf1242115efea5382d33. * Perf tweak --- benchmark/index.dart | 171 ------------------ benchmark/index.html | 73 -------- benchmark/object_benchmark.dart | 28 --- benchmark/observable_list_benchmark.dart | 58 ------ benchmark/observation_benchmark_base.dart | 120 ------------ benchmark/path_benchmark.dart | 42 ----- benchmark/setup_object_benchmark.dart | 15 -- .../setup_observable_list_benchmark.dart | 26 --- .../setup_observation_benchmark_base.dart | 76 -------- benchmark/setup_path_benchmark.dart | 23 --- benchmark/test_observable.dart | 39 ---- benchmark/test_path_observable.dart | 27 --- lib/html.dart | 2 +- lib/src/auto_observable.dart | 7 +- lib/src/list_path_observer.dart | 2 +- lib/src/metadata.dart | 2 +- lib/src/observable_box.dart | 2 +- pubspec.yaml | 4 +- test/list_path_observer_test.dart | 2 +- test/path_observer_test.dart | 16 +- 20 files changed, 23 insertions(+), 712 deletions(-) delete mode 100644 benchmark/index.dart delete mode 100644 benchmark/index.html delete mode 100644 benchmark/object_benchmark.dart delete mode 100644 benchmark/observable_list_benchmark.dart delete mode 100644 benchmark/observation_benchmark_base.dart delete mode 100644 benchmark/path_benchmark.dart delete mode 100644 benchmark/setup_object_benchmark.dart delete mode 100644 benchmark/setup_observable_list_benchmark.dart delete mode 100644 benchmark/setup_observation_benchmark_base.dart delete mode 100644 benchmark/setup_path_benchmark.dart delete mode 100644 benchmark/test_observable.dart delete mode 100644 benchmark/test_path_observable.dart diff --git a/benchmark/index.dart b/benchmark/index.dart deleted file mode 100644 index 49e7cad..0000000 --- a/benchmark/index.dart +++ /dev/null @@ -1,171 +0,0 @@ -// Copyright (c) 2013, 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. -library observe.test.benchmark.index; - -import 'dart:async'; -import 'dart:html'; -import 'package:benchmark_harness/benchmark_harness.dart'; -import 'package:chart/chart.dart'; -import 'package:observe/mirrors_used.dart' as mu; // Makes output smaller. -import 'package:smoke/mirrors.dart'; -import 'object_benchmark.dart'; -import 'setup_object_benchmark.dart'; -import 'observable_list_benchmark.dart'; -import 'setup_observable_list_benchmark.dart'; -import 'path_benchmark.dart'; -import 'setup_path_benchmark.dart'; - -/// Benchmark names to factory functions. -/// Uses [mu]. -typedef BenchmarkBase BenchmarkFactory( - int objectCount, int mutationCount, String config); -final Map benchmarkFactories = { - 'ObjectBenchmark': (int o, int m, String c) => new ObjectBenchmark(o, m, c), - 'SetupObjectBenchmark': (int o, int m, String c) => - new SetupObjectBenchmark(o, c), - 'ObservableListBenchmark': (int o, int m, String c) => - new ObservableListBenchmark(o, m, c), - 'SetupObservableListBenchmark': (int o, int m, String c) => - new SetupObservableListBenchmark(o, c), - 'PathBenchmark': (int o, int m, String c) => new PathBenchmark(o, m, c), - 'SetupPathBenchmark': (int o, int m, String c) => - new SetupPathBenchmark(o, c), -}; - -/// Benchmark names to possible configs. -final Map> benchmarkConfigs = { - 'ObjectBenchmark': [], - 'SetupObjectBenchmark': [], - 'ObservableListBenchmark': ['splice', 'update', 'push/pop', 'shift/unshift'], - 'SetupObservableListBenchmark': [], - 'PathBenchmark': ['leaf', 'root'], - 'SetupPathBenchmark': [], -}; - -Iterable objectCounts; -Iterable mutationCounts; - -final ButtonElement goButton = querySelector('#go'); -final InputElement objectCountInput = querySelector('#objectCountInput'); -final InputElement mutationCountInput = querySelector('#mutationCountInput'); -final SpanElement mutationCountWrapper = querySelector('#mutationCountWrapper'); -final SpanElement statusSpan = querySelector('#status'); -final DivElement canvasWrapper = querySelector('#canvasWrapper'); -final SelectElement benchmarkSelect = querySelector('#benchmarkSelect'); -final SelectElement configSelect = querySelector('#configSelect'); -final UListElement legendList = querySelector('#legendList'); -final List colors = [ - [0, 0, 255], - [138, 43, 226], - [165, 42, 42], - [100, 149, 237], - [220, 20, 60], - [184, 134, 11] -].map((rgb) => 'rgba(' + rgb.join(',') + ',.7)').toList(); - -main() { - // TODO(jakemac): Use a transformer to generate the smoke config so we can see - // how that affects the benchmark. - useMirrors(); - - benchmarkSelect.onChange.listen((_) => changeBenchmark()); - changeBenchmark(); - - goButton.onClick.listen((_) async { - canvasWrapper.children.clear(); - goButton.disabled = true; - goButton.text = 'Running...'; - legendList.text = ''; - objectCounts = - objectCountInput.value.split(',').map((val) => int.parse(val)); - - if (benchmarkSelect.value.startsWith('Setup')) { - mutationCounts = [0]; - } else { - mutationCounts = - mutationCountInput.value.split(',').map((val) => int.parse(val)); - } - - var i = 0; - mutationCounts.forEach((count) { - var li = document.createElement('li'); - li.text = '$count mutations.'; - li.style.color = colors[i % colors.length]; - legendList.append(li); - i++; - }); - - var results = >[]; - for (int objectCount in objectCounts) { - int x = 0; - for (int mutationCount in mutationCounts) { - statusSpan.text = - 'Testing: $objectCount objects with $mutationCount mutations'; - // Let the status text render before running the next benchmark. - await new Future(() {}); - var factory = benchmarkFactories[benchmarkSelect.value]; - var benchmark = factory(objectCount, mutationCount, configSelect.value); - // Divide by 10 because benchmark_harness returns the amount of time it - // took to run 10 times, not once :(. - var resultMicros = benchmark.measure() / 10; - - if (results.length <= x) results.add([]); - results[x].add(resultMicros / 1000); - x++; - } - } - - drawBenchmarks(results); - }); -} - -void drawBenchmarks(List> results) { - var datasets = []; - for (int i = 0; i < results.length; i++) { - datasets.add({ - 'fillColor': 'rgba(255, 255, 255, 0)', - 'strokeColor': colors[i % colors.length], - 'pointColor': colors[i % colors.length], - 'pointStrokeColor': "#fff", - 'data': results[i], - }); - } - var data = { - 'labels': objectCounts.map((c) => '$c').toList(), - 'datasets': datasets, - }; - - new Line(data, { - 'bezierCurve': false, - }).show(canvasWrapper); - goButton.disabled = false; - goButton.text = 'Run Benchmarks'; - statusSpan.text = ''; -} - -void changeBenchmark() { - var configs = benchmarkConfigs[benchmarkSelect.value]; - configSelect.text = ''; - configs.forEach((config) { - var option = document.createElement('option'); - option.text = config; - configSelect.append(option); - }); - - document.title = benchmarkSelect.value; - - // Don't show the configSelect if there are no configs. - if (configs.isEmpty) { - configSelect.style.display = 'none'; - } else { - configSelect.style.display = 'inline'; - } - - // Don't show the mutation counts box if running a Setup* benchmark. - if (benchmarkSelect.value.startsWith('Setup')) { - mutationCountWrapper.style.display = 'none'; - } else { - mutationCountWrapper.style.display = 'inline'; - } -} diff --git a/benchmark/index.html b/benchmark/index.html deleted file mode 100644 index ce2bf9f..0000000 --- a/benchmark/index.html +++ /dev/null @@ -1,73 +0,0 @@ - - - - Observation Benchmarks - - - - -

Observation Benchmarks

- - - - - - -Object Count: - - - Mutation Count: -
-
-
- - -
-
-
- Times in ms -
-
-
-
-
    -
-
-
-
-

Object Set Size

- - - - diff --git a/benchmark/object_benchmark.dart b/benchmark/object_benchmark.dart deleted file mode 100644 index 91282be..0000000 --- a/benchmark/object_benchmark.dart +++ /dev/null @@ -1,28 +0,0 @@ -// Copyright (c) 2013, 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. -library observe.test.benchmark.object_benchmark; - -import 'observation_benchmark_base.dart'; -import 'test_observable.dart'; - -class ObjectBenchmark extends ObservationBenchmarkBase { - ObjectBenchmark(int objectCount, int mutationCount, String config) - : super('ObjectBenchmark:$objectCount:$mutationCount:$config', - objectCount, mutationCount, config); - - @override - int mutateObject(TestObservable obj) { - // Modify the first 5 properties. - obj.a++; - obj.b++; - obj.c++; - obj.d++; - obj.e++; - // Return # of modifications. - return 5; - } - - @override - TestObservable newObject() => new TestObservable(); -} diff --git a/benchmark/observable_list_benchmark.dart b/benchmark/observable_list_benchmark.dart deleted file mode 100644 index d0f8ad9..0000000 --- a/benchmark/observable_list_benchmark.dart +++ /dev/null @@ -1,58 +0,0 @@ -// Copyright (c) 2013, 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. -library observe.test.benchmark.observable_list_benchmark; - -import 'package:observable/observable.dart'; -import 'observation_benchmark_base.dart'; - -class ObservableListBenchmark extends ObservationBenchmarkBase { - final int elementCount = 100; - - ObservableListBenchmark(int objectCount, int mutationCount, String config) - : super('ObservableListBenchmark:$objectCount:$mutationCount:$config', - objectCount, mutationCount, config); - - @override - int mutateObject(ObservableList obj) { - switch (config) { - case 'update': - var size = (elementCount / 10).floor(); - for (var j = 0; j < size; j++) { - obj[j * size]++; - } - return size; - - case 'splice': - var size = (elementCount / 5).floor(); - // No splice equivalent in List, so we hardcode it. - var removed = obj.sublist(size, size * 2); - obj.removeRange(size, size * 2); - obj.insertAll(size * 2, removed); - return size * 2; - - case 'push/pop': - var val = obj.removeLast(); - obj.add(val + 1); - return 2; - - case 'shift/unshift': - var val = obj.removeAt(0); - obj.insert(0, val + 1); - return 2; - - default: - throw new ArgumentError( - 'Invalid config for ObservableListBenchmark: $config'); - } - } - - @override - ObservableList newObject() { - var list = new ObservableList(); - for (int i = 0; i < elementCount; i++) { - list.add(i); - } - return list; - } -} diff --git a/benchmark/observation_benchmark_base.dart b/benchmark/observation_benchmark_base.dart deleted file mode 100644 index f8fc983..0000000 --- a/benchmark/observation_benchmark_base.dart +++ /dev/null @@ -1,120 +0,0 @@ -// Copyright (c) 2013, 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. -library observe.test.benchmark.observation_benchmark_base; - -import 'dart:async'; -import 'dart:html'; - -import 'package:observable/observable.dart'; -import 'package:observe/observe.dart'; -import 'package:benchmark_harness/benchmark_harness.dart'; - -abstract class ObservationBenchmarkBase - extends BenchmarkBase { - /// The number of objects to create and observe. - final int objectCount; - - /// The number of mutations to perform. - final int mutationCount; - - /// The current configuration. - final String config; - - /// The number of pending mutations left to observe. - int mutations; - - /// The objects we want to observe. - List objects; - - /// The change listeners on all of our objects. - List observers; - - /// The current object being mutated. - int objectIndex; - - ObservationBenchmarkBase( - String name, this.objectCount, this.mutationCount, this.config) - : super(name); - - /// Subclasses should use this method to perform mutations on an object. The - /// return value indicates how many mutations were performed on the object. - int mutateObject(T obj); - - /// Subclasses should use this method to return an observable object to be - /// benchmarked. - T newObject(); - - /// Subclasses should override this to do anything other than a default change - /// listener. It must return either a StreamSubscription or a PathObserver. - /// If overridden this observer should decrement [mutations] each time a - /// change is observed. - newObserver(T obj) { - decrement(_) => mutations--; - if (obj is ObservableList) return obj.listChanges.listen(decrement); - return obj.changes.listen(decrement); - } - - /// Set up each benchmark by creating all the objects and listeners. - @override - void setup() { - mutations = 0; - - objects = []; - observers = []; - objectIndex = 0; - - while (objects.length < objectCount) { - var obj = newObject(); - objects.add(obj); - observers.add(newObserver(obj)); - } - } - - /// Tear down each benchmark and make sure that [mutations] is 0. - @override - void teardown() { - if (mutations != 0) { - window.alert('$mutations mutation sets were not observed!'); - } - mutations = 0; - - while (observers.isNotEmpty) { - var observer = observers.removeLast(); - if (observer is StreamSubscription) { - observer.cancel(); - } else if (observer is PathObserver) { - observer.close(); - } else { - throw 'Unknown observer type ${observer.runtimeType}. Only ' - '[PathObserver] and [StreamSubscription] are supported.'; - } - } - observers = null; - - bool leakedObservers = false; - while (objects.isNotEmpty) { - leakedObservers = objects.removeLast().hasObservers || leakedObservers; - } - if (leakedObservers) window.alert('Observers leaked!'); - objects = null; - } - - /// Run the benchmark - @override - void run() { - var mutationsLeft = mutationCount; - while (mutationsLeft > 0) { - var obj = objects[objectIndex]; - mutationsLeft -= mutateObject(obj); - this.mutations++; - this.objectIndex++; - if (this.objectIndex == this.objects.length) { - this.objectIndex = 0; - } - obj.deliverChanges(); - if (obj is ObservableList) obj.deliverListChanges(); - } - AutoObservable.dirtyCheck(); - } -} diff --git a/benchmark/path_benchmark.dart b/benchmark/path_benchmark.dart deleted file mode 100644 index a612c55..0000000 --- a/benchmark/path_benchmark.dart +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) 2013, 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. -library observe.test.benchmark.path_benchmark; - -import 'package:observe/observe.dart'; -import 'observation_benchmark_base.dart'; -import 'test_path_observable.dart'; - -class PathBenchmark extends ObservationBenchmarkBase { - final PropertyPath path = new PropertyPath('foo.bar.baz'); - - PathBenchmark(int objectCount, int mutationCount, String config) - : super('PathBenchmark:$objectCount:$mutationCount:$config', objectCount, - mutationCount, config); - - @override - int mutateObject(TestPathObservable obj) { - switch (config) { - case 'leaf': - obj.foo.bar.baz += 1; - // Make sure [obj.foo.bar] delivers its changes synchronously. The base - // class already handles this for [obj]. - obj.foo.bar.deliverChanges(); - return 1; - - case 'root': - obj.foo = new Foo(obj.foo.bar.baz + 1); - return 1; - - default: - throw new ArgumentError('Invalid config for PathBenchmark: $config'); - } - } - - @override - TestPathObservable newObject() => new TestPathObservable(1); - - @override - PathObserver newObserver(TestPathObservable obj) => - new PathObserver(obj, path)..open((_) => mutations--); -} diff --git a/benchmark/setup_object_benchmark.dart b/benchmark/setup_object_benchmark.dart deleted file mode 100644 index 6fda9fc..0000000 --- a/benchmark/setup_object_benchmark.dart +++ /dev/null @@ -1,15 +0,0 @@ -// Copyright (c) 2013, 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. -library observe.test.benchmark.setup_object_benchmark; - -import 'setup_observation_benchmark_base.dart'; -import 'test_observable.dart'; - -class SetupObjectBenchmark extends SetupObservationBenchmarkBase { - SetupObjectBenchmark(int objectCount, String config) - : super('SetupObjectBenchmark:$objectCount:$config', objectCount, config); - - @override - TestObservable newObject() => new TestObservable(); -} diff --git a/benchmark/setup_observable_list_benchmark.dart b/benchmark/setup_observable_list_benchmark.dart deleted file mode 100644 index b40aced..0000000 --- a/benchmark/setup_observable_list_benchmark.dart +++ /dev/null @@ -1,26 +0,0 @@ -// Copyright (c) 2013, 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. -library observe.test.benchmark.setup_observable_list_benchmark; - -import 'package:observable/observable.dart'; -import 'setup_observation_benchmark_base.dart'; - -class SetupObservableListBenchmark extends SetupObservationBenchmarkBase { - final int elementCount = 100; - - SetupObservableListBenchmark(int objectCount, String config) - : super('SetupObservableListBenchmark:$objectCount:$config', objectCount, - config); - - @override - ObservableList newObject() { - var list = new ObservableList(); - for (int i = 0; i < elementCount; i++) { - list.add(i); - } - list.deliverChanges(); - list.deliverListChanges(); - return list; - } -} diff --git a/benchmark/setup_observation_benchmark_base.dart b/benchmark/setup_observation_benchmark_base.dart deleted file mode 100644 index 2b26b72..0000000 --- a/benchmark/setup_observation_benchmark_base.dart +++ /dev/null @@ -1,76 +0,0 @@ -// Copyright (c) 2013, 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. -library observe.test.benchmark.setup_observation_benchmark_base; - -import 'dart:async'; -import 'dart:html'; -import 'package:observable/observable.dart'; -import 'package:observe/observe.dart'; -import 'package:benchmark_harness/benchmark_harness.dart'; - -abstract class SetupObservationBenchmarkBase - extends BenchmarkBase { - /// The number of objects to create and observe. - final int objectCount; - - /// The current configuration. - final String config; - - /// The objects we want to observe. - List objects; - - SetupObservationBenchmarkBase(String name, this.objectCount, this.config) - : super(name); - - /// Subclasses should use this method to return an observable object to be - /// benchmarked. - T newObject(); - - /// Subclasses should override this to do anything other than a default change - /// listener. It must return either a StreamSubscription or a PathObserver. - newObserver(T obj) => obj.changes.listen((_) {}); - - /// Set up each benchmark by creating all the objects. - @override - void setup() { - objects = []; - while (objects.length < objectCount) { - objects.add(newObject()); - } - } - - /// Tear down each the benchmark and remove all listeners. - @override - void teardown() { - while (objects.isNotEmpty) { - var obj = objects.removeLast(); - if (obj.hasObservers || (obj is ObservableList && obj.hasListObservers)) { - window.alert('Observers leaked!'); - } - } - objects = null; - } - - /// Run the benchmark by creating a listener on each object. - @override - void run() { - for (var object in objects) { - var observer = newObserver(object); - - // **Note:** This is different than the JS implementation. Since run can - // be called an arbitrary number of times between [setup] and [teardown], - // we clean up all observers as we go. This means we are measuring both - // the setup and teardown of observers, versus the setup only in the - // JS benchmark. Not cleaning these up ends up giving `oh snap` errors. - if (observer is StreamSubscription) { - observer.cancel(); - } else if (observer is PathObserver) { - observer.close(); - } else { - throw 'Unknown observer type ${observer.runtimeType}. Only ' - '[PathObserver] and [StreamSubscription] are supported.'; - } - } - } -} diff --git a/benchmark/setup_path_benchmark.dart b/benchmark/setup_path_benchmark.dart deleted file mode 100644 index 72bba82..0000000 --- a/benchmark/setup_path_benchmark.dart +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright (c) 2013, 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. -library observe.test.benchmark.setup_path_benchmark; - -import 'package:observe/observe.dart'; -import 'setup_observation_benchmark_base.dart'; -import 'test_path_observable.dart'; - -class SetupPathBenchmark - extends SetupObservationBenchmarkBase { - final PropertyPath path = new PropertyPath('foo.bar.baz'); - - SetupPathBenchmark(int objectCount, String config) - : super('SetupPathBenchmark:$objectCount:$config', objectCount, config); - - @override - TestPathObservable newObject() => new TestPathObservable(1); - - @override - PathObserver newObserver(TestPathObservable obj) => - new PathObserver(obj, path)..open(() {}); -} diff --git a/benchmark/test_observable.dart b/benchmark/test_observable.dart deleted file mode 100644 index 15ef2d7..0000000 --- a/benchmark/test_observable.dart +++ /dev/null @@ -1,39 +0,0 @@ -// Copyright (c) 2013, 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. -library observe.test.benchmark.test_observable; - -import 'package:observe/observe.dart'; - -class TestObservable extends AutoObservable { - @observable - int a = 0; - @observable - int b = 0; - @observable - int c = 0; - @observable - int d = 0; - @observable - int e = 0; - @observable - int f = 0; - @observable - int g = 0; - @observable - int h = 0; - @observable - int i = 0; - @observable - int j = 0; - @observable - int k = 0; - @observable - int l = 0; - @observable - int m = 0; - @observable - int n = 0; - @observable - int o = 0; -} diff --git a/benchmark/test_path_observable.dart b/benchmark/test_path_observable.dart deleted file mode 100644 index 6675822..0000000 --- a/benchmark/test_path_observable.dart +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) 2013, 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. -library observe.test.benchmark.test_observable; - -import 'package:observe/observe.dart'; - -class Bar extends AutoObservable { - @observable - int baz; - - Bar(this.baz); -} - -class Foo extends AutoObservable { - @observable - Bar bar; - - Foo(int value) : bar = new Bar(value); -} - -class TestPathObservable extends AutoObservable { - @observable - Foo foo; - - TestPathObservable(int value) : foo = new Foo(value); -} diff --git a/lib/html.dart b/lib/html.dart index 5000a78..e29b0db 100644 --- a/lib/html.dart +++ b/lib/html.dart @@ -19,7 +19,7 @@ import 'observe.dart'; /// An observable version of [window.location.hash]. final ObservableLocationHash windowLocation = new ObservableLocationHash._(); -class ObservableLocationHash extends Observable { +class ObservableLocationHash extends PropertyChangeNotifier { Object _currentHash; ObservableLocationHash._() { diff --git a/lib/src/auto_observable.dart b/lib/src/auto_observable.dart index bcb486a..2fae812 100644 --- a/lib/src/auto_observable.dart +++ b/lib/src/auto_observable.dart @@ -13,7 +13,7 @@ import 'package:smoke/smoke.dart' as smoke; import 'dirty_check.dart' show dirtyCheckObservables, registerObservable; import 'metadata.dart' show ObservableProperty; -abstract class AutoObservable implements Observable { +abstract class AutoObservable implements ChangeNotifier { /// Performs dirty checking of objects that inherit from [AutoObservable]. /// This scans all observed objects using mirrors and determines if any fields /// have changed. If they have, it delivers the changes for the object. @@ -147,9 +147,8 @@ abstract class AutoObservable implements Observable { /// - Unlike [Observable] this will not schedule [deliverChanges]; use /// [AutoObservable.dirtyCheck] instead. @override - void notifyChange(ChangeRecord record) { - if (!hasObservers) return; - + void notifyChange([ChangeRecord record]) { + if (record == null || !hasObservers) return; if (_records == null) _records = []; _records.add(record); } diff --git a/lib/src/list_path_observer.dart b/lib/src/list_path_observer.dart index 09f1b6c..c329103 100644 --- a/lib/src/list_path_observer.dart +++ b/lib/src/list_path_observer.dart @@ -14,7 +14,7 @@ import 'package:observe/observe.dart'; /// Observes a path starting from each item in the list. @deprecated -class ListPathObserver extends Observable { +class ListPathObserver extends PropertyChangeNotifier { final ObservableList list; final String _itemPath; final List _observers = []; diff --git a/lib/src/metadata.dart b/lib/src/metadata.dart index 6811332..15e7905 100644 --- a/lib/src/metadata.dart +++ b/lib/src/metadata.dart @@ -37,7 +37,7 @@ const Reflectable reflectable = const Reflectable(); /// it available to `PathObserver` at runtime. For example: /// /// @reflectable -/// class Monster extends Observable { +/// class Monster extends AutoObservable { /// int _health; /// int get health => _health; /// ... diff --git a/lib/src/observable_box.dart b/lib/src/observable_box.dart index 51c584a..5749890 100644 --- a/lib/src/observable_box.dart +++ b/lib/src/observable_box.dart @@ -13,7 +13,7 @@ import 'package:observe/observe.dart'; /// value. For other cases, it is better to use [AutoObservableList], /// [AutoObservableMap], or a custom [AutoObservable] implementation based on /// [AutoObservable]. The property name for changes is "value". -class ObservableBox extends Observable { +class ObservableBox extends PropertyChangeNotifier { T _value; ObservableBox([T initialValue]) : _value = initialValue; diff --git a/pubspec.yaml b/pubspec.yaml index e74974a..e9a4b36 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,5 +1,5 @@ name: observe -version: 0.14.0 +version: 0.15.0 author: Polymer.dart Authors description: > Observable properties and objects for use in template_binding. @@ -13,7 +13,7 @@ dependencies: barback: '>=0.14.2 <0.16.0' func: ^0.1.0 logging: '>=0.9.0 <0.12.0' - observable: '^0.14.0' + observable: '^0.17.0' path: '>=0.9.0 <2.0.0' smoke: '>=0.1.0 <0.4.0' source_maps: '>=0.9.4 <0.11.0' diff --git a/test/list_path_observer_test.dart b/test/list_path_observer_test.dart index e3df022..f0e89b5 100644 --- a/test/list_path_observer_test.dart +++ b/test/list_path_observer_test.dart @@ -85,7 +85,7 @@ _runTests() { _nextMicrotask(_) => new Future(() {}); @reflectable -class TestModel extends Observable { +class TestModel extends PropertyChangeNotifier { var _a, _b; TestModel(); diff --git a/test/path_observer_test.dart b/test/path_observer_test.dart index ba9cc22..bc7731a 100644 --- a/test/path_observer_test.dart +++ b/test/path_observer_test.dart @@ -175,7 +175,8 @@ observePathTests() { }); test('get value at path ObservableBox', () { - var obj = new ObservableBox(new ObservableBox(new ObservableBox(1))); + var obj = + new ObservableBox(new ObservableBox(new ObservableBox(1))); expect(new PathObserver(obj, '').value, obj); expect(new PathObserver(obj, 'value').value, obj.value); @@ -188,7 +189,7 @@ observePathTests() { obj.value.value = new ObservableBox(3); expect(new PathObserver(obj, 'value.value.value').value, 3); - obj.value = new ObservableBox(4); + obj.value = new ObservableBox(4); expect(() => new PathObserver(obj, 'value.value.value').value, _throwsNSM('value')); expect(new PathObserver(obj, 'value.value').value, 4); @@ -753,7 +754,7 @@ class IndexerModel implements Indexable { } @reflectable -class TestModel extends Observable implements WatcherModel { +class TestModel extends ChangeNotifier implements WatcherModel { var _a, _b, _c; TestModel([this._a, this._b, this._c]); @@ -775,6 +776,15 @@ class TestModel extends Observable implements WatcherModel { void set c(newValue) { _c = notifyPropertyChange(#c, _c, newValue); } + + @override + /*=T*/ notifyPropertyChange/**/( + Symbol field, /*=T*/ oldValue, /*=T*/ newValue) { + if (hasObservers && oldValue != newValue) { + notifyChange(new PropertyChangeRecord(this, field, oldValue, newValue)); + } + return newValue; + } } class WatcherModel extends AutoObservable {