Chromium Code Reviews| Index: pkg/observe/lib/src/path_observer.dart |
| diff --git a/pkg/observe/lib/src/path_observer.dart b/pkg/observe/lib/src/path_observer.dart |
| index 0d631a0c192829fb51726b968157ebbf13c3b554..b7d83172d1606a0b7924772af55fe04d272ab4a9 100644 |
| --- a/pkg/observe/lib/src/path_observer.dart |
| +++ b/pkg/observe/lib/src/path_observer.dart |
| @@ -83,7 +83,10 @@ class PathObserver extends _Observer implements Bindable { |
| /// A dot-delimieted property path such as "foo.bar" or "foo.10.bar". |
|
Jennifer Messerly
2014/03/25 22:32:44
this was an issue before but: do you mind adding a
Siggi Cherem (dart-lang)
2014/03/26 00:32:07
Done.
|
| /// The path specifies how to get a particular value from an object graph, where |
| -/// the graph can include arrays. |
| +/// the graph can include arrays and maps. Each segment of the path describes |
| +/// how to take a single step in the object graph. Properties like 'foo' or |
| +/// 'bar' are read as properties on objects, or as keys if the object is a Map |
| +/// or an [StringIndexer], while integer values are read as indexes in an array. |
|
Jennifer Messerly
2014/03/25 22:32:44
should be "a [StringIndexer]"
also, this was an i
Siggi Cherem (dart-lang)
2014/03/26 00:32:07
Done.
|
| // TODO(jmesserly): consider specialized subclasses for: |
| // * empty path |
| // * "value" |
| @@ -180,7 +183,7 @@ class PropertyPath { |
| return 0x1fffffff & (hash + ((0x00003fff & hash) << 15)); |
| } |
| - /// Returns the current of the path from the provided [obj]ect. |
| + /// Returns the current value of the path from the provided [obj]ect. |
| getValueFrom(Object obj) { |
| if (!isValid) return null; |
| for (var segment in _segments) { |
| @@ -233,6 +236,13 @@ bool _changeRecordMatches(record, key) { |
| return false; |
| } |
| +/// Properties in [Map] that need to be read as properties and not as keys in |
| +/// the map. We exclude methods ('containsValue', 'containsKey', 'putIfAbsent', |
| +/// 'addAll', 'remove', 'clear', 'forEach') because there is no use in reading |
| +/// them as part of path-observer segments. |
| +const _MAP_PROPERTIES = |
| + const ['keys', 'values', 'length', 'isEmpty', 'isNotEmpty']; |
| + |
| _getObjectProperty(object, property) { |
| if (object == null) return null; |
| @@ -241,21 +251,25 @@ _getObjectProperty(object, property) { |
| return object[property]; |
| } |
| } else if (property is Symbol) { |
| - final type = object.runtimeType; |
| + var name = smoke.symbolToName(property); |
|
Jennifer Messerly
2014/03/25 22:32:44
move this inside the if, below? and make _MAP_PROP
Siggi Cherem (dart-lang)
2014/03/26 00:32:07
Done.
|
| + // Support indexer if available, e.g. Maps or polymer_expressions Scope. |
| + // This is the default syntax used by polymer/nodebind and |
| + // polymer/observe-js PathObserver. |
| + // TODO(sigmund): should we also support using checking dynamically for |
| + // whether the type practically implements the indexer API |
| + // (smoke.hasInstanceMethod(type, const Symbol('[]')))? |
| + if (object is StringIndexer || |
| + object is Map && !_MAP_PROPERTIES.contains(name)) { |
| + return object[name]; |
| + } |
| try { |
| - if (smoke.hasGetter(type, property) || smoke.hasNoSuchMethod(type)) { |
| - return smoke.read(object, property); |
| - } |
| - // Support indexer if available, e.g. Maps or polymer_expressions Scope. |
| - // This is the default syntax used by polymer/nodebind and |
| - // polymer/observe-js PathObserver. |
| - if (smoke.hasInstanceMethod(type, const Symbol('[]'))) { |
| - return object[smoke.symbolToName(property)]; |
| - } |
| - } on NoSuchMethodError catch (e) { |
| + return smoke.read(object, property); |
| + } on NoSuchMethodError catch (e, s) { |
| // Rethrow, unless the type implements noSuchMethod, in which case we |
| // interpret the exception as a signal that the method was not found. |
| - if (!smoke.hasNoSuchMethod(type)) rethrow; |
| + if (!smoke.hasNoSuchMethod(object.runtimeType)) { |
| + new Completer().completeError(e, s); |
|
Jennifer Messerly
2014/03/25 22:32:44
hmmm. Upon second look I'm not sure this is the ri
Siggi Cherem (dart-lang)
2014/03/26 00:32:07
No worries, changed it back to sync. Thanks for fi
|
| + } |
| } |
| } |
| @@ -274,19 +288,20 @@ bool _setObjectProperty(object, property, value) { |
| return true; |
| } |
| } else if (property is Symbol) { |
| - final type = object.runtimeType; |
| + // Support indexer if available, e.g. Maps or polymer_expressions Scope. |
| + var name = smoke.symbolToName(property); |
| + if (object is StringIndexer || |
| + object is Map && !_MAP_PROPERTIES.contains(name)) { |
| + object[name] = value; |
| + return true; |
| + } |
| try { |
| - if (smoke.hasSetter(type, property) || smoke.hasNoSuchMethod(type)) { |
| - smoke.write(object, property, value); |
| - return true; |
| - } |
| - // Support indexer if available, e.g. Maps or polymer_expressions Scope. |
| - if (smoke.hasInstanceMethod(type, const Symbol('[]='))) { |
| - object[smoke.symbolToName(property)] = value; |
| - return true; |
| + smoke.write(object, property, value); |
| + return true; |
| + } on NoSuchMethodError catch (e, s) { |
| + if (!smoke.hasNoSuchMethod(object.runtimeType)) { |
| + new Completer().completeError(e, s); |
| } |
| - } on NoSuchMethodError catch (e) { |
| - if (!smoke.hasNoSuchMethod(type)) rethrow; |
| } |
| } |
| @@ -470,6 +485,13 @@ class CompoundObserver extends _Observer implements Bindable { |
| } |
| } |
| +/// An object accepted by [PropertyPath] where properties are read and written |
| +/// as indexing operations, just like a [Map]. |
| +abstract class StringIndexer { |
|
Siggi Cherem (dart-lang)
2014/03/25 21:44:25
I was not sure about the name. Other ideas/suggest
Jennifer Messerly
2014/03/25 22:32:44
Indexable<K, V>? then do the is check for Indexabl
Siggi Cherem (dart-lang)
2014/03/26 00:32:07
Done.
|
| + operator [](String name); |
| + operator []=(index, value); |
| +} |
| + |
| const _observerSentinel = const _ObserverSentinel(); |
| class _ObserverSentinel { const _ObserverSentinel(); } |