ushumpei’s blog

生活で気になったことを随時調べて書いていきます。

Railsからキーがキャメルケースのjsonを返す(jbuilder)

 Reactでアプリを書いていて思ったことのメモです。

 大概jsのオブジェクトのプロパティはキャメルケース(camel case)ですよね。
 Railsをサーバサイドにしたのですが、返却されるjsonがスネークケース(snake case)でした。

 クライアントサイドで書き換えるのも面倒だと思ったので、調べてみたところRails側で対応するのが楽なようです。

内容

 Rails(4から?)はjsonをリクエストした際に返却するオブジェクトの定義を、jbuilderというテンプレートエンジンで行うようです。

生成されている(例: _model.json.jbuilder)ファイルの先頭に

json.key_format! camelize: :lower
...

と記述するとキャメルケースに変更できました。

感想

 ちゃんとしたapiを作るならkey_formatも引数で指定できたほうがいいのだろうか?と思いましたが使う気がしないので何もしませんでした。
 クライアントからサーバへの送信の際にも書き換えが必要になると思いますが、どうしようかなーと考え中です。

 json.key_format!は単に文字列変換の関数を引数にとり、keyに適応する関数のようです。ここではcamelize: :lowerを渡していますが、他にも色々渡せますね。
 この関数はそんなに使い込む機会はないと思いますが、私は関数を引数に取る関数が結構好きです。だからどうしたという話ですが。

rubydoc: Jbuilder:key_format!

Promise + reduceで逐次処理

setIntervalでもいいですが、Promisereduceでもできるようです。

/* 逐次処理したいデータ */
const arr = [1,2,3,4,5];

arr.map( /* データの配列から`Promise`を返す関数の配列を作る */
  e => (
    () => new Promise(
      (res, _) => {
        setTimeout(
          () => {
            /* ここに処理を書く、ここではコンソールに出力 */
            console.log(e);
            res(e);
          },
          /* 処理の間隔 */
          1000
        );
      }
    )
  )
).reduce( /* reduceを使って、Promiseをthenでつなぐ */
  (p, c) => p.then(c),
  Promise.resolve() /* 初期値 */
)

一応のメリットは、処理を中断する際の記述がわかりやすくなることだと思います。

const arr = [1,2,3,4,5];

arr.map(
  e => (
    () => new Promise(
      (res, rej) => {
        setTimeout(
          () => {
            if(e == 4) return rej('4 is an unlucky number');
            console.log(e);
            res(e);
          },
          1000
        );
      }
    )
  )
).reduce(
  (p, c) => p.then(c),
  Promise.resolve()
).catch(
  e => console.error('Error!!!: ' + e)
)

ちゃんとする場合はsetTimeoutのコールバック関数内にtry...catchで記述するのがいいでしょう。

setTimeout(
  () => {
    try {
      if(e == 4) throw new Error('4 is an unlucky number');
      console.log(e);
      res(e);
    } catch(e) {
      rej(e);
    }
  },
  1000
);

感想

なんとなくメソッドチェーンにしたがる性分なのかもしれません。

React Native実機動作中のcommand+d

お疲れ様です。

とりあえず結論というか、言いたい事です。

React Nativeで作ったアプリを開発段階で実機にXcodeで転送した場合、
シミュレータでcommand+dしたときに出るメニューは、実機を振ると出すことができるようです。
(2017/02/22時点)

説明

最近、とりあえずiOSアプリのデモ作ってみないか?という縁がありReact Nativeを触ったりしています。

React Nativeはreact-native run-iosとか打てばシミュレータが立ち上がるのですが、カメラを使う機能などシミュレータでできないことは、Xcode経由で実機に転送する必要があります。

シミュレータではLive Reloadという、コードを修正するたびに再読込してくれる機能を有効にできるのですが、実機ではコードを修正するたびにビルド → 転送みたいな事をしないといけないと思っていました。

というのもLive Reloadを有効にするためのメニューは、シミュレータではcommand+dで出るのですが、実機ではショートカット打てないためです。

しかし実機に入れた場合でも、立ち上げ時にはローカル経由でjavascriptを読み込みに行っているようだし(完全にReact Native勉強不足です)。どうにかならないかなーと思い色々いじってみると、実機を振ったらメニューが出ました。その他やってみたこと

  • 音量ボタン同時押し
  • 二本指で画面下をスワイプ
  • 三本指で画面下をスワイプ
  • 二本指で画面をピンチ
  • 三本指で画面をピンチ

だからどうしたという感じですね。

感想

結局実機を振るとメニューが出たのですが、振る動作を使ったアプリを作りたい場合はどうするのでしょうか?

それはそうと毎回場当たり対応で知識が集積していかない感が集積しています。

ブラウザでテキスト読み上げるコンポーネント: react-voice-components

テキスト読み上げをしてくれるReactコンポーネントの存在を知りました。grvcoelho/react-voice-components

ブラウザで音声を使って何かしたいと思っていたので、試しに触ってみて、GitHub Pageにあげてみました。 以下ちょっと苦労したので、メモです。

Reactを動かせる環境の作成

半年前くらいに作ったコンパイルの環境がかなり古くなっていたので、facebookincubator/create-react-appで作り直しました。インストールに少々時間がかかりましたが、とても便利ですね。

npmで入れたreact-voice-componentsが動かない?

npmで入れたreact-voice-componentsだと、create-react-appで作った環境との相性なのか、コンパイルされずブラウザエラーが発生して動きませんでした。webpackの設定ファイルを上書けばいいようですが、とりあえず、git submoduleリポジトリコンパイル対象のディレクトリにクローンして使用することにしました。せっかくなので、本当に問題があるのなら、いずれ修正を送ってみようかと思います。

書いたコードです;

ushumpei/play-with-react-voice-components

GitHubページを公開する

GitHubページの公開方法は3つあるようで、mastergh-pagesブランチのindex.htmlからか、master/docsを使うか、だそうです。

今回はdocsを作成して公開しました。静的リソース(cssjs)の指定が絶対パスだったため、読み込まれなくて困りました。

感想

  • テキストから音声ファイルとして吐き出すことはできるか気になりました。
  • Reactで綺麗に書けるようになりたいです。
  • GitHubはとても太っ腹です。
  • リポジトリの作者がすでにデモページを作成してくださっているようです。。。

GitHubのIssuesを閉じる方法

GitHubのIssuesを閉じる方法、GitHubのHelpページでも紹介されていますが、commit messageに関して書かれているだけなので、PullRequestからでも閉じられるか確認しました。

確認内容

結論から言うと、PullRequestからでも閉じられます。

以下試したことです。これらは全て、マージするとIssue nを閉じてくれました。なお確認したのは、PullRequestの向き先がmasterの場合です。;

  • commit messageの1行目にClose #nが記述されたcommitを持つPullRequest
  • commit messageの3行目にClose #nが記述されたcommitを持つPullRequest
  • titleにClose #nが記述されたPullRequest
  • descriptionにClose #nが記述されたPullRequest

試してみたリポジトリ(特にどうでもいい内容です)。

余談

Closecloseでも問題なく、この単語以外には次の単語群が使用可能らしいです。

GitHubのHelpページ

Keywords for closing issues

The following keywords will close an issue via commit message:

close
closes
closed
fix
fixes
fixed
resolve
resolves
resolved

(転載日時: 2016/12/20)

Helpページでは、あるリポジトリから別のリポジトリのIssueを閉じる方法なども紹介されてます。

感想

PullRequestとIssueはID(#番号)の空間を共有していることに今更気がつきました。

repositoryのカタカナ表記をリポジトリとしましたが、レポジトリという発音をよく聞きます、どちらがいいのでしょう?

Yesodのquick startが重い

 題に掲げた問題を解決するための記事ではないです。HaskellのwebアプリケーションフレームワークYesodquickstartをDockerfileで行っただけの記事です。

Dockerfile

 Dockerfileを書きます。

FROM haskell:latest
MAINTAINER ushumpei
ARG project_name
RUN stack new $project_name yesod-sqlite \
  && cd $project_name \
  && stack build yesod-bin cabal-install --install-ghc \
  && stack build
CMD ["/bin/sh"]

 ビルドします。任意のプロジェクト名を引数に取れるようにARGで指定しています。引数を渡すには--build-argオプションをつけて、イメージ自体に名前をつけるために-tオプションをつけます。

docker build -t yesod_sample . --build-arg project_name=sample

 ビルドできたらコンテナを立ち上げます。めちゃくちゃ時間がかかります。。。

docker run -i -t --rm -p 3000:3000 yesod_sample /bin/bash

 立ち上がったらコンテナのシェルが起動します、/以下にARGで指定した名前のプロジェクトができているので移動し、起動コマンドを実行します。

cd /sample
stack exec -- yesod devel

 コンパイルマイグレーションが終わればlocalhost:3000で「Welcome To Yesod!」のページにアクセスできるようになります。

感想

 stack build yesod-bin cabal-install --install-ghcがめちゃくちゃ重くて面倒でした。DockerHubに重い部分がいい感じに済んでいるイメージとかありそうですね。dockerstackyesodとわからないことが二つ以上あるともうしっちゃかめっちゃかです。

Leap Motionを手に入れました

 Leap Motionを手に入れました。Leap Motionは手の動きをかなりの精度で取得できるセンサーです。たくさんの言語でプログラミング可能なAPIが提供されていますが、とりあえずJavaScriptAPIを使ってみます。また、各クラスの内容もざっくりと整理していこうと思います。

 ここでは、開発PCがmacなのでSDKV2 desktopを使います。Windowsの方は新しいSDKが使えるようなのでそちらを使ったほうがいいかもしれません。(VR関係に強化されているように見えます)

参考

とりあえず

 環境設定やインストールは省略します、公式サイトの指示通りにすれば問題ないはずです。

 仕組みを理解するために、とりあえずブラウザ上に手を表示させてみます。まずはセンサーの値を取れるか確認をするためのコードを記述します。

ブラウザのコンソールに吐き出すだけ

<html>
  <head>
    <!-- <script src="./leap-0.6.4.js"></script> -->
    <script src="https://js.leapmotion.com/leap-0.6.4.js"></script>
    <script>
      Leap.loop(frame => console.log(frame));
    </script>
  </head>
  <body>
  </body>
</html>

 LeapJSを外部リソースとして取得します。LeapはLeapJSがネームスペースとして確保しているオブジェクトのようです。

 値をとるにはLeap.loopにコールバック関数を渡します。この関数にセンサーが取得したframeオブジェクトが引数で渡されるので、それに対する処理を記述するのがアプリケーション作成の基本的な流れになると思います。

 frameオブジェクトの詳細はリファレンスに書いてあります。手、指、ツール(棒状のもの)などのデータをプロパティとして持っていてくれています。

プラグイン Rigged Handを使う

 LeapJSはプラグインという形で機能拡張できるようになっています。プラグインControllerクラスによって管理されます。各プラグインpluginメソッドにより登録しuseメソッドにより有効にしたり、useメソッドに直接関数を渡すことで、loop実行時にコールバックとして呼び出されるようになります。

 プラグインを使うための準備として、まずは先ほどの処理をLeap.loopを使わない記述方法に変えておきます。

<html>
  <head>
    <!-- <script src="./leap-0.6.4.js"></script> -->
    <script src="https://js.leapmotion.com/leap-0.6.4.js"></script>
    <script>
      const controller = new Leap.Controller();
      controller.use(
        () => ({
          frame: frame => console.log(frame),
        })
      );
      controller.connect();
    </script>
  </head>
  <body>
  </body>
</html>

 プラグインを追加する準備が整ったところで、リアルな手を表示することができるRigged Handというプラグインを追加してみます。

 プラグインを使用するにはleap.rigged-hand-0.1.7.jsの他に、いくつかのライブラリを読み込む必要があります。useメソッドでriggedHandを使用するようにします。

<html>
  <head>
    <!--
      以下から必要なライブラリを取得
      https://cdnjs.cloudflare.com/ajax/libs/three.js/r70/three.js
      https://js.leapmotion.com/leap-0.6.4.js
      https://js.leapmotion.com/leap-plugins-0.1.10.js
      https://github.com/leapmotion/leapjs-rigged-hand/blob/master/build/leap.rigged-hand-0.1.7.js
    -->
    <script type="text/javascript" src="three.js"></script>
    <script type="text/javascript" src="leap-0.6.4.js"></script>
    <script type="text/javascript" src="leap-plugins-0.1.10.js"></script>
    <script type="text/javascript" src="leap.rigged-hand-0.1.7.js"></script>

    <script>
      const controller = new Leap.Controller();
      controller.use('riggedHand');
      controller.connect();
    </script>
  </head>
  <body>
  </body>
</html>

   動作はこんな感じになりました。実際の手も一緒に撮影すればよかったです。。。


Leap Motion - Rigged Hand Demo

LeapJSのクラスに関する考察

 API Referenceによると、LeapJSには次のクラスが存在します。

制御

クラス名 概要
Controller Leap MotionAPIに接続するためのインターフェース。オプションや、フレーム更新時のコールバックの設定など、最もさわりそうなオブジェクト
InteractionBox Leap Motion Controllerに紐づいた表示領域を扱うオブジェクト?領域に応じたベクトルの正規化方法などを提供してくれるみたいです
Frame センサーがフレーム更新ごとに取得した手、指に関するデータを含むオブジェクト

パーツ

クラス名 概要
Pointable 指(Finger)やツールなどの抽象クラスで位置や方向、速度などを保持しているオブジェクトです
Hand 手のオブジェクトで、5本の指の配列や腕などプロパティに持っています。かなり豊富な情報を持っているようです
Finger 指のオブジェクトで、生えている位置や、手の骨の本数文の骨オブジェクトに関する情報を持っています。何指か、などの識別子も持っています
Bone 骨のオブジェクトで、指の骨を表しています。前後の関節を持っています

ジェスチャー

 ジェスチャーは多いので個々の概要は省略します。認識してくれるハンドサインという認識です。独自に追加できるかはちょっとわからないです。

  • Gesture
    • CircleGesture
    • ScreenTapGesture
    • KeyTapGesture
    • SwipeGesture

計算要素

クラス名 概要
Matrix math 行列のオブジェクト。WebGL用外部ライブラリを使っているようです
Vector math ベクトルのオブジェクト。WebGL用外部ライブラリに入っているvec3を使っているようです

感想

 API Referenceを読んで、勝手に各クラスの概要などを書きましたが、このドキュメントを和訳した方が随分人のためになるんだろうな、と思いました。(もしかしたら和訳されている?)

 まだまだわかっていないことが多いので、ご指摘いただければ幸いです。

screenコマンドの小さな話

 ターミナル操作をいい感じにできる仮想端末マネージャコマンドscreenを最近知りました。メモしておきます。

 私の理解では、ターミナルをラップして、通常のシェル操作に加え、セッション、ウィンドウ、領域という概念を取り込み、それらを操作できるようにするものです。

参考: Screen User's Manual

 screenを実行すると仮想端末のセッション(session)とそれに紐づく一つのウィンドウ(window)が起動します。ウィンドウ内ではいつも通りのシェルの操作に加え、セッションに紐づくウィンドウを複数起動できるようになるので、ssh等でサーバに接続した後で起動すると便利です。今まで複数ログインしていた場合、一度ログインしてウィンドウを複数起動することで済ますことができます。(TeraTermのセッションの複製に似た感じです。詳しく見ていないですが内部的に使っているのでしょうか?)

 使うことのメリットとして、

  • 複数ウィンドウを起動できるので、面倒な踏み台経由のssh接続時に結構楽できます。
  • 接続が切れてもセッションが残っていてくれるので、再度つなぎなおした時に作業をすぐに再開できます。一つのウィンドウで長い処理を走らせて寝かせておくこともできます。

 他にも、コマンドによるコピー&ペーストの操作をキーボードのみでできるようになることも、なかなか嬉しいことです。

基本的な使い方

 触っていてよく使っているコマンドを羅列します。

セッション管理系

コマンド 内容
screen 新しいsessionとそれに紐づいた一つのwindowを起動します。
screen -ls 現在起動しているsessionの一覧を表示します
screen -r 最後に繋いでいたsessionを再開します。sessionのidを渡せば指定したセッションにつなぎ直すことができます
Ctrl+a d session起動中に現在のsessionから抜ける(detach)ことができます。detach後もsessionは起動しているので、一覧で確認できます
Ctrl+a \ session起動中、session自体を削除します。一覧からも消えます。起動中の紐づいた全てのwindowも削除されます。私の環境だとCtrl+a Ctrl+¥になっていました

チートシート

 セッション起動後は、Ctrl+a ?でコマンドのチートシートが表示されます。私のメモの存在意義を奪いかねないですが、ただ表示されるコマンドがアルファベット順なのでちょっと見にくいです。そこに漬け込みます。

 以下主にセッション起動後のコマンドになります。

ウィンドウ管理系

コマンド 内容
Ctrl+a c 新しいwindowを開きます
Ctrl+a k windowを削除します、正確には削除しますか?と(y/n)で聞かれます
Ctrl+a " windowの一覧を表示します。j,kでwindowを切り替えることができます
Ctrl+a N 現在開いているwindowの名前(Name?)を表示します
Ctrl+a n, Ctrl+a p 別のwindowに切り替えます。多分切り替え先はprevious,nextに対応していると思います
Ctrl+a Ctrl+a 切り替え前のwindowに切り替えます

領域管理系

コマンド 内容
Ctrl+a S windowを水平に分割します。windowが紐づかない新しい領域(region)を作成します
Ctrl+a | windowを垂直に分割します。windowが紐づかない新しいregionを作成します
Ctrl+a TAB 分割されたregion間を移動します
Ctrl+a X 分割時、現在有効になっているregionを削除します
Ctrl+a Q 分割時、現在有効になっていない他のregionを削除します

メタ操作系(未整理)

コマンド 内容
Ctrl+[ コピーモードに入ります。hjkl等のvimライクな入力で移動することができます。spaceを押すとコピー開始位置を指定、もう一度spaceを押すと選択範囲をコピーします
Ctrl+] バッファのコピーした内容をペーストします

使っていての感想

 色々あります。

  • Ctrl+aがシェルの行頭移動を奪ってしまいます。Ctrl+a aに行頭移動が振り分けられているので頭を切り替えて使っています。セッションの中にいる、と言うことを意識できるのでこれはこれでいいかもしれないです。キーバインドを変えるのは嫌なので私はこのままです。慣れました。
  • vimの画面分割と一緒に使うと結構混乱します。vimCtrl+w系の画面移動とごっちゃになったり、screenでのコピー範囲が行単位なので行番号入っちゃったりしました。これは対応方法がわからないですが、慣れました。
  • スクロールについて最初どうすればいいか不明でした。ログ出力等で流れてしまった時は、コピーモードに入って遡っています。別にコピーしたいわけではないのでちょっと気持ち悪いです。vimの気分で操作しています、less同様いまだに正しい移動操作がわかりません。
  • macにデフォルトで入っているscreenはヴァージョンが古いようで垂直分割ができないです(2016/12/14に確認)。homebrewで入れ直しました。あと、ssh接続時に便利とか書いていましたが意外にコマンド自体が入っていないことがあったりします、注意です。

 他にもウィンドウ操作を記録することができたりするのですが、使い道がわからず今のところ使っていないです。さらに他にも複数人で同じセッションを共有するマルチディスプレーモードという便利なものもあるそうですが、私はぼっちなので使っていません。

感想

 コピー&ペーストがキーボードから手を動かさずに使えるので、嬉しくてローカルでも使っています。早く使いこなせるようになるといいのですが。まだまだ不明点が多いです。

 上記内容に間違いがあれば申し訳ないですが、修正しますので是非教えていただきたいです。

dockerに関するメモ

golangを少しだけ試して見たくなったけれど、環境を作りたくなかったのでdockerを使って見ました。特に目新しい内容ではないですが、自分用にメモします。

構成というほどでもないですが、

  • コーディング: 自分のマシン
  • 実行環境: コンテナ

とするために、まずはディレクトリを作成し、そのディレクトリをコンテナと共有して起動します。

mkdir ~/my_golang_src
cd ~/my_golang_src
docker run -i -t --rm -v `pwd`:/my_golang_src golang /bin/bash

シェルが開くので、/my_golang_srcに移動してgo runなどでソースを実行できるようになります。

redisのレプリケーション

 redisレプリケーションがとても簡単だったのでメモです。勉強も兼ねてdockerを無駄に使っています。環境は以下です。

  • macOS Sierra
  • Docker for Mac Version 1.12.3-beta29.2

 とりあえずredisが入ったAlpine Linuxのイメージを作成します。my-alpineディレクトリを作りその中にDockerfileを以下の内容で作成します;

FROM alpine:latest
MAINTAINER ushumpei
RUN apk --no-cache add redis
CMD ["/bin/sh"]
$ docker build -t my-alpine .
$ docker run -it --rm  my-alpine

 redisがインストールされた状態でAlpine Linuxが起動しました。

単一マシン上で

 先ほどのmy-alpineを使って、同一ホストで複数のredisを起動し、master、slaveのレプリケーション構成を行ってみます;

/ # redis-server --port 3679 &
/ # redis-server --port 3680 --slaveof localhost 3679 &

 本当はちゃんと設定ファイルを書いたほうがいいんだと思います。レプリケーションを確認すると;

/ # redis-cli -p 3679 INFO
...
# Replication
role:master
connected_slaves:1
slave0:ip=::1,port=3680,state=online,offset=519,lag=1
...

/ # redis-cli -p 3680 INFO
...
# Replication
role:slave
master_host:localhost
master_port:3679
...

/ # redis-cli -p 3679 set hoge fuga
OK
/ # redis-cli -p 3680 get hoge
"fuga"

とちゃんとなっているようです。

docker

 docker-composeでmaster: 1台、slave: 2台の構成を作ってみようと思います。新たにディレクトリ(docker-redisにしました)を作成し、その中にdocker-compose.ymlを以下のように作成しました。

version: '2' 

services:
  master:
    image: redis:latest
    restart: always
    ports:
      - 3679:3679
  slave_1:
    image: redis:latest
    restart: always
    ports:
      - 3680:3679
    command: redis-server --slaveof master 6379
  slave_2:
    image: redis:latest
    restart: always
    ports:
      - 3681:3679
    command: redis-server --slaveof master 6379

 slave_1slave_2からはmasterhostmasterで参照できるようになっているようで、分かるまで悩みました(参考: Compose のネットワーク機能)。docker-compose upで起動します。

 動作確認を先ほどのmy-alpineから行います。--netオプションで先ほどのdocker-compose upで起動したコンテナたちのネットワークに参加します。こうすることで、masterなどのホストを参照することができるようになります。

(ネットワーク名はデフォルトではディレクトリ名_defaultになるらしく、docker network lsでも確認できます。ディレクトリのハイフンが無視されています、どういうルールでしょう?)

$ docker run -it --rm --net dockerredis_default my-alpine

/ # redis-cli -h master INFO
...
# Replication
role:master
connected_slaves:2
slave0:ip=172.19.0.4,port=6379,state=online,offset=2367,lag=1
slave1:ip=172.19.0.2,port=6379,state=online,offset=2367,lag=1
...

/ # redis-cli -h slave_1 INFO
...
# Replication
role:slave
master_host:master
master_port:6379
...

/ # redis-cli -h slave_2 INFO
# Replication
role:slave
master_host:master
master_port:6379
...

/ # redis-cli -h master set hoge fuga
OK
/ # redis-cli -h slave_1 get hoge
"fuga"
/ # redis-cli -h slave_2 get hoge
"fuga"

感想

 redisレプリケーションってすごく簡単にできるように思えました。pub/sub使って何か作ってみたいです。

¥eあるいはedit

 mysqlの対話環境でちょっと長い処理を実行したくなった時のメモです。

 mysqlコマンドを実行すると対話環境が起動します。ただ改行を含んだクエリを書こうとすると、どこか間違えた時に書き直すのが非常に面倒です。

 そういった時は¥eまたはeditコマンドを使うと便利です。コマンドを実行するとエディタが起動し直近に実行したクエリが表示されます。編集を行い保存して閉じるとコマンドを抜けて対話環境に戻ります。あとは;を入力してエンターキーを押せば内容が実行されます。毎回エンターキーを押すのも面倒な場合は、¥e;で実行します、この場合はエディタを閉じたら即時実行されます。

 開くエディタは選べるようです。私の環境ではデフォルトはviでした。これは環境変数EDITORで設定できます。(export EDITOR=vimとか設定しときました)

 調べたいクエリがあった時に、

  1. mysql> ¥e;実行
  2. vimが開くので挿入コマンド:a!でコピーしてきたクエリをペーストする
  3. 適宜修正して:wqvimを終了する
  4. 結果を確認し、必要なら1に戻る

 という感じで使っていました。

 ちなみに¥eを実行した時に編集しているファイルは/tmp以下に作成されていることが確認できました、しかしこれはエディタを閉じると削除されるようです。ちゃんと取っておきたいなら保存した方がいいと思います。(viなら:w ~/hogehogeなど)

感想

 rails consoleでもeditコマンドが使えるみたいですirbはダメか、コマンドが違うようです?)。他の対話環境ではどうなんでしょうか?

追記: 2017/01/13 - 今手元にあるrails 5で試してみると、editコマンドは使えないみたいです。動作が確認できていた環境はすでに手を離れてしまったので再確認できません。。。何かわかり次第追記します。

git logの折り返し

 gitのlogdiff表示時の、文字列の折り返しの切り替え方をメモします。

 自分の環境(mac 10.12terminalgit version 2.8.4 (Apple Git-73))ではデフォルトで折り返しがされていたのですが、以下の指定で折り返しが無効になりました。

折り返し無効

$ git config --global core.pager "less -S"

折り返し有効

$ git config --global core.pager "less -r"

 (デフォルトで有効だったので、折り返し有効のコマンドは未確認です。。。)

 git log --graph --decorateなどでログを見たい場合は、折り返さない方が見やすい気がします。

 ちなみにcore.pagergit loggit diffで表示するときの出力コマンドを指定しているそうで、lessSオプションをつけて折り返しの制御が行われているようです。catとかも指定できるようです。moreは私の環境では文字化けしました。

アロー関数(Arrow function)の書き方色々

 アロー関数は引数や戻り値の種類によって色々な書き方ができます。分割代入を使うことで柔軟な関数をシンプルに宣言できてとても気持ちいです。

 基本的な書き方から、やや直感的ではない書き方まで、メモしていこうと思います。

ざっくり

 アロー関数の記述方法は、引数に関しては、引数なし、引数1、引数N、引数オブジェクトリテラルによる分割代入、の4種類があります。関数の処理部分に関しては波括弧、括弧なし、丸括弧の3種類があります。

  • 引数1、括弧なし
  • 引数N、丸括弧
  • 引数オブジェクトリテラルによる分割代入、丸括弧
  • 引数なし、波括弧

 を並べてみます。

引数1、括弧なし

 引数が1のときは、引数の括弧は省略できて、右側が評価され戻り値が返ります。Promiseのcatchとかすっきりします。

const factorial = n => (n > 0) ? n * factorial(n-1) : 1;

引数N、丸括弧

 引数N個は単純にfunctionのときと同じように並べるだけです。戻り値にオブジェクトリテラルを返したいときに丸括弧を使うとすっきりです。

let projection = (a, b) => ({ 
  x: (2 * a) / (1 + a * a + b * b),
  y: (2 * b) / (1 + a * a + b * b),
  z: (-1 + a * a + b * b) / (1 + a * a + b * b),
});

引数オブジェクトリテラルによる分割代入、丸括弧

 上の例と近いです。ただ引数個数が頻繁に変わる可能性がある場合この記法がいいようです。ですが、個人的に好きなので何でもかんでもこれで書きたいです。Reactの純粋な関数スタイルのコンポーネントを書いたりするとき便利です。

const Deco = ({ deco, children }) => (
  <div>
    {deco + children + deco}
  </div>
);

 呼び出すときは引数で代入しているプロパティをもったオブジェクトを渡せば大丈夫です。引数いっぱいなのは嫌だけど、オブジェクトまるまる渡したら何されるかわからない、といった不安を綺麗に取り去ってくれます。

引数なし、波括弧

 グローバルなオブジェクトに対して何かしたいときに使う、気がします。波括弧なので複数行書くことができます。

const values = () => {
  const inputs = [...document.querySelectorAll('input')];
  const values = inputs.map(input => input.value)
  return values;
};

感想

 戻り値に関して補足です。1行で済む場合は括弧なしか丸括弧、複数行必要なときは波括弧でいいと思います。

 引数オブジェクトリテラルによる分割代入は、修正による影響を少なくできるし、オプションのようなものを渡すことが簡単にできるのでかなり好きです。

 説明の中で複数行とか言っていますが、宣言とか式とか、ちゃんとした言葉をいい加減覚えなければいけないなと思います。

Reactコンポーネントを純粋な関数で書こう

 Reactコンポーネントの書き方は色々あり、es6を使う場合の選択肢は以下の2つがあると思います;

  • クラス
  • 純粋な関数

クラス

 classの構文を使う場合、React.Componentクラスを継承してコンポーネントを定義します。

class App extends React.Component {
  render() {
    return (
      <div className="app-component">
        {this.props.hello}
      </div>
    );
  }
}

純粋な関数

純粋な関数としてコンポーネントを定義する場合、JSX記法で書いたDOMを返すような関数を記述します。なかなか直感的に書くことができます、親コンポーネントから渡されるpropsも引数として宣言します。

const App = ({ text }) => (
  <div className="app-component">
    {text}
  </div>
);

違いは?

 ざっくり言うと状態(state)を持つか持たないかのようです。クラス構文であればstateを持ったコンポーネントを作ることができますが、純粋な関数のコンポーネントではできません。純粋な関数のコンポーネントは引数(props)のみ使用し、実際それはコード上で関数の引数として表現されます。(2つの例でのtextの扱いの違いのような感じです)

 また純粋な関数のコンポーネントではrefが使えないそうです。その理由は説明によるとbacking instanceを持っていないから、だそうです。 静的コンポーネント、というイメージでしょうか。申し訳ないですが詳しくはこちらを参照くださいStateless functions

例:コンストラクタ内でstateを定義する。

class App extends React.Component {
  constructor(props) {
    super(props);
    this.state = {
      ...
    };
  }
  ...
  render() {
    ...
  }
}

感想

 reduxチュートリアルで初めてStateless functionで書かれたReactコンポーネントを見ましたが、状態管理をreduxに任せる立場からするとそれは当然なんだろうな、と今になって思いました。

 ReactのStatelessなコンポーネントを作ることは、新しいhtmlのタグを定義することに近い気がしました。

オブジェクトリテラル内でのスプレッド演算子

 こんにちは。

 スプレッド演算子(spread operator)がオブジェクトリテラル内で使えませんでした。babel-preset-es2015入れとけばなんとかなるだろうと思っていたのですが、babel-preset-stage-2が必要みたいです。ECMAScriptの仕様策定方法を知らないのでstage-2の意味はわからないですが、なんかよさそうなものがあったので読もうと思います。

 ざっくりとした設定方法をメモしておきます。

インストール

npm install --save-dev babel-core babel-loader babel-preset-es2015 babel-preset-stage-2 webpack

webpack.config.jsはこんな感じになりました。

module.exports = {
  entry: './index.js',
  output: {
    path: __dirname,
    filename: 'bundle.js',
  },
  module: {
    loaders: [
      {
        test: /\.js[x]?$/,
        exclude: /node_modules/,
        loader:  'babel',
        query: {
          presets: [
            'es2015',
            'stage-2',
          ],
        },
      },
    ],
  },
}

以下動くかどうか確認のためindex.jsindex.htmlを用意。

index.js

let obj1 = { 'before': '...oh' };
alert(JSON.stringify(obj1,null,2));
let obj2 = { ...obj1 , 'after': 'oh!' };
alert(JSON.stringify(obj2,null,2));
// ひどいサンプル

index.html

<!DOCTYPE html>
<html>
<head>
  <meta charset="UTF-8" />
  <title>Spread</title>
</head>
<body>
  <div id="root"></div>
  <script type="text/javascript" src="./bundle.js"></script>
</body>
</html>

webpackでビルド実行

./node_modules/.bin/webpack --colors --progress

 index.htmlをブラウザで開くとアラートが2回表示されます。オブジェクトリテラルが再代入なしで更新されているのが、なんとなくわかるかと思います。もっとプロパティが多いと、魅力が伝わる気がします。

感想

 ちゃんとした例を書かないとダメですね。あとECMAScriptに関しても知っておきたいです。