Add StringScanner.substring.

R=rnystrom@google.com

Review URL: https://codereview.chromium.org//701723002

git-svn-id: https://dart.googlecode.com/svn/branches/bleeding_edge/dart/pkg/string_scanner@41536 260f80e4-7a28-3924-810f-c04153c831b5
diff --git a/pkgs/string_scanner/CHANGELOG.md b/pkgs/string_scanner/CHANGELOG.md
index d7f09f3..d273748 100644
--- a/pkgs/string_scanner/CHANGELOG.md
+++ b/pkgs/string_scanner/CHANGELOG.md
@@ -1,3 +1,7 @@
+## 0.1.2
+
+* Add `StringScanner.substring`, which returns a substring of the source string.
+
 ## 0.1.1
 
 * Declare `SpanScanner`'s exposed `SourceSpan`s and `SourceLocation`s to be
diff --git a/pkgs/string_scanner/lib/src/string_scanner.dart b/pkgs/string_scanner/lib/src/string_scanner.dart
index 44d5d2d..bc5e1f5 100644
--- a/pkgs/string_scanner/lib/src/string_scanner.dart
+++ b/pkgs/string_scanner/lib/src/string_scanner.dart
@@ -131,6 +131,15 @@
     return _lastMatch != null;
   }
 
+  /// Returns the substring of [string] between [start] and [end].
+  ///
+  /// Unlike [String.substring], [end] defaults to [position] rather than the
+  /// end of the string.
+  String substring(int start, [int end]) {
+    if (end == null) end = position;
+    return string.substring(start, end);
+  }
+
   /// Throws a [FormatException] with [message] as well as a detailed
   /// description of the location of the error in the string.
   ///
diff --git a/pkgs/string_scanner/pubspec.yaml b/pkgs/string_scanner/pubspec.yaml
index 831dfac..d14a43e 100644
--- a/pkgs/string_scanner/pubspec.yaml
+++ b/pkgs/string_scanner/pubspec.yaml
@@ -1,5 +1,5 @@
 name: string_scanner
-version: 0.1.1
+version: 0.1.2
 author: "Dart Team <misc@dartlang.org>"
 homepage: http://www.dartlang.org
 description: >
diff --git a/pkgs/string_scanner/test/string_scanner_test.dart b/pkgs/string_scanner/test/string_scanner_test.dart
index 6144bf9..fcd904a 100644
--- a/pkgs/string_scanner/test/string_scanner_test.dart
+++ b/pkgs/string_scanner/test/string_scanner_test.dart
@@ -61,6 +61,10 @@
       expect(scanner.position, equals(0));
     });
 
+    test("substring returns the empty string", () {
+      expect(scanner.substring(0), isEmpty);
+    });
+
     test('setting position to 1 throws an ArgumentError', () {
       expect(() {
         scanner.position = 1;
@@ -165,6 +169,18 @@
       expect(scanner.rest, equals('foo bar'));
     });
 
+    test("substring from the beginning returns the empty string", () {
+      expect(scanner.substring(0), isEmpty);
+    });
+
+    test("substring with a custom end returns the substring", () {
+      expect(scanner.substring(0, 3), equals('foo'));
+    });
+
+    test("substring with the string length returns the whole string", () {
+      expect(scanner.substring(0, 7), equals('foo bar'));
+    });
+
     test('setting position to 1 moves the cursor forward', () {
       scanner.position = 1;
       expect(scanner.position, equals(1));
@@ -260,6 +276,18 @@
       expect(scanner.position, equals(7));
     });
 
+    test("substring from the beginning returns the whole string", () {
+      expect(scanner.substring(0), equals('foo bar'));
+    });
+
+    test("substring with a custom start returns a substring from there", () {
+      expect(scanner.substring(4), equals('bar'));
+    });
+
+    test("substring with a custom start and end returns that substring", () {
+      expect(scanner.substring(3, 5), equals(' b'));
+    });
+
     test('setting position to 1 moves the cursor backward', () {
       scanner.position = 1;
       expect(scanner.position, equals(1));