デーモンとして動かすSinatraアプリにユーザーのインストールしたRubyを使わせる

以前作った Sinatra アプリ(フォトビューワー)をデーモンとして動かそうとしてハマった記録。
Sinatra アプリをデーモン化したことは前にもやったことがあるので、基本的にはその時のエントリを見ながらやったんだけど、一つだけ、ハマりどころがあった。それはアプリが Ruby 2.0 以降(だっけ?)にサポートしているキーワード引数を使って書いてあるのに対して、システムにインストールされているのは Ruby 1.9.3 だってこと。ユーザーは rvm でインストールした 2.3.0 を使っているのでテスト中は動くけど、いざ本番になってみるとシステムの 1.9.3 が使われるので動かない。
どうにかしてデーモンにも rvm でインストールした 2.3.0 を使わせたい。
探し方が悪いのか、ググっても情報が出てこない。結局解決策を見つけたのは、自分のエントリだった。

つまり、起動スクリプトで GEM_PATH と GEM_HOME に rvm のパスを設定して export すればいいようだ。書いた起動スクリプトがこれ:

当然 PATH も rvm の Ruby のパスを設定している。
ともあれ、これで無事起動するようになった。

Windows 10環境のrubygemsでSSLエラーが発生した場合の対処法

新しい PC のセットアップ中、rubygems でエラーが発生した。環境は次の通り。

  • Windows 10 Home
  • Ruby 2.3.1 (RubyInstaller)
  • gem 2.5.1

発生したエラーは:

^o^ > gem install acm
ERROR:  Could not find a valid gem 'acm' (>= 0), here is why:
          Unable to download data from https://rubygems.org/ - SSL_connect returned=1 errno=0 state=SSLv3 read server certificate B: certificate verify failed (https://api.rubygems.org/specs.4.8.gz)

どうも、SSLのエラーらしい。

で、いろいろとググりながら試した結果、次の手順でうまく回避できたのでメモしておく。

rubygemsのアップデート

普通なら gem コマンドでアップデートできるけど、それが使えないので rubygems.org からダウンロードしてアップデートする。
 cf. rubygems-update 2.6.8
上のリンクから、rubygems-update の最新版 2.6.8 をダウンロード、インストールする。

^o^ > gem install rubygems-update-2.6.8.gem --local
Successfully installed rubygems-update-2.6.8
Parsing documentation for rubygems-update-2.6.8
Installing ri documentation for rubygems-update-2.6.8
Done installing documentation for rubygems-update after 39 seconds
1 gem installed

^o^ > gem -v
2.5.1

インストールしただけではアップデートされないので、update_rubygems コマンドでアップデートする。

^o^ > update_rubygems
RubyGems 2.6.8 installed
Parsing documentation for rubygems-2.6.8
Installing ri documentation for rubygems-2.6.8
(以下略)

長々とメッセージが出るけど、これでアップデートできた。

^o^ > gem -v
2.6.8

確認

これで、正常に使えるようになったはず。

^o^ > gem install acm
Fetching: thor-0.19.1.gem (100%)
Successfully installed thor-0.19.1
Fetching: acm-0.4.2.gem (100%)
Successfully installed acm-0.4.2
Parsing documentation for thor-0.19.1
Installing ri documentation for thor-0.19.1
Parsing documentation for acm-0.4.2
Installing ri documentation for acm-0.4.2
Done installing documentation for thor, acm after 2 seconds
2 gems installed

OK。

参考ページ

 cf. Ruby distros, RubyGems, and SSL—Oy vey!

九九表のすべてのマスの和

前回から時間が開いてしまった。本当は Text.Parsec の話題を書こうと思ってるんだけど、今日も時間がないので小ネタ、しかも他人のネタ。

 cf. 九九表のすべてのマスの和 – 無駄と文化

詳しくはリンク先を見て。いくつかの言語でやってるんだけど、Ruby と Scheme がなかったのでやってみた。

まずは Ruby。

takatoh@apostrophe $ ruby sum_of_kuku.rb
2025

1〜9までの配列の直積をとって、それぞれを掛けあわせて、最後に全部足してるだけ。

Scheme でも同じ考え方。でもリストの直積を取る手続きが見当たらなかったので direct-product を自作した。

takatoh@apostrophe $ gosh sum-of-kuku.scm
2025

逆関数法で指数分布する乱数を生成する

[0,1)区間の一様乱数から、指数分布にならう乱数を生成するには、逆関数法というのが使える。
指数分布の密度関数は、パラメータをτとすると:
f(\tau)=\lambda e^{-\lambda\tau}
であり、分布関数 g(τ) は:
g(\tau)=\int^\tau_{-\infty}{\lambda e^{-\lambda\tau}}d\tau=1-e^{-\lambda\tau}
となる。g(τ)は 0~1 の値をとるので、この逆関数:
\tau=-\frac{1}{\lambda}log(1-g(\tau))
の g(τ) の代わりに一様乱数を入力してやれば、τ は指数分布する乱数になる。

じゃあ Ruby でやってみよう。

λ=0.5とし、10000個の乱数を発生させている。
これを Excel でグラフ化したのがこれ。
expon
「指数分布」の曲線は、上に書いた密度関数の曲線を、スケールを合わせるために8000倍して描いている。乱数はちゃんと指数分布になっているようだ。

参考にしたページ:
 cf. http://www.ishikawa-lab.com/montecarlo/4shou.html

Box-Muller法で正規分布する乱数を生成する

一様分布する乱数から、正規分布に従う乱数を生成する方法に、Box-Muller法というのがある。
Wikipediaによれば、(0,1) 区間の一様分布乱数2つ(X,Y)から、下の式で2つの正規分布乱数 Z_1Z_2 が得られる。

Z_1=\sqrt{-2log{X}}\cos{2\pi{Y}}
Z_2=\sqrt{-2log{X}}\sin{2\pi{Y}}

Z_1Z_2 は標準正規分布となるので、これらに標準偏差 σ をかけて平均 μ を足してやれば、任意の正規分布に従う乱数が得られる。

Ruby で 10000個の乱数を発生させるスクリプトを書いてみた。ここでは平均 μ=1.0、標準偏差 σ=0.2 とした。

結果を Excel でグラフ化してみた。水色の点が 0.1 単位のヒストグラム。黄緑の線が Excel に用意されている MORM.DIST 関数で描いたもの(スケールを合わせるために NORM.DIST 関数の値は 1000 倍している)。

Box-Muller

こうしてみると、ほぼぴったりと正規分布になっているようだ。

ちなみに Excel で平均値と標準偏差を求めたら、それぞれ μ=0.997、σ=0.201 となった。

Windowsマシンで動かしているSinatraアプリにほかのマシンからアクセスできなくてハマった

おおよその事情はタイトルの通り。
Windows マシンで Sinatra アプリを動かす。

^o^ > rackup config.ru

ポート 9292 で待機するので、ほかのマシンからアクセスするも繋がらない。ローカルホストからだとちゃんと繋がるので、アプリのせいではない……と思ったら、これが大間違いだった。

最初、ファイアウォールのせいだと思って Norton Internet Security のポート開放方法とかをググって試してみたけど、どうやっても繋がらない。
さんざんやったあげく、ふと Sinatra で同じ目にあってる人がいるかと思って「ruby sinatra ポート」でググったら、次のページを見つけた。

 cf. Sinatraがデフォルトでは外部から繋がらなくなってたよ – Qiita

なんてこった。Sinatra 1.4.0 から development 環境ではデフォルトでローカルホストからしかアクセスを受け付けなくなったようだ。
ともあれ、原因と解決法が分かった。次のようしてどのホストからのアクセスも受け付けるようにすればいい。

^o^ > rackup -o 0.0.0.0 config.ru

これで無事OK。

ダイクストラ法

ダイクストラ法とは、グラフ上の最短経路問題をとくアルゴリズム。↓このページに詳しいアルゴリズムの説明がある。

 cf. ダイクストラ法(最短経路問題) – deq notes

Ruby でやってみた。
例題は、上のページにもあるこのグラフ(ただしノードにつけた番号のせいか上下が逆になっている)。

g

円(ノード)に番号がふられ、ノードをつなぐ辺(エッジ)にはそこを通るときのコスト(距離とも時間とも解釈できる)が付されている。この中の任意の 2 つのノードをつなぐ最短経路とコストを求めるのが最短経路問題だ。
今回は 0 番のノードをスタートし 5 番のノードをゴールとする最短経路とそのコストを求めてみる。

実行結果:

takatoh@nightschool $ ruby dijkstra.rb
10
0 -> 2 -> 4 -> 5

というわけで、最短経路は 0 -> 2 -> 4 -> 5、コストは 10 という答えが得られた。これは上のリンク先の答えと同じなので、あっていると思っていいだろう。

g1

Explorer-likeなPhotoViewer作った

名前は Potov。「ポトフ」と発音してほしい。

Potov-20160207

 cf. https://github.com/takatoh/Potov

Explorer-like とはつまり、左側にディレクトリツリーが、右側に選択したディレクトリの中の画像(サムネイル)が表示されるってこと。ディレクトリツリーの表示には jsTree を、画像の表示には Colorbox を使っている。表示専用で、画像の移動なんかは出来ない(するつもりもない)。
メインの実装言語は Ruby。フレームワークには Sinatra を使っている。一応シングルページアプリケーション。

画像を追加したり移動したりはファイルシステムで物理的に行う。今のところ、サムネイルを手動で作成する必要があるので、このへんは今後改修したいところだ。

FlaskでJSONを受け取る

Flask で POST された JSON を受け取るには request.json を使えばいい。
サーバー側(Flask)のコードはこんな感じ:

POST するクライアント側(こっちは Ruby)はこう:

HTTPClient#post_content に JSON と "Content-Type" => "application/json" を渡してるのがミソ。Content-Typeapplication/json になってることで、Flask.request.json でデコードされたデータが得られる。

filestorageとfilestorage-s3の0.1.0をリリースした

以前作って rubygems.org に登録した gem、filestorage を filestorage と filestorage-s3 に分割してリリースした。どっちもバージョン0.1.0。

機能的には直前のバージョン0.0.6と変わったところはないけど、ローカルファイルシステム用の filestorage と Amazon S3 用の filestorage-s3 に分けた。これでローカルファイルシステムしか使わないのに、aws-sdk とかがインストールされることもなくなった。
良かったら使ってください。

ソースコードはこちら: