Start implementing Dart 2.0 collection methods. (#77)

* Start implementing Dart 2.0 collection methods.

* Travis and tests.
diff --git a/.travis.yml b/.travis.yml
index 264316d..a31bd64 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -2,7 +2,6 @@
 
 dart:
   - dev
-  - stable
 
 dart_task:
   - test: --platform vm
@@ -13,12 +12,6 @@
 branches:
   only: [master]
 
-matrix:
-  # Only run dartfmt checks with stable.
-  exclude:
-    - dart: dev
-      dart_task: dartfmt
-
 cache:
   directories:
     - $HOME/.pub-cache
diff --git a/CHANGELOG.md b/CHANGELOG.md
index b676ee1..4f14f32 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+## 1.14.7-dev
+
+* Only the Dart 2 dev SDK (`>=2.0.0-dev.22.0`) is now supported.
+* Add support for `Map.{addEntries|entries}` for Dart 2.0.
+
 ## 1.14.6
 
 * Make `DefaultEquality`'s `equals()` and `hash()` methods take any `Object`
diff --git a/lib/src/canonicalized_map.dart b/lib/src/canonicalized_map.dart
index 117cd63..e586420 100644
--- a/lib/src/canonicalized_map.dart
+++ b/lib/src/canonicalized_map.dart
@@ -69,14 +69,10 @@
     other.forEach((key, value) => this[key] = value);
   }
 
-  // TODO: Dart 2.0 requires this method to be implemented.
-  void addEntries(Iterable<Object> entries) {
-    // Change Iterable<Object> to Iterable<MapEntry<K, V>> when
-    // the MapEntry class has been added.
-    throw new UnimplementedError('addEntries');
-  }
+  void addEntries(Iterable<MapEntry<K, V>> entries) =>
+      _base.addEntries(entries.map(
+          (e) => new MapEntry(_canonicalize(e.key), new Pair(e.key, e.value))));
 
-  // TODO: Dart 2.0 requires this method to be implemented.
   Map<K2, V2> cast<K2, V2>() {
     throw new UnimplementedError('cast');
   }
@@ -93,12 +89,8 @@
   bool containsValue(Object value) =>
       _base.values.any((pair) => pair.last == value);
 
-  // TODO: Dart 2.0 requires this method to be implemented.
-  Iterable<Null> get entries {
-    // Change Iterable<Null> to Iterable<MapEntry<K, V>> when
-    // the MapEntry class has been added.
-    throw new UnimplementedError('entries');
-  }
+  Iterable<MapEntry<K, V>> get entries =>
+      _base.entries.map((e) => new MapEntry(e.value.first, e.value.last));
 
   void forEach(void f(K key, V value)) {
     _base.forEach((key, pair) => f(pair.first, pair.last));
diff --git a/lib/src/typed_wrappers.dart b/lib/src/typed_wrappers.dart
index cef2a58..f713d0b 100644
--- a/lib/src/typed_wrappers.dart
+++ b/lib/src/typed_wrappers.dart
@@ -395,11 +395,8 @@
     _base.addAll(other);
   }
 
-  // TODO: Dart 2.0 requires this method to be implemented.
-  void addEntries(Iterable<Object> entries) {
-    // Change Iterable<Object> to Iterable<MapEntry<K, V>> when
-    // the MapEntry class has been added.
-    throw new UnimplementedError('addEntries');
+  void addEntries(Iterable<MapEntry<K, V>> entries) {
+    _base.addEntries(entries);
   }
 
   // TODO: Dart 2.0 requires this method to be implemented.
@@ -415,12 +412,7 @@
 
   bool containsValue(Object value) => _base.containsValue(value);
 
-  // TODO: Dart 2.0 requires this method to be implemented.
-  Iterable<Null> get entries {
-    // Change Iterable<Null> to Iterable<MapEntry<K, V>> when
-    // the MapEntry class has been added.
-    throw new UnimplementedError('entries');
-  }
+  Iterable<MapEntry<K, V>> get entries => _base.entries;
 
   void forEach(void f(K key, V value)) {
     _base.forEach((key, value) => f(key as K, value as V));
diff --git a/lib/src/wrappers.dart b/lib/src/wrappers.dart
index 1abfd45..cef99b7 100644
--- a/lib/src/wrappers.dart
+++ b/lib/src/wrappers.dart
@@ -450,11 +450,8 @@
     _base.addAll(other);
   }
 
-  // TODO: Dart 2.0 requires this method to be implemented.
-  void addEntries(Iterable<Object> entries) {
-    // Change Iterable<Object> to Iterable<MapEntry<K, V>> when
-    // the MapEntry class has been added.
-    throw new UnimplementedError('addEntries');
+  void addEntries(Iterable<MapEntry<K, V>> entries) {
+    _base.addEntries(entries);
   }
 
   void clear() {
@@ -470,12 +467,7 @@
 
   bool containsValue(Object value) => _base.containsValue(value);
 
-  // TODO: Dart 2.0 requires this method to be implemented.
-  Iterable<Null> get entries {
-    // Change Iterable<Null> to Iterable<MapEntry<K, V>> when
-    // the MapEntry class has been added.
-    throw new UnimplementedError('entries');
-  }
+  Iterable<MapEntry<K, V>> get entries => _base.entries;
 
   void forEach(void f(K key, V value)) {
     _base.forEach(f);
diff --git a/pubspec.yaml b/pubspec.yaml
index e97a358..972f6c6 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,9 +1,12 @@
 name: collection
-version: 1.14.6
+version: 1.14.7-dev
 author: Dart Team <misc@dartlang.org>
 description: Collections and utilities functions and classes related to collections.
 homepage: https://www.github.com/dart-lang/collection
+
 environment:
-  sdk: '>=1.21.0 <2.0.0'
+  # Required for Dart 2.0 collection changes.
+  sdk: '>=2.0.0-dev.22.0 <2.0.0'
+
 dev_dependencies:
   test: '^0.12.0'
diff --git a/test/canonicalized_map_test.dart b/test/canonicalized_map_test.dart
index f48778d..9586cf3 100644
--- a/test/canonicalized_map_test.dart
+++ b/test/canonicalized_map_test.dart
@@ -7,9 +7,10 @@
 
 void main() {
   group("with an empty canonicalized map", () {
-    var map;
+    CanonicalizedMap<int, String, String> map;
+
     setUp(() {
-      map = new CanonicalizedMap<int, String, String>(int.parse,
+      map = new CanonicalizedMap(int.parse,
           isValidKey: (s) => new RegExp(r"^\d+$").hasMatch(s as String));
     });
 
@@ -130,6 +131,29 @@
 
       expect(map.values, equals(["value 01", "value 2", "value 03"]));
     });
+
+    test("entries returns all key-value pairs in the map", () {
+      map.addAll({
+        "1": "value 1",
+        "01": "value 01",
+        "2": "value 2",
+      });
+
+      var entries = map.entries.toList();
+      expect(entries[0].key, "01");
+      expect(entries[0].value, "value 01");
+      expect(entries[1].key, "2");
+      expect(entries[1].value, "value 2");
+    });
+
+    test("addEntries adds key-value pairs to the map", () {
+      map.addEntries([
+        new MapEntry("1", "value 1"),
+        new MapEntry("01", "value 01"),
+        new MapEntry("2", "value 2"),
+      ]);
+      expect(map, {"01": "value 01", "2": "value 2"});
+    });
   });
 
   group("CanonicalizedMap builds an informative string representation", () {