@kyanny's blog

My thoughts, my life. Views/opinions are my own.

Google API Client (Ruby) で Refresh Token を使って Access Token を発行するサンプルコード

google-api-client-example/refresh_token.rb

Signet::OAuth2::Client#new の引数に refresh_token を渡して、そのインスタンスを Google::APIClient#authorization= に入れて、 Signet::OAuth2::Client#refresh! (または fetch_access_token!)を呼ぶと新しいアクセストークンが取得できる。

client = Google::APIClient.new
client.authorization = Signet::OAuth2::Client.new(
  ...snip...
  refresh_token: refresh_token
)
client.authorization.refresh!

アクセストークンそのものが文字列で欲しい場合は client.authorization.access_token で取得可能。

リフレッシュトークンを得るためには get-google-oauth-token を使うのが楽。

vagrant share の実装を読もうと思ったら暗号化されていた

Vagrant に再入門している。 Getting Started を読んで vagrant share という機能があることを知った。手元の仮想マシンがコマンド一つでインターネットに公開されてすごい。どうやっているのか気になったのでソースコードを読んでみようと思ったら RubyEncoder という商用製品で暗号化されていた。

vagrant はオープンソースソフトウェアなので Share 機能のコードもリポジトリにあるのだろうと思って探し始めたがそれっぽいものが見つからなかった。公式サイトで配布しているインストーラを使ってインストールしたので、オープンソース版に含まれていないプログラムが同梱されているのかな?と思い、 /usr/bin/vagrant というシェルスクリプトを読んでもろもろの実態がどこにあるのかを調べ、たどっていった。

$ tree /Applications/Vagrant/embedded/gems/gems/vagrant-share-1.1.1/lib/
/Applications/Vagrant/embedded/gems/gems/vagrant-share-1.1.1/lib/
├── vagrant-share
│   └── activate.rb
└── vagrant-share.rb

最終的に vagrant-share-1.1.1 というディレクトリが見つかったが中にある .rb ファイルを開いてみたら暗号化されていた。 vagrant-share という Gem は公開されておらず、 GitHub でリポジトリも見つけられなかった。「vagrant share 用のコードだけクローズドソースにしても配布物に含まれていたら結局その気になれば読めちゃうんじゃないの?」と思っていたが、 Ruby プログラムの暗号化ツールがあるとは知らなかった。

なお RubyEncoder で暗号化されたプログラムのリバースエンジニアリングは難しそうなので試していない(vagrant の利用規約も精読していないので、もしかしたらリバースエンジニアリングは禁止されているかもしれないし、ひょっとすると vagrant-share が暗号化されていることに言及するのもまずいのかもしれない。問題があったらこの記事は削除するかもしれない)

ブログのテーマを「Hatena2 for はてなブログ」に変更

これまでに使ってきたテーマ(デザインテンプレート)はどれもコードブロックの表示が気に入らなかった。このブログの記事の多くは本文中にいくらかのコードを含み、それらのコードスニペットが一番重要な情報であることも少なくない。肝心の情報が見づらいデザインは良いとはいえないので、コードブロックが見やすいデザインを探して、結局古き良きスタンダードに落ち着いた。

Hatena2 for はてなブログ - テーマ ストア - はてなブログ

Hatena for はてなブログ というテーマもありこちらのほうがさらにノスタルジックだが、さすがにちょっと古めかしすぎるように感じたのでやめておいた。自分がはてなダイアリーのほうに書いていたとき長く Hatena2 のデザインを使っていた(ような記憶がある)ので、単に慣れの問題なのかもしれない。

capybara-webkit で Invalid Date エラーが出る場合の対処法

capybara-webkit は QtWebKit を使うが、 QtWebKit が Qt 4 でビルドされていると Invalid Date エラーが発生することがある。 QtWebKit を Qt 5 でビルドしなおせば解決する。

Improper date parsing · Issue #570 · thoughtbot/capybara-webkit · GitHub

  • new Date('2013-12-31'); はエラーになる。日付はなんでもよくて、 YYYY-MM-DD というフォーマットがまずい。
  • new Date('Dec 31, 2013'); はエラーにならない。なお、どちらも Chrome や Firefox などの Web ブラウザではエラーにならない。

Mac OSX を使っていて Homebrew で Qt をインストールしている場合に capybara-webkit を明示的に Qt5 でビルドしたときの作業ログ。

$ brew update
$ brew uninstall qt
$ brew install qt5
$ export PATH=/usr/local/opt/qt5/bin:$PATH
$ gem install capybara-webkit -v 1.1.0 -- --with-cppflags=-I/usr/local/opt/qt5/include --with-ldflags=-L/usr/local/opt/qt5/lib

window.location は stub できない

JavaScript の window.location は read-only プロパティなので上書きできず、したがって Sinon.JS でスタブすることもできない。知らなかった。

Window.location - Web API Interfaces | MDN

The Window.location read-only property returns a Location object with information about the current location of the document.

Mocha とかを使ってブラウザでテストを走らせる場合、 window.location.reload() とかが実行されるコードパスを通ると test.html 的なページが延々リフレッシュされ、永遠にテストが終わらない。

そういう場合は window.location.reload() を呼び出すだけのラッパー関数を定義して、ラッパー関数を Sinon.JS でスタブすれば無限ループを防いでテスト可能。たぶんこんな感じ。

class Foo
  run: ->
    @reload()
  reload: ->
    window.location.reload()

describe "Foo", ->
  describe "run", ->
    it "reloads page", ->
      foo = new Foo
      sinon.stub(foo, 'reload')
      foo.run()
      expect(foo.reload).to.have.been.calledOnce
      foo.reload.restore()

一方で window.open はそういう制限はなく自由に上書きできる(関数以外の値も代入可能)。どのプロパティが上書き不可なのかは調べて覚えるしかなさそう(そういうオブジェクトは host object と呼ばれるらしい。参考リンク