AsciiDocでbackendがHTMLかどうかを判定する

AsciiDocではHTMLも直接埋め込む事が出来ます。

++++
<iframe src="http://ghbtns.com/github-btn.html?user=azu&repo=promises-book&type=fork&count=true&size=large"
  allowtransparency="true" frameborder="0" scrolling="0" width="120" height="30"></iframe>
<iframe src="http://ghbtns.com/github-btn.html?user=azu&repo=promises-book&type=watch&count=true&size=large"
  allowtransparency="true" frameborder="0" scrolling="0" width="170" height="30"></iframe>
++++

しかし、このHTMLの埋め込みはbackend(出力形式)がHTML以外の時にあると逆に困ってしまいます。
(PDFとかの場合パースエラーの原因になったりする)

そのため、backendに何が指定されたかを判定して埋め込む必要があります。

AsciidocにはSystem Macrosというものでif分岐が出来ます。

定義されてるかどうかの判定をするifdef

ifdef::<attribute>[]
trueの時
endif::</attribute><attribute>[]

変数の比較をして判定するifevalがあります。

rs458が2かどうか

ifeval::[{rs458}==2]
:
endif::[]

本題に戻ってifevalを使って--backendで指定されたものを判定すれば、
htmlに出力してるかがわかります。

ifeval::["{backend}" == "html5"]
++++
<a href="https://github.com/azu/promises-book/" style="position: fixed; top: 0; right: 0;border: 0;"><img style="border: 0;" src="https://camo.githubusercontent.com/38ef81f8aca64bb9a64448d0d70f1308ef5341ab/68747470733a2f2f73332e616d617a6f6e6177732e636f6d2f6769746875622f726962626f6e732f666f726b6d655f72696768745f6461726b626c75655f3132313632312e706e67" alt="Fork me on GitHub" data-canonical-src="https://s3.amazonaws.com/github/ribbons/forkme_right_darkblue_121621.png" /></a>
++++
endif::[]

という感じで書いておけば、$ asciidoctor -b html5 index.adocでビルドした時だけ埋め込むことが出来ます。

最近気になったJavaScript AST周りの動き

最近、気になったJavaScript AST関係のものについてのメモです。

JavaScript ASTについては以下などを見て下さい。

esnext

元々ES6 Module Transpiler等やっていたSquare社がesnextというプロジェクトを立ち上げました。

esnextTraceurと同様にES6のコードを今日のJavaScriptに変換するツールです。

@eventualbuddhaさんがメインでやっていて、それぞれのシンタックスの変換はes6-spreadのように、ひとつのモジュールとして分けて作られています。

また変換の書き方も大体統一したやり方(まあ一人で大体書かれてるので)が取られていて、
Facebookの@benjamnさんが作っているast-typesrecastを使ったものになっています。

テストはexample-runnerを使っています。
examples/*.jsにあるテストファイルを変換モジュールで変換した結果がresultsディレクトリに出力されて、それの実行結果が期待通りになるかという感じで書かれています。

それぞれが小さくシンプルに書かれているので、JavaScript ASTを使った変換モジュールを書きたい人は参考になるかもしれません。

後、この辺のES6 -> なものはaddyosmani/es6-toolsを見ると大体まとまってると思います。

CST

JavaScriptのAST(抽象構文木)に対してCST(解析木)の標準を決めようというプロジェクトがgetify/concrete-syntax-treeで議論されています。

JavaScriptのASTはParser APIによるものが大体標準といえますが、
このASTのNodeオブジェクトには、ホワイトスペースの位置やコメント、( )という文字そのもの等、含んでない情報があります。(Esprimaなどパーサーによってはtokens等で取得できるようになっていますが)

そのような情報も含めたCSTの標準を決めようというものを@getifyさんが中心になってやっています。

まだ始まったばかりで、ちゃんとConsensus取れるものになるか微妙なところです。

doctrine

JavaScript ASTを触ると必ず触れることになるコンストウェアと呼ばれるものの一つにdoctrineというJSDocパーサーがあります。

doctrine自体はJavaScript ASTに直接関係ありませんが、JSDocをパースした結果をTreeのオブジェクトとして取得することが出来ます。
(そのオブジェクトの構造はASTに似ているところはある)

ここ1-2ヶ月で@jonathanKingstonさん等が中心となって一気にJSDocのtagのサポートが増えました。

ESLintvalid-jsdocルールでも使われていて、closure-tsなどJSDocを扱ったツールが増えてくるかもしれません。

AST Query

大体の場合JS ASTを使ったものを作るときにEstraverse等の走査をする関数を使ったりすると思います。

DOMにもTreeWalkerというTraverse関数はありますが、普段ウェブ開発とかで特定のElementを取得する場合はDOM API(getElement..やquerySelector)のようなものを使うと思います。

AST Queryというライブラリは、DOM APIのような感じでASTから特定のnodeを取得したり、変更したりできるライブラリです。

DOM APIのように全てをカバーするわけではありませんが、最近0.2.0がリリースされて少しづつできることが増えてきました。

決まった名前の変数や関数を変更したい等の用途だとかなり直感的に書けるようになると思います。

var tree = program('var a = 1');
var variable = tree.var("a");
console.log(JSON.stringify(variable, null, 4));
/*
{
    "nodes": [
        {
            "type": "VariableDeclarator",
            "id": {
                "type": "Identifier",
                "name": "a"
            },
            "init": {
                "type": "Literal",
                "value": 1,
                "raw": "1"
            }
        }
    ],
    "length": 1
}
*/
console.log(variable.value());
/*
{
    node: { type: 'Literal', value: 1, raw: '1' },
    type: 'Literal'
}
*/

// ==> rename + update
variable.rename("b");
variable.value("2");

console.log(JSON.stringify(variable, null, 4));
/*
{
    "nodes": [
        {
            "type": "VariableDeclarator",
            "id": {
                "type": "Identifier",
                "name": "b"
            },
            "init": {
                "type": "Literal",
                "value": 2,
                "raw": "2"
            }
        }
    ],
    "length": 1
}
 */

テストとセキュリティの葉桜JSに参加してきた

#葉桜JS に参加してきたので記憶メモ。

(脳内記憶で書いたので、何かと解釈が間違ってる場合があります)

葉桜JSとは

唐突にネタを持ち寄って食事とかする場所です。
@kyo_agoさんとかが適当に投げた、
それっぽいハッシュタグに反応した人を適当に呼んで開始しました。


kyo_ago

Buster.JSはどうなってるのか

  • dwittnerさんがメンテしてる
  • ドキュメントよりの人なので、あんまり機能開発は進んでてない
  • Buster.JSにみたいにSinon.JSが統合されてると、stubの開放処理をミスらない
  • テストコードをASTパースして自動的に開放処理を入れられるか?
    • 非同期処理の時に何時終わったのか分からない

テストのコスト、メトリクス

  • 重要なテストといらないテストを見分けたい
  • テストコードを読むときにどれが重要なのか分からない
  • 不要なテストが多いとテスト実行時間がかさむ
  • Seleniumはテストの実行時間の増加が顕著
  • バグを修正するときにそれのSeleniumのテストを書くべきか問題
  • テストにラベル/タグ付けをして、必要なテストをグループで実行出来るような仕組みが有用?
  • YUIのテスト構成について
    • CIではたっぷりテストを回す、テストを回す効率について書かれてる
    • Testing YUI Everywhere
  • 昔のテストといえば、特定のディレクトリにまとまってたのでディレクトリ単位だった
  • 今は色んな所にテストがある
    • そのためテストにタグ付けをしていくの主流かも?
    • テストカテゴライズ

sourcemapを複数回変換する問題

  • 現状だと特に複数回に対する仕様はない
  • a -> b -> c みたいにそれぞれがちゃんとやってることを期待するしかない
  • ウンヨウデカバー
  • a – …. -> c みたいなマッピングならできるはず

teppeis

TypeScript用フルスタック型付きライブラリのご提案

TypeScript用フルスタック型付きライブラリのご提案 #葉桜JS

  • 「我々には型が必要な事は明白です」
  • Closure Library という型を持ったライブラリがある
  • JSDoc から TypeScriptの d.ts 型宣言ファイルへと変換するツールを書いてみた
  • Esprimadoctrineを使った

言語に依存しない汎用型定義

  • 特定の言語に依存しない、型を定義するだけの物体が欲しい
  • doctrineではJSDocをパースした時にJS ASTのように定義をASTっぽい感じにする

現実問題

  • 現実的な問題として、言語によってそのものが等の扱いがバラバラ
  • JSXとTypeScriptでさえnullable等の違いがある
  • d.ts -> 他 は TypeScriptの型が少ない目なので意外とできなくはない
  • 「汎用型定義生成の夢」
  • write once run anywhereや!

azu

Test Runner Tips

大体はスライドTest Runner Tips書いてあります。

  • Mocha
    • 実質的な覇者
    • やってる範囲は狭いので他と合わせて使う
    • mocha.optsという謎の設定ファイルのユースケース
    • Node.jsとブラウザで同じものを動かしたい
    • mochaオブジェクトを直接弄ってテストの設定を動的に変更する
  • testem
    • まっとう
    • 既存ツールと連携しやすい
    • testem2の進捗どうですか?
  • Karma
    • 大きい
    • プリプロセッサという拡張について
    • sourcemapを使ってスタックトレースの書き換えまでサポートしてる
    • Karmaの未来について
      • よりコミュニティを意識するという話

jxck

テストライブラリ

  • QUnitは最近どうですか?
  • 深刻なバグ(requireで使えない)のfixが中々マージされなかった
  • QUnitの基本的な使い方 – Block Rockin’ Codesの記事が未だに参照されまくってる話
    • この記事の時に非同期のテストサポートなかった
    • Mochaの記事にかえてしまおうか?
  • substack/tapeについて
  • assertの数を最初に書くのはperl文化っぽい
  • 本当にそのassertがテストで実行されたのかを保証したい
    • spyとやりたい事は似てる
    • けど、単純にassertの数を数えるだけでそれが実現できる
  • QUnitはその辺もあって、テストが失敗してもテストが続く(今だとQunitだけ?)
  • QUnitの歴史、どのようなテストフレームワークに影響を受けてうまれてたかについて

nanotest

  • 最小のテストを目指してた
  • assertの数を数えるメソッドをassertに拡張してた
  • assertを書き換えるのは難しい
    • power-assertでもやってて難しい話
  • requireを盗むのはやめましょう」

mochaのdoneについて

  • doneは非同期に対するテスト?
  • それともコールバックに対するテスト?
  • Promiseみたいな例外はテストライブラリがサポートしてないと上手くいかない感
    • 本当にthenが呼ばれたのかが心配になる
    • assertのカウントがやっぱり必要?

「人類は Harmony を使いこなせるか? – Generator 編 」

  • generatorを直接使いたいか?
  • ライブラリ側で使って、直接は使いたくないかもという話
  • テストだけでgeneratorを使いたい?
  • コードとテストのパラダイムが違うのは問題かどうか?
    • テストをどうしたいかの方針によって違う
    • できるだけ簡単に書きたい => 別パラダイムあり
    • できるだけ読みやすくしたい、サンプルとしてのテスト => 同じパラダイム

テストの課題

  • テストはドキュメント or テストを簡単に書きたい
  • 相反する課題
  • テストを簡単に書きたい => 極論はaltjsでテストを書くようなモノになっていく

FormのPUT/Delete 再び

  • Formの場合はクッキーを送ってしまう所がXHRでやるのと異なるケースが出てくるかも
    • イントラネットでFormからPut/Deleteがコない前提のものとか
  • JavaScriptが発展する前に、Formの拡張の話がきてたら流れは違ったかも。
  • 現実面ではサポートコストが大きすぎる部分が多い
  • HTMLの仕様としては欠けてる感がある
  • Amayaの話まで戻る
  • 「ホントにPOSTあってよかった」

t-wada

「power-assertができるまで」

power-assertができるまで

  • power-assertが出来るまでの背景
  • Pythonの人がPythonでもPOWER ASSERTができると言ってた
  • PythonでできるならJavaScriptでも出来るはず
  • Node学園でsubstackやIsaacの話を聞いてNodeにもUnix文化があると知った
  • 最初はC1以上のカバレッジツールを作りたかった
  • SQLアンチパターンが忙しかった
    • 現実逃避 -> power-assertのプロトタイプ作成
  • 最初はQunitと合わせてた、assert互換になるのは結構後
  • SimpleとEasyは別もの
  • Rich Hickeyの話を聞いて、power-assertの構造を決めていった
    • それぞれsimpleのレイヤーを分けた
  • AST < -> AST、Source < -> Source、File < -> Fileをやる所がある

power-assert 0.6.0

  • 今まで一番大きなアーキテクチャ変更
  • ASTのメタ情報を生成してASTに埋め込む
    • 実行時にメタ情報を取り出して、解釈する
    • メリットとしてはレポーター等からもメタ情報を利用できる
    • estraverseのpathを使う事で一意にASTのnodeを得られる
    • 実行時にそこを見る

Concrete Syntax Tree

  • CSTについて
  • ASTだとBinaryExpression(+)の+の位置等の情報そのものはない(tokenとか駆使)
  • CSTはそういった情報やコメントについても定義しようというプロジェクト
  • 議論がどこまで進んでいるのか気になる

yosuke_furukawa

Docker Node Tester

Docker Node Testerの話 in 葉桜js // Speaker Deck

Docker Node Testerを使ってNode.jsをバージョン毎にテストする #葉桜js – from scratch

  • Node.jsの v0.10と0.11を一緒にテストしたい
  • Githubのtag等を直接checkoutしてテスト環境を作れる
  • 多分Node.js以外でもいける
  • TravisだといちいちPushしないといけない、Dockerなのでローカルで出来る

Docker

  • Dockerが突然死ぬことがある
  • JenkinsおじさんからDocker職人へ
  • まだ脆い部分もあるので、Docker一本だと難しい所がある
  • Ubuntuについて
    • 本番環境がUbuntuならデスクトップもUbuntuで合わせると楽
    • CentOSツライ
    • 最近は色んなソフトがUbuntuサポートしてる

mala

なぜAngular.jsを使ってXSSがおきるのか


メモ: Twitterに直接と脳内記憶

その他

後、自分は作って発表する時間なかったので発表してませんでしたが、
power-assertの記事が出来るまでというスライドを作りました。

という2つの記事を書くまでに至った思考の流れとかをまとめた感じです。

調査しながら記事書く時の話みたいな感じです。

power-assertでJavaScriptのテストをする ブラウザ編

power-assert

power-assertという単純なアサーションでも、テストが失敗した時に分かりやすい情報を出せるテストライブラリ/ツールについての記事です。

前回、power-assertの使い方 Node.js編 | Web scratchではpower-assertの動作やNode.jsプロジェクトでの簡単な導入方法について解説しました。

前回のpower-assert + gulpで紹介したプロジェクトをそのまま使っていくので、見ていない場合はそちらから見ていたほうがいいかと思います。

今回は、ブラウザでのpower-assertの動かし方とデバッグについて書いていきたいと思います。

今回扱う実行環境

  • Node.js <= 前回
  • ブラウザ
  • Browserify

前回やったこと

まずは前回紹介したgulp + power-assertのプロジェクトを元にやっていきます。

どんな事をやったかを簡単にまとめてみます。

必要なモジュールのインストール

$ npm install --save-dev power-assert gulp gulp-espower
$ npm install -g gulp

テストコードをpower-assert化、mochaでテストを実行するgulpfile.jsのタスクを書きました。

そして、gulp testとするとNode.jsでのテストが動くところまでやりました。

$ gulp test

今回は、これにtestemを使ってブラウザでも同じpower-assertを使ったテストが動くようにしたいと思います。

Testemを使ったブラウザ対応

ブラウザでpower-assertを実行するには、次のようなものが必要です。

  • power-assert化したテストコード(これは既にありますね)
  • test runnerとなるHTMLページ
  • HTMLページで読み込むブラウザ向けのpower-assertの関連ライブラリ
    • Node.jsの場合はrequire("power-assert");で済みますがブラウザは自分で依存関係を解決する必要があります。

素でHTMLページを作り、変換したコード等を読み込んで実行するのでもよいのですが、
その辺はKarmatestem等を使って出来ると思うので、今回はtestemを使ってやってみたいと思います。

そのため、方針としては次のようになります。

  1. ブラウザ向けのpower-assertライブラリをbower install
  2. testem.json でブラウザでmocha + power-assertで実行出来る環境を作る

完成したサンプルプロジェクトは以下に置いてあります。

ブラウザ向けにpower-assertBowerを使うことで簡単にインストールできます。

bower init
bower install power-assert --save

1のインストールが完了です。

次にTestemをインストールしてない場合はインストールしておきましょう

npm install testem -g

Test runnerとなるHTMLページは、testemが内蔵しているため気にする必要はありません。

しかし、<script>タグで必要なアサーションライブラリやpower-asssert等を読み込む必要があります。(require("power-assert");の代わりですね)

その読み込みを、testemの設定ファイルであるtestem.jsonに定義します。

{
    "framework": "mocha",
    "before_tests": "gulp power-assert",
    "on_exit": "rm -rf ./powered-test/",
    "src_files": [
        "./test/*.js"
    ],
    "serve_files": [
        "./bower_components/estraverse/estraverse.js",
        "./bower_components/assert/assert.js",
        "./bower_components/empower/lib/empower.js",
        "./bower_components/power-assert-formatter/lib/power-assert-formatter.js",
        "./bower_components/power-assert/lib/power-assert.js",
        "./powered-test/*.js"
    ]
}

設定ファイルの内容を簡単に紹介します。

  • "src_files"は監視対象のファイルです
    • ファイルが変更されたらテストが実行されます
  • "before_tests" はテスト実行前に行う処理です
    • gulp power-assertでpower-assert化しています
  • "on_exit" はtestemが終了した時のクリーンアップ処理です
  • "serve_files" はHTMLページで読み込むファイルです
    • ブラウザで読み込まれるファイルはここに記述します

ブラウザで読み込むべきpower-assertのライブラリ関係はusing grunt-espowerの部分にも書いてあります。

これに加えて、power-assert化したテストファイル("./powered-test/*.js")を読み込みます。

これでブラウザでのテスト準備は完了です。

Testemの実行

設定が面倒くさい分実行は簡単でtestemとすると、ブラウザを受付状態になるので、後はテストしたいブラウザでアクセスするだけです。

$ testem

以下のような感じでテストが出来ます。

Testemの中ではmochaでテストが実行されてるので、基本はあまり変わらないと思います。

power-assert化したコードはsourcemapに対応しているため、
デバッガー等を使ってデバッグも普通に行えます。

ハイブリッドテスト

最初に書いたテストコードではrequireを使ってpower-assertを読み込んでいたので、そのままでは実行時エラーになります。

Node.js環境なら読み込むようにして、ブラウザでは既にglobalで読み込まれているので読み込まないようにすることが出来ます。

if (typeof require == "function" && typeof module == "object") {
    var assert = require('power-assert');
}

これで、Node.js と ブラウザ どちらでも動くテストが書けるようになりました。

先ほどのプロジェクトもNode.jsとブラウザを同時にテスト出来るようにしています。

注記: ブラウザだけがテスト対象なら、上記のrequireそのものを削除しても問題ありません。(というか削除すべき)

また、global.assert = require("power-assert");と定義したものを別のhelperファイルで読み込む等もありでしょう。


Task Runner + Test Runner を使って何とかブラウザでも実行出来るようになりましたが、
上のハイブリッドテストを見て「Nodeで書いたコードをBrowserifyで変換してブラウザで実行すればいいのでは?」と思った方もいると思います。

そういう需要にもpower-assertは対応していて、espowerifyを使うことで出来ます。

espowerifyはその名前の通り、browserifyの変換時にpower-assert化を行えるbrowserifyの変換モジュールです。

browserifyとはNode.jsのコードをブラウザで実行出来るように変換するツールで詳しくは下記を参照して下さい

Browserify

espowerifyはBroserifyの変換モジュールとして扱います。

使い方は単純で browserify -t espowerify のように変換モジュールとして指定するだけで、
browserifyによるnode.jsのコードの変換 + power-assert化を行ってくれます。

この方法のメリットは

  • Node.jsとブラウザで同じテストコードが共有できる
  • 一つのファイルにまとまるため、読み込むファイルの順番などを気にしなくてよい
  • power-asert化も行えるので、他のビルドツール(gulpとか)などは必要としない
  • ソースマップも対応してるのでデバッグできる

デメリットとして、browserifyの変換も入るため変換にかかる時間が増える事があげられます。

先ほどのプロジェクトでやったような依存するライブラリの読み込み等は、
変換して1つになったJavaScriptをtest runnerとなるHTMLページで読み込むだけで良くなるので単純です。

今度はKarmaを使ってブラウザテストしてみましょう。

Karma + Browserify

azu/power-assert-karma-seed

Testemでも出来なくはないですが、karmaにはプリプロセッサという機能があります。
この機能ではプラグインを追加することで、テストを行う前に処理をすることが出来ます。(testemの"before_tests"をより柔軟にできる感じですね)

karma-coffee-preprocessorでcoffeescriptをコンパイルする等色々とプラグインがあります。

そのプリプロセッサで先ほどのbrowserifyによる変換も行う事が出来ます。(これがKarmaを選んだ理由です)

Browserifyを扱う事が出来るプリプロセッサのプラグインとしてkarma-browserifastを使います。

Karmaを使ったプロジェクト設定

まずは必要なものをインストールします(数が多いのでpackage.jsonを見るといいです)

npm install -g karma-cli
npm install --save-dev espowerify karma karma-browserifast browserify mocha

必要なモジュールをインストールしたら、Karmaのセットアップを行います。

詳しいKarmaの使い方はKarma - Configuration等を見ましょう。

karma init # mochaを選択する、後は自由に

次に、browserifyの設定を行います。

詳しくは設定方法karma-browserifastの説明を見ると良いです。

実際のkarma.confの設定はazu/power-assert-karma-seedを参照して下さい

frameworks: ['mocha', "browserify"],
files: [
],
browserify: {
    debug: true,
    files: [
        "test/**/*.js"
    ],
    transform: [
        "espowerify"
    ]
},
preprocessors: {
    "/**/*.browserify": "browserify"
},

本来はfilesでテスト時に読み込むファイルを指定しますが、今回テストしたいファイルはプリプロセッサでbrowserifyしたファイルになります。

そのため、files は空でよくて、代わりにbrowserifyというプロパティのfilesにテストしたいファイルを指定しています。

  • "frameworks""browserify" を入れる
  • browserify の設定をする
    • browserify"transform""espowerify" を指定する
  • preprocessors を設定する(これは常に同じ)

という感じでKarmaの設定は終わりです。

この状態で、karma start + ブラウザでキャプチャ または karma start --browsers Chrome --single-run"という感じでテストを実行すると以下のような事をしてくれます。

  • test/**/*.js 以下のファイルをそれぞれ power-assert化 + browserify化
  • キャプチャしてるブラウザで変換されたテストファイルを読み込んでテストを実行

Karmaのテストサイクルの中で変換、テストの実行をしてくれるので、
見た目的には一時ファイルが必要なくなったり、karma.conf.jsという設定ファイル一つだけ良くなるのがメリットかもしれません。

karma+browserify

こちらもsourcemapに対応してるので、ブレークポイントを貼ったデバッグも可能です。

上記でやってるのは、karma startでサーバを立ち上げて、ブレークポイントを貼って、http://localhost:9876/debug.html に対してChromeでアクセスしてデバッグという感じです。(KarmaのConfigurationをDebug実行だと上手くできない?)

(WebStormでの)Karmaのデバッグ実行は少し特殊な感じなので下記を参照して下さい。


デバッグ

さきほどからsourcemapによるデバッグが可能 ということが書いてありますが、
sourcemapとは何かが気になる人は下記などを見るといいでしょう。

簡単に言うと変換したコード(power-assert化したテストコード)と元のコードの関係をマッピングしたファイルがあることにより、通常のJavaScriptのようにデバッグが可能になる感じです。

現在のブラウザに載ってる開発者ツールやWebStorm等のIDEやエディタでも対応してるものが多いため、デバッグ時にかなり有用になると思います。

こうしたsourcemapの対応が比較的に簡単にできるのもJavaScript ASTをベースとしたツールの特徴でもあるかもしれません。


まとめ

この記事では、以下の事について解説しました。

  • power-assertをブラウザで動かすのに必要なもの
  • Testem + gulp でのブラウザテスト対応
  • Karma + browserifyでのブラウザテスト

power-assertの使い方 Node.js編に比べると、Mocha以外にもtest runnerが必要だったり(両方共内部的にMochaを利用してます)、設定が必要だったりしますが、
power-assert化したテストファイルも問題なくブラウザで動かすことができました。

また、sourcemapにも対応しているのでデバッグも問題なくできることがわかりました。

どんなテストライブラリ(アサーション)を使うか迷ってる人は、一度 power-assert を試してみるのも楽しいと思います。

より良きJavaScriptテストを!

power-assertの使い方 Node.js編

power-assert

Power Assertとはassert(a === b); のような単純なアサーションでも、
Assert失敗時(テストが通らなかった時)に分かりやすい情報を表示できるようにする機能の事を言います。

Power assert

JasmineChaiが持つshouldexpect等言った豊富なアサーションを覚える必要なく、
シンプルにassert()を使うだけでも十分な失敗時の情報が得られるため、沢山のアサーションを使い分けしなくていいというメリットがあります。

この記事ではPower AssertのJavaScript実装であるtwada/power-assertの使い方について紹介します。

記事を読む前に

このNode.js編とブラウザ編で分けるぐらい長い記事となってるので、
お忙しい方は5分ぐらいで分かるpower-assertというスライドもあるので、そちらを読んでざっくり把握してみるのもいいでしょう。

使い方の前に

power-assert の役割について簡単に解説します。

power-assertはchai等のようなアサーションのライブラリというわけではなく、コードの変換や失敗時の出力等がまとまったツールに近い位置のものです。

簡単に流れを見ると以下のような事を行います。
(この流れは自動化できるので単純に実行時に全部やってるわけじゃないということがわかればいいと思います)

  1. テストコードをpower-assert用に変換したコードを生成します
  2. power-assert化されたテストコードを実行します
  3. テストが失敗してる時は、ロードしてるpower-assertモジュールが整形してエラー情報を出力します

1 でテストコードを変換する事で、3でテストが失敗した時に詳細な情報が出力出来るように書き換えたテストコードを作成しています。

2 で実行する際に使われる assert() といったアサーションは、Node.jsのAssert等をそのまま使うようになっています。

詳しくは下記を見るといいと思います

使い方

本題のpower-assertの使い方について実行環境別に紹介します。

gif

実行環境

それぞれ実行するまでの設定をしていくので、必要な部分だけ見ていくといいでしょう。

twada/power-assert – HOW TO USE にも使い方が書いてあるためそちらも参照して下さい。

この記事ではまず、Node.jsでの使い方について解説します。

また、power-assertはMochaで実行するのが一番相性がよいため、基本的にTest RunnerはMochaを使っていきます。


Node.jsで簡単にpower-assertを使う

power-assertはNode.js環境で動かすのが一番簡単です。

Mochaには--requireで指定したモジュールをテスト実行に読み込む仕組みがあります。

この読み込むモジュールにespower-loaderを使うことで、使い方の前にで説明したような変換フェーズ等を意識しないで使う事が出来ます。

espower-loaderの説明を読むと、enable-power-assert.js 等の設定ファイルが必要になりますが、毎回書くことは同じなので、intelli-espower-loaderを使うと余計な設定ファイルなしに利用できます。

そもそも何を設定する必要があるかというと、テストファイルがどこにあるかという事を指定する必要があります。intelli-espower-loaderではこれをpackage.jsonに持たせることが出来ます。

power-assertをプロジェクトに導入する

サンプルプロジェクトは以下に置いてあります

Power assert node seed 2014 04 06 22 50 36 2014 04 06 22 51 51

power-assertを使いたいプロジェクトにpower-assertintelli-espower-loaderをインストールします。

$ npm install power-assert intelli-espower-loader --save-dev

次に、package.jsonに"directories"という項目を追加して、"test" の値にテストディレクトリを指定します。(そのディレクトリ以下にあるファイルがpower assert化の対象になります)

"directories": {
    "test": "test/"
}

最後に、テストコードを書いてtest/ディレクトリ以下に置きます。

test.js

var assert = require('power-assert');
describe('Array', function () {
    beforeEach(function () {
        this.ary = [1, 2, 3];
    });
    describe('#indexOf()', function () {
        it('should return index when the value is present', function () {
            var zero = 0, two = 2;
            assert(this.ary.indexOf(zero) === two);
        });
    });
});

後は、mochaでテストを実行するときに--requireでintelli-espower-loaderを指定するだけです。

$ mocha --require intelli-espower-loader

Power assert node seed  zsh 2014 04 06 22 58 57 2014 04 06 22 59 07

毎回--requireを指定するのが面倒な場合はmocha.optsファイルを作って書いておくことでも同様の効果が得られます。

テストコードについて

テストコードに書くアサーションはNode.jsのAssertを使った場合と全く同じです(裏側でAssertモジュールそのものが使われています)

そのため書くテストコードはrequire("assert")require('power-assert')にした以外はMocha + Assertで書いた場合と全く同じで問題ありません。

また、アサーションのメソッド名等の細かい設定はespower-loaderで行う事が出来ます。
intelli-espower-loaderでは細かい設定をしないことを前提にして簡略化してるので、細かい設定をしたい場合はespower-loaderを直接利用しましょう。

power-assert + gulp

使い方の前にで紹介したように、power-assertは変換と実行の2つフェーズがあることを紹介しました。

espower-loaderを使うとその部分を意識しないでいいことが分かりましたが、今度はGruntやgulpを使って一個づつフェーズを得てテストを実行してみたいと思います。

変換のフェーズはgulp-espowergrunt-espowerというタスクが用意されているので、これを使うのが簡単でしょう。

power-assertはアサーション周りについてのみ扱うので、describe() や Qunitのtest() といった部分に何を使うかというのは特に制限はありません。

既に記事やデモでMocha + Gruntについて書かれているので、今回はMocha + Gulpでやってみたいと思います。

power-assert+gulpのサンプルプロジェクト

サンプルプロジェクトは以下に置いてあります。

まずは、必要なモジュールをインストールします

$ npm install --save-dev power-assert gulp gulp-espower
$ npm install -g gulp

次にgulpの設定ファイルであるgulpfile.jsを書きます。

gulpのtaskでは次の2つを定義しています。

  1. power-assert化されたテストコードに変換する "power-assert" タスク
  2. 変換されたテストコードをmochaで実行する "test" タスク

2の "test" タスクを行う前に、自動的に変換しておいて欲しいのでgulp.taskの依存関係も定義しておくと、
gulpfile.jsは以下のように書けると思います。

"use strict";
var gulp = require("gulp");
var espower = require("gulp-espower");
var mocha = require("gulp-mocha");
var paths = {
    test: "./test/*.js",
    powered_test: "./powered-test/*.js",
    powered_test_dist: "./powered-test/"
};
gulp.task("power-assert", function () {
    return gulp.src(paths.test)
        .pipe(espower())
        .pipe(gulp.dest(paths.powered_test_dist));
});
gulp.task("test", ["power-assert"], function () {
    gulp.src(paths.powered_test)
        .pipe(mocha());
});

これでnodeで実行出来る環境が出来ました。

test/ 以下にテストを書いていって、テストを実行したい時は以下のようにコマンドを叩くと実行結果が出力されるようになります。

$ gulp test

次の記事では、これをブラウザでも実行出来るようにしたいと思います。


まとめ

この記事では power-assert という単純なアサーションでも十分なエラー情報が出せるようにするテストツールについて、機能の概要とNode.jsでの導入方法について解説しました。

Node.jsのプロジェクトでは、ちょっとした設定をして、require("assert")require('power-assert')に変更する程度で導入出来ます。

var assert = require("assert");
// => 
var assert = require('power-assert');

アサーション自体はNode.jsのAssertと同じものが使うことができます。
そのため、power-assertが仮に無くなった場合もNode.jsのAssertに戻ることが簡単です。

Chaiのような多種多様のアサーションを使い分ける自信がない場合や、テストを書くことに集中したい人などは一度power-assertを試してみるといいでしょう。

今回はNode.jsをメインとしましたが、power-assertはブラウザ向けのテストでも動作させることができるため、次の記事ではブラウザ向けの設定について書いていきたいと思います。

追記

ブラウザでpower-assertを動かす方法について書きました。

Estraverseの動きを可視化する

Estraverse

EstraverseというJavaScript ASTのtraverseを行うライブラリがあります。

JavaScript ASTについては以下を参照して下さい。

このtraverse関数にはそれぞれのnodeの通り方としてenterleaveというものが用意されています。

estraverse.traverse(ast, {
    enter: function (node, parent) {
        if (node.type == 'FunctionExpression' || node.type == 'FunctionDeclaration')
            return estraverse.VisitorOption.Skip;
    },
    leave: function (node, parent) {
        if (node.type == 'VariableDeclarator')
          console.log(node.id.name);
    }
});

という感じで書くとastenterでは上から下へ、leaveでは下から上というイメージで探索することが出来ます。

木構造なので、enterではroot nodeからleaf nodeへ、leaveではleaf nodeからroot node(parent node)へという感じの流れになっていると思います。

自分は探索とかアルゴリズムが苦手なので、こういう動きが直感的にわからなかったため、どういう動きをするのか可視化するツールを書きました。

azu/visualize_estraverse

azu/visualize_estraverseにソースコードが置いてあります。

上記のように、適当にコードを入れてそれぞれのボタンを押せば、enter, leave又はenterleave両方がどのような流れtraverseされるかが見られます。

ASTそのもの(JSON)も同じように可視化できると良さそうな気がしたのですが、イマイチいいUIとかが思いつかなかったのでコード上で色付けしています。

CodeMirrorの選択色を変えてやるという荒業でやってるので、かなり大雑把な実装です。

桜JSでご飯を食べながらLT大会をした

#桜JSでご飯を食べてきた

さくらのクラウドのCLIについて – azu

node v0.12で変わること – yosuke_furukawa

1年後ぐらいのモバイルHTMLゲーム – tkihira

  • HTMLとCanvas
  • Canvasの方が今のところ速度でる
  • WebGLがモバイルにきたら始まる
  • ライトなモバイルユーザー層、タップした瞬間反応しないと離脱する。
    • ゲームだと最初のローディング待ちが結構でかい
    • ネイティブありきなゲームとHTMLゲームではそこが違うかも
    • 非同期がより重要になる?

Webの未来の話 – kyo_ago

  • Webとは何か
  • 定義が曖昧になってきてる
  • DOMがドキュメント以外になってきた
  • インターネットとウェブ
  • URLがあるのがウェブか?
  • URLをシェア出来るゲーム

TypeScript – otiai10

  • TypeScriptの使い勝手
  • 踏み絵
  • CoffeeScriptはaltjs?
    • シンタックスシュガー
  • そもそもaltjsとは?

Closure Libraryの今 – teppeis

  • 最近更新されてない?
  • Closure Libraryのコミットが超活発
  • Promiseが入った
    • Lab -> stable
    • 元々Deferredっぽいのはあった
  • 型付き文字列
  • closure-npc
    • Closure Node Package Checker, a type-checker for NodeJS programs
    • コメントアノテーション
  • Closure Linter
    • ドキュメントにGoogle社内リンクが多い
    • GAsLintという謎ツールがある
    • コレ知ってるとClosure界隈で一目置かれる
  • Closureマニアの夢は、全てのClosureツールを揃える
    • html css js リソース 全てを1つのJSファイルに圧縮できるようになる

続: なぜ html の form は PUT / DELETE をサポートしないのか? – Jxck

なぜ html の form は PUT / DELETE をサポートしないのか? – Block Rockin’ Codes

  • Cameron氏がformの拡張仕様を書いてた
  • Cameron氏にメールした
    • 手直しとかしてHTML WGに投稿して議論していきたい
    • HTML5.1に入れて行きたいとの話

最近のJSフレームワークは結局バインディングとコンポーネント化したいだけなのでは – hokaccha

  • 最近のJavaScriptはバインディングとコンポーネント化に集約されてる
  • MVCいうなー問題
  • RESTいうなー問題
  • MVCとREST一緒にするなー問題

5分で分かるpower assert – azu

5minで分かるpower-assert

  • power assertの動作の概要
  • ブラウザ/Node/Browserifyで動かす設定

今度もうちょっと詳しい記事を書きます


結局、全員LTをした桜JSだった

お疲れ様でした。

メモ: 脳内記憶

コマンドラインからSourceTreeのコミット画面を開くAppleScript

普段はWebStorm等のIDEで直接コミットするのでいいですが、
コマンドラインからちょっとした変更をコミットしたい時に git commit 使うのが億劫でした。

gitコマンドを直接使うと、一部ファイルだけコミットするのが面倒なのもあります。
tigを使えば出来ますが、そこまでやるならGUIでやりたい

SourceTreeはそういうことが大体できますが、SourceTreeを起動 -> コミット画面を開くというのが面倒でした。

それを解決するために、azu/sourcetree-commitというAppleScriptを書きました。
(なのでMacのみです)

gif

使い方は簡単で、

$ osascript sourcetree-commit.scpt "path/to/directory"

という感じで、開きたいリポジトリがあるディレクトリを指定するだけです。
そうすれば、上記のGifみたいな勝手にコミット画面を開く所までやってくれます。

自分は以下みたいのにaliasを貼って使っています。

osascript ~/bin/sourcetree-commit.scpt "`git rev-parse --show-toplevel`"

寿司jsでPromisesの基礎について発表してきた

寿司.js でPromisesのキホンについて発表してきました。


Promises StarterではPromiseの基本的な部分だけなので、Pormise.all等実際に使うと便利的な話は入れてないです。

PromiseのAPIの概要、Promiseの状態の種類、基本的なresolve/rejectの流れ、XHRの例、エラーハンドリングについてがメインな感じです。

続きはウェブで ということで、今azu/promises-bookというものを書いているので、
ここが分かりにくいとかここが間違ってるとか、こういうこと書いたほうがいいとかあったらフィードバックお願いします。

まだ全然書き途中なのですが、書いていく内容については[WIP] この書籍で扱う内容について by azu · Pull Request #1 · azu/promises-bookazu/promises-book – Gitter等で議論できればなーと思います

Gitter chat

Gitterにチャットルームもあるのでそちらに適当に書き殴っていってもいいと思います。


戻って寿司.jsのアウトライン

Promises Starter – azu

Promises Starter

最初に自分がPromiseについて発表しました


git pullした時にbowerとか変更があった時にどうする問題 – yosuke_furukawa


名古屋のLT – kyo_ago

  • 時間制限が緩い
    • ドラがない
    • 続きは二次会でみたいな現象
  • Hue
    • WifiベースでAPIから操作出来るLED 電球
    • サムスンが似たようなのだしてきた
    • 将来心配
  • Hadoop
  • フレームワークの地域性
    • Knockoutは関西人気?

寿司で学ぶWebComponents – hokaccha

  • Web Compoenentsを構成する4つの要素

    • CustomElement
    • Templete要素
    • HTML Imports
    • Shadow DOM
  • document.registerElement で独自の要素を登録できる

  • CustomElement
    • document.createElement した時にも定義が継承されるようにできる
  • Shadow DOMで要素が外からアクセスできないような子要素が作れる
    • 外のCSSの影響を受けない要素を作れる 
  • <x -sushi> のデモ

名称未設定 2014 04 01 00 21 01 2014 04 01 00 21 15

Docker による Rails Application 開発環境の構築 – y_imaya

Docker による Rails Application 開発環境の構築

#寿司js で Docker について雑に話してきました : document

  • 手元の環境を汚さずに開発環境を作りたい
  • IDEとか動かせる環境
  • データダウンロードの問題をデータコンテナを使って解決
  • CentOSまわりのハマりどころ色々

大体の流れは#寿司js – Togetterまとめに載っています。

スタートアップiOS勉強会 #3 アウトラインメモ

スタートアップiOS勉強会 #3

スタートアップiOS勉強会 #3 #startup_ios on Zusaar に参加してきたのでメモ。


「スタートアップの人材獲得戦略」@laisoさん

スタートアップの人材獲得戦略とは何か – laiso

  • ユビレジ
  • スタートアップ
  • リソースが足りない

基本戦略

  • 大企業だとできない方法取る必要がある
  • エンジニアが採用に関わる
  • 小さいチームで進めていく

優秀なエンジニア

  • 自分よりエンジニアを探す
  • 知り合いから探す(縁故採用)

WANTEDLY

  • スタートアップ向けという思想でできてる

コミュニティ

  • 勉強会を開く
  • 勉強会で発表する
  • 非エンジニアはイベントの運営を手伝う
    • 会場の貸出をするとか
  • 注意 : コミュニティの現場で採用活動目的だと嫌がられる

自分たちからアプローチする

  • 自分たちから誘わないと誰もコない
  • 気になる人に声を直接書ける
  • ポジションとかで募集じゃなくて、個人を指定して募集する
  • クックパッドの連鎖パターン

柔軟に参加出来るようにする

  • リモートワーク
    • クラスメソッド事例

まとめ

  • 自分よりすごい人を紹介してもらう
  • コミュニティへ貢献して良い人元関係を作る
  • 来て欲しい人に自分たちからアプローチする
  • スタートアップiOS勉強会みたいなイベントを開く

「Appleのテンプレートは有害と考えられる:UITableViewControllerとSRPについて」@modocacheさん

Apple Templates Considered Harmful

単一責任原則(SRP)

  • クラスを変更する理由はひとつ以上存在してはならない
  • Clean Codeの著者

UITableViewController

  • ViewController
  • TableDataSource
  • TableDelegate

の3つすべて入ってる

GithubViewer(サンプルアプリ)

TableViewController -> ViewController(Detail)
なアプリ

バットパターン

  1. reloadData
  2. インジケータの表示
  3. APIClientでデータを取得する

ViewControllerにデータを持ってるのが問題

  • UITableViewDataSource で使うものもControllerにあってあんまり美味しくない

ViewControllerが持ってしまってる責任が3つもある

  • ViewControllerの責任
  • UITableViewDataSourceの責任
  • UITableViewDelegateの責任

責任の分割

  • ViewControllerの責任
  • UITableViewDelegateの責任

モデル部分は別に分けてしまって、DataSourceは外に出す

特にひどいMasterDetailApplication

  • MasterDetailApplicationはやばい
  • CoreDataは難しいのに、AppDelegateが責任持ちまくり
  • エラーハンドリングをちゃんとやってない

OpenGL Application

  • 400行以上ある

ましになったテンプレート

  • Page-Based Application
  • Sprite-Kit

最近作られたものはまともなテンプレートになってる

ファイル数が増えるデメリット

  • SRPだとクラスが増える
  • クラスエクプローション
  • あんまりない

「OHHTTPSutbsを使って進めるiOSアプリ開発」@yimajoさん

OHHTTPStubsを使ったiOSアプリ開発

  • 通信をフックしてレスポンスのstubを行うライブラリ
  • レスポンスのステータスコードも決められる

APIがまだ出来てなくてもテストを書いていける

  • APIの仕様を決めて実装を進められる
  • サーバ側がまだ実装されてなくても、アプリ側の実装を進められる

  • リリースビルドに含めないようにする

  • リジェクトされる

まとめ

  • API開発者にスタブ用のデータは作ってもらおう
  • スタブはあくまで単体テストのためだったり無駄なコミュニケーションの時間を減らす
  • WebViewも同じようにレスポンスのstubできる?

「地方零細スタートアップの失敗ノウハウ」Masayasu Shigeokaさん

「地方零細スタートアップの失敗ノウハウ」in iOSスタートアップ勉強会 #3

  • 福岡でiOSアプリのセミナー

ビジネス担当としての失敗事例について

何でもできます!

  • 何でもできるというと、何を注文していいのか分からない
  • お客から見て専門的な事に絞る

お金のコンプレックス

  • 1000万の札束メモを使ったお金の苦手の意識を解決

やらないことを決める

  • やらないをきめて、他に集中する

受託サービス嫌い

  • 立ち上げ労力がかかる
  • スタッフの給料とかの問題
  • 受け入れると安定して資金ができるので経営が楽

過剰なサービス提供

  • お客が求める需要よりも大きすぎる提供
  • 営業のバランスがわるくなった。
  • バランスをちゃんと決めて提供する
  • 他の企業への経営に入ってバランスを学ぶ

体のメンテナンス

  • 体壊れた
  • 体のメンテナンスを定期的に行う

起業前

  • 起業時の計画は上手くいかない
  • ビジネスをやればやるほど「なんか違う」
  • ポジショニングだけ変えて再スタート
    • ITエンジニアを大事にする企業をサポートしていく

「iOSでの計測とカイゼン」Gunosy @y_matsuwitterさん

iOSの検証と改善 // Speaker Deck

  • 最近GoLangを書いてる
  • 数字は紙より正しい

改善 > 開発

  • リリースより、改善の方が大事
  • 1つの改善の効果を見るのに大体3週間かかる
  • 時間がない

無駄なく改善したい

  • 仮説の精度
    • 目的をしっかり決める
    • 各画面の遷移などから明確に定義していく
    • 会社内に仮説のナレージをためる
  • 検証の精度
    • 外部の計測ツールについて
    • なんとなくスクリーンビューとかが見える
      • 数値が何となくしかでてこない
      • セッション単位で何をしたかぐらいな感じ
    • 検証をする上であんまり使いやすくない
    • 仮説の検証に必要な変数を用意しにくい
    • 仮設用のログを取る仕組みを取る必要がある
    • 自前でLoggerを作成してる
      • 各ユーザーのクリックや遷移や滞在時間等を取得してる
  • 検証の手数を増やす
    • 開発と検証の分離
    • リモートから変更可能なUI
      • APIレスポンスにUIに関数情報を含める
      • { color : 'xxx' : 'size' : "xxx"}`

「NJKWebViewProgressを使ってローディングの表示を工夫する」@ninjinkunさん

アプリ内にWebViewを使いたい

  • 大分サイトを表示したい
  • アプリの画面をHTML+JSで作りたい
  • ヘルプやガイドなどをHTMLにしたい

アプリ内WebView

  • ローディングの白い画面が出てしまう
  • コンテンツにローディングアイコンを出す
    • 消すタイミングが難しい
    • UIWebViewDelegateで消す
    • 読み込み完了 ≠ 画面が表示
  • HTMLが見える前に処理が始まってキレイにフェードできない

ninjinkun/NJKWebViewProgress

まとめ

  • 白い画面をさけよう

「私のアプリがTVで紹介された時の話」- koogawa

  • ダウンロード40万ぐらいのまりもアプリ
  • ダウンロード数が一瞬で3倍ぐらいになった

放送前

  • 事前に使用許諾メール
  • メール見てなかった
  • きゃか出してないけど放送された

放送後

  • テレビ局にお礼のメールした
  • 放送時の映像を送ってもらった

「メモリを節約する工夫」- @k_katsumi

メモリを節約する工夫

  • ユビレジのメモリ消費
  • 普通の画面フローで40MBもメモリ消費してしまっていた
  • 今回これを改善した
  • 画像が大量にある
  • 4画面ぐらい確保 + 画像が一杯あったのでメモリ消費されてた

解決方法

  • 大きな1枚の画像 => パターン的に使える画像に分割して利用
  • 小さい画像を分割してパターンを利用するようにした
  • 複数の箇所で同じ画像が使いまわす
  • 20MBぐらいまで減った

連打や同時押しに気をつけよう

  • ナビゲーションバーをカスタマイズしてるアプリでの問題
  • 同時押しの対応をしないと、Navigation Stackに不整合がおきて死ぬ問題
  • UIButtonのexlusiveTouch = YESにして排他的にボタン処理をする
  • デフォルトexlusiveTouch = YESにしてしまうとかでもいいじゃないかな

「アプリのインタラクションデザイン」@yskm_

  • Share画面
  • openFrameworks
  • デジタルサイネージ
    • OpenCVを使って動体を検知してインタラクション的な映像
  • cal
  • アイコンのPicker
    • 選択した時に震えるフィードバックして選択できることを示してる
    • UIScrollViewベース + アイコンのPickerViewで表示
    • Scrollしてる位置でalpha値とかを変えてる
    • scrollDidEnd でアイコンの位置を決定してる

「iPad 観光アプリのご紹介」- @aplink_hidaka

  • 観光するときにどうやって情報を収集するうか
  • それを行うiPadアプリ
    • 福岡の糸島エリア
  • お気に入りのスポットの順番を並び替え出来る
    • 情報誌とかだと順番は管理できない
  • 個人だと広報が難しい
    • 福岡ローカルで放送してもらった総合のランキングに入った

人力で調査、反映してる

  • マネタイズは難しい
  • 採算性は全然あわない

「ショートムービーアプリ•メチカブーラ」@kaz_piro_piroさん

  • デザイン
  • 美容室を起業

動画アプリ

  • スタンプを動画に貼れる感じ
  • 15秒
  • メインが2秒x6コマ
    • ユーザーは後からコマを切り出すのが苦手
  • 投稿の9割ぐらいは非公開になった
  • リテラシー低い人はオフラインでアプリを教える
    • その活性化する週末を以下に最大化するかについて

メモ : Markdown Life

懇談会はにんじんくんさんとiOSアプリのコードレビュー的な勉強会あると楽しそうだよねという話をした。

1 2 3 4 5 6 40
プロフィール: azu(アズ)
JavaScriptやObjective-CやWeb系色々について。
  • OS:Windows Vista, 7、Max OS X
  • ブラウザ:Firefox
  • Twitterのアカウントはこちら
  • azu_re
  • メールアドレス(Twitterの方が確実)
  • info@ドメイン名
リンク