React Router v4 でルーティング先の component に Props を渡す方法

「React Router v4 でルーティング先の component に Props を渡す方法」について調査したので記事にします。

基本的なReact Router v4 の基本的なルーティング

React Router v4 の基本的なルーティングは次のような感じでコーディングします。

import React from 'react';
import ReactDOM from 'react-dom';
import { BrowserRouter } from 'react-router-dom';

ReactDOM.render((
  <BrowserRouter>
    <AppFrame />
  </BrowserRouter>
  ),
  document.getElementById('root'),
);

class AppFrame extends Component {
  render() {
    return (
      <main>
        <Switch>
          <Route path='/login'   component={Login} />
          <Route path='/getbook' component={GetBooks} />
          <Route path='/addbook' component={Addbook} />
        </Switch>
      </main>
    );
  }
}

今回は “component={xxxx}” で起動する React component に props を渡す方法を考えます。

React component に props を渡す

変数を props として渡す方法

上記 /getbook の URI でルーティングされる GetBook component に、ある変数(ここでは書籍ID(bookID)とします) を props として渡したい!となった場合、、その時は、以下のように書くと良いでしょう。

class AppFrame extends Component {
  render() {
    this.bookId = 2;    // とりあえず仮に書籍ID = 2 と設定
    return (
      <main>
        <Switch>
          <Route path='/login' component={Login} />
          // GetBook component に、bookID を props として渡します 
          <Route
            path='/getbook'
            render={props => <GetBook bookId={this.bookId} {...props} />}
          />
          <Route path='/addbook' component={Addbook} />
        </Switch>
      </main>
    );
  }
}

“component” ではなく “render” を使うところがミソですね。

function を props として渡す方法

続いて、/login の URI でルーティングされる Login component に、認証処理を行う function auth() を props として渡たしたい!となったらどうするか?

同じく render を使用して渡してあげれば大丈夫です。

class AppFrame extends Component {
  auth(userInfo) {
    // 何かの認証処理
  }
  render() {
    return (
      <main>
        <Switch>
          // Login component に、認証処理を行う function auth() を props として渡します 
          <Route
              path='/login'
              render={props => <Login onSubmit={userinfo => this.auth(userinfo)} {...props} />}
          />
          <Route path='/getbook' component={GetBooks} />
          <Route path='/addbook' component={Addbook} />
        </Switch>
      </main>
    );
  }
}

参考となった情報

いろいろ調査しましたが、特に、下記の Github issue が参考になりました。様々なアプローチが議論されており見るだけで勉強になります。

github.com

まとめ?

最近、React Router が V4 になっていろいろ変わって大変だ!との嘆きを耳にしました。ですが、React 初心者である私は「へー」とか「ふーん」と実感も伴わずに聞き流していましたが、最近、実際にコードを書く段になって「大変」の意味がわかりました。

今回の調査もそうでしたが、とにかくまだ情報が少なく、あっても英語なことが多いので、どうしても時間がかかってしまします。また、v4に関する情報かどうかを見極めるのも(特に初心者は v2 や v3 の情報と混同しがち)以外に大変だったりしました。

ということで「英語は重要だ!」というまとめを以って終了です。

React 始めたので vim の jsHint を ESLint に変更した話

いまさらですが、React 書き始めました。すると、これまで利用していた jsHint ではエラーや警告が誤検出されるので、この対策をした時のメモになります。

React なら ESLint ですわ

React は JSX など独特な書き方がありますし、これからは ES6 になりますので、これらをうまく解釈できるものはないか? と調査すると jsHint で JSX をチェックする JSXHint というラッパーがありました。

GitHub - STRML/JSXHint: Wrapper around JSHint for linting JSX files. 100% compatible with existing tools using JSHint.

よし、これを試すか、、と思ったらのっけから

Don’t use JSXHint anymore if you can switch to ESLint.

ということで、これまでお世話になった jsHint を辞めて ESLint に Switch しましょう。どうも現代では、React で書くなら ESLint を使うのが当たり前のようです。*1

ESLint セットアップ

私の開発環境(MAC OS Sierra)に ESLint を導入します。

eslint.org

導入方針

ESLint についていろいろ調べたところ、グローバルにインストールするのではなく、アプリケーション毎にローカルにインストールして、それぞれ専用の設定をして使用することができるようです。確かに、React 使う時や Angular 使う時やその他でコンフィグレーション内容が大きく変わりそうなので、ローカルにインストールする方が理に適っています。

また、ESLint がローカルにインストールされていれば、それをグローバル的に利用可能とする “eslint-cli” というツールを発見、便利そうなのでこれも併せて導入します。

www.npmjs.com

(1) ESLint をローカルにインストール

前提として node.js がインストールされている必要があります。ちなみに、私の場合は、nodebrew で利用する node.js のバージョンを選択できるようにしています。

$ node -v
v7.8.0

$ npm -v
4.2.0

以下のようにローカルに ESLint をインストールします。今回 React が前提なので eslint-plugin-react も必要となります。

$ npm install --save-dev eslint eslint-plugin-react

ちなみにインストールした ESLint のバージョンは 3.19.0 でした。

$ eslint -v
v3.19.0

(2) ESLint 初期設定

ESLint を使用するには、予めルールなどを定義した設定ファイルを作成する必要がありますが、自作するのは結構メンドくさそうです。ですが最近では “eslint –init” で簡単に設定ファイルを作成できるようです。

というか、本家の Getting Start のページを見ると、むしろこの手順で初期化することが前提となっていますね。

Getting Started with ESLint - ESLint - Pluggable JavaScript linter

さっそくやってみましょう。
今回は対話(質問に答える)形式で初期化する方法で実行してみました。

$ ./node_modules/.bin/eslint --init
? How would you like to configure ESLint? Answer questions about your style
? Are you using ECMAScript 6 features? Yes
? Are you using ES6 modules? Yes
? Where will your code run? Browser
? Do you use CommonJS? No
? Do you use JSX? Yes
? Do you use React? Yes
? What style of indentation do you use? Spaces
? What quotes do you use for strings? Single
? What line endings do you use? Unix
? Do you require semicolons? Yes
? What format do you want your config file to be in? JavaScript
Successfully created .eslintrc.js file in /Users/naoki/DEV/SANDBOX/react

成功です。下記のようにESLint の設定ファイル “.eslintrc.js” ができています。

$ cat .eslintrc.js

module.exports = {
    "env": {
        "browser": true,
        "es6": true
    },
    "extends": "eslint:recommended",
    "parserOptions": {
        "ecmaFeatures": {
            "experimentalObjectRestSpread": true,
            "jsx": true
        },
        "sourceType": "module"
    },
    "plugins": [
        "react"
    ],
    "rules": {
        "indent": [
            "error",
            4
        ],
        "linebreak-style": [
            "error",
            "unix"
        ],
        "quotes": [
            "error",
            "single"
        ],
        "semi": [
            "error",
            "always"
        ]
    }
};

(3) eslint-cli をグローバルにインストール

ここで、冒頭で説明した “eslint-cli” をインストールしておきます。これで、わざわざ “./node_module/.bin/eslit” とせずに “eslint” だけで実行できるようになります。

$ mpn install eslint-cli -g

(4) ESLint の動作確認テスト

ESLint 実行環境が整ったので動作確認します。テスト対象としたコードは、React Tutorial で作成した “index.js” です。

$ eslint src/index.js

/Users/naoki/DEV/SANDBOX/react/src/index.js
    5:10  error  'Square' is defined but never used            no-unused-vars
    6:3   error  Expected indentation of 4 spaces but found 2  indent
   13:7   error  'Board' is defined but never used             no-unused-vars
   14:3   error  Expected indentation of 4 spaces but found 2  indent
   15:5   error  Expected indentation of 6 spaces but found 4  indent
   17:3   error  Expected indentation of 4 spaces but found 2  indent
   18:5   error  Expected indentation of 6 spaces but found 4  indent
   40:7   error  'Game' is defined but never used              no-unused-vars
   41:3   error  Expected indentation of 4 spaces but found 2  indent
   42:5   error  Expected indentation of 6 spaces but found 4  indent

   ... 省略 ...

  128:5   error  Expected indentation of 6 spaces but found 4  indent
  129:5   error  Expected indentation of 6 spaces but found 4  indent
  130:7   error  Expected indentation of 8 spaces but found 6  indent
  133:3   error  Expected indentation of 4 spaces but found 2  indent

✖ 48 problems (48 errors, 0 warnings)

ご覧の通りたくさんのエラーが出てしまいました。よく見ると、そのほとんとがインデント数が変だと言っていますが、これは誤検出です。むしろ設定ファイルのタブ数の設定に問題がありますので “.eslintrc.js” の “rules.indent” を 4 から 2 に変更します。

   "indent": [
      "error",
      2
   ],

再度実行してみます。

$ eslint src/index.js

/Users/naoki/DEV/SANDBOX/react/src/index.js
   5:10  error  'Square' is defined but never used  no-unused-vars
  13:7   error  'Board' is defined but never used   no-unused-vars
  40:7   error  'Game' is defined but never used    no-unused-vars

✖ 3 problems (3 errors, 0 warnings)

だいぶマシになりましたが、3箇所エラーが検出されてしまいました。うむむ。
こちらは ES6 のプログラム的には問題ない(never used となっていますが JSXから参照しています)ので、やはり ESLint の誤検出で、設定に問題があります。

(5) no-unused-vars 問題を解決する

こちらに解決策がありました。ありがたや。

ESLintでReactを扱う - Qiita

また、eslint-plugin-react のページでも、no-unused-vars を prevent するルールについての記述がありますね。

eslint-plugin-react

ということで、次のルールを “.eslintrc.js” に加します。

  "rules": {
    "react/jsx-uses-react": "error",
    "react/jsx-uses-vars": "error",
  }

これで再実行して Lint エラー(誤検出)が全て無くなりました。OKです。

vim のチェッカを jsHint から ESLint に変更

最終的な目的は、vim で自動的に Lint チェックしてもらうことなので、.vimrc の設定を変更します。

具体的には、下記の通り “let g:syntastic_javascript_checkers” の値を “jshint” から “eslint” に変更するだけです。

let g:syntastic_mode_map = { 'mode': 'active',
  \ 'active_filetypes': [],
  \ 'passive_filetypes': [] }
let g:syntastic_javascript_checkers = ['eslint']
let g:syntastic_check_on_wq = 0

これで、vim で編集する javascript の コードは、ESLint でチェックすることが可能となりました。これでとりあえずの作業は全て完了です。

まとめ

  • React なら ESLint を使え
  • ローカルインストールすれば、アプリケーション毎に専用の設定ができる
  • ESLint の設定ファイルを一から自作するのはちょっと大変だが、"eslint –init" でこの作業を簡単にすることができる

今回はこれくらいです。 これからは ES6 必須ですし、しばらくは ESLint のお世話になりそうです。ということは、さらにきめ細かな設定方法や、様々なツールやエディタとの連携方法なども習得していく必要がありますね。

*1:世間の速さに追いついていないです。キャッチアップしないとだめです

Ruby で カウントダウン Twitter BOT 作って Scaleway の Docker で動かす- 後半(完成まで)

大事な日までのカウントダウンを毎日 tweet してくれる BOTRuby で作成して Scaleway サーバで動かそうと思います。こんな感じでつぶやきます。

前半のおさらい

このエントリは、先日書いた以下の記事の続きです。

ngzm.hateblo.jp

前半は下記のことを行ないました。

  1. カウントダウン Twitter BOTRuby で作成しました
  2. Scaleway に Docker コンテナが動く仮想サーバを立てました
  3. 上記仮装サーバの Docker 上で Ruby:latest コンテナが動くことを確認しました。

今回はその続きで、実際に Scaleway の Docker で動かすまでの話です。

カウントダウン Twitter BOT の Docker コンテナを作成

1) Docker Ruby イメージについて

まず最初は、今回の Docker コンテナのベースとなる Ruby イメージについて、その基本的な使い方や構成などを確認しておく必要があります。これらは、 DockerHub の Ruby ページ で確認できます。

どうも Ruby アプリケーションは /usr/src/app/ にデプロイして動かせば良いようです。

2) Dockerfile などコンテナ環境の準備

さて、Twitter BOT アプリケーション用の Docker イメージを作成するための Dockerfile を作成します。

今回、この Docker ファイルは、Twitter BOT アプリケーション(countdown_bot.rb など)と同じディレクトリに作成しました。

FROM ruby:latest
MAINTAINER ngzm<nk.ngzm@gmail.com>
ADD . /usr/src/app
RUN cd /usr/src/app && bundle install
RUN cd /usr/src/app && chmod u+x countdown_bot.sh
CMD ["/usr/src/app/countdown_bot.sh"]

countdown_bot.sh というのはこのアプリを起動するだけの簡単なシェルスクリプトです。次のような感じです。これもアプリケーションと同じディレクトリに保存します。

#!/bin/bash
cd /usr/src/app
if [ $? -eq 0 ]; then
    ruby countdown_bot.rb
fi

なお、作成した Docker ファイルや、起動スクリプト countdown_bot.sh は、アプリケーションコードと同様、github のページ に置いてありますので適宜参照してください。

3) Docker コンテナを作成

準備が完了したので、docker build で Twitter BOT アプリケーション用の Docker イメージを作成します。

# docker build -t countdown .

Sending build context to Docker daemon 68.61 kB
Step 1 : FROM ruby:latest
 ---> d2cee8adb148
Step 2 : MAINTAINER ngzm<nk.ngzm@gmail.com>
 ---> Using cache
 ---> 276ca2d970a3
Step 3 : ADD . /usr/src/app
 ---> f7a2c4909d42
Removing intermediate container 8730da1e725f
Step 4 : RUN cd /usr/src/app && bundle install
 ---> Running in 7895f7170efc
Fetching gem metadata from https://rubygems.org/........
Fetching version metadata from https://rubygems.org/..
Fetching dependency metadata from https://rubygems.org/.
Installing public_suffix 2.0.5
Installing buftok 0.2.0
Installing unf_ext 0.0.7.4 with native extensions
Installing equalizer 0.0.11
Installing multipart-post 2.0.0
Installing http-form_data 1.0.1
Installing http_parser.rb 0.6.0 with native extensions
Installing thread_safe 0.3.6
Installing naught 1.1.0
Installing simple_oauth 0.3.1
Using bundler 1.14.6
Installing addressable 2.5.1
Installing unf 0.1.4
Installing faraday 0.11.0
Installing memoizable 0.4.2
Installing domain_name 0.5.20170404
Installing http-cookie 1.0.3
Installing http 2.2.1
Installing twitter 6.1.0
Bundle complete! 1 Gemfile dependency, 19 gems now installed.
Bundled gems are installed into /usr/local/bundle.
 ---> 6842c8ee3be4
Removing intermediate container 7895f7170efc
Step 5 : RUN cd /usr/src/app && chmod u+x countdown_bot.sh
 ---> Running in b14e152beca3
 ---> b581ef596c71
Removing intermediate container b14e152beca3
Step 6 : CMD /usr/src/app/countdown_bot.sh
 ---> Running in 28768d88b292
 ---> 40c6fe50a43f
Removing intermediate container 28768d88b292
Successfully built 40c6fe50a43f

成功です。Twitter BOT アプリケーションファイルをコピーして、bundle install もうまく行っていますね。docker images で確認すると、きちんとDocker イメージが生成されていました。

続いて、 Docker イメージから、Docker コンテナの作成 + 起動を行います。

# docker run --name countdown_bot countdown

エラーなく終了しました。ここで Twitter を見てみると、無事につぶやきが投稿されていました。OKです。カウントダウン Twitter BOT の Docker コンテナができました。

cron で定期的に実行させる

ここまできたら、後は、カウントダウン Twitter BOT コンテナを、定期的に自動実行できれば良い訳です。とりあえず、今回は、cron に仕込んで実行させることにします。

# crontab -e

0 9 * * * docker start countdown_bot

私の生活リズム都合で、毎朝 9時につぶやいてもらうように設定しました。

その後追記

と言う訳で、翌日の朝9時になりました。が、その時間になっても一向につぶやきませんでした。むむむ。

どこか不具合があったかぁ、、と考えたら、はっと問題点に気づきました。私がセットしたのは確かに 9:00AM ですが、それは日本時間ではありません。そうです Scaleway サーバは Paris にあるのです。早速サーバにログインして、タイムゾーンを確認すると UTC でした。なるほど。

ということで対策を行います。今回は、せっかくUTCで動いているので、タイムゾーンはそのままで、Twitter BOT アプリケーションの起動時間を -9時間するように cron を設定し直しました。

# crontab -e

3 0 * * * docker start countdown_bot

なお、ジャスト0時に起動するのもなんなので*1、0時3分に起動するようにして完了です。翌日 9時3分に無事につぶやきを確認してとりあえずおしまいデス。

まとめ

  • Scaleway の VC1s + Docker で Ruby アプリケーションが割と簡単に動かせる
  • 海外のサーバは JST じゃない(当然ですが)ので気をつけろ
  • 毎朝 9時3分にこのつぶやきを見ながら、その日に向かってしっかり頑張ろう!!

*1:経験的にこのような境界値に思わぬ問題が潜んでいることが多いので、今回は簡単に少しだけずらしてリスクを回避します

Ruby で カウントダウン Twitter BOT 作って Scaleway の Docker で動かす- 前半(ただしWIP)

大事な日までのカウントダウンを毎日 tweet してくれる BOTRuby で作成して Scaleway サーバで動かそうと思います。こんな感じでつぶやきます。

モチベーション

どうしてそんなものを作る気になったのか?とか「大事な日」とは何の日なの?とかは、いろいろあって、ここでは公にできないのですが、とりあえず、その日までの過ごし方が重要なので「その日に向かって日々頑張ろう!!」的な気持ちを継続するために、本 BOT に毎日つぶやいてもらいます。

また Scaleway とはフランスの格安サーバ会社で、ベアメタルなサーバが 日本円で 400円/月くらいからレンタルできるのが特徴です。2年ほど前に kawasaki.rb の LT で教えてもらって気になっていたやつです。

今回はサーバ上の Docker コンテナにアプリを入れて動かすつもりです。

www.scaleway.com

Twitter Bot の作成

Ruby では twitter という Gem があって、これを利用すればあっさりと実現できます。以下、簡単に実装の流れを説明します。

1)Twitter API 利用するアプリケーション登録

Twitter に投稿するためには Twitter API を利用する必要がありますが、そのためには、アプリケーション登録をする必要があります。ということで、さっそく Twitter developers へログインしてアプリケーション情報を登録します。

Welcome — Twitter Developers

注意点として、今回はTwitter 投稿するので、Access Level を “Read and write” にしておく必要があります。

アプリの情報が登録できたら、アプリが利用する Twitter API の認証と認可に必要な Consumer の情報と Access Token の情報を取得できます。
具体的には、下記の4つの情報をコピーします。

  1. Consumer Key (API Key)
  2. Consumer Secret (API Secret)
  3. Access Token
  4. Access Token Secret

2)Twitter Bot のコーディング

twitter Gem を使用した Twitter 投稿処理は、次のコードが基本となります。

require 'twitter'

client = Twitter::REST::Client.new(
    consumer_key:        'YOUR-CONSUMER-KEY',
    consumer_secret:     'YOUR-CONSUMER-SECRET',
    access_token:        'YOUR-ACCESS-TOKEN',
    access_token_secret: 'YOUR-ACCESS_TOKEN_SECRET'
)
client.update 'Some Tweet Message ...'

consumer_key、consumer_secret、access_token、access_token_secret の各値は、Twitter developers で登録したアプリケーションの情報をセットしてください。

私の場合は、大事な日までのカウントダウンを呟いてもらわなくてはなりませんので、その辺りも含めて(現在)以下のコードになってます。

require 'twitter'
require 'date'
require 'yaml'

# SayTwitter
class Tweeter
  def initialize(config)
    @config = config
  end

  def say(message)
    client = Twitter::REST::Client.new(
      consumer_key:     @config['tweet']['consumer_key'],
      consumer_secret:  @config['tweet']['consumer_secret'],
      access_token:     @config['tweet']['access_token'],
      access_token_secret: @config['tweet']['access_token_secret']
    )
    client.update message
  end
end

# Countdown Class
class CountDown
  def initialize(config)
    @config = config
  end

  def post
    the_day = Date.new(@config['theday']['year'],
                       @config['theday']['month'],
                       @config['theday']['day'])
    boring_days = (the_day - Date.today).to_i

    # Say to Twitter
    message = "Hi! just #{boring_days} days left until the Special Day."
    yield message
  end
end

# Load CONFIG FILE
CONFIG_FILE = 'countdown_bot.yml'.freeze
config = YAML.load_file(CONFIG_FILE)

countdown = CountDown.new(config)
tweet = Tweeter.new(config)

# Tweet Count Down Message
countdown.post do |message|
  tweet.say message
end

consumer_key、consumer_secret、access_token、access_token_secret などの情報は、外部 YAML ファイルで定義するようにしています。コード全体は、github のページ を参照してください。

Scaleway サーバの作成

アプリは作成できたので、これを動作させるサーバを Scaleway 上に準備します。前提として、今回も 400円/月 の範囲で活用したいと思います。

1)C1 サーバ + docker イメージで試してみる

まずは、Scaleway の C1 という ARM CORE のベアメタルサーバで一番チープな構成(400円/月)で試してみます。

f:id:ngzm:20170426183844p:plain

サーバで稼働するOSイメージは、ubuntu などメジャーなデストリビューションから選択できます。

f:id:ngzm:20170426183909p:plain

また、あらかじめミドルウェアまで入ったOSイメージも用意されています。こうなると PaaS みたいです。

f:id:ngzm:20170426183913p:plain

今回は、Docker コンテナでアプリを動かすので、OSのイメージは Dokcer を選択してオーケストレーションします。こうして、しばらくするとマシンが立ち上がってきました。起動できたので、次は Docker コンテナを作成しますが、とりあえず Docker -v でバージョンを確認すると Version 1.12 でした。現在の最新版が 1.17 系なので、ちょっと古いですね。

続いて、ruby:latest イメージを pull して、docker run してみます。するとナゾの go-lang エラーがばんばん出ました。

# docker run --rm -it ubuntu:trusty

panic: standard_init_linux.go:175: exec user process caused "exec format error" [recovered]
    panic: standard_init_linux.go:175: exec user process caused "exec format error"

goroutine 1 [running, locked to thread]:
panic(0x3339c8, 0x10747800)
    /usr/local/go/src/runtime/panic.go:481 +0x330
github.com/urfave/cli.HandleAction.func1(0x107c5958)
    /go/src/github.com/opencontainers/runc/Godeps/_workspace/src/github.com/urfave/cli/app.go:478 +0x328
...
... 以下省略
...

よく見ると、Docker コンテナのフォーマットエラーとか何とか書いてあります。とにかくうまく動きません。

2)C1 サーバ + ubuntu イメージで試してみる

どうもダメなので、一旦サーバを破棄して、C1 サーバ + ubuntu xenial (16.04 LTS) イメージ でサーバを作って、そこに Docker を入れて試してみます。無事に Docker のインストールまで完了したので、 そのバージョンを確認すると Version 1.17 最新版です。

まずは、Docker の動作確認用コンテナ “Hello World” で動作確認してみます、すると、さっきと同様に go-lang のエラーが発生!それでも、あきらめずに、ruby:latest イメージで docker run してみますと、やっぱりエラーとなりうまく動きませんでした。

3)C1 サーバ の問題

どうしてもダメなので、C1 サーバのドキュメントをちゃんとみて見ると、その CPU は「ARM v7」であると書いてありました。

f:id:ngzm:20170426183855p:plain

「ARM v7」って?さらに調べたところ、どうやら 32bit CPU らしき情報を発見!なるほど、32 bit なら docker は動かないですね。この事実が分かるまで2〜3時間かかってしまいました。

せっかくのベアメタルサーバなのに、これでは目的が達成できなません。ちなみに、これより上位の構成(当然お金も高くなる)であれば、64bit のCPUを採用しているので、あとは金で解決するか・・いや止めよう

4)VC1s サーバ + docker イメージで試してみる

Scaleway はベアメタルなサーバ以外にも、一般的な仮装サーバの提供も行なっており、それであれば、約400円/月 かつ 64bit の環境が使えます。

f:id:ngzm:20170426183905p:plain

ということで、ベアメタルサーバは諦め、仮装サーバ VC1s での実現を目指します。OSイメージはとりあえず Docker で行きます。

と、無事にマシンが起動できました。そこで、先ほどと同様 “Hello World” コンテナで動作確認をしてみると無事に成功しました。今度は大丈夫そうです。 ということで、ruby:latest イメージを pull して docker run で Ruby コンテナを実行させると、きちんと irb が起動しました。

# docker run --rm -it ruby:latest
irb(main):001:0>
irb(main):002:0* puts "Hello!!"
Hello!!
=> nil

とりあえず、現在はここまでの状況です。明日以降で Ruby で作成した Twitter BOT を Scaleway のVC1s サーバ + Docker に乗せて動かす作業を行います。

ここまでのまとめ

  • twitter Gem を使うと簡単に RubyTwitter API 使えそう
  • Scaleway サーバで Docker を動かすなら C1 サーバは使えない
  • 大事な日まで心折れずにがんばろう

後半につづく

2017/4/30 - 後半の記事を書きましたのでお知らせいたします。

ngzm.hateblo.jp

macOS Sierra にしたら photoanalysisd というプロセスでホットになった

Sierra にしてしばらく遊んでたら、どうも常時CPU使用率が7割以上回っている様子で、MAC BOOK がホットになったので、どのプロセスが原因なのか見てみました。

どうも photoanalysisd というプロセスですね。

検索してみると、なるほど 「photoanalysisd 暴走」 というタイトルの記事がたくさんありました。どうやら、一時中断もできるが、しばらく放っておくとそのうちおさまるとの噂です。ならばと、そのまま数日間放置していたら、なんとなく静かになりました。

と安心したのも束の間、続いて mediaanalysisd という第二の刺客が現れ、こいつは4割くらい CPU を占有するようになりました。私はあまり動画とか保存していなかったのもあってか、mediaanalysisd の暴走は数時間で解消しました。

ということで今ここ。次は 何analysisd が暴走するのだろうか?

macOS Sierra に Karabiner-Elements 入れて「英数」キーを「Command」にして、単独で押した時は「英数」として認識させた話

2017/07/08 追記

本エントリは 2016年12月現在の情報です。それから半年+α 経って、ついに本家の Karabiner-Elements で同機能がサポートされました。その詳細を、次のエントリに記載しましたので、今後はこちらを参考にしてください。

ngzm.hateblo.jp

以下、当時の情報です。

はじめに

タイトル長い。。

MAC OS Sierra がリリースされてはや3ヶ月。"そろそろアップデートしないとなー"と思いつつも、これまで Karabiner にお世話になっていたこともありなかなかバージョンアップに踏み切れずいたのですが、、先日、改めて調べてみると Karabiner-Elements でいけそうな気配を感じたので、思い切って Sierra にアップデートしました!!という、その時の話です。

すなわち、MAC OS Sierra にアップデートした後、Karabiner-Elements でタイトルのようなことをゴニョゴニョしたときのメモです。

これまで Karabiner にお世話になっていたこと

自宅のMACでは日本語キーボードを使っています。なので、別に Karabiner 使わなくても何とかなるのですが、日本語キーボードは英語キーボードに比べ、左「Command」キーの位置が左に寄り過ぎていて気に食わない、そこで、できれば「英数」キーを左「Command」キー的に利用したい。さらに単独で「英数」キーや左「Command」キーを押した時は「英数」として認識してほしいというのが私の願望でして、その願望をうまいこと叶えてくれていたのが Karabiner でございました。

また、会社では英語キーボードを使用しており、単独で左「Command」キーを押した時は「英数」として、右「Command」の時は「かな」として認識してもらわないと、なおのこと日本語切り替えに困惑する訳でありまして、やっぱし karabiner の導入は必須となってしまうのです。

今回導入した Karabiner-Elements について

「英数」キーを左「Command」キー的に利用したいというのは、本家の Karabiner-elements でも問題なく実現できるのですが、単独で「英数」キーや左「Command」キーを押した時は「英数」として認識させるということはできませんでした。

ここで諦める訳にはいかないので、さらに調査を進めてみると、wwwjfy さんが単独で何かのキーを押した場合だけ、特別な認識をさせるという、いわゆる「StandAlone Key」という機能を開発されていて、これをマージすればよさげなことが分かりました。さっそくマージだ!とビルド環境を整備していた矢先、なんと wwwjfy さんご自身でマージ版のインストールパッケージご提供されておりましたよ。至れり尽くせり、ありがたや。

github.com

ということで、「StandAlone Key」がマージされた Karabiner-Elements を Sierra にインストールしました。

Karabiner-Elements の設定内容

無事にインストールが完了したら、まず最初にキーボードの種類をきちんと設定します。現在 Karabiner-Elements の “Keybord Type” のデフォルトが、英語配列になってますので、日本語配列のキーボードを利用する場合は、"Keybord Type" を “JIS” に変更する必要があります。以下のように Karabiner-Elements の設定画面上で設定します。

f:id:ngzm:20161222003352p:plain

続いてキースワップを設定します。今回は「英数」キーを左「Command」として認識するように設定します。こちらも Karabiner-Elements の設定画面上から行います。

f:id:ngzm:20161222003357p:plain

そしていよいよ StandAlone Key の設定です。すなわち、単独で「英数」キーや左「Command」キーを押した時は「英数」として認識させます。これについては、Karabiner−Elements の設定画面で設定できないので、定義ファイルを直接編集して行います。定義ファイルは ~/.karabiner.d/configuration/karabiner.json *1です。これに以下の定義を追加します。

   "standalone_keys" : {
       "left_command" : "japanese_eisuu"
    }

一部だけだとよく分からないので、ここまでの設定が反映された karabiner.json 全体を以下に示します。

{
    "profiles": [
        {
            "devices": [
                {
                    "disable_built_in_keyboard_if_exists": false,
                    "identifiers": {
                        "is_keyboard": true,
                        "is_pointing_device": false,
                        "product_id": 599,
                        "vendor_id": 1452
                    },
                    "ignore": false,
                    "keyboard_type": 42
                },
                {
                    "disable_built_in_keyboard_if_exists": false,
                    "identifiers": {
                        "is_keyboard": true,
                        "is_pointing_device": false,
                        "product_id": 627,
                        "vendor_id": 1452
                    },
                    "ignore": false,
                    "keyboard_type": 42
                }
            ],
            "fn_function_keys": {
                "f1": "vk_consumer_brightness_down",
                "f10": "mute",
                "f11": "volume_down",
                "f12": "volume_up",
                "f2": "vk_consumer_brightness_up",
                "f3": "vk_mission_control",
                "f4": "vk_launchpad",
                "f5": "vk_consumer_illumination_down",
                "f6": "vk_consumer_illumination_up",
                "f7": "vk_consumer_previous",
                "f8": "vk_consumer_play",
                "f9": "vk_consumer_next"
            },
            "name": "Default profile",
            "selected": true,
            "simple_modifications": {
                "japanese_eisuu": "left_command"
            },
            "standalone_keys" : {
              "left_command" : "japanese_eisuu"
            }
        }
    ]
}

一番下にある定義が、StandAlone Key の設定ですね。。

さて、これでOKかテストして、うまくいきましたよ。今回は、「英数」と左「command」キーだけでやって見ましたが、「かな」と右「command」でも同様に設定可能です。

また、英語キーボードの場合でも、この StandAlone Key を使えば「Commnd」キー単独の時は「かな」や「英数」となるように設定できるので便利かと思います。

ご注意

このエントリは2016年12月20日時点のことなので、将来は状況が変わっているためご注意ください。

なお、wwwjfy さんの StandAlone Key 機能は、現在のところ、本家の Karabiner−Elements に Pull Request が上がっております。こちらがマージされれば、本家の正式版でも同様の設定が可能になるはずです。楽しみですね。

*1: 2017年4月現在では、~/.config/karabiner/karabiner.json に変更されています

Homebrew で nodebrew をインストールしたら少々はまった

MAC OS 10.11 の MAC BOOK PRO にて。

タイトルどおりはまったのでメモ。はまった内容ですが、普通に Homebrew から nodebrew をインストールして、

$ brew install nodebrew

PATH を追加しろとか言ってくるので、その通りに PATH を設定して、さぁ stable版 node を入れようとしたら、次のエラーに遭遇したのでした。

$ nodebrew install stable

Fetching: https://nodejs.org/dist/v6.6.0/node-v6.6.0.tar.gz
Warning: Failed to create the file
Warning: /Users/naoki/.nodebrew/src/v6.6.0/node-v6.6.0.tar.gz: No such file or
Warning: directory

curl: (23) Failed writing body (0 != 940)
download failed: https://nodejs.org/dist/v6.6.0/node-v6.6.0.tar.gz

ちょっと調べてみると、どうやら同じエラーに遭遇した先輩がたくさんいる模様。原因は、 $HOME/.nodebrew が作成されていなかったから? ということで、それ作成してリトライ。

$ mkdir ~/.nodebrew
$ nodebrew install stable

Fetching: https://nodejs.org/dist/v6.6.0/node-v6.6.0.tar.gz
Warning: Failed to create the file
Warning: /Users/naoki/.nodebrew/src/v6.6.0/node-v6.6.0.tar.gz: No such file or
Warning: directory

curl: (23) Failed writing body (0 != 940)
download failed: https://nodejs.org/dist/v6.6.0/node-v6.6.0.tar.gz

あらっ?またか。
どうやら $HOME/.nodebrew/src も必要なようです。でも、なんだかこのまま行くと、「あれも」「これも」という感じで、次々に同様の作業を繰り返す気がします。なのでさらに調査してみます。。

すると、今回の正解らしき情報が得られました。それは、わざわざ手でこれらのディレクトリを作るのではなく、コマンド nodebrew setup をたたくということです。

$ nodebrew setup

Fetching nodebrew...
Installed nodebrew in $HOME/.nodebrew

========================================
Export a path to nodebrew:

export PATH=$HOME/.nodebrew/current/bin:$PATH
========================================

これで nodebrew の実行に必要な環境がセットアップできたはずです。

$ ls ~/.nodebrew

completions/ current@     default/     iojs/        node/        nodebrew*    src/

よさそうですね。再度、node 安定版をインストールしてみます。

$ nodebrew install stable

Fetching: https://nodejs.org/dist/v6.6.0/node-v6.6.0.tar.gz
######################################################################## 100.0%
creating  ./icu_config.gypi

... (省略)
...

$ nodebrew use v6.6.0
use v6.6.0

$ nodebrew ls
v6.6.0

current: v6.6.0

うまくいきました。done。

【補足】nodebrew は、環境変数 NODEBREW_ROOT で node のインストール先を変更できますが、このときも nodebrew setup を実行すると一発で必要な環境が作成されるので非常に便利。ぜひ覚えておきましょう。