Revert "Update to pkg/observable 0.17.0"
This reverts commit c124c2c2b7448ba649d32d75af93c0fa5e2a3fde.
diff --git a/benchmark/index.dart b/benchmark/index.dart
new file mode 100644
index 0000000..49e7cad
--- /dev/null
+++ b/benchmark/index.dart
@@ -0,0 +1,171 @@
+// 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<String, BenchmarkFactory> 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<String, List<String>> benchmarkConfigs = {
+ 'ObjectBenchmark': [],
+ 'SetupObjectBenchmark': [],
+ 'ObservableListBenchmark': ['splice', 'update', 'push/pop', 'shift/unshift'],
+ 'SetupObservableListBenchmark': [],
+ 'PathBenchmark': ['leaf', 'root'],
+ 'SetupPathBenchmark': [],
+};
+
+Iterable<int> objectCounts;
+Iterable<int> 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<String> 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 = <List<double>>[];
+ 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<List<double>> 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
new file mode 100644
index 0000000..ce2bf9f
--- /dev/null
+++ b/benchmark/index.html
@@ -0,0 +1,73 @@
+<html>
+<!--
+Copyright (c) 2014 The Polymer Project Authors. All rights reserved.
+This code may only be used under the BSD style license found at http://polymer.github.io/LICENSE.txt
+The complete set of authors may be found at http://polymer.github.io/AUTHORS.txt
+The complete set of contributors may be found at http://polymer.github.io/CONTRIBUTORS.txt
+Code distributed by Google as part of the polymer project is also
+subject to an additional IP rights grant found at http://polymer.github.io/PATENTS.txt
+-->
+<head>
+ <title>Observation Benchmarks</title>
+ <meta charset="utf-8">
+ <style>
+ * {
+ font-family: arial, helvetica, sans-serif;
+ font-weight: 400;
+ }
+ body {
+ margin: 0;
+ padding: 0;
+ background-color: rgba(0, 0, 0, .1);
+ }
+ #canvasWrapper {
+ width: 800px;
+ height: 400px;
+ }
+ </style>
+</head>
+<body>
+<h1>Observation Benchmarks</h1>
+
+<select id="benchmarkSelect">
+ <option>ObjectBenchmark</option>
+ <option>SetupObjectBenchmark</option>
+ <option>ObservableListBenchmark</option>
+ <option>SetupObservableListBenchmark</option>
+ <option>PathBenchmark</option>
+ <option>SetupPathBenchmark</option>
+</select>
+<select id="configSelect">
+</select>
+
+<button id="go">Run Benchmarks</button>
+
+<span>Object Count: </span>
+<input id="objectCountInput" style="width: 200px" value="4000, 8000, 16000, 32000">
+<span id="mutationCountWrapper">
+ <span>Mutation Count: </span>
+ <input id="mutationCountInput" style="width: 200px"
+ value="0, 100, 200, 400, 800, 1600"><br>
+</span>
+<br>
+<span id="status"></span>
+
+<section style="width: 100%">
+ <article>
+ <div style="display:inline-block; padding-bottom: 20px">
+ Times in ms
+ </div>
+ <div id="canvasWrapper" style="display:inline-block">
+ </div>
+ <div style="display:inline-block">
+ <ul id="legendList">
+ </ul>
+ </div>
+ </article>
+</section>
+<h3 style="margin-left: 440px">Object Set Size</h3>
+<script type="application/dart" src="index.dart"></script>
+<script src="packages/browser/dart.js">
+</script>
+</body>
+</html>
diff --git a/benchmark/object_benchmark.dart b/benchmark/object_benchmark.dart
new file mode 100644
index 0000000..91282be
--- /dev/null
+++ b/benchmark/object_benchmark.dart
@@ -0,0 +1,28 @@
+// 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<TestObservable> {
+ 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
new file mode 100644
index 0000000..d0f8ad9
--- /dev/null
+++ b/benchmark/observable_list_benchmark.dart
@@ -0,0 +1,58 @@
+// 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<ObservableList> {
+ 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
new file mode 100644
index 0000000..f8fc983
--- /dev/null
+++ b/benchmark/observation_benchmark_base.dart
@@ -0,0 +1,120 @@
+// 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<T extends Observable>
+ 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<T> 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
new file mode 100644
index 0000000..a612c55
--- /dev/null
+++ b/benchmark/path_benchmark.dart
@@ -0,0 +1,42 @@
+// 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<TestPathObservable> {
+ 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
new file mode 100644
index 0000000..6fda9fc
--- /dev/null
+++ b/benchmark/setup_object_benchmark.dart
@@ -0,0 +1,15 @@
+// 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
new file mode 100644
index 0000000..b40aced
--- /dev/null
+++ b/benchmark/setup_observable_list_benchmark.dart
@@ -0,0 +1,26 @@
+// 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
new file mode 100644
index 0000000..2b26b72
--- /dev/null
+++ b/benchmark/setup_observation_benchmark_base.dart
@@ -0,0 +1,76 @@
+// 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<T extends Observable>
+ 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<T> 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
new file mode 100644
index 0000000..72bba82
--- /dev/null
+++ b/benchmark/setup_path_benchmark.dart
@@ -0,0 +1,23 @@
+// 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<TestPathObservable> {
+ 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
new file mode 100644
index 0000000..15ef2d7
--- /dev/null
+++ b/benchmark/test_observable.dart
@@ -0,0 +1,39 @@
+// 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
new file mode 100644
index 0000000..6675822
--- /dev/null
+++ b/benchmark/test_path_observable.dart
@@ -0,0 +1,27 @@
+// 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 e29b0db..5000a78 100644
--- a/lib/html.dart
+++ b/lib/html.dart
@@ -19,7 +19,7 @@
/// An observable version of [window.location.hash].
final ObservableLocationHash windowLocation = new ObservableLocationHash._();
-class ObservableLocationHash extends PropertyChangeNotifier {
+class ObservableLocationHash extends Observable {
Object _currentHash;
ObservableLocationHash._() {
diff --git a/lib/src/auto_observable.dart b/lib/src/auto_observable.dart
index 542bccc..bcb486a 100644
--- a/lib/src/auto_observable.dart
+++ b/lib/src/auto_observable.dart
@@ -13,7 +13,7 @@
import 'dirty_check.dart' show dirtyCheckObservables, registerObservable;
import 'metadata.dart' show ObservableProperty;
-abstract class AutoObservable implements ChangeNotifier {
+abstract class AutoObservable implements Observable {
/// 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,8 +147,8 @@
/// - Unlike [Observable] this will not schedule [deliverChanges]; use
/// [AutoObservable.dirtyCheck] instead.
@override
- void notifyChange([ChangeRecord record]) {
- if (!hasObservers || record == null) return;
+ void notifyChange(ChangeRecord record) {
+ if (!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 c329103..09f1b6c 100644
--- a/lib/src/list_path_observer.dart
+++ b/lib/src/list_path_observer.dart
@@ -14,7 +14,7 @@
/// Observes a path starting from each item in the list.
@deprecated
-class ListPathObserver<E, P> extends PropertyChangeNotifier {
+class ListPathObserver<E, P> extends Observable {
final ObservableList<E> list;
final String _itemPath;
final List<PathObserver> _observers = <PathObserver>[];
diff --git a/lib/src/metadata.dart b/lib/src/metadata.dart
index 15e7905..6811332 100644
--- a/lib/src/metadata.dart
+++ b/lib/src/metadata.dart
@@ -37,7 +37,7 @@
/// it available to `PathObserver` at runtime. For example:
///
/// @reflectable
-/// class Monster extends AutoObservable {
+/// class Monster extends Observable {
/// int _health;
/// int get health => _health;
/// ...
diff --git a/lib/src/observable_box.dart b/lib/src/observable_box.dart
index 5749890..51c584a 100644
--- a/lib/src/observable_box.dart
+++ b/lib/src/observable_box.dart
@@ -13,7 +13,7 @@
/// 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<T> extends PropertyChangeNotifier {
+class ObservableBox<T> extends Observable {
T _value;
ObservableBox([T initialValue]) : _value = initialValue;
diff --git a/pubspec.yaml b/pubspec.yaml
index e9a4b36..e74974a 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: observe
-version: 0.15.0
+version: 0.14.0
author: Polymer.dart Authors <web-ui-dev@dartlang.org>
description: >
Observable properties and objects for use in template_binding.
@@ -13,7 +13,7 @@
barback: '>=0.14.2 <0.16.0'
func: ^0.1.0
logging: '>=0.9.0 <0.12.0'
- observable: '^0.17.0'
+ observable: '^0.14.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 f0e89b5..e3df022 100644
--- a/test/list_path_observer_test.dart
+++ b/test/list_path_observer_test.dart
@@ -85,7 +85,7 @@
_nextMicrotask(_) => new Future(() {});
@reflectable
-class TestModel extends PropertyChangeNotifier {
+class TestModel extends Observable {
var _a, _b;
TestModel();
diff --git a/test/path_observer_test.dart b/test/path_observer_test.dart
index bc7731a..ba9cc22 100644
--- a/test/path_observer_test.dart
+++ b/test/path_observer_test.dart
@@ -175,8 +175,7 @@
});
test('get value at path ObservableBox', () {
- var obj =
- new ObservableBox<dynamic>(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);
@@ -189,7 +188,7 @@
obj.value.value = new ObservableBox(3);
expect(new PathObserver(obj, 'value.value.value').value, 3);
- obj.value = new ObservableBox<int>(4);
+ obj.value = new ObservableBox(4);
expect(() => new PathObserver(obj, 'value.value.value').value,
_throwsNSM('value'));
expect(new PathObserver(obj, 'value.value').value, 4);
@@ -754,7 +753,7 @@
}
@reflectable
-class TestModel extends ChangeNotifier implements WatcherModel {
+class TestModel extends Observable implements WatcherModel {
var _a, _b, _c;
TestModel([this._a, this._b, this._c]);
@@ -776,15 +775,6 @@
void set c(newValue) {
_c = notifyPropertyChange(#c, _c, newValue);
}
-
- @override
- /*=T*/ notifyPropertyChange/*<T>*/(
- Symbol field, /*=T*/ oldValue, /*=T*/ newValue) {
- if (hasObservers && oldValue != newValue) {
- notifyChange(new PropertyChangeRecord(this, field, oldValue, newValue));
- }
- return newValue;
- }
}
class WatcherModel extends AutoObservable {