Crystal でのプログラミングを支援するツール達

この記事は Crystal Advent Calendar 2015 の13日目の記事です.

Ruby の構文が好きなので Crystal もぼちぼち触っていて,標準ライブラリに Random::MT19937 とか Array#transpose を実装したり,Lisp 実装してみたりコマンドラインからドキュメント開くやつつくったりしています.

また,Vim 上で Crystal のコードを書くために vim-crystal というファイルタイププラグインをつくっていて,これから紹介するいくつかのツールも統合されています.

Crystal はつくりかけの言語であり,まだまだ言語機能的にも変更があったり足りないところがあったりしますが,つくりかけながらもプラグラミングをサポートする機能やツールがいくつかあります.今回はそれらを紹介します.

紹介するツール

Crystal Tool

Crystal Tool は Crystal コンパイラが公式にサポートしているツール群です.コンパイラの一部として実装されているので,下記のコマンドで概要が表示されます.

$ crystal tool

実装者は implementationscontext@bcardiff さん,それ以外は @asterite さんです.

format

crystal tool format はコードを整形するフォーマッタです.Crystal で推奨されているコードスタイルでコードを整形できます.最初は公式でフォーマッタが実装される予定は無かったのですが,方針が変わり 0.9.0 で実装されました.

引数を何も指定しないとカレントディレクトリ下の Crystal コードを,ディレクトリを指定するとそのディレクトリ下の Crystal コードを,ファイルを指定するとそのファイルをそれぞれ整形します.

~/Dev/github.com/rhysd/Crisp % crystal tool format
Format ./foo.cr
Format ./spec/helper.cr
Format ./src/crisp/core.cr
Format ./src/crisp/env.cr
Format ./src/crisp/error.cr
Format ./src/crisp/evaluator.cr
Format ./src/crisp/expr.cr
Format ./src/crisp/interpreter.cr
Format ./src/crisp/printer.cr
Format ./src/crisp/reader.cr

どんな感じで整形されるのかは,試しに自分のプロジェクトに整形をかけてみた diff を gist に貼ったので,そちらを見てみてください.

Go 言語の gofmt のように,Crystal のコードを書く時はこれでコードを整形することが推奨されています.vim-crystal では Vim のコマンドで直接カレントバッファを整形したり,保存時に整形したりできます.

implementations, context

crystal tool implementations は,メソッド呼び出しから呼び出し元がどこで定義されているかを解析します.

また,crystal tool context は Crystal コードの特定の箇所におけるコンテキスト(式や変数およびその型)を表示してくれます.

Open Class などの機能がある Crystal ではコード全体を見ないと特定箇所のコンテキストが定まらないので,これらのツールはプロジェクト全体のファイルをターゲットとして実行する必要があります.また,-c でファイル内の位置を指定する必要があります.出力は -f で指定でき,人間に優しい text フォーマットとプログラムに優しい json フォーマットが選べます. ユーザが直接使うものというよりは Crystal 用のツールやエディタプラグインが使うもので,atom-crystal-tools, vim-crystal では既にサポートされています.

Crystal は型推論やテンプレートを使って極力型を書かなくて良いようになっているので,こういったツールで式が実際にどのような型になっているのかや,どこのどのメソッドを呼び出しているのかなどを確認できます.

手前味噌ですが,vim-crystal ではこのようにカーソル下の呼び出し元にジャンプしたり,カーソル下のコンテキストが表示できたりします.

screenshort screenshot

hierarchy

crystal tool hierarchy は,指定したファイルのクラス階層を表示してくれるツールです.これによって,実際にメソッドのテンプレートがどのようなメソッドを生成しているかや,ジェネリックなクラスがどのようなクラス (struct) を生成しているかを見ることができます.Crystal のコードを書いている時だけでなく,Crystal コンパイラ本体のデバッグをしている時にも便利です.

試しに手元のプロジェクトで crystal tool hierarchy を実行してみた 出力結果を gist に貼ってみました

なお,vim-crystal では :CrystalHierarchy でカレントバッファに対して直接実行できます.

crdoc

github.com

crdocコマンドラインから Crystal のドキュメントを開くためのコマンドラインツールで,Crystal で書かれています.

Crystal は元々ドキュメントサーバを立ててブラウザからドキュメントを見られる仕組みがあるのですが,コマンドライン内でコードを書いているときはシェルから直接ドキュメントを開けると良いなと思いつくりました.

main usage

release ページ から落としてきたバイナリなり,ビルドしたバイナリなりを PATH の通ったディレクトリに置くとすぐ使えます.初回時にキャッシュを生成するためにリポジトリを clone してくるので,少しだけ時間がかかります.

基本的には crdoc search 検索ワード で検索し,複数の候補が見つかった場合は選択肢が表示されますので,番号で指定すると対応するドキュメントが開きます.

また,pecopercol のようなフィルタリングツールも意識していて,例えば OS X だと下記のようなコマンドでドキュメントをインタラクティブに絞り込んで選択できます.

$ open "$(crdoc list --path | peco)"
$ open "$(crdoc list --path | percol)"

peco example

この他にも rake の Crystal 版である crake など,色々なツールが Crystal で書かれています.

Playground

最近の多くの言語にあるように,実は Crystal にもブラウザ上で言語を試せる Playground があります.Crystal collaborator の @jhass さん作です.

carc.in

常にリリースされた最新の Crystal が利用できるようになっており,バグ報告やコードの共有などで使われています. Crystal は LinuxOS X では簡単にインストールできますが,それ以外の対応できていないプラットフォームでは playground で Crystal を試すことが出来ます.

f:id:rhysd:20151212182246p:plain

まとめ

Crystal のコードを書く上で便利なツールを紹介しました.これ以外にも依存管理をやってくれる shards など便利なツールがたくさんあるので,ガンガン活用していきたいです.

いらすとやヘビーユーザのために Irasutoyer というアプリをつくった

この記事は いらすとや Advent Calendar 2015 の6日目の記事です.

いらすとやとは?

いらすとや とは,フリーのかわいいイラスト素材を提供しているサイトです.実用的で種類が豊富,たまにシュールなのもあり,利用条件のゆるさから至る所で使われています.この間は近所のヨドバシでも使われてました.

http://www.irasutoya.com/

検索性の問題

いらすとやでは10000点以上のイラストが公開されています.その多さゆえ,ほしいイラストを探すのは少し大変です.unite.vim のようにさっとインタラクティブに絞込み検索できれば良いなぁと思っていました.

いらすとやヘビーユーザのためのデスクトップアプリ Irasutoyer

というわけで,今回はいらすとやをもっと便利に利用するためのアプリ Irasutoyer(イラストヤー)をつくってみました.

https://github.com/rhysd/Irasutoyer

$ npm install -g electron-prebuilt irasutoyer
$ irasutoyer # start app

現在は npm パッケージとしてのみ公開しているため,下記のようにしてインストールします.もしパッケージングして欲しいという方がいましたら,対応しますのでご連絡ください.

screenshot

インクリメンタル検索用のテキストエリアがアプリの一番上にあり,その下にイラスト一覧のリストがあるだけの非常にシンプルなアプリです.

検索窓に入れたものがインクリメンタルに検索され,絞り込むことが出来ます.スペース(全角可)で区切ることで複数の検索ワードを指定できます. ほしい画像が見つかったら,そのアイテムをクリックすると本家のいらすとページがブラウザで開きます.また,テキストエリアで Enter を押すと一番上のアイテムをクリックしたのと同じ動作をします.

画像のダウンロードまですべて自動化してしまうといらすとやさんの広告利益的に問題がありそうだったので,一旦本家のページを経由するようにしました.また,アイテムの右側の「…」ボタンをクリックすることで markdown 形式のリンクをクリップボードへ保存するなどの便利アクションが取れるようになっています.

いらすとやのイラストは日々更新されますが,Irasutoyer はローカルに保存したキャッシュを使っているため動的にそれを反映することはできません.キャッシュを更新するためにはアプリ右上の更新ボタンを押して再度スクレイピングする必要があります.スクレイピングはいらすとやに負荷をかけないようにかなりゆっくりやるので時間がかかります.アプリ初期時は2015/12/5時点でのキャッシュが bundle されています.

unite.vim の source をつくることも考えましたが,画像メインなので画像が簡単に表示できない Vim 上でやるのは得策ではないとなってやめました.

実装について

Electron で作成しました.OS XLinuxUbuntu) では動作確認済みで,Windows でも動いているようです.

機能自体は非常に簡素ですが,テキストの入力に対してリストを動的に絞り込んだりもとに戻したりする動的な処理が必要な SPA です.今回は React を使ってレンダリングし,Redux を使って状態管理をしました.また,UI は React 向けコンポーネントライブラリの material-ui を,言語は TypeScript で書きました.

いらすとやのイラストは10000点以上あるため,そのままリスト全体を表示すると重すぎて表示できません.かといってページングしてしまうとクリック数が多くなって不便です.リストの全体をレンダリングするのではなく,見えている領域のアイテムだけを描画してスクロールを自前でハンドリングする必要があります.そこで,今回は infinite list 系の React コンポーネントである react-infinite を使いました.

実装行は大体1200行ぐらいです.

お気に入りイラスト

favorite

これは「犬の顔のイラスト」 です. マークダウンプレビューアプリ Shiba のアイコンに使わせていただいています.どう見ても柴犬ですが,「柴犬」で検索してもヒットしないところがポイントです.

まとめ

いらすとやヘビーユーザのために簡単にほしいイラストを見つけられるデスクトップアプリ Irasutoyer を作成しました.これからもいらすとやさんにはお世話になります.

「とりあえず入門書は読んだけど…」の次に進むプルリク駆動学習

汎用性の高い技術ポエム Advent Calendar 2015 の3日目の投稿です.

普段はつくったものの紹介とか技術的に調べたことのメモとか勉強会参加記事を書いていて雑感とかは大体ツイッターに書いているんですが,最近どことなく頭にこびりついていることがあるので整理がてらブログに書きます.

とりあえず入門書は読んだ問題

新しい言語やフレームワークを学ぶ動機は様々です. つくりたいものがあってそれをつくるための知識として,言語機能が魅力的だから,流行っているからなどなど… 僕は一番最初の理由で始めることが多いですが,どれが良いとかいう話ではなく Pros Cons があると思います. 例えば僕の場合はつくりたいものが先にあるので体系的に学ぶよりはチュートリアルなどをさっと済ませてしまって動くものに取り掛かるので知識が偏ったりします.

そしてとりわけ後者2つに多いのが「とりあえず入門書は読んだけど次どうしよう」問題だと思っています.実際に「何かつくるアイデア無い?」とか聞かれることはたまにありますし,入門書を読んだだけで終わってしまうケースもあり勿体無いと思います.(僕も身に覚えがあります…) なぜこうなりがちなのか考えてみると,入門は大体皆同じような道を辿って学習するので本にしやすくやることもはっきりしやすくて良いのですが,その後進む方向はより具体的になって人によってばらばらになるからじゃないかなと思っています.

そんなときはプルリク駆動学習?

この「とりあえず入門書は読んだ」問題の次に進むのに,最近「こうすれば良いんじゃないかなぁ」と思っているのが GitHubPull Request(プルリク)駆動学習です.ざっとまとめると次のような手順です.

  1. 入門した言語・フレームワークを使ったプロジェクトで気になるもの,貢献したいものを探す
  2. そのプロジェクトのコードを読みまくる,何かのツールなら使いまくる
  3. 小さくても良いので改善点や不満点が出てきたら実際にコードをいじって直してみる
  4. プルリクエストにしてレビューを受ける

1. 入門した言語・フレームワークを使ったプロジェクトで気になるもの,貢献したいものを探す

学んだ言語・フレームワークで書かれたものを探します.何か気になっているものがあればそれを,無ければ GitHub で検索 します. 何でも良いと思っていますが,次の点に注意するのが良いのかなと思います.

  • なるべく小さいものを選ぶ(大きすぎると読むのが大変で 2. で力尽きそうです.1000〜2000行ぐらいが良さそう?)
  • 作り捨てられたものではなくメンテされているもの,テストがあるもの
  • Issues や Pull requests で活発に反応がある
  • マージ前にプルリクエストにレビューが入っている(重要)
  • すでに詳しい知人がいれば,その人のプロジェクトとか

2. そのプロジェクトのコードを読みまくる,何かのツールなら使いまくる

読んでいるコードは「同じ言語・フレームワークを使うけれども自分よりも習熟した人」が書いたコードのはずなので,基本的に読むだけでもかなり勉強になると思います. また,(printf などをはさみながら)実際に動かしてみるとどこがどう動いているのか分かって良いと思います.

ここでは,コードの書き方だけでなく,関連ツール群の使い方とかテストの書き方なども読み取れます(なかなかそういうことは入門書には書いていないと思います).

3. 小さくても良いので改善点や不満点が出てきたら実際にコードをいじって直してみる

そうこうしているうちに,「こういうオプションがあると便利なんじゃないか」とか「ここはこうコードを変えたほうが効率が良いんじゃないか」とか「ここ間違ってるんじゃないか」とか出てくると思います.(TODO とか FIXMEgrep してみるのも有効かもしれません.)

ここでリポジトリを fork し,新しいブランチ(名前は変更内容を反映していると良いですが,小さい変更なら patch-1 とかでも良いと思います)を作成し,実際にコードを足したり修正したりしてみます.

おそらく一発でうまくいかないので,デバッグしたり色々試したりすることになります.新規追加ならその箇所のテストを,修正なら修正できたことが確認できるテストを実際に書いて走らせてみます.

4. プルリクを出してレビューを受ける

GitHub の自分の fork したリポジトリページに行き,プルリク作成ボタンを押します. 自分の変更の目的・理由や変更内容の説明をします.あと,素直に「初心者なのでレビューお願いします」と書いておいたり,レビューしてほしい点をまとめて書いておくとさらに良いかもしれません.

ここで受けるレビューがとても勉強になると思っています.merge する側にとっても修正や機能追加してくれるのはありがたいですし,merge した後は自分がメンテしないといけないコードなので,積極的にレビューしてくれる可能性が高いです. 指摘された箇所はガンガン直していきます.ただし,プルリク作成時は以下の点に注意したほうが良いと思います.

  • ローカルでテストが通ることを確認する
  • CONTRIBUTING.md がある場合は絶対読む
  • コードスタイルに気を配る

英語が必要になったりしますが,相手も人間なので頑張れば割と通じます.日本語の issue OK なリポジトリを探してみるのも良いかもしれません(1. がちょっと大変になりますが…) また,3. の時点で書ききれなかった場合でも [WIP] とタイトルの頭につけてとりあえずでプルリクを出し,プルリクの説明中に目的ややりたいこと,どこで詰まっているかを書けばアドバイスがもらえてプルリクを完成出来たりします.

僕の場合

僕の場合は

などなど… どれも学習の助けになったと感じていますし,自分の欲しかった機能が入ったりリリースノートに自分の名前が載ったりして良かったです.

まとめ

GitHub は単なるリポジトリホスティングサービスじゃなく,ある種の SNS だと感じているので,それを学習に生かせるんじゃないかというのが最初の考えでした. もちろん必ずこれでうまくいくと思っているわけではないですが,「とりあえず入門書は読んだけど次どうしよ…」となったときの進め方の1つとして有りなんじゃないかなと思っています. 思っていることを整理しながら書いたのでところどころ偉そうな文になっている気がしますが,僕も分かっていないことだらけなのでもっと実践していきたいです. 「試しにやってみた」とか「ここはこうやったほうが良い」とか「もっと良い方法知ってる」などありましたら,ぜひ教えてもらえると喜びます.

なお,(力不足ですが)僕のリポジトリはどれも日本語 OK プルリク歓迎です.