Chapter 06

deno_stdを使ってみよう

uki00a
uki00a
2021.08.22に更新

deno_stdとは?

deno_stdとは、Denoのコアチームによって開発・メンテナンスされているDenoの標準ライブラリです。

Goの標準パッケージに影響を受けており、パスの操作やテストなどに関する様々な機能を提供しています。

この章では、deno_stdの中から比較的使用頻度の高いと思われる以下のモジュールについて解説します。

この章では、説明のため、バージョンを指定せずにdeno_stdをimportしています。

import { join } from "https://deno.land/std/path/mod.ts";

ただし、このようにバージョンを指定せずに外部モジュールをimportすることは理想的ではありません。[1]

以下のように、しっかりバージョンを指定しましょう。

import { join } from "https://deno.land/std@0.95.0/path/mod.ts";

std/path

このモジュールはファイルパスを操作するための機能を提供します。

Node.jsにおけるpathパッケージに相当します。

mod.tsposix.tsについて

ファイルパスのスタイルはOSごとに異なります。

例えば、Windowsではパスの区切り文字として\を使用しますが、Unix系だと/です。

このような違いを考慮して、mod.tsは、使用しているOSに応じて振る舞いを提供します。

Winodows環境においてもUnix環境と同様の振る舞いを期待する場合は、mod.tsの代わりにposix.tsをimportするか、posix名前空間で提供されている関数を利用するとよいでしょう。

import { posix } from "https://deno.land/std/path/mod.ts";
posix.join("dist", "index.html"); // => "dist/index.html"

join

与えられたパスを連結します。

import { join } from "https://deno.land/std/path/mod.ts";
join("dist", "index.html"); // => "dist/index.html"

extname

ファイルの拡張子を返却します。

import { extname } from "https://deno.land/std/path/mod.ts";
extname("public/index.html"); // => ".html"

basename

与えられたパスのファイル名を返却します。

import { basename } from "https://deno.land/std/path/mod.ts";
basename("src/protocol/mod.ts"); // => "mod.ts"

dirname

与えられたパスのディレクトリ名を返却します。

import { dirname } from "https://deno.land/std/path/mod.ts";
dirname("src/protocol/mod.ts"); // => "src/protocol"

isAbsolute

与えられたパスが絶対パス形式であればtrue、そうでなければfalseを返却します。

import { isAbsolute } from "https://deno.land/std/path/mod.ts";
isAbsolute("/path/to/file.txt"); // => true
isAbsolute("file.txt"); // => false

parse

与えられたパスを解析し、オブジェクトの形式で返却します。

import { parse } from "https://deno.land/std/path/mod.ts";
parse("/path/to/file.txt"); // => { root: "/", dir: "/path/to", base: "file.txt", ext: ".txt", name: "file" }

resolve

与えられたパスを絶対パス形式に変換します。

import { resolve } from "https://deno.land/std/path/mod.ts";

resolve("public/index.html"); // => "/home/uki00a/work/public/index.html"

std/fs

このモジュールはファイルシステムに関する機能を提供します。

Node.jsにおけるfsパッケージに相当します。

使い方

fs/mod.tsで全ての関数をまとめてimportできます。

import { ensureDir, exists } from "https://deno.land/std/fs/mod.ts";

また、個別の機能ごとにimportすることもできます。

import { exists } from "https://deno.land/std/fs/exists.ts";
import { ensureDir } from "https://deno.land/std/fs/ensure_dir.ts";

exists

指定されたファイルが存在すればtrue、そうでなければfalseに解決されます。

import { exists } from "https://deno.land/std/fs/exists.ts";
await exists("./sample.txt"); // => `true` or `false`

ensureDir

mkdir -pコマンドに相当します。

import { ensureDir } from "https://deno.land/std/fs/ensure_dir.ts";
await ensureDir("./path/to/dir");

emptyDir

指定されたディレクトリを空にします。

もし指定されたディレクトリが存在しなければ、作成されます。

import { emptyDir } from "https://deno.land/std/fs/empty_dir.ts";
await emptyDir("./path/to/dir");

move

ファイルの移動を行います。

例えば、次のコードは./sample.txt./subdirディレクトリへ移動します。

import { move } from "https://deno.land/std/fs/move.ts";
await move("./sample.txt", "./subdir/sample.txt");

移動元と移動先が同じディレクトリであれば、ファイルがリネームされます。 例えば、以下のコードは./src.txt./dest.txtへリネームします。

await move("./src.txt", "./dest.txt");

moveは宛先のファイルがすでに存在する場合は、例外を投げます。 宛先のファイルを上書きしたいときは、overwrite: trueを指定します。

await move("./src.txt", "./dest.txt", { overwrite: true });

walk

指定されたディレクトリの内容を再帰的に走査します。

import { walk } from "https://deno.land/std/fs/walk.ts";

for await (const entry of walk("./books")) {
  console.log(entry.name);
}

expandGlob

指定したglobパターンにマッチするファイルを走査します。

import { expandGlob } from "https://deno.land/std/fs/expand_glob.ts";

for await (const entry of expandGlob("./books/**/*.md")) {
  console.log(entry.name);
}

std/io

IOに関わる機能を提供するモジュールです。

std/io/util

Deno.ReaderDeno.Writerに関するユーティリティを提供します。

readAll

EOFを受信するまで、指定されたDeno.Readerオブジェクトから全ての内容を読み取ります。

import { readAll } from "https://deno.land/std/io/util.ts";

const decoder = new TextDecoder();
const deno = Deno.run({
  cmd: [Deno.execPath(), "--version"],
  stdout: "piped",
});
const output = await readAll(deno.stdout);
deno.stdout.close();
deno.close();
console.log(decoder.decode(output));
/*
 * deno 1.9.2 (release, x86_64-unknown-linux-gnu)
 * v8 9.1.269.5
 * typescript 4.2.2
 */

writeAll

指定された全てのデータをDeno.Writerオブジェクトへ書き込みます。

import { writeAll } from "https://deno.land/std/io/util.ts";
const encoder = new TextEncoder();
await writeAll(Deno.stdout, encoder.encode("Hello, Deno!"));

iter

Deno.ReaderAsyncIterableIteratorに変換します。

import { iter } from "https://deno.land/std/io/util.ts";
import { StringReader } from "https://deno.land/std/io/readers.ts";

const decoder = new TextDecoder();
const r = new StringReader("Hello, Deno!");
const it = iter(r, { bufSize: 1 });
const results = [];
for await (const x of it) {
  results.push(decoder.decode(x));
}
console.log(results);
/* => ["H", "e", "l", "l", "o", ",", " ", "D", "e", "n", "o", "!"] */

std/io/buffer

Bufferクラスを提供します。

Buffer

可変長のバッファを提供します。(Node.jsのBufferクラスとは異なるものです)

Deno.ReaderDeno.Writerの両方を実装しています。

GoのBuffer型がベースになっています。

import { readAllSync, writeAllSync } from "https://deno.land/std/io/util.ts";
import { Buffer } from "https://deno.land/std/io/buffer.ts";
const decoder = new TextDecoder();
const encoder = new TextEncoder();
const buffer = new Buffer();
writeAllSync(buffer, encoder.encode("Hello, "));
writeAllSync(buffer, encoder.encode("World!"));
decoder.decode(readAllSync(buffer)); // => "Hello, World!"

std/io/bufio.ts

Deno.ReaderDeno.Writerにバッファリングを実装するため、BufReaderBufWriterなどが提供されています。

BufReader

Deno.Readerをラップし、バッファリング機能を提供します。

import { BufReader } from "https://deno.land/std/io/bufio.ts";

const decoder = new TextDecoder();
const buf = BufReader.create(Deno.stdin);
const result = await buf.readLine();
if (result !== null) {
  console.log(decoder.decode(result.line));
}

BufWriter

Deno.Writerをラップし、バッファリング機能を提供します。

import { BufWriter } from "https://deno.land/std/io/bufio.ts";

const encoder = new TextEncoder();
const file = await Deno.open("sample.txt", { write: true, create: true });
try {
  const buf = BufWriter.create(file);
  await buf.write(encoder.encode("Hello, Deno!\n"));
  await buf.write(encoder.encode("Hello, World!\n"));
  await buf.flush();
} finally {
  file.close();
}
console.log(await Deno.readTextFile("sample.txt"));
/*
 * Hello, Deno!
 * Hello, World!
 *
 */

std/io/readers

Deno.Readerを実装したオブジェクトを提供します。

StringReader

Deno.Readerに依存したコードのユニットテストを書く際に便利です。

import { readAll } from "https://deno.land/std/io/util.ts";
import { StringReader } from "https://deno.land/std/io/readers.ts";

const r = new StringReader("Hello, Deno!");
const decoder = new TextDecoder();
decoder.decode(await readAll(r)); // => "Hello, Deno!"

std/io/writers

Deno.Writerを実装したオブジェクトを提供します。

StringWriter

toStringメソッドを呼ぶと、書き込まれた文字列を取得できます。

Deno.Writerに依存したコードのユニットテストを書く際に便利です。

import { writeAll } from "https://deno.land/std/io/util.ts";
import { StringWriter } from "https://deno.land/std/io/writers.ts";

const encoder = new TextEncoder();
const w = new StringWriter();
await writeAll(w, encoder.encode("Hello, Deno!"));
w.toString(); // => "Hello, Deno!"

std/testing

このモジュールでは、テストを記述する際に必要となる機能が提供されています。

std/testing/asserts

このモジュールは、主にテストで使用するための様々なアサーション関数を提供します。

assert(expr, msg = "")

exprfalseに評価された場合、例外を投げます。

import { assert } from "https://deno.land/std/testing/asserts.ts";
assert(true); // => OK
assert(false); // => NG

assertEquals(actual, expected, msg = "")

actualexpectedの深い比較を行い、それらが一致しなければ例外を投げます。

import { assertEquals } from "https://deno.land/std/testing/asserts.ts";
assertEquals(1, 1); // => OK
assertEquals([1, { foo: "bar" }], [1, { foo: "bar" }]); // => OK
assertEquals(1, 2); // => NG
assertEquals({ bar: "foo" }, { foo: "bar" }); // => NG

assertNotEquals(actual, expected, msg = "")

actualexpectedの深い比較を行い、それらが一致したら例外を投げます。

import { assertNotEquals } from "https://deno.land/std/testing/asserts.ts";
assertNotEquals(1, 2); // => OK
assertNotEquals({ bar: "foo" }, { foo: "bar" }); // => OK
assertNotEquals(1, 1); // => NG
assertNotEquals([1, { foo: "bar" }], [1, { foo: "bar" }]); // => NG

assertStrictEquals(actual, expected, msg = "")

actual === expectedfalseに評価された場合、例外を投げます。

import { assertStrictEquals } from "https://deno.land/std/testing/asserts.ts";
const obj = { foo: "bar" };
assertStrictEquals(1, 1); // => OK
assertStrictEquals(obj, obj); // => OK
assertStrictEquals([1, { foo: "bar" }], [1, { foo: "bar" }]); // => NG
assertStrictEquals(1, 2); // => NG
assertStrictEquals({ bar: "foo" }, { foo: "bar" }); // => NG

assertNotStrictEquals(actual, expected, msg = "")

actual !== expectedfalseに評価された場合、例外を投げます。

import { assertNotStrictEquals } from "https://deno.land/std/testing/asserts.ts";
const obj = { foo: "bar" };
assertNotStrictEquals([1, { foo: "bar" }], [1, { foo: "bar" }]); // => OK
assertNotStrictEquals(1, 2); // => OK
assertNotStrictEquals({ bar: "foo" }, { foo: "bar" }); // => OK
assertNotStrictEquals(1, 1); // => NG
assertNotStrictEquals(obj, obj); // => NG

assertExists(actual, msg = "")

actualnullまたはundefinedであれば、例外を投げます。

import { assertExists } from "https://deno.land/std/testing/asserts.ts";
assertExists(0); // => OK
assertExists(""); // => OK
assertExists(false); // => OK
assertExists(null); // => NG
assertExists(undefined); // => NG

assertStringIncludes(actual, expected, msg = "")

actualexpectedを部分文字列として含まない場合、例外を投げます。

import { assertStringIncludes } from "https://deno.land/std/testing/asserts.ts";
assertStringIncludes("foobar", "bar"); // => OK
assertStringIncludes("foobar", "baz"); // => NG

assertArrayIncludes(actual, expected, msg = "")

actualexpectedの全ての要素を含まない場合、例外を投げます。

import { assertArrayIncludes } from "https://deno.land/std/testing/asserts.ts";
assertArrayIncludes([1, 2, 3], [1, 2]); // => OK
assertArrayIncludes([1, 2, 3], [3, 4]); // => NG

assertMatch(actual, expected, msg = "")

actualexpectedで指定された正規表現にマッチしなければ、例外を投げます。

import { assertMatch } from "https://deno.land/std/testing/asserts.ts";
assertMatch("foobar", /bar$/); // => OK
assertMatch("foobar", /baz$/); // => NG

assertNotMatch(actual, expected, msg = "")

actualexpectedで指定された正規表現にマッチする場合、例外を投げます。

import { assertNotMatch } from "https://deno.land/std/testing/asserts.ts";
assertNotMatch("foobar", /baz$/); // => OK
assertNotMatch("foobar", /bar$/); // => NG

assertObjectMatch(actual, expected, msg = "")

expectedactualのサブセットでなければ、例外を投げます。

import { assertObjectMatch } from "https://deno.land/std/testing/asserts.ts";

assertObjectMatch({ foo: "bar" }, { foo: "bar" }); // => OK
assertObjectMatch(
  { a: 1, foo: "bar" },
  { foo: "bar" },
); // => OK
assertObjectMatch({ obj: { a: 1, b: 2 } }, { obj: { b: 2 } }); // => OK
assertObjectMatch({ a: 1 }, { b: 2 }); // => NG
assertObjectMatch({ obj: { a: 1, b: 2 } }, { obj: { b: 2, c: 3 } }); // => NG

assertThrows(fn, errorClass = undefined, msgIncludes = "", msg = "")

fnerrorClassで指定された例外を投げなければ、例外を投げます。

import {
  assertEquals,
  AssertionError,
  assertThrows,
} from "https://deno.land/std/testing/asserts.ts";

assertThrows(() => assertEquals(1, 2)); // => OK
assertThrows(() => assertEquals(1, 2), AssertionError); // => OK
assertThrows(() => assertEquals(1, 2), AssertionError, "Values are not equal"); // => OK

assertThrows(() => assertEquals(1, 2), TypeError); // => NG
assertThrows(() => assertEquals(1, 2), AssertionError, "hoge"); // => NG

assertRejects(fn, errorClass = undefined, msgIncludes = "", msg = "")

fnerrorClassで指定された例外でrejectされたPromiseを返却しなければ、例外を投げます。

import {
  assertEquals,
  AssertionError,
  assertRejects,
} from "https://deno.land/std/testing/asserts.ts";

await assertRejects(async () => assertEquals(1, 2)); // => OK
await assertRejects(async () => assertEquals(1, 2), AssertionError); // => OK
await assertRejects(
  async () => assertEquals(1, 2),
  AssertionError,
  "Values are not equal",
); // => OK

await assertRejects(async () => assertEquals(1, 2), TypeError); // => NG
await assertRejects(async () => assertEquals(1, 2), AssertionError, "hoge"); // => NG

std/testing/bench

ベンチマークを計測するための機能を提供します。

使い方

benchでベンチマーク関数を定義し、runBenchmarksによってそれらを実行します。

bench.ts
import {
  bench,
  runBenchmarks,
} from "https://deno.land/std/testing/bench.ts";
import { connect } from "https://deno.land/x/redis@v0.22.0/mod.ts";

const redis = await connect({ hostname: "localhost" });

bench({
  name: "ping",
  runs: 10_000, // 10,000回実行し、平均実行時間を計測
  async func(b) {
    b.start();
    await redis.ping("PING");
    b.stop();
  },
});

await runBenchmarks();

このコードを実行すると、ベンチマークが実行され、以下のように計測結果が表示されます。

$ deno run --allow-net bench.ts
running 1 benchmark ...
benchmark ping ...
    10000 runs avg: 0.069ms
benchmark result: DONE. 1 measured; 0 filtered

deno_stdの使い方を調べる

この章で紹介した以外にも、deno_stdには様々なモジュールや機能が提供されています。

deno_stdの各モジュールの使い方は、以下の方法で調べられます。

各モジュールのREADME.mdを参照する

deno_stdの各モジュールには、README.mdファイルが提供されています。

例えば、std/fsモジュールのREADME.mdは以下のURLから閲覧できます。

doc.deno.landからAPIドキュメントを閲覧する

doc.deno.landというWebサイトが存在します。

ここでは、deno_stdに限らず、Web上で公開されている様々なモジュールのAPIドキュメントを閲覧することができます。

例えば、以下のURLをブラウザで開くと、deno_std v0.95.0のpath/mod.tsのAPIドキュメントを閲覧できます。

ポイント

  • Denoにはdeno_stdという標準ライブラリが存在します。
  • deno_stdの使い方を知りたいときは、README.mdやdoc.deno.landから調べられます。
脚注
  1. 理由については依存モジュールのバージョンを明示しようを参照ください。 ↩︎