Add browser-compatible version.
Still need to find a way to test it.
R=floitsch@google.com
Review URL: https://codereview.chromium.org//1612003002 .
diff --git a/CHANGELOG.md b/CHANGELOG.md
index dd213b1..674b8df 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,10 @@
# Changelog
+## 1.1.0
+
+- Added browser-compatible version as `browser_resource.dart` library.
+ Only needed because configurable imports are not available yet.
+
## 1.0.0
- Initial version
diff --git a/README.md b/README.md
index b5f5d74..1fc9691 100644
--- a/README.md
+++ b/README.md
@@ -4,8 +4,10 @@
## Features and bugs
-The current version depends on the `dart:io` library, and doesn't work
-in the browser. A browser alternative will be added soon.
+The current version of `resource.dart` depends on the `dart:io` library,
+and doesn't work in the browser.
+Use `package:resource/browser_resource.dart` in the browser until
+further notice.
Please file feature requests and bugs at the [issue tracker][tracker].
diff --git a/lib/browser_resource.dart b/lib/browser_resource.dart
new file mode 100644
index 0000000..d66eeb3
--- /dev/null
+++ b/lib/browser_resource.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+/// A [Resource] is data that can be read into a Dart program.
+///
+/// A resource is identified by a URI. It can be loaded as bytes or data.
+/// The resource URI may be a `package:` URI.
+///
+/// Example:
+///
+/// var resource = new Resource("package:foo/foo_data.txt");
+/// var string = await resource.readAsString(UTF8);
+/// print(string);
+///
+/// Example:
+///
+/// var resource = new Resource("http://example.com/data.json");
+/// var obj = await resource.openRead() // Reads as stream of bytes.
+/// .transform(UTF8.fuse(JSON).decoder)
+/// .first;
+///
+///
+/// Notice: Currently this library requires `dart:Html` to do the reading,
+/// so it doesn't work outside of a browser.
+/// This library will eventually be mergeded into the `resource.dart` when
+/// features are available to make that possible.
+library resource;
+
+export "src/browser/resource.dart" show Resource;
+export "src/browser/loader.dart" show ResourceLoader;
diff --git a/lib/resource.dart b/lib/resource.dart
index 83c75c6..91c74a0 100644
--- a/lib/resource.dart
+++ b/lib/resource.dart
@@ -1,4 +1,4 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
@@ -21,9 +21,10 @@
/// .first;
///
///
-/// Notice: Currently this package requires `dart:io` to do the reading,
-/// so it doesn't work in the browser.
+/// Notice: Currently this library requires `dart:io` to do the reading,
+/// so it doesn't work in the browser. Use `browser_resource.dart` in the
+/// browser.
library resource;
-export "src/resource.dart" show Resource;
-export "src/loader.dart" show ResourceLoader;
+export "src/io/resource.dart" show Resource;
+export "src/io/loader.dart" show ResourceLoader;
diff --git a/lib/src/browser/html_io.dart b/lib/src/browser/html_io.dart
new file mode 100644
index 0000000..2896967
--- /dev/null
+++ b/lib/src/browser/html_io.dart
@@ -0,0 +1,60 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async" show Future, Stream;
+import "dart:convert" show Encoding, LATIN1, UTF8;
+import "dart:html";
+import "dart:typed_data" show Uint8List, ByteBuffer;
+
+/// Reads the bytes of a URI as a stream of bytes.
+Stream<List<int>> readAsStream(Uri uri) async* {
+ // TODO(lrn): Should file be run through XmlHTTPRequest too?
+ if (uri.scheme == "http" || uri.scheme == "https") {
+ // TODO: Stream in chunks if DOM has a way to do so.
+ List<int> response = await _httpGetBytes(uri);
+ yield response;
+ return;
+ }
+ if (uri.scheme == "data") {
+ yield uri.data.contentAsBytes();
+ return;
+ }
+ throw new UnsupportedError("Unsupported scheme: $uri");
+}
+
+/// Reads the bytes of a URI as a list of bytes.
+Future<List<int>> readAsBytes(Uri uri) async {
+ if (uri.scheme == "http" || uri.scheme == "https") {
+ return _httpGetBytes(uri);
+ }
+ if (uri.scheme == "data") {
+ return uri.data.contentAsBytes();
+ }
+ throw new UnsupportedError("Unsupported scheme: $uri");
+}
+
+/// Reads the bytes of a URI as a string.
+Future<String> readAsString(Uri uri, Encoding encoding) async {
+ if (uri.scheme == "http" || uri.scheme == "https") {
+ // Fetch as string if the encoding is expected to be understood,
+ // otherwise fetch as bytes and do decoding using the encoding.
+ if (encoding != null) {
+ return encoding.decode(await _httpGetBytes(uri));
+ }
+ return HttpRequest.getString(uri.toString());
+ }
+ if (uri.scheme == "data") {
+ return uri.data.contentAsString(encoding: encoding);
+ }
+ throw new UnsupportedError("Unsupported scheme: $uri");
+}
+
+Future<List<int>> _httpGetBytes(Uri uri) {
+ return HttpRequest
+ .request(uri.toString(), responseType: "arraybuffer")
+ .then((request) {
+ ByteBuffer data = request.response;
+ return data.asUint8List();
+ });
+}
diff --git a/lib/src/browser/loader.dart b/lib/src/browser/loader.dart
new file mode 100644
index 0000000..0ecaf67
--- /dev/null
+++ b/lib/src/browser/loader.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async" show Future, Stream;
+import "dart:convert" show Encoding;
+
+import "../resource_loader.dart" as base;
+import "../package_loader.dart"as base;
+import "html_io.dart" as io;
+
+/// Resource loading strategy.
+///
+/// An abstraction of the functionality needed to load resources.
+///
+/// Implementations of this interface decide which URI schemes they support.
+abstract class ResourceLoader implements base.ResourceLoader {
+ /// A resource loader that can load as many of the following URI
+ /// schemes as are supported by the platform:
+ /// * file
+ /// * http
+ /// * https
+ /// * data
+ /// * package
+ ///
+ /// (For example, file: URIs are not supported in the browser).
+ /// Relative URI references are accepted - they are resolved against
+ /// [Uri.base] before being loaded.
+ static ResourceLoader get defaultLoader =>
+ const PackageLoader(const DefaultLoader());
+}
+
+/// Default implementation of [ResourceLoader]..
+///
+/// Uses the system's available loading functionality to implement the
+/// loading functions.
+///
+/// Supports as many of `http:`, `https:`, `file:` and `data:` URIs as
+/// possible.
+class DefaultLoader implements ResourceLoader {
+ const DefaultLoader();
+
+ Stream<List<int>> openRead(Uri uri) => io.readAsStream(uri);
+
+ Future<List<int>> readAsBytes(Uri uri) => io.readAsBytes(uri);
+
+ Future<String> readAsString(Uri uri, {Encoding encoding}) =>
+ io.readAsString(uri, encoding);
+}
+
+// A loader that implements base.PackageLoader *and* ResourceLoader from this
+// file.
+class PackageLoader extends base.PackageLoader implements ResourceLoader {
+ const PackageLoader(ResourceLoader loader) : super(loader);
+}
diff --git a/lib/src/browser/resource.dart b/lib/src/browser/resource.dart
new file mode 100644
index 0000000..9368e4e
--- /dev/null
+++ b/lib/src/browser/resource.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:core" hide Resource;
+
+import "loader.dart" show ResourceLoader, DefaultLoader;
+
+// TODO(lrn): Merge with implementation when configured imports removes
+// the need to share code.
+import "../resource.dart" as base show Resource;
+
+class Resource extends base.Resource {
+ /// Creates a resource object with the given [uri] as location.
+ ///
+ /// The [uri] must be either a [Uri] or a string containing a valid URI.
+ /// If the string is not a valid URI, using any of the functions on
+ /// the resource object will fail.
+ ///
+ /// The URI may be relative, in which case it will be resolved
+ /// against [Uri.base] before being used.
+ ///
+ /// The URI may use the `package` scheme, which is always supported.
+ /// Other schemes may also be supported where possible.
+ ///
+ /// If [loader] is provided, it is used to load absolute non-package URIs.
+ /// Package: URIs are resolved to a non-package URI before being loaded, so
+ /// the loader doesn't have to support package: URIs, nor does it need to
+ /// support relative URI references.
+ /// If [loader] is omitted, a default implementation is used which supports
+ /// as many of `http`, `https`, `file` and `data` as are available on the
+ /// current platform.
+ const Resource(uri, {ResourceLoader loader})
+ : super(uri, (loader != null) ? loader : const DefaultLoader());
+}
diff --git a/lib/src/io.dart b/lib/src/io/io.dart
similarity index 89%
rename from lib/src/io.dart
rename to lib/src/io/io.dart
index ff8761b..b24244d 100644
--- a/lib/src/io.dart
+++ b/lib/src/io/io.dart
@@ -1,14 +1,13 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
-// dart:io based strategy for loading resources.
-
import "dart:async" show Future, Stream;
import "dart:convert" show Encoding, LATIN1, UTF8;
import "dart:io" show
File, HttpClient, HttpClientResponse, HttpClientRequest, HttpHeaders;
import "dart:typed_data" show Uint8List;
+
import "package:typed_data/typed_buffers.dart" show Uint8Buffer;
/// Read the bytes of a URI as a stream of bytes.
@@ -18,7 +17,7 @@
return;
}
if (uri.scheme == "http" || uri.scheme == "https") {
- HttpClientResponse response = await _httpGet(uri);
+ HttpClientResponse response = await _httpGetBytes(uri);
yield* response;
return;
}
@@ -35,7 +34,7 @@
return new File.fromUri(uri).readAsBytes();
}
if (uri.scheme == "http" || uri.scheme == "https") {
- HttpClientResponse response = await _httpGet(uri);
+ HttpClientResponse response = await _httpGetBytes(uri);
int length = response.contentLength;
if (length < 0) length = 0;
var buffer = new Uint8Buffer(length);
@@ -74,7 +73,7 @@
await for (var bytes in response) {
buffer.addAll(bytes);
}
- var byteList = new Uint8List.view(buffer.buffer, 0, buffer.length);
+ var byteList = buffer.buffer.asUint8List(0, buffer.length);
return new String.fromCharCodes(byteList);
}
return response.transform(encoding.decoder).join();
@@ -85,7 +84,7 @@
throw new UnsupportedError("Unsupported scheme: $uri");
}
-Future<HttpClientResponse> _httpGet(Uri uri) async {
+Future<HttpClientResponse> _httpGetBytes(Uri uri) async {
HttpClientRequest request = await new HttpClient().getUrl(uri);
request.headers.set(HttpHeaders.ACCEPT, "application/octet-stream, */*");
return request.close();
diff --git a/lib/src/io/loader.dart b/lib/src/io/loader.dart
new file mode 100644
index 0000000..d52cf44
--- /dev/null
+++ b/lib/src/io/loader.dart
@@ -0,0 +1,55 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async" show Future, Stream;
+import "dart:convert" show Encoding;
+
+import "../resource_loader.dart" as base;
+import "../package_loader.dart"as base;
+import "io.dart" as io;
+
+/// Resource loading strategy.
+///
+/// An abstraction of the functionality needed to load resources.
+///
+/// Implementations of this interface decide which URI schemes they support.
+abstract class ResourceLoader implements base.ResourceLoader {
+ /// A resource loader that can load as many of the following URI
+ /// schemes as are supported by the platform:
+ /// * file
+ /// * http
+ /// * https
+ /// * data
+ /// * package
+ ///
+ /// (For example, file: URIs are not supported in the browser).
+ /// Relative URI references are accepted - they are resolved against
+ /// [Uri.base] before being loaded.
+ static ResourceLoader get defaultLoader =>
+ const PackageLoader(const DefaultLoader());
+}
+
+/// Default implementation of [ResourceLoader]..
+///
+/// Uses the system's available loading functionality to implement the
+/// loading functions.
+///
+/// Supports as many of `http:`, `https:`, `file:` and `data:` URIs as
+/// possible.
+class DefaultLoader implements ResourceLoader {
+ const DefaultLoader();
+
+ Stream<List<int>> openRead(Uri uri) => io.readAsStream(uri);
+
+ Future<List<int>> readAsBytes(Uri uri) => io.readAsBytes(uri);
+
+ Future<String> readAsString(Uri uri, {Encoding encoding}) =>
+ io.readAsString(uri, encoding);
+}
+
+// A loader that implements base.PackageLoader *and* ResourceLoader from this
+// file.
+class PackageLoader extends base.PackageLoader implements ResourceLoader {
+ const PackageLoader(ResourceLoader loader) : super(loader);
+}
diff --git a/lib/src/io/resource.dart b/lib/src/io/resource.dart
new file mode 100644
index 0000000..4ca3b8f
--- /dev/null
+++ b/lib/src/io/resource.dart
@@ -0,0 +1,35 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:core" hide Resource;
+
+import "loader.dart" show ResourceLoader, DefaultLoader;
+
+// TODO(lrn): Merge with implementation when configured imports removes
+// the need to share code.
+import "../resource.dart" as base show Resource;
+
+class Resource extends base.Resource {
+ /// Creates a resource object with the given [uri] as location.
+ ///
+ /// The [uri] must be either a [Uri] or a string containing a valid URI.
+ /// If the string is not a valid URI, using any of the functions on
+ /// the resource object will fail.
+ ///
+ /// The URI may be relative, in which case it will be resolved
+ /// against [Uri.base] before being used.
+ ///
+ /// The URI may use the `package` scheme, which is always supported.
+ /// Other schemes may also be supported where possible.
+ ///
+ /// If [loader] is provided, it is used to load absolute non-package URIs.
+ /// Package: URIs are resolved to a non-package URI before being loaded, so
+ /// the loader doesn't have to support package: URIs, nor does it need to
+ /// support relative URI references.
+ /// If [loader] is omitted, a default implementation is used which supports
+ /// as many of `http`, `https`, `file` and `data` as are available on the
+ /// current platform.
+ const Resource(uri, {ResourceLoader loader})
+ : super(uri, (loader != null) ? loader : const DefaultLoader());
+}
diff --git a/lib/src/loader.dart b/lib/src/loader.dart
deleted file mode 100644
index b6b4e67..0000000
--- a/lib/src/loader.dart
+++ /dev/null
@@ -1,92 +0,0 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
-// for details. All rights reserved. Use of this source code is governed by a
-// BSD-style license that can be found in the LICENSE file.
-
-import "dart:async" show Future, Stream;
-import "dart:convert" show Encoding;
-import "dart:isolate" show Isolate;
-import "io.dart" as io; // TODO: make this import configuration dependent.
-
-/// Resource loading strategy.
-///
-/// An abstraction of the functionality needed to load resources.
-///
-/// Implementations of this interface decide which URI schemes they support.
-abstract class ResourceLoader {
- /// A resource loader that can load as many of the following URI
- /// schemes as are supported by the platform:
- /// * file
- /// * http
- /// * https
- /// * data
- /// * package
- ///
- /// (For example, file: URIs are not supported in the browser).
- /// Relative URI references are accepted - they are resolved against
- /// [Uri.base] before being loaded.
- static const ResourceLoader defaultLoader = const PackageLoader();
-
- /// Reads the file located by [uri] as a stream of bytes.
- Stream<List<int>> openRead(Uri uri);
-
- /// Reads the file located by [uri] as a list of bytes.
- Future<List<int>> readAsBytes(Uri uri);
-
- /// Reads the file located by [uri] as a [String].
- ///
- /// The file bytes are decoded using [encoding], if provided.
- ///
- /// If [encoding] is omitted, the default for the `file:` scheme is UTF-8.
- /// For `http`, `https` and `data` URIs, the Content-Type header's charset
- /// is used, if available and recognized by [Encoding.getByName],
- /// otherwise it defaults to Latin-1 for `http` and `https`
- /// and to ASCII for `data` URIs.
- Future<String> readAsString(Uri uri, { Encoding encoding });
-}
-
-/// Default implementation of [ResourceLoader].
-///
-/// Uses the system's available loading functionality to implement the
-/// loading functions.
-///
-/// Supports `http:`, `https:`, `file:` and `data:` URIs.
-class DefaultLoader implements ResourceLoader {
- const DefaultLoader();
-
- Stream<List<int>> openRead(Uri uri) => io.readAsStream(uri);
-
- Future<List<int>> readAsBytes(Uri uri) => io.readAsBytes(uri);
-
- Future<String> readAsString(Uri uri, { Encoding encoding }) =>
- io.readAsString(uri, encoding);
-}
-
-
-/// Implementation of [ResourceLoader] that accepts relative and package: URIs.
-///
-/// Like [DefaultLoader] except that it resolves package URIs and relative
-/// URI references as well.
-///
-/// This class may be useful when you don't want to bother creating a [Resource]
-/// object, and just want to load a resource directly.
-class PackageLoader implements ResourceLoader {
- const PackageLoader();
-
- Stream<List<int>> openRead(Uri uri) async* {
- yield* io.readAsStream(await resolveUri(uri));
- }
-
- Future<List<int>> readAsBytes(Uri uri) async =>
- io.readAsBytes(await resolveUri(uri));
-
- Future<String> readAsString(Uri uri, { Encoding encoding }) async =>
- io.readAsString(await resolveUri(uri), encoding);
-}
-
-/// Helper function for resolving to a non-relative, non-package URI.
-Future<Uri> resolveUri(Uri uri) async {
- if (uri.scheme == "package") {
- return Isolate.resolvePackageUri(uri);
- }
- return Uri.base.resolveUri(uri);
-}
diff --git a/lib/src/package_loader.dart b/lib/src/package_loader.dart
new file mode 100644
index 0000000..b834c79
--- /dev/null
+++ b/lib/src/package_loader.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async" show Future, Stream;
+import "dart:convert" show Encoding;
+
+import "resource_loader.dart";
+import "resolve.dart";
+
+/// Implementation of [ResourceLoader] that accepts relative and package: URIs.
+///
+/// Acts like the `loader` it is provided with except that it resolves
+/// package URIs and relative URI references before loading them.
+///
+/// This class may be useful when you don't want to bother creating a resource
+/// object, and just want to load a resource directly.
+class PackageLoader implements ResourceLoader {
+ final ResourceLoader _loader;
+ const PackageLoader(ResourceLoader loader) : _loader = loader;
+
+ Stream<List<int>> openRead(Uri uri) async* {
+ yield* _loader.openRead(await resolveUri(uri));
+ }
+
+ Future<List<int>> readAsBytes(Uri uri) async =>
+ _loader.readAsBytes(await resolveUri(uri));
+
+ Future<String> readAsString(Uri uri, { Encoding encoding }) async =>
+ _loader.readAsString(await resolveUri(uri), encoding: encoding);
+}
diff --git a/lib/src/resolve.dart b/lib/src/resolve.dart
new file mode 100644
index 0000000..7a54520
--- /dev/null
+++ b/lib/src/resolve.dart
@@ -0,0 +1,14 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async" show Future;
+import "dart:isolate" show Isolate;
+
+/// Helper function for resolving to a non-relative, non-package URI.
+Future<Uri> resolveUri(Uri uri) async {
+ if (uri.scheme == "package") {
+ return Isolate.resolvePackageUri(uri);
+ }
+ return Uri.base.resolveUri(uri);
+}
diff --git a/lib/src/resource.dart b/lib/src/resource.dart
index 924ec05..2b19d9e 100644
--- a/lib/src/resource.dart
+++ b/lib/src/resource.dart
@@ -1,87 +1,57 @@
-// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+import "dart:core" hide Resource;
import "dart:async" show Future, Stream;
import "dart:convert" show Encoding;
-import "dart:isolate" show Isolate;
-import "loader.dart";
-/// A resource that can be read into the program.
-///
-/// A resource is data that can be located using a URI and read into
-/// the program at runtime.
-/// The URI may use the `package` scheme to read resources provided
-/// along with package sources.
-abstract class Resource {
- /// Creates a resource object with the given [uri] as location.
- ///
- /// The [uri] must be either a [Uri] or a string containing a valid URI.
- /// If the string is not a valid URI, using any of the functions on
- /// the resource object will fail.
- ///
- /// The URI may be relative, in which case it will be resolved
- /// against [Uri.base] before being used.
- ///
- /// The URI may use the `package` scheme, which is always supported.
- /// Other schemes may also be supported where possible.
- ///
- /// If [loader] is provided, it is used to load absolute non-package URIs.
- /// Package: URIs are resolved to a non-package URI before being loaded, so
- /// the loader doesn't have to support package: URIs, nor does it need to
- /// support relative URI references.
- /// If [loader] is omitted, a default implementation is used which supports
- /// as many of `http`, `https`, `file` and `data` as are available on the
- /// current platform.
- const factory Resource(uri, {ResourceLoader loader}) = _Resource;
+import "resource_loader.dart";
+import "resolve.dart";
- /// The location URI of this resource.
- ///
- /// This is a [Uri] of the `uri` parameter given to the constructor.
- /// If the parameter was a string that did not contain a valid URI,
- /// reading `uri` will fail.
- Uri get uri;
+/// Base resource implementation.
+class Resource {
+ // Default implementation of a generic `Resource` class.
+ //
+ // Actually exposed `Resource` interfaces uses this as implementation,
+ // but expose a different `Resource` class with plaform-dependent statics.
+ // Requires a loader to be provided.
- /// Reads the resource content as a stream of bytes.
- Stream<List<int>> openRead();
-
- /// Reads the resource content as a single list of bytes.
- Future<List<int>> readAsBytes();
-
- /// Reads the resource content as a string.
- ///
- /// The content is decoded into a string using an [Encoding].
- /// If no other encoding is provided, it defaults to UTF-8.
- Future<String> readAsString({Encoding encoding});
-}
-
-class _Resource implements Resource {
/// Loading strategy for the resource.
final ResourceLoader _loader;
/// The URI of the resource.
final _uri;
- const _Resource(uri, {ResourceLoader loader})
- : _uri = uri, _loader = (loader != null) ? loader : const DefaultLoader();
- // TODO: Make this `loader ?? const DefaultLoader()` when ?? is const.
+ const Resource(uri, ResourceLoader loader)
+ : _uri = uri, _loader = loader;
+ /// The location URI of this resource.
+ ///
+ /// This is a [Uri] of the `uri` parameter given to the constructor.
+ /// If the parameter was a string that did not contain a valid URI,
+ /// reading `uri` will fail.
Uri get uri => (_uri is String) ? Uri.parse(_uri) : (_uri as Uri);
+ /// Reads the resource content as a stream of bytes.
Stream<List<int>> openRead() async* {
- Uri uri = await _resolvedUri;
+ Uri uri = await resolveUri(this.uri);
yield* _loader.openRead(uri);
}
+ /// Reads the resource content as a single list of bytes.
Future<List<int>> readAsBytes() async {
- Uri uri = await _resolvedUri;
+ Uri uri = await resolveUri(this.uri);
return _loader.readAsBytes(uri);
}
+ /// Reads the resource content as a string.
+ ///
+ /// The content is decoded into a string using an [Encoding].
+ /// If no encoding is provided, an encoding is chosen depending on the
+ /// protocol and/or available metadata.
Future<String> readAsString({Encoding encoding}) async {
- Uri uri = await _resolvedUri;
+ Uri uri = await resolveUri(this.uri);
return _loader.readAsString(uri, encoding: encoding);
}
-
- Future<Uri> get _resolvedUri => resolveUri(uri);
}
diff --git a/lib/src/resource_loader.dart b/lib/src/resource_loader.dart
new file mode 100644
index 0000000..1a189e1
--- /dev/null
+++ b/lib/src/resource_loader.dart
@@ -0,0 +1,31 @@
+// Copyright (c) 2016, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+import "dart:async" show Future, Stream;
+import "dart:convert" show Encoding;
+
+/// Resource loading strategy.
+///
+/// An abstraction of the functionality needed to load resources.
+///
+/// Implementations of this interface decide which URI schemes they support.
+abstract class ResourceLoader {
+ /// Reads the file located by [uri] as a stream of bytes.
+ Stream<List<int>> openRead(Uri uri);
+
+ /// Reads the file located by [uri] as a list of bytes.
+ Future<List<int>> readAsBytes(Uri uri);
+
+ /// Reads the file located by [uri] as a [String].
+ ///
+ /// The file bytes are decoded using [encoding], if provided.
+ ///
+ /// If [encoding] is omitted, the default for the `file:` scheme is UTF-8.
+ /// For `http`, `https` and `data` URIs, the Content-Type header's charset
+ /// is used, if available and recognized by [Encoding.getByName],
+ /// otherwise it defaults to Latin-1 for `http` and `https`
+ /// and to ASCII for `data` URIs.
+ Future<String> readAsString(Uri uri, {Encoding encoding});
+}
+
diff --git a/pubspec.yaml b/pubspec.yaml
index d4734e4..5b3d5f5 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -1,5 +1,5 @@
name: resource
-version: 1.0.1
+version: 1.1.0
description: Reading resource data from (package and other) files.
author: Dart Team <misc@dartlang.org>
homepage: https://github.com/dart-lang/resource
diff --git a/test/browser_http_test.dart b/test/browser_http_test.dart
new file mode 100644
index 0000000..ecec680
--- /dev/null
+++ b/test/browser_http_test.dart
@@ -0,0 +1,56 @@
+// Copyright (c) 2015, the Dart project authors. Please see the AUTHORS file
+// for details. All rights reserved. Use of this source code is governed by a
+// BSD-style license that can be found in the LICENSE file.
+
+@TestOn("browser")
+
+import "dart:async";
+import "dart:convert";
+
+import "package:resource/browser_resource.dart";
+import "package:test/test.dart";
+
+const content = "Rødgrød med fløde";
+
+main() {
+ // Assume test files located next to Uri.base.
+ // This is how "pub run test" currently works.
+
+ test("Default encoding", () async {
+ var loader = ResourceLoader.defaultLoader;
+ // The HTTPXmlRequest loader defaults to UTF-8 encoding.
+ var uri = Uri.base.resolve("testfile-utf8.txt");
+ String string = await loader.readAsString(uri);
+ expect(string, content);
+ });
+
+ test("Latin-1 encoding", () async {
+ var loader = ResourceLoader.defaultLoader;
+ var uri = Uri.base.resolve("testfile-latin1.txt");
+ String string = await loader.readAsString(uri, encoding: LATIN1);
+ expect(string, content);
+ });
+
+ test("UTF-8 encoding", () async {
+ var loader = ResourceLoader.defaultLoader;
+ var uri = Uri.base.resolve("testfile-utf8.txt");
+ String string = await loader.readAsString(uri, encoding: UTF8);
+ expect(string, content);
+ });
+
+ test("bytes", () async {
+ var loader = ResourceLoader.defaultLoader;
+ var uri = Uri.base.resolve("testfile-latin1.txt");
+ List<int> bytes = await loader.readAsBytes(uri);
+ expect(bytes, content.codeUnits);
+ });
+
+ test("byte stream", () async {
+ var loader = ResourceLoader.defaultLoader;
+ var uri = Uri.base.resolve("testfile-latin1.txt");
+ Stream<List<int>> bytes = loader.openRead(uri);
+ var buffer = [];
+ await bytes.forEach(buffer.addAll);
+ expect(buffer, content.codeUnits);
+ });
+}
diff --git a/test/loader_data_test.dart b/test/loader_data_test.dart
index 8c84f7d..6a575e1 100644
--- a/test/loader_data_test.dart
+++ b/test/loader_data_test.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+@TestOn("vm");
+
import "dart:async";
import "dart:convert";
import "dart:io";
diff --git a/test/loader_file_test.dart b/test/loader_file_test.dart
index aa4c238..8264855 100644
--- a/test/loader_file_test.dart
+++ b/test/loader_file_test.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+@TestOn("vm");
+
import "dart:async";
import "dart:convert";
import "dart:io";
@@ -11,11 +13,11 @@
const content = "Rødgrød med fløde";
-
main() {
var dir;
+ int dirCounter = 0;
setUp(() {
- dir = Directory.systemTemp.createTempSync('testdir');
+ dir = Directory.systemTemp.createTempSync('testdir${dirCounter++}');
});
testFile(Encoding encoding) {
group("${encoding.name}", () {
@@ -25,10 +27,7 @@
var dirUri = dir.uri;
uri = dirUri.resolve("file.txt");
file = new File.fromUri(uri);
- file.createSync();
- var sink = file.openWrite(encoding: encoding);
- sink.write(content);
- sink.close();
+ file.writeAsBytesSync(encoding.encode(content));
});
test("read string", () async {
diff --git a/test/loader_http_test.dart b/test/loader_http_test.dart
index c47fa27..5b61f86 100644
--- a/test/loader_http_test.dart
+++ b/test/loader_http_test.dart
@@ -2,6 +2,8 @@
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.
+@TestOn("vm");
+
import "dart:async";
import "dart:convert";
import "dart:io";
diff --git a/test/testfile-latin1.txt b/test/testfile-latin1.txt
new file mode 100644
index 0000000..64cfd84
--- /dev/null
+++ b/test/testfile-latin1.txt
@@ -0,0 +1 @@
+Rødgrød med fløde
\ No newline at end of file
diff --git a/test/testfile-utf8.txt b/test/testfile-utf8.txt
new file mode 100644
index 0000000..802b46b
--- /dev/null
+++ b/test/testfile-utf8.txt
@@ -0,0 +1 @@
+Rødgrød med fløde
\ No newline at end of file