Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(978)

Side by Side Diff: pkg/observe/lib/src/observable.dart

Issue 173473002: Adapting observe to use smoke (this is built on top of the previous change that (Closed) Base URL: https://dart.googlecode.com/svn/branches/bleeding_edge/dart
Patch Set: Created 6 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « no previous file | pkg/observe/lib/src/path_observer.dart » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file 1 // Copyright (c) 2013, the Dart project authors. Please see the AUTHORS file
2 // for details. All rights reserved. Use of this source code is governed by a 2 // for details. All rights reserved. Use of this source code is governed by a
3 // BSD-style license that can be found in the LICENSE file. 3 // BSD-style license that can be found in the LICENSE file.
4 4
5 library observe.src.observable; 5 library observe.src.observable;
6 6
7 import 'dart:async'; 7 import 'dart:async';
8 import 'dart:collection'; 8 import 'dart:collection';
9 9
10 // TODO(sigmund): figure out how to remove this annotation entirely
10 // Note: ObservableProperty is in this list only for the unusual use case of 11 // Note: ObservableProperty is in this list only for the unusual use case of
11 // dart2js without deploy tool. The deploy tool (see "transformer.dart") will 12 // dart2js without deploy tool. The deploy tool (see "transformer.dart") will
12 // add the @reflectable annotation, which makes it work with Polymer's 13 // add the @reflectable annotation, which makes it work with Polymer's
13 // @published. 14 // @published.
14 @MirrorsUsed(metaTargets: const [Reflectable, ObservableProperty], 15 @MirrorsUsed(metaTargets: const [Reflectable, ObservableProperty],
15 override: 'observe.src.observable') 16 override: 'smoke.mirrors')
16 import 'dart:mirrors'; 17 import 'dart:mirrors' show MirrorsUsed;
17 18 import 'package:smoke/smoke.dart' as smoke;
18 import 'package:observe/observe.dart'; 19 import 'package:observe/observe.dart';
19 20
20 // Note: this is an internal library so we can import it from tests. 21 // Note: this is an internal library so we can import it from tests.
21 // TODO(jmesserly): ideally we could import this with a prefix, but it caused 22 // TODO(jmesserly): ideally we could import this with a prefix, but it caused
22 // strange problems on the VM when I tested out the dirty-checking example 23 // strange problems on the VM when I tested out the dirty-checking example
23 // above. 24 // above.
24 import 'dirty_check.dart'; 25 import 'dirty_check.dart';
25 26
26 /** 27 /**
27 * Represents an object with observable properties. This is used by data in 28 * Represents an object with observable properties. This is used by data in
(...skipping 11 matching lines...) Expand all
39 */ 40 */
40 abstract class Observable { 41 abstract class Observable {
41 /** 42 /**
42 * Performs dirty checking of objects that inherit from [Observable]. 43 * Performs dirty checking of objects that inherit from [Observable].
43 * This scans all observed objects using mirrors and determines if any fields 44 * This scans all observed objects using mirrors and determines if any fields
44 * have changed. If they have, it delivers the changes for the object. 45 * have changed. If they have, it delivers the changes for the object.
45 */ 46 */
46 static void dirtyCheck() => dirtyCheckObservables(); 47 static void dirtyCheck() => dirtyCheckObservables();
47 48
48 StreamController _changes; 49 StreamController _changes;
49 InstanceMirror _mirror;
50 50
51 Map<Symbol, Object> _values; 51 Map<Symbol, Object> _values;
52 List<ChangeRecord> _records; 52 List<ChangeRecord> _records;
53 53
54 /** 54 /**
55 * The stream of change records to this object. Records will be delivered 55 * The stream of change records to this object. Records will be delivered
56 * asynchronously. 56 * asynchronously.
57 * 57 *
58 * [deliverChanges] can be called to force synchronous delivery. 58 * [deliverChanges] can be called to force synchronous delivery.
59 */ 59 */
60 Stream<List<ChangeRecord>> get changes { 60 Stream<List<ChangeRecord>> get changes {
61 if (_changes == null) { 61 if (_changes == null) {
62 _changes = new StreamController.broadcast(sync: true, 62 _changes = new StreamController.broadcast(sync: true,
63 onListen: _observed, onCancel: _unobserved); 63 onListen: _observed, onCancel: _unobserved);
64 } 64 }
65 return _changes.stream; 65 return _changes.stream;
66 } 66 }
67 67
68 /** 68 /**
69 * True if this object has any observers, and should call 69 * True if this object has any observers, and should call
70 * [notifyChange] for changes. 70 * [notifyChange] for changes.
71 */ 71 */
72 bool get hasObservers => _changes != null && _changes.hasListener; 72 bool get hasObservers => _changes != null && _changes.hasListener;
73 73
74 void _observed() { 74 void _observed() {
75 // Register this object for dirty checking purposes. 75 // Register this object for dirty checking purposes.
76 registerObservable(this); 76 registerObservable(this);
77 77
78 var mirror = reflect(this);
79 var values = new Map<Symbol, Object>(); 78 var values = new Map<Symbol, Object>();
80 79
81 // Note: we scan for @observable regardless of whether the base type 80 // Note: we scan for @observable regardless of whether the base type
82 // actually includes this mixin. While perhaps too inclusive, it lets us 81 // actually includes this mixin. While perhaps too inclusive, it lets us
83 // avoid complex logic that walks "with" and "implements" clauses. 82 // avoid complex logic that walks "with" and "implements" clauses.
84 for (var type = mirror.type; type != objectType; type = type.superclass) { 83 var queryOptions = new smoke.QueryOptions(includeInherited: true,
85 for (var field in type.declarations.values) { 84 includeProperties: false, withAnnotations: const [ObservableProperty]);
86 if (field is! VariableMirror || 85 for (var decl in smoke.query(this.runtimeType, queryOptions)) {
87 field.isFinal || 86 var name = decl.name;
88 field.isStatic || 87 // Note: since this is a field, getting the value shouldn't execute
89 field.isPrivate) continue; 88 // user code, so we don't need to worry about errors.
90 89 values[name] = smoke.read(this, name);
91 for (var meta in field.metadata) {
92 if (meta.reflectee is ObservableProperty) {
93 var name = field.simpleName;
94 // Note: since this is a field, getting the value shouldn't execute
95 // user code, so we don't need to worry about errors.
96 values[name] = mirror.getField(name).reflectee;
97 break;
98 }
99 }
100 }
101 } 90 }
102 91
103 _mirror = mirror;
104 _values = values; 92 _values = values;
105 } 93 }
106 94
107 /** Release data associated with observation. */ 95 /** Release data associated with observation. */
108 void _unobserved() { 96 void _unobserved() {
109 // Note: we don't need to explicitly unregister from the dirty check list. 97 // Note: we don't need to explicitly unregister from the dirty check list.
110 // This will happen automatically at the next call to dirtyCheck. 98 // This will happen automatically at the next call to dirtyCheck.
111 if (_values != null) { 99 if (_values != null) {
112 _mirror = null;
113 _values = null; 100 _values = null;
114 } 101 }
115 } 102 }
116 103
117 /** 104 /**
118 * Synchronously deliver pending [changes]. Returns true if any records were 105 * Synchronously deliver pending [changes]. Returns true if any records were
119 * delivered, otherwise false. 106 * delivered, otherwise false.
120 */ 107 */
121 // TODO(jmesserly): this is a bit different from the ES Harmony version, which 108 // TODO(jmesserly): this is a bit different from the ES Harmony version, which
122 // allows delivery of changes to a particular observer: 109 // allows delivery of changes to a particular observer:
(...skipping 15 matching lines...) Expand all
138 // Harmony as well as predictability for app developers. 125 // Harmony as well as predictability for app developers.
139 bool deliverChanges() { 126 bool deliverChanges() {
140 if (_values == null || !hasObservers) return false; 127 if (_values == null || !hasObservers) return false;
141 128
142 // Start with manually notified records (computed properties, etc), 129 // Start with manually notified records (computed properties, etc),
143 // then scan all fields for additional changes. 130 // then scan all fields for additional changes.
144 List records = _records; 131 List records = _records;
145 _records = null; 132 _records = null;
146 133
147 _values.forEach((name, oldValue) { 134 _values.forEach((name, oldValue) {
148 var newValue = _mirror.getField(name).reflectee; 135 var newValue = smoke.read(this, name);
149 if (oldValue != newValue) { 136 if (oldValue != newValue) {
150 if (records == null) records = []; 137 if (records == null) records = [];
151 records.add(new PropertyChangeRecord(this, name, oldValue, newValue)); 138 records.add(new PropertyChangeRecord(this, name, oldValue, newValue));
152 _values[name] = newValue; 139 _values[name] = newValue;
153 } 140 }
154 }); 141 });
155 142
156 if (records == null) return false; 143 if (records == null) return false;
157 144
158 _changes.add(new UnmodifiableListView<ChangeRecord>(records)); 145 _changes.add(new UnmodifiableListView<ChangeRecord>(records));
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 // public instead? 182 // public instead?
196 // NOTE: this is not exported publically. 183 // NOTE: this is not exported publically.
197 notifyPropertyChangeHelper(Observable obj, Symbol field, Object oldValue, 184 notifyPropertyChangeHelper(Observable obj, Symbol field, Object oldValue,
198 Object newValue) { 185 Object newValue) {
199 186
200 if (obj.hasObservers && oldValue != newValue) { 187 if (obj.hasObservers && oldValue != newValue) {
201 obj.notifyChange(new PropertyChangeRecord(obj, field, oldValue, newValue)); 188 obj.notifyChange(new PropertyChangeRecord(obj, field, oldValue, newValue));
202 } 189 }
203 return newValue; 190 return newValue;
204 } 191 }
205
206 // NOTE: this is not exported publically.
207 final objectType = reflectClass(Object);
OLDNEW
« no previous file with comments | « no previous file | pkg/observe/lib/src/path_observer.dart » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698