Sublime Text3で書いたファイルをVagrant仮想環境に同期させる

うちのPython環境はVagrantで作ったゲストOSの中にある。
一方でエディタはSublime Text3を使っている。flake8で補完が効いてらくらく。
なので、ホストOSでSublime Text3を使って書いたファイルを、手間なくゲストOSにも同期させたいと思っていた。

Sublime Text3にはSFTPパッケージがあるので、最初はそれを使おうと思っていたが、それよりもVagrantで共有フォルダの設定をしてしまった方が楽だと気づいた。SFTPパッケージは$30かかるし。

rsyncを使う

ファイルの共有を楽にするためには、vagrantrsync機能を使うのがおすすめ。前提としてVagrantのバージョンは1.5以上が必要。
これを使うと、 vagrant rsyncコマンドを打つだけで同期ができる。
さらに、 vagrant rsync-autoとすれば、共有フォルダを監視してくれて、ファイル更新のたびに自動で同期される。

ちなみに、vagrant rsyncが有効なのは、ホストOS→ゲストOSという流れでファイル共有をするときのみ。
その逆をしたいときは、Vagrantの外部プラグインを使う必要がある。例えばvagrant-rsync-backなどがある。

共有フォルダの設定をする

Vagrantfileの中に設定を書き加えればよい。

www.vagrantup.com

このとき、rsyncを使うために、オプションとしてtype: "rsync"とする必要がある。 設定の例はこんな感じ。

Vagrant.configure("2") do |config|
  # other config here

config.vm.synced_folder "/Users/Udomomo/python_project", "/home/vagrant/python_project/",
   type: "rsync",
   owner: "vagrant",
   group: "vagrant"

end

【17/10/15 追記】 上記だけでは足りなかった。以下のようにしなければならない。

config.vm.synced_folder "/Users/Udomomo/python_project", "/home/vagrant/python_project/",
   type: "rsync",
   owner: "vagrant",
   group: "vagrant"
   rsync__exclude: [".git", ".gitignore", "tmp", "log", "cache"],
   rsync__chown: false

rsync__excludeは、ゲストOS上で同期の対象外とするファイルやディレクトリを指定する。.git.gitignorelogcacheなどを設定するとよい。
これが必要なのは、rsyncによる同期をするとホストOS上にないファイルは全て削除されてしまうから。ゲストOS側でgitレポジトリを作った後に同期をしたら、レポジトリが消えてしまうという痛い目に遭った。

また、rsync__chownは、rsyncによってゲストOS側のファイルのオーナーやグループ名などが変わらないようにするための設定。v1.6.3から追加されたとのこと。
【追記終】

後はVagrantを再起動させれば、設定が完了する。
vagrant rsync-autoとしておけば、ホストOSのUsers/Udomomo/python_project配下で更新されたファイルが、ゲストOSの/home/vagrant/python_project/配下に自動的に同期される。

ちなみにこの設定だが、複数個書くこともできる。新しいプロジェクトが始まるごとにVagrantfileに書き足し、不要なものを消せばよい。
共有フォルダを一つしか設定できないと、毎回そこに行ってファイルを取ってこないといけないので、複数個設定できるのは本当に助かる...。

TypeScriptの型推論について学んだ

型推論とは

最近TypeScriptを使って開発していたけれど、大きな勘違いをしていた。
強い型付けをする言語ということなので、変数を定義するときに毎回型を宣言しなければいけないと思っていたのだ。
例えばこんな感じ。

let x: number = 3;

人間から見れば、この number はノイズでしかない。3は数値だと、誰が見てもわかるはずだ。
入力が手間なうえ、可読性を下げてしまう。

この場合は以下のような記述で問題ない。

let x = 3;

TypeScriptは3が数値であることを知っており、xを数値型とみなしてくれる。これを型推論という。

「最も共通する型」による型推論

この機会にもう少し公式ドキュメントを読んで深掘ってみる。
例えば以下の場合は、Arrayであることは間違いないが、その要素の型は何と推論されるだろうか?

let x = [0, 1, null];

TypeScriptは、提供される候補の型から「最も共通する型」を選ぶ。これは、他の全ての候補と互換性がある、すなわち他の候補がその型からの派生した型であるという意味だ。
上の場合、Arrayの中にはnumberとnullの2つの型があるが、TypeScriptでは、nullは全ての型の部分型(subtype)とみなされる。
このため、上の変数xの型はnumber[]と推論される。

ちなみに、この方法で型が選べない場合は、推論の結果が空のオブジェクト{}になってしまうので、最初に示したように自分で型を書いてやる必要がある。

「文脈上の型」による型推論

さきほどの共通する型による型推論は、平たく言うと右辺をもとに左辺の型を判定するという流れだった。
しかし、その逆で左辺から右辺の型を判定することもある。

window.onmousedown = function(mouseEvent) {
    console.log(mouseEvent.button);  //<- Error
};

上の場合、mouseEventの型は定義されていないはずだが、なぜエラーが起きるのだろうか?
TypeScriptは以下のように推論するようだ。

window.onmousedown は、mouseEvent型の引数を取る関数であることを知っている
・このため、右辺の引数 mouseEvent は、 mouseEvent 型であると推論される
・しかし、 mouseEvent 型に button というプロパティはない。そのためエラーとなる
developer.mozilla.org

このとき、function(mouseEvent: any) {...} のように、引数mouseEventの型を明示していれば、推論が上書きされてエラーは生じない。

人間が快適にコードを書けるよう、影でいろいろな苦労があるんだなあとしみじみ実感した。

ReactとHTMLでは使えるAttributes名が違うことがある

Reactで class のAttributeを出力しようとしたら、Visual Studio Codeが以下のようなエラーを返してきた。

[ts] Property 'class' does not exist on type 'DetailedHTMLProps<HTMLAttributes<HTMLDivElement>, HTMLDivElement>'.

何かと思ったら、単にJSXで class が使えないというだけだった。
class はJSでの予約語なので、HTMLをrenderしたいときは className を使わなければいけない。
HTMLをJSで扱えるようにしているので、このようなコンフリクトが生まれるのは確かに仕方がないだろう。

他にもこのように名前が違うケースがあるのだろうかと思って調べたら、Reactの公式ドキュメントに一覧が載っていた。

facebook.github.io

checkedhtmlFor などは、フォームを作るときによく使いそう。
単純な話だけど、知らなかったので時間を食ってしまった。

Javascriptでサイコロスロットを作ってみました

フロントエンド開発の業務に来月から入るので、今のうちにJavascriptを勉強中。
まだ何のライブラリも使えていない素のJavascriptですが、とりあえず何か作ろうと思い、サイコロスロットを作ってみました。

See the Pen Dice Roll Game by Udomomo (@Udomomo) on CodePen.

Rollボタンを押すとサイコロが回り、Holdにチェックを入れると回らなくなるという単純なものです。
目の合計がgoalの数字と同じになれば終了。

とりあえず、思ったものを無事に作れてよかったです。
これを作るのに正味5時間くらいかかったけど、そのうち半分くらいは実はCSSだったりします。
これくらいのCSSなら見よう見まねで書けるだろうと思って勉強してなかったんですが、ものすごく苦労しました。ちゃんと体系的に基礎を学ばないといけないですね。
本当はFlexboxとか使ってみたかったんですが、永遠に完成しない気がしたのでまた今度。

習作なので粗があると思います。
突っ込みがあればどんどんしてください。コメント・フォークなどどなたでも大歓迎です!