「Effective Deno」を読みながら、Denoを触ってみる
2021/05/17
ZennにDenoのめちゃくちゃ良さげなテキスト(Effective Deno)が公開されていたので、それを読みながらDenoを触ってみた
いい感じのテーマが思い浮かばなかったのでFizzBuzz問題を実装することにした
「1から100までの数字を画面に表示する。ただし、3の倍数のときは数字の代わりにFizzと表示し、5の倍数のときは数字の代わりにBuzzと表示し、15の倍数のときは数 字の代わりにFizzBuzzと表示する」
Denoの環境
前に書いた記事(DenoでHello, World!)同様、Dockerで用意する
.bashrcに記述して、使える状態にした
Denoのバージョンは触った時点で最新の1.9.2を使った
deno () {
docker run \
--interactive \
--tty \
--rm \
--volume $PWD:/app \
--volume $HOME/.deno:/deno-dir \
--workdir /app \
hayd/ubuntu-deno:1.9.2 \
deno "$@"
}
$ deno --version
deno 1.9.2 (release, x86_64-unknown-linux-gnu)
v8 9.1.269.5
typescript 4.2.2
実装
仮のfizzbuzz関数の実装
まずはfizzbuzz関数のガワだけを作る
受け取った引数の値を文字列にして返す
export function fizzbuzz(number: number): string {
return String(number);
}
本来、Fizz
,Buzz
,FizzBuzz
はString型で、数値はNumber型で返してあげた方がいい気がするけど、今回はすべてString型で返すことにする
テストの実装
fizzbuzz関数のガワだけできたので、先にテストを書く
import { assertEquals } from 'https://deno.land/[email protected]/testing/asserts.ts';
import { fizzbuzz } from './fizzbuzz.ts';
Deno.test('fizzbuzz(1)', () => {
assertEquals(fizzbuzz(1), '1');
});
Deno.test('fizzbuzz(3)', () => {
assertEquals(fizzbuzz(3), 'Fizz');
});
Deno.test('fizzbuzz(5)', () => {
assertEquals(fizzbuzz(5), 'Buzz');
});
Deno.test('fizzbuzz(15)', () => {
assertEquals(fizzbuzz(15), 'FizzBuzz');
});
テストの実行
deno test
で実行できる
もちろんString型にして返すだけなので、1の場合しかテストは通らない
$ deno test
running 4 tests
test fizzbuzz(1) ... ok (4ms)
test fizzbuzz(3) ... FAILED (4ms)
test fizzbuzz(5) ... FAILED (2ms)
test fizzbuzz(15) ... FAILED (1ms)
failures:
fizzbuzz(3)
AssertionError: Values are not equal:
[Diff] Actual / Expected
- "3"
+ "Fizz"
at assertEquals (https://deno.land/[email protected]/testing/asserts.ts:222:9)
at file:///app/fizzbuzz_test.ts:9:3
at asyncOpSanitizer (deno:runtime/js/40_testing.js:37:15)
at resourceSanitizer (deno:runtime/js/40_testing.js:73:13)
at Object.exitSanitizer [as fn] (deno:runtime/js/40_testing.js:100:15)
at TestRunner.[Symbol.asyncIterator] (deno:runtime/js/40_testing.js:272:24)
at AsyncGenerator.next (<anonymous>)
at Object.runTests (deno:runtime/js/40_testing.js:347:22)
at async file:///app/$deno$test.ts:3:1
fizzbuzz(5)
AssertionError: Values are not equal:
[Diff] Actual / Expected
- "5"
+ "Buzz"
at assertEquals (https://deno.land/[email protected]/testing/asserts.ts:222:9)
at file:///app/fizzbuzz_test.ts:13:3
at asyncOpSanitizer (deno:runtime/js/40_testing.js:37:15)
at resourceSanitizer (deno:runtime/js/40_testing.js:73:13)
at Object.exitSanitizer [as fn] (deno:runtime/js/40_testing.js:100:15)
at TestRunner.[Symbol.asyncIterator] (deno:runtime/js/40_testing.js:272:24)
at AsyncGenerator.next (<anonymous>)
at Object.runTests (deno:runtime/js/40_testing.js:347:22)
at async file:///app/$deno$test.ts:3:1
fizzbuzz(15)
AssertionError: Values are not equal:
[Diff] Actual / Expected
- "15"
+ "FizzBuzz"
at assertEquals (https://deno.land/[email protected]/testing/asserts.ts:222:9)
at file:///app/fizzbuzz_test.ts:17:3
at asyncOpSanitizer (deno:runtime/js/40_testing.js:37:15)
at resourceSanitizer (deno:runtime/js/40_testing.js:73:13)
at Object.exitSanitizer [as fn] (deno:runtime/js/40_testing.js:100:15)
at TestRunner.[Symbol.asyncIterator] (deno:runtime/js/40_testing.js:272:24)
at AsyncGenerator.next (<anonymous>)
at Object.runTests (deno:runtime/js/40_testing.js:347:22)
at async file:///app/$deno$test.ts:3:1
failures:
fizzbuzz(3)
fizzbuzz(5)
fizzbuzz(15)
test result: FAILED. 1 passed; 3 failed; 0 ignored; 0 measured; 0 filtered out (11ms)
正しく動くfizzbuzz関数に書き換える
テストが書けたので、fizzbuzz関数の中身を実装する
export function fizzbuzz(number: number): string {
if (number % 15 == 0)
return 'FizzBuzz';
else if (number % 3 == 0)
return 'Fizz';
else if (number % 5 == 0)
return 'Buzz';
else
return String(number);
}
$ deno test
Check file:///app/$deno$test.ts
running 4 tests
test fizzbuzz(1) ... ok (4ms)
test fizzbuzz(3) ... ok (1ms)
test fizzbuzz(5) ... ok (1ms)
test fizzbuzz(15) ... ok (1ms)
test result: ok. 4 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out (8ms)
テストが無事通った
メインのコードを書く
fizzbuzz関数が無事完成したので、「1から100までの数字を画面に表示する。ただし、3の倍数のときは数字の代わりにFizzと表示し、5の倍数のときは数字の代わりにBuzzと表示し、15の倍数のときは数字の代わりにFizzBuzzと表示する」コードを書く
import { fizzbuzz } from './fizzbuzz.ts';
for (let i = 1; i <= 100; i++) {
console.log(fizzbuzz(i));
}
$ deno run app.ts
Check file:///app/app.ts
1
2
Fizz
4
Buzz
Fizz
7
8
Fizz
Buzz
11
Fizz
13
14
FizzBuzz
... 省略 ...
86
Fizz
88
89
FizzBuzz
91
92
Fizz
94
Buzz
Fizz
97
98
Fizz
Buzz
無事完成
フォーマッタを掛ける
特にコーディングルールを読まずに普段のRubyを書くように書いただけなので、フォーマッタを掛ける
deno fmt
でフォーマットしてくれる
$ deno fmt
/app/app.ts
/app/fizzbuzz.ts
/app/fizzbuzz_test.ts
Checked 4 files
そこそこ修正された
# fizzbuzz.ts
export function fizzbuzz(number: number): string {
- if (number % 15 == 0)
- return 'FizzBuzz';
- else if (number % 3 == 0)
- return 'Fizz';
- else if (number % 5 == 0)
- return 'Buzz';
- else
+ if (number % 15 == 0) {
+ return "FizzBuzz";
+ } else if (number % 3 == 0) {
+ return "Fizz";
+ } else if (number % 5 == 0) {
+ return "Buzz";
+ } else {
return String(number);
+ }
}
# fizzbuzz_test.ts
-import { assertEquals } from 'https://deno.land/[email protected]/testing/asserts.ts';
-import { fizzbuzz } from './fizzbuzz.ts';
+import { assertEquals } from "https://deno.land/[email protected]/testing/asserts.ts";
+import { fizzbuzz } from "./fizzbuzz.ts";
-Deno.test('fizzbuzz(1)', () => {
- assertEquals(fizzbuzz(1), '1');
+Deno.test("fizzbuzz(1)", () => {
+ assertEquals(fizzbuzz(1), "1");
});
-Deno.test('fizzbuzz(3)', () => {
- assertEquals(fizzbuzz(3), 'Fizz');
+Deno.test("fizzbuzz(3)", () => {
+ assertEquals(fizzbuzz(3), "Fizz");
});
-Deno.test('fizzbuzz(5)', () => {
- assertEquals(fizzbuzz(5), 'Buzz');
+Deno.test("fizzbuzz(5)", () => {
+ assertEquals(fizzbuzz(5), "Buzz");
});
-Deno.test('fizzbuzz(15)', () => {
- assertEquals(fizzbuzz(15), 'FizzBuzz');
+Deno.test("fizzbuzz(15)", () => {
+ assertEquals(fizzbuzz(15), "FizzBuzz");
});
# app.ts
-import { fizzbuzz } from './fizzbuzz.ts';
+import { fizzbuzz } from "./fizzbuzz.ts";
for (let i = 1; i <= 100; i++) {
console.log(fizzbuzz(i));
}
CIを用意する
GitHub Actionsでテストやリンタが自動で実行されるようにセットアップする
name: ci
on: [push, pull_request]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@master
- uses: denoland/setup-deno@main
with:
deno-version: "1.9.2"
- name: Run fmt
run: |
deno fmt --check
- name: Run lint
run: |
deno lint --unstable
- name: Run tests
run: |
deno test -A
ちゃんと動いた良き
first commit · ytkg/deno_fizzbuzz@d2e6104
リポジトリ
今回やった内容をGitHubにあげた