[Deno事始め] Denoでコマンドラインから動く対話型アプリケーションを作成する


2020/10/30

Denoは2020年5月にリリース版が出たばかりの新しいjavascript/typescriptのランタイムです。

node.jsの開発者であるRyan Dahl氏がnode.jsでの反省点を踏まえた形で開発が進められているため、改良版型Nodeと言っても過言では無く今後も注目が集まりそうです。

さて今回はDenoの標準ライブラリを利用して、コマンドラインから対話型アプリを作ってみようと思います。


準備編

インストール方法はここで説明されている通りで非常に簡単です。

各種の主要なOSのインストールの仕方が載っています。

この記事の中ではLinux系の方法でインストールを試します。

とはいってもcurlでインストール用のスクリプトを実行しているだけです。

            
            $ curl -fsSL https://deno.land/x/install/install.sh | sh
$ deno --version
deno 1.4.6
v8 8.7.220.3
typescript 4.0.3
        
導入はとっても簡単です。

以下でdenoのhello world的なことも行えます。

            
            $ deno run https://deno.land/std/examples/welcome.ts
Download https://deno.land/std/examples/welcome.ts
Warning Implicitly using latest version (0.75.0) for https://deno.land/std/examples/welcome.ts
Download https://deno.land/std@0.75.0/examples/welcome.ts
Check https://deno.land/std@0.75.0/examples/welcome.ts
Welcome to Deno 🦕
        
denoの特徴として、一度リモートレジストリから取り込んだリソースは環境変数DENO_DIRで指定しているパスにキャッシュとして取り込まれるため、2回目以降の実行の際にはダウンロードがスキップされます。

            
            $ deno run https://deno.land/std/examples/welcome.ts
Welcome to Deno 🦕
        

コードの実装

それではdenoでコマンドライン上で動く簡単な対話型アプリケーションを作成してみます。

もっとも単純な対話型のプログラムとして、stdinから何か文字をインプットして、エンターキー後にその入力を出力させるだけのプログラムは以下のようになります。

これを
main.tsとしてプロジェクトのルートに保存します。

            
            import { readLines } from "https://deno.land/std/io/mod.ts";

async function main() {
    for await (const line of readLines(Deno.stdin)) {
        console.log(">", line);
        if (/quit/.test(line)) {
            console.log("Bye!");
            return true;
        }
    }
}

console.log("Type 'quit' when you want to close the app.");
console.log("Reading line from stdin:");
await main();
        
ではこれを実行してみます。

            
            $ deno run main.ts
Type 'quit' when you want to close the app.
Reading line from stdin:
hoge #👈hogeを入力
> hoge
fuga #👈fugaを入力
> fuga
piyo #👈piyoを入力
> piyo
quit #👈quitを入力
> quit
Bye!
        
上のように、deno run <ソースコード>で実行できます。

また
quitを入力したらプログラムが止まるようにしています。

これは
for awaitのループの中身で何か値をreturnすることでループ処理が完了することを利用しています。

denoのプログラミングでは、
for await ~ of構文に出くわすことがあります。

この構文を使うとasync/awaitの並列化の設計思想と違っていて、並列処理の恩恵があまり無くなってしまうのでESLintで警告扱いになっていますが、denoでは割と開放的に利用されいます。

また同期処理のループでは
Promise.all()を用いたリファクタリングが推奨されています。

Lint原理主義的な開発を行いたい場合にはそちらコーディングを検討されてもよいと思います。


質問内容をjsonで抽出する

対話型で良くある質問事項をjson形式で取りまとめるプログラムを作ります。

denoのスタンダードライブラリから独自に実装しても良いのですが、まずは
サードパーティのモジュール置き場に誰か有志の方が公開されていないかチェックしてみるのが良いと思います。

まだまだnpmと違い公開されているパッケージも少ないものの、現時点でコマンドラインから入力した内容をjson形式で出力してくれそうなのは、
deno-promptaskなどを使うのが良さそうです。

ここでは
deno-promptを使って、質問内容からjsonを抽出してみます。

main.tsの内容を以下に書き換えてみます。

            
            import Prompt from "https://deno.land/x/prompt/mod.ts";
import PromptError from "https://deno.land/x/prompt/src/errors/PromptError.ts";

const answers = await Prompt.prompts([
    { type: "text", name: "name", message: "Please input your name" },
    {
        type: "text",
        name: "sex",
        message: "Please input your sex(male or female)",
        validate(result: string) {
            if (!["male", "female"].includes(result)) {
                throw new PromptError("input must be [male] or [female]");
            }
        },
    },
    { type: "number", name: "birthYear", min: 1900 },
    { type: "number", name: "age", min: 1, max: 100 },
    { type: "confirm", name: "agree", defaultValue: true },
]);
console.log(answers);
        
これを実行してみます。

            
            $ deno run main.ts
? Please input your name: Hoge Piyo
? Please input your sex(male or female): male
? BirthYear (>=1900): 1999
? Age (1-100): 21
? Agree (Y/n): true
{ name: "Hoge Piyo", sex: "male", birthYear: 1999, age: 21, agree: true }
        
質問内容からjsonが狙い通り抽出出来ているようです。


まとめ

denoを使ったjs/tsプログラミングは、node.jsの時代から比べると様々なプロセスが簡素化されています。

あまりに簡素化されているためnode.jsからdenoに移行を検討している方にとっては、
package.jsonnode_modulesで辛酸を嘗めたときの経験があるほど、「こんなに旨い話はあるのか」と疑ってかかりそうなくらい色んなことが楽になっています。

ただ、まだまだライブラリやユーティリティの厚みが本家node.jsよりも薄いので、複雑な機能を実現しようとすると物足りなさを感じます。

暫くはnode.jsが取って代わられることも無い気がします。

今後、波が来るときに備え今のうちにdenoを勉強しておくと良い気がします。


参考サイト

Deno(ディーノ)を使ってみよう!【Node.jsの時代は終わる?】

Denoとはなにか - 実際につかってみる

記事を書いた人

記事の担当:taconocat

ナンデモ系エンジニア

主にAngularでフロントエンド開発することが多いです。 開発環境はLinuxメインで進めているので、シェルコマンドも多用しております。 コツコツとプログラミングするのが好きな人間です。