最近は採用面接にコーディングテストを取り入れている会社も多いようです。ホワイトボードにプログラムを書かせるのですが、その定番とも言われるのがFizzBuzz。本当に書かせる会社があるのかは知らない。
もし何かのタイミングで書けと言われたとき、モジュールをOSSにして公開していたらimport
するだけで試験突破じゃない?ということで作りました。
moromii-fizzbuzz
というモジュールです。名前空間汚さないように適当な名前にしました(というかfizzbuzz
既出だった)。
$ npm i moromii-fizzbuzz
あとはimportして関数を実行するだけ。たった2行でFizzBuzzが書けます。
import fizzbuzz from 'moromii-fizzbuzz';
fizzbuzz(3)
// => 'Fizz'
配列を渡しても変換してくれるので対応できる問題の幅も広く
import fizzbuzz from 'moromii-fizzbuzz';
fizzbuzz([1, 3, 15])
// => ['1', 'Fizz', 'FizzBuzz']
なんとCLIでも実行できます
$ npm i moromii-fizzbuzz -g
$ fizzbuzz 1 3 5
// => ['1', 'Fizz', 'Buzz']
これで採用面接中に突然「FizzBuzzを書け」と言われても10秒で合格です。
FizzBuzzモジュールの作り方
というネタはここまでにして、FizzBuzz関数の中身というより、FizzBuzzをどうnpmモジュールにしたらいいのか、という観点でまとめてみました。
個人的にはコードは公開しているだけだとOSSではなく、使える状態にするのが大事だと思うので、ここらでnpmにpublishする方法を覚えましょう。
リポジトリはこちら
KeitaMoromizato/fizzbuzz
package.json
{
"name": "moromii-fizzbuzz",
"version": "1.0.1",
"description": "fizzbuzz",
"main": "index.js",
"bin": {
"fizzbuzz": "./bin/index.js"
},
"repository": {
"type": "git",
"url": "https://github.com/KeitaMoromizato/fizzbuzz.git"
},
"scripts": {
"build": "tsc index.ts -d",
"pretest": "npm run build",
"test": "mocha --compilers js:babel-register test/**.spec.js",
"prepublish": "npm run build && npm test"
},
"keywords": [
"fizzbuzz"
],
"author": "Keita Moromizato <keita.moromi@gmail.com>",
"license": "MIT",
"devDependencies": {
"babel-core": "^6.22.1",
"babel-preset-es2015": "^6.22.0",
"babel-preset-power-assert": "^1.0.0",
"babel-register": "^6.22.0",
"mocha": "^3.2.0",
"power-assert": "^1.4.2",
"typescript": "^2.1.5"
}
}
npm init
npmモジュールを作るときは、npm init
コマンドから始まります。まずは適当なディレクトリを作ってnpm init
を実行しましょう。
$ mkdir hoge
$ npm init hoge
README.md
OSSにするならREADMEは必須です。とりあえず
- 概要
- 実行方法(簡易ドキュメント)
- テスト方法(コントリビュート方法)
- ライセンス
くらいがあれば必要十分でしょうか。
devDependencies
npmモジュールを作るときにも、もちろん世に公開されているモジュールを活用します。そのときに注意すべきなのがdependencies
とdevDependencies
の違い。npm install
したときに、devDependencies
に書かれたモジュールはインストールされません。
モジュールサイズの増大を防ぐためにも、ビルドやテスト用のモジュールなど開発中にしか使わないものはdevDependencies
に入れておきましょう。
$ npm install mocha --dev
main
require
もしくはimport
でモジュールをインポートしたときのエンドポイントを指定します。index.js
とかapp.js
が主流でしょうか。
repository
これを書いておくとnpmjsで見たときにリポジトリが表示されます。昔ここをミスって別のリポジトリを参照していたら怒られました。
bin
npmモジュールはrequire()
で読み込むだけでなく、install -g
でグローバルインストールすることでCLIとしても使えます。そのためには、bin
スクリプトにコマンド名と、実行するJSファイルを指定します。
パッケージ名をそのままコマンド名としたいときは下のような形でも大丈夫です。
"bin":"./bin/index.js"
ここではパッケージ名はmoromii-fizzbuzz
だけどコマンドとしてはfizzbuzz
としたいので、次のような書き方をしています。
"bin": {
"fizzbuzz": "./bin/index.js"
}
実行されるJSは先頭に#!/usr/bin/env node
と書き、パラメータはprocess.argv
で参照します。
#!/usr/bin/env node
var fizzbuzz = require('../index').default;
var args = process.argv.slice(2);
console.log(fizzbuzz(args));
scripts
開発中に使うコマンドはscriptsにまとめて置きましょう。例えば"build": "tsc index.ts -d"
と書いてあるのであれば、npm run build
と実行すると該当のコマンドが呼ばれます。
build
ビルドスクリプトはbuild
に書くのが一般的です。ここでは、コードをTypeScriptで書いているので、TypeScript=>JavaScriptにコンパイルする設定を記述しています(TypeScriptで書いたものをpublishしても使えないので)。
ちなみに、.gitignore
ではコンパイル時に生成されるJavaScriptファイルは除き(TSファイルから生成されるのでgitで管理する必要がない)、.npmignore
ではコンパイル用のTypeScriptファイルを除きます(実行するのはJSなのでTSファイルは必要ない)。
./index.ts
test
テストコードはtest
に書いておくと、Circle CIのようなCIツールが勝手に読んでくれるので楽です。
pretest
pre
が付いたスクリプトは、該当のスクリプト(ここではtest
)の実行前に自動的に呼ばれます。ここでは、テスト対象がテスト実行前に必ず最新にビルドされるようにしています。
prepublish
npmモジュールを公開するときはnpm publish
を実行するのですが、その前に呼ばれるスクリプトです。ビルド&テストを実行して、エラーが出なければpublishされます。
(おまけ)Typescriptフレンドリー
モジュールにTypeScriptの型定義ファイルを含めておくと、それをrequire/import
しただけで型定義ファイルも読みにいってくれます。これをTypeScriptフレンドリーと言ったりします。界隈の人たちに喜ばれるので、できるだけ対応しましょう。
コードをTypeScriptで書いていれば、コンパイル時に-d
オプションを付けるだけで自動的にd.ts
ファイルも生成されます。
"build": "tsc index.ts -d"
まとめ
という訳でnpmの作り方サンプルでした。FizzBuzzくらいの簡単なモジュールをnpmモジュール化してみるのは、ハードルも低くて練習には良いなと。