トップ 最新 追記

2019-09-01 [長年日記]

_ SeleniumWebDriverでブラウザのconsoleの出力を取得することでRubyだけでCORSのテストをする

Rails + rack-corsの設定をRSpecだけである程度お手軽にテストする - あーありがち(2019-06-01) の完成版とも言える。

できたこと

  1. rack middleware の設定をサーバサイドフレームワークから独立させることでテスト用の rack アプリで再利用
  2. Capybara の機能ではなく Thread と rack handler を使ってテスト目的のサーバを自由にいくつでも起動する
    • Capybara にはアクセス先の URI だけ教える
  3. Selenium::WebDriver から browser の中を探っていくと log の interface がある driver もある
    • 2019-09-01 時点で ChromeDriver でしか確認できていない。GeckoDriver では動かなかった

地味に 1 の設定を独立させる、つまり rack middleware に与える block を別な場所に分離するのが面倒だった。

3 は Capybara が古いとダメ。確認できたのは 3.x 系。(selenium/CHANGES at master · SeleniumHQ/selenium によると 2013年の 2.38 で beta API として登場しているが、公式になったのかどうかよく分からない。)

期待できること

  • 単純に console の出力を取得できるのでレガシーな JavaScript のテストにも使える
  • 本物のサーバサイドアプリからも本物のクライアントサイドアプリからも独立してインターフェイスをテストすることはまだまだできる

成果物

wtnabe/example-cors-test-with-capybara-and-webdriver


2019-09-13 [長年日記]

_ WebExtensionsとNativeMassagingを実装してみた時に役に立ったもの

自分用まとめ

リンク集

ドキュメント

安定の MDN. 本家のはずの Chrome 方面からはなかなか情報が拾えない感じがする。

ライブラリ

web-ext は指定のディレクトリ以下にある拡張を自動で読み込んだブラウザを起動してくれ、かつ Hot Reloader してくれる。マジで便利。zip の作成も自動化できる。

URL にこだわらなくてよい時は asset bundler は Parcel が便利。

Firefox でも chrome オブジェクトを参照できるのでそっちに寄せる手もあるけど、一応 Polyfill も挙げておく。callback はイヤなので。ただし、一部メソッドのシグニチャチェックがバグってる気がする。

気づいたこと

  • ツールバーの button を押したらとりあえず popup を開くのが基本
  • ツールバーの button を押したら「ページ」を開くタイプの拡張は存在しない
    • OptionPage を開くアクションをボタンクリックに割り当てる必要あり
    • そのためにはロード時点で動作する background script が必要

NativeMessaging については続きをどうぞ。 → NativeMessagingの処理とNativeMessagingHostを作るときのTips

Tags: JavaScript

2019-09-14 [長年日記]

_ NativeMessagingの処理とNativeMessagingHostを作るときのTips

試しに WebExtensions と Native Messaging Host を作って message のやり取りをしてみた時にハマったのでメモ。

WebExtensions側

  1. runtime.connectNative() で Host を起動する。起動したら runtime.Port が取得できる
  2. Host との communication はこの Port を通じて行う
  3. Port の diconnect() を呼ぶと起動した Host は終了する
    • disconnect() を呼ばずに破棄すると起動した Host は迷子プロセスになる
    • 例えば Extension を作る際になんらかの View Framework を利用している場合、この Framework の component の lifecycle と整合させる必要がある
  4. この Port には isConnected() のような API は存在せず、何らかの理由で disconnected な Port に message を送ると Error が発生する
    • runtime.onDisconnect プロパティで接続断は検知できるので、そっちのイベントで処理する

Native Messaging Host側

勝手が分かるまではなかなかつらい。

  1. STDIN, STDOUT が WebExtensions に握られるのでいつものデバッグ方法は使えない
    • STDERR に出力すればブラウザに何かメッセージを出すことはできるが、それも connection が keep できている場合だけなので、例えば例外のある言語の場合は例外の起きそうな場所で拾いまくる必要がある
  2. 先頭 32bit でその長さ + JSONエンコード済みのデータ(これの長さが先頭32bitに入る)のデータを読み書き
    • native endian で write はともかく read はちょっと気を使う
  3. 拾い損ねた例外や普段 STDOUT に出力したい情報は Logger などで外に出していくしかない
    • 例えば Ruby では $@ で最後の Backtrace を拾えるので、at_exit でこいつを Logger などに渡してやる
    • この時点ですでに WebExtensions との connection は切れている
  4. STDIN からの入力はいつ来るか分からないので無限ループを作る必要がある
    • 終了は WebExtensions から行われるので WebExtensions にバグがなければ問題はない(危険)
サンプル

ブラウザがHost起動時に渡す情報が変わる

これがめちゃくちゃハマった。

Native Messaging Host を起動する際に環境変数の渡し方がブラウザによって違う。この環境変数に依存する部分があると挙動が変わる。

これによって何が起きるかというと、例えば

#! /usr/bin/env ruby

のような shebang から Ruby を起動する場合に、以下のように異なる Ruby インタプリタを起動してしまう。

  • web-ext 経由の Firefox は rbenv 経由の Ruby
  • Chrome は system の Ruby

結果、Firefox と Chrome で WebExtensions の挙動が変わってしまっているように見える。

web-ext 経由でない Firefox では試していないが、Host 起動時に利用できる環境が変わっている可能性は十分にあるので、起動したプロセスから確認するクセをつけた方がよさそう。

cf.

感想

Native Messaging Host の開発は STDIN, STDOUT を奪われるのでだいぶ勝手の違う開発になるのと、普段から daemon process を扱っていないと勘所が分からずに苦労する。本当に力不足を感じましたとさ。

先にこの辺の取り回しをよくするライブラリを整備するといいんだろうなぁ。あと処理が複雑になると message に構造を持たせてそれで処理を分ける必要が出てくるだろうから、その router のようなものも欲しくなりそうな気がする。

あーあれだ。dRuby 使えばいいのか?


2019-09-16 [長年日記]

_ Flycheck入れてみた

Flymake 名前だけは知ってたけど、Emacs が古くて設定するのがダルくて入れてなかったやつ。

今回 Flymake 使ってみるかと思ったけど、やりたいことは make じゃなくて単なる lint レベルなんだよなーと思ったら Flycheck という別なものがあることに気づいた。

Flycheck — Syntax checking for GNU Emacs — Flycheck 32-cvs documentation

  • Rubyは標準で対応していて、何も設定しなくても ruby -c はとりあえず掛けてくれる
  • JavaScript は Automatically disabled! になっちゃう

うーん? Flymake の方がいいのか? と思ったけど、表示がババーンと邪魔くさく出ないので無視しちゃいそう。

Golang はなんか flycheck-golang を入れたらそれっぽく動いた。

weijiangan/flycheck-golangci-lint: Flycheck checker for golangci-lint

JavaScript はいろいろ試したけど全自動でちゃんと local の eslint を使うのが難しそうというのが分かったので、npm install -g standard したら zero config で動いた。

あーなるほど。話は逸れるけど今後は lint は standard 使うのがいちばんよさそうという気がしてきている。「style guide はとりあえず standard です」と言えるのはメリット多そうだし、すでに動いてるレガシーコードに合わせて緩めのルールを模索しがちだけど、判断のコストが大きすぎて進まないし、ちゃんと潰していった方がよさそう。

Tags: Emacs

2019-09-21 [長年日記]

_ OAuth2の動くサンプルサーバ

見つけたのでメモ。

Rails OAuth Provider Example

  • random accountの作成
  • アプリの登録

ができる。

  • client_id
  • client_secret

が取得できるので、これを使って

  • redirect_uri

を設定すると、redirect 先で

  • authorization_code

を取得できる。

OAuth2 の authorization code grant をそのまま試すことができるし、この流れがちゃんと Quick Start Guide

Rails OAuth Provider Example

にまとまっているので迷わず使える。

Tags: OAuth

2019-09-22 [長年日記]

_ RubyでOpenAPI clientの動的生成させてみた

OpenAPI に対応してる API の client 側を触る機会ができたのでせっかくならということで client の動的生成させてみた。本当はクライアントサイドは Ruby より JavaScript とかの方が充実しているような気がしないでもないけど、一応第一言語なので、悩むことが少なくていいんじゃないかと思って試してみた。

動的生成

notonthehighstreet/svelte: Dynamic Ruby API Client from Swagger JSON Spec

Svelte::Sevice.create(module_name: <NAME>, (url|json): <String>)

と呼ぶと、

Svelte::Sevice::NAME

という Module が生成される。ここ以下の名前空間に OpenAPI の path に応じた module がどんどんできていく。最終的には

Module::Path::To::Resource.operation_id_to_snake_case

みたいなメソッドができあがる。これを call すると、API を叩ける。他の option で大事なのはたぶん

  • options
    • protocol
    • auth

辺り。

とにかく OpenAPI の JSON を読みながら module を掘り、メソッドを call していくことができる。なるほどこれは便利だ。

ついでに静的生成

使い方はこんな感じ。

npx openapi-generator generate -i path/to/api.json -g ruby

OpenAPI 3 対応

OpenAPI parser と名乗っているものが OpenAPI 3 対応し始めている。

今回は試してません。


2019-09-23 [長年日記]

_ Signet gem + HttpLog gemがよかった

Signet gem

以前紹介した

Rails OAuth Provider Example

を利用して OAuth2 client の挙動を確認していたが、OAuth2 gem という誰よりも大事な名前を使っている gem で試してみたところ、そもそも OAuth2 gem の挙動があやしいことに気がついた。どう考えてもメジャーなのにドキュメントと挙動が合ってないように見える。少なくとも上のデモアプリでは期待通りに token を取得することができない。そこで代わりに使ってみたのが ruby-toolbox ですぐ近くに見えるこれ。

googleapis/signet: Signet is an OAuth 1.0 / OAuth 2.0 implementation.

当然だけど Google が自前の SDK を書く際に OAuth の部分はこれにお任せにしているので、利用実績も十分に多いと言ってよさそう。

やってみたらサクッと動いた。なんだったんだ OAuth2 gem ...

HttpLog gem

OAuth2 gem も Signet gem も内部で HTTP の部分は Faraday に依存していて、挙動をどうしても細かく確認したくなったのでしばらく log の設定をゴニョゴニョやっていたんだけど、外から設定を入れる方法がどうにもよく分からない。積極的に自分で Faraday を使ったことがないので。そこで別なアプローチを採ることにした。そのために活用できたのがこれ。

trusche/httplog: Log outgoing HTTP requests in ruby

完璧に意図通りではないが、概ね期待通りに動く。いろんな HTTP ライブラリの挙動を外部から logging できる。これはなかなか便利。

Tags: Ruby OAuth HTTP