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

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, 10 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 @unused.MirrorsUsed(
15 override: 'observe.src.observable') 16 metaTargets: const [Reflectable, ObservableProperty],
16 import 'dart:mirrors'; 17 override: 'smoke.mirrors')
17 18 import 'dart:mirrors' as unused;
Jennifer Messerly 2014/02/20 21:46:40 import 'dart:mirrors' show MirrorsUsed?
19 import 'package:smoke/smoke.dart' as smoke;
18 import 'package:observe/observe.dart'; 20 import 'package:observe/observe.dart';
19 21
20 // Note: this is an internal library so we can import it from tests. 22 // 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 23 // 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 24 // strange problems on the VM when I tested out the dirty-checking example
23 // above. 25 // above.
24 import 'dirty_check.dart'; 26 import 'dirty_check.dart';
25 27
26 /** 28 /**
27 * Represents an object with observable properties. This is used by data in 29 * Represents an object with observable properties. This is used by data in
(...skipping 11 matching lines...) Expand all
39 */ 41 */
40 abstract class Observable { 42 abstract class Observable {
41 /** 43 /**
42 * Performs dirty checking of objects that inherit from [Observable]. 44 * Performs dirty checking of objects that inherit from [Observable].
43 * This scans all observed objects using mirrors and determines if any fields 45 * 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. 46 * have changed. If they have, it delivers the changes for the object.
45 */ 47 */
46 static void dirtyCheck() => dirtyCheckObservables(); 48 static void dirtyCheck() => dirtyCheckObservables();
47 49
48 StreamController _changes; 50 StreamController _changes;
49 InstanceMirror _mirror;
50 51
51 Map<Symbol, Object> _values; 52 Map<Symbol, Object> _values;
52 List<ChangeRecord> _records; 53 List<ChangeRecord> _records;
53 54
54 /** 55 /**
55 * The stream of change records to this object. Records will be delivered 56 * The stream of change records to this object. Records will be delivered
56 * asynchronously. 57 * asynchronously.
57 * 58 *
58 * [deliverChanges] can be called to force synchronous delivery. 59 * [deliverChanges] can be called to force synchronous delivery.
59 */ 60 */
60 Stream<List<ChangeRecord>> get changes { 61 Stream<List<ChangeRecord>> get changes {
61 if (_changes == null) { 62 if (_changes == null) {
62 _changes = new StreamController.broadcast(sync: true, 63 _changes = new StreamController.broadcast(sync: true,
63 onListen: _observed, onCancel: _unobserved); 64 onListen: _observed, onCancel: _unobserved);
64 } 65 }
65 return _changes.stream; 66 return _changes.stream;
66 } 67 }
67 68
68 /** 69 /**
69 * True if this object has any observers, and should call 70 * True if this object has any observers, and should call
70 * [notifyChange] for changes. 71 * [notifyChange] for changes.
71 */ 72 */
72 bool get hasObservers => _changes != null && _changes.hasListener; 73 bool get hasObservers => _changes != null && _changes.hasListener;
73 74
74 void _observed() { 75 void _observed() {
75 // Register this object for dirty checking purposes. 76 // Register this object for dirty checking purposes.
76 registerObservable(this); 77 registerObservable(this);
77 78
78 var mirror = reflect(this);
79 var values = new Map<Symbol, Object>(); 79 var values = new Map<Symbol, Object>();
80 80
81 // Note: we scan for @observable regardless of whether the base type 81 // Note: we scan for @observable regardless of whether the base type
82 // actually includes this mixin. While perhaps too inclusive, it lets us 82 // actually includes this mixin. While perhaps too inclusive, it lets us
83 // avoid complex logic that walks "with" and "implements" clauses. 83 // avoid complex logic that walks "with" and "implements" clauses.
84 for (var type = mirror.type; type != objectType; type = type.superclass) { 84 // TODO(sigmund): should we exclude getters here? users should only use
85 for (var field in type.declarations.values) { 85 // @observable on fields, but 'smoke' includes getters with fields (might
86 if (field is! VariableMirror || 86 // need to extend smoke for this). See also note below on `smoke.read`.
87 field.isFinal || 87 var queryOptions = new smoke.QueryOptions(includeInherited: true,
Jennifer Messerly 2014/02/20 21:46:40 hmmm, yeah, it's pretty important not to find gett
Siggi Cherem (dart-lang) 2014/02/21 03:50:27 yeah, I had a feeling this was going to be necessa
88 field.isStatic || 88 withAnnotations: const [ObservableProperty]);
89 field.isPrivate) continue; 89 for (var decl in smoke.query(this.runtimeType, queryOptions)) {
90 90 var name = decl.name;
91 for (var meta in field.metadata) { 91 // Note: since this is a field, getting the value shouldn't execute
92 if (meta.reflectee is ObservableProperty) { 92 // user code, so we don't need to worry about errors.
93 var name = field.simpleName; 93 values[name] = smoke.read(this, name);
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 } 94 }
102 95
103 _mirror = mirror;
104 _values = values; 96 _values = values;
105 } 97 }
106 98
107 /** Release data associated with observation. */ 99 /** Release data associated with observation. */
108 void _unobserved() { 100 void _unobserved() {
109 // Note: we don't need to explicitly unregister from the dirty check list. 101 // Note: we don't need to explicitly unregister from the dirty check list.
110 // This will happen automatically at the next call to dirtyCheck. 102 // This will happen automatically at the next call to dirtyCheck.
111 if (_values != null) { 103 if (_values != null) {
112 _mirror = null;
113 _values = null; 104 _values = null;
114 } 105 }
115 } 106 }
116 107
117 /** 108 /**
118 * Synchronously deliver pending [changes]. Returns true if any records were 109 * Synchronously deliver pending [changes]. Returns true if any records were
119 * delivered, otherwise false. 110 * delivered, otherwise false.
120 */ 111 */
121 // TODO(jmesserly): this is a bit different from the ES Harmony version, which 112 // TODO(jmesserly): this is a bit different from the ES Harmony version, which
122 // allows delivery of changes to a particular observer: 113 // allows delivery of changes to a particular observer:
(...skipping 15 matching lines...) Expand all
138 // Harmony as well as predictability for app developers. 129 // Harmony as well as predictability for app developers.
139 bool deliverChanges() { 130 bool deliverChanges() {
140 if (_values == null || !hasObservers) return false; 131 if (_values == null || !hasObservers) return false;
141 132
142 // Start with manually notified records (computed properties, etc), 133 // Start with manually notified records (computed properties, etc),
143 // then scan all fields for additional changes. 134 // then scan all fields for additional changes.
144 List records = _records; 135 List records = _records;
145 _records = null; 136 _records = null;
146 137
147 _values.forEach((name, oldValue) { 138 _values.forEach((name, oldValue) {
148 var newValue = _mirror.getField(name).reflectee; 139 var newValue = smoke.read(this, name);
149 if (oldValue != newValue) { 140 if (oldValue != newValue) {
150 if (records == null) records = []; 141 if (records == null) records = [];
151 records.add(new PropertyChangeRecord(this, name, oldValue, newValue)); 142 records.add(new PropertyChangeRecord(this, name, oldValue, newValue));
152 _values[name] = newValue; 143 _values[name] = newValue;
153 } 144 }
154 }); 145 });
155 146
156 if (records == null) return false; 147 if (records == null) return false;
157 148
158 _changes.add(new UnmodifiableListView<ChangeRecord>(records)); 149 _changes.add(new UnmodifiableListView<ChangeRecord>(records));
(...skipping 36 matching lines...) Expand 10 before | Expand all | Expand 10 after
195 // public instead? 186 // public instead?
196 // NOTE: this is not exported publically. 187 // NOTE: this is not exported publically.
197 notifyPropertyChangeHelper(Observable obj, Symbol field, Object oldValue, 188 notifyPropertyChangeHelper(Observable obj, Symbol field, Object oldValue,
198 Object newValue) { 189 Object newValue) {
199 190
200 if (obj.hasObservers && oldValue != newValue) { 191 if (obj.hasObservers && oldValue != newValue) {
201 obj.notifyChange(new PropertyChangeRecord(obj, field, oldValue, newValue)); 192 obj.notifyChange(new PropertyChangeRecord(obj, field, oldValue, newValue));
202 } 193 }
203 return newValue; 194 return newValue;
204 } 195 }
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