読者です 読者をやめる 読者になる 読者になる

hatenablog-writer 0.1.1 と hatenablog 0.3.0

Ruby

今月は自分の gem にいくつか PR をいただいて新バージョンをリリースしました。PR をくださった方々、ありがとうございました。

hatenablog-writer 0.1.1

hatenablog-writer は CLI からはてなブログに投稿できるツールです。作ったきりほったらかしていたのですがブログ投稿に使ってもらっており、バグ修正の PR をいただきました。

github.com

hatenablog 0.3.0

上記の hatenablog-writer でも使っている、はてなブログ AtomPub API に Ruby からアクセスするための gem です。設定ファイルで ERB の記法が使えるようになる PR をいただきました。

github.com

この機能によって、例えば設定ファイルで次のように環境変数を使えます。アプリケーションにこの gem を組み込むときなどに使いやすくなるかと思います。

consumer_key: <%= ENV['CONSUMER_KEY'] %>
consumer_secret: <%= ENV['CONSUMER_SECRET'] %>
access_token: <%= ENV['ACCESS_TOKEN'] %>
access_token_secret: <%= ENV['ACCESS_TOKEN_SECRET'] %>
user_id: <%= ENV['USER_ID'] %>
blog_id: <%= ENV['BLOG_ID'] %>

所感

メンテや必要な機能に対する想像力が不足しがちなので、ちゃんとやっていきたい…

Ruby で順列の列挙を実装する

Ruby

最近いろいろな人が次の本をやっているのを見かけるので、気になって読み進めてみています。

プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問

プログラマ脳を鍛える数学パズル シンプルで高速なコードが書けるようになる70問

ほとんどの問題の解答例が Ruby で書かれているのが特徴で(たまに JS もある)、Ruby の機能やライブラリをうまく使うと簡潔に書けることがわかります。

数学パズル的な問題なので、よく順列を列挙する必要に迫られます。順列は、次のように要素列から要素を選んで並べるときの並べかたです。高校数学で場合の数を計算するときに散々やるやつですね。

[1, 2] から 2 個とる順列 → {[1, 2], [2, 1]} の 2 通り
[1, 2, 3] から 2 個とる順列 → {[1, 2], [1, 3], [2, 1], [2, 3], [3, 1], [3, 2]} の 6 通り

プログラミングで順列を解くとき、場合の数は n 個から r 個とるときは n! / (n - r)! を計算すれば求められるので簡単です。一方、実際の列挙ですが、Ruby では Array#permutation という便利メソッドがあり、これを呼び出すだけで OK です。

[1, 2, 3].permutation { |p| puts p }
# [1, 2, 3]
# [1, 3, 2]
# [2, 1, 3]
# [2, 3, 1]
# [3, 1, 2]
# [3, 2, 1]

これはとても便利なのですが、Array#permutation のような順列の列挙アルゴリズムを自前で実装しようとするとどうなるっけ……と不安を感じてしまったので、調べつつ Ruby で再実装してみました。

このスクリプトを実行すると、次の出力を得ます。

[["a", "b", "c"], ["a", "c", "b"], ["b", "a", "c"], ["b", "c", "a"], ["c", "a", "b"], ["c", "b", "a"]]
[["a", "b"], ["a", "c"], ["a", "d"], ["b", "a"], ["b", "c"], ["b", "d"], ["c", "a"], ["c", "b"], ["c", "d"], ["d", "a"], ["d", "b"], ["d", "c"]]

1 行目が ['a', 'b', 'c'] から 3 個とる順列の列挙、2 行目が ['a', 'b', 'c', 'd'] から 2 個とる順列の列挙です。1 行目のほうは何個とるかの引数を省略しているので、渡している配列のサイズ分とるようにしています。

アルゴリズムは次のページを参考にしました。再帰を使って、樹形図の作成をシミュレートすればよいことがわかります。

……こういう筋力的な部分をもっと強くしておきたい人生でした。

Yokohama.rb Monthly Meetup #71 に参加した

Ruby 日記

2016-08-06(土)の Yokohama.rb Monthly Meetup #71 に参加しました。

yokohamarb.doorkeeper.jp

  • 前半はもくもく会
  • 後半は LT 2 本
  • 吉田飯店で懇親会

という流れでした。今回も初参加の方が 2 名いらっしゃいました。

もくもく会

僕は次のようなことをやってました。

LT

1 本目は仮想通貨決済ビジネスをやっておられる方から、Rails で作っているサービスについての話でした。消費者がお店に対する注文を仮想通貨で支払えるように、消費者とお店の間を Web サービスでサポートし、手数料をもらうというビジネスモデルだそうです。仮想通貨のよいところは支払いが速いところで、お店としては売掛金がすぐに回収できてよいという話でした。

2 本目は @hamakn さんから、Rails 5 の新機能である Action Cable について素振りしたという話でした。Action Cable は WebSocket を使って簡単にチャットのようなアプリケーションを作成できる機能です。用意されていたデモアプリケーションを皆で触ったりしていました。

github.com

懇親会

懇親会では、若人の悩みを聞くなかで、最終的には基礎が大事という合意が形成されました。話のなかで SICP(『計算機プログラミングの構造と解釈』)が Web 上で読めるという話が出ていました。調べてみると原文のほか、いくつか和訳もあるようです。僕は読んだことないです……


次回 2016-09-03(土)の Yokohama.rb は以下リンクから申し込めます。

yokohamarb.doorkeeper.jp

Itamae + Vagrant でステージング環境を構築しようとしている

ツール Ruby

ここ数日、構成管理ツールの練習と自作の Rails アプリケーションを本番に近い環境で動かせるようにすることを兼ねて、Itamae を使って Vagrant 上にステージング環境を作ろうとしています。

とりあえず、Rails で構築した自分の web サイトである kymmt.com を動かすべく、Vagrant で CentOS 7 の VM を作って環境構築をやっていて、現状は Itamae で次の項目を実行できるようになりました。

  • rbenv で Ruby をインストール
  • Bundler をインストール
  • GitHub からアプリケーションのリポジトリをダウンロード
  • nginx のインストールと設定
  • PostgreSQL のインストールと設定

あまりキレイではないですが、試行錯誤しつつ作った現在の Itamae レシピは次のとおりです。

ハマった点

ここまでの作業でハマった点をメモしておきます。

psql を使うときは実行ユーザを変える

コマンド itamae ssh --vagrant で Vagrant の VM に対してプロビジョニングするとき、プロビジョニングの実行ユーザは root です。一方、PostgreSQL の DB アクセス用コマンド psql は、postgres というユーザから実行するコマンドとなっています。

ユーザ postgres としてコマンドを実行するために、次のように sudo を使います。

$ sudo -u postgres -i sh -c '<実行したいコマンド>'

sudo にオプション -u をつけると、指定したユーザになることができます。オプション -i/etc/profile.bash_profile などを読み込み直します。

その後ろの sh -c '<実行したいコマンド>' が大事なところです。ここに -u で指定したユーザとして実行したいコマンドを書きます。例えば、

sh -c "psql -c \\"SELECT * FROM pg_user WHERE usename='#{node['kymmt']['dbuser']}'\\""

と書くことで、ユーザ postgres として、psql を叩いて DB 用のユーザ作成を実行しています。

SELinux を無効にする

SELinux が有効なままだと、nginx 起動時に設定ファイルを読み込めないエラーが出たりします。

Itamae プラグインの itamae-recipe-plugin-selinux で SELinux を無効にしました。

include_recipe 'selinux::disabled'

レシピ内で利用できるヘルパーメソッドを作る

今回、リソース内の commandsudo を任意ユーザで実行できるように、ヘルパーメソッドを定義しました。

module ResourceHelper
  def sudo(user); "sudo -u #{user} -i"; end
end

これを Itamae のリソース内で使えるようにするためには、Itamae::Resource::Base::EvalContext にインクルードする必要があります。

Itamae::Resource::Base::EvalContext.include(ResourceHelper)

この方法は次のエントリを参考にしました。

今後の展望

まだ次のような TODO が残っているので、引き続きやっていきます。

  • Best Practice として紹介されているディレクトリ構成にする
  • Rails アプリケーションのデプロイを自動化する
  • Let's Encrypt の設定を自動化できるか調査する

Let's Encrypt は certbot-auto でインストールすると、TUI で対話式になって自動化しにくいので、ACME プロトコルで証明書を取得できるレシピを作らないといけないのかどうかが気になってます……

Yokohama.rb Monthly Meetup #70 に参加した

Ruby 日記

2016-07-09(土)の Yokohama.rb Monthly Meetup #70 に参加しました。

yokohamarb.doorkeeper.jp

参加者は 8 人。内容は次のような感じでした。

  • レシピブック読書会
  • どう書く
  • 吉田飯店で懇親会

レシピブック読書会

今回はレシピ 234 から 237 まで読みました。

レシピ 234

Ruby が require, load するときに参照するパスである ロードパス を制御するレシピです。ロードパスを設定するには、次の三つの方法

  • 環境変数 RUBYLIB
  • オプション -I
  • グローバル変数 $LOAD_PATH ($:)

がありますが、一番下の $LOAD_PATH を使うことが多いという話でした。

パスの区切りは OS によって違う(Windows なら ;, UNIX 系なら :)ので、定数になってるんじゃないかという話が出ました。実際のところ定数 File::PATH_SEPARATOR として存在していて、システムに応じて ;, :, , のどれかが入っているようです。

どの OS で使われるのかわからなかった謎のカンマ , については、次のとおり RISC OS 用に存在していたものだそうです。

レシピ 235

ruby コマンドでスクリプトを実行するときに、バグになりそうな箇所などについて警告を出せます。すべての警告を出すには、次のようにオプションに -w または -W2 を指定します。

$ ruby -w foo.rb

自前で警告を出したいときは、次のようにコードを書くと、オプションに -w または -W2 を指定したときだけ警告が出せます。

warn 'foobar' if $VERBOSE

これは、-w または -W2 指定を指定したとき、$VERBOSEtrue になるからです。

なお、stderr.puts$VERBOSE の値にかかわらず普通に出力されます。

また、require している外部 gem についての警告を抑止するための gem があるという話が出ました。

github.com

レシピ 236

デバッグ関係のレシピです。

ruby コマンドで -d オプションをつけて実行すると、例外発生時に例外をすぐ表示します。また、マルチスレッド環境でどれかのスレッドが例外を投げると、メインスレッドに例外を投げ直してくれます。

処理系組み込みのデバッガもあります。次のコマンドで debugrequire しつつスクリプトを実行すると、デバッガが起動します。

$ ruby -r debug foo.rb

実際には byebug を使うことが多いのではという話でした。

レシピ 237

UNIX 系の OS 上で /etc 次の情報(ユーザ情報やグループ情報)を取得するためのレシピです。

Etc.passwdEtc.group にブロックを渡すと、ユーザ情報やグループ情報を表す Struct::PasswdStruct::Group を順に取得できます。

Etc.passwd do |pw|
  p pw
end

この Etc.passwdEtc.group へブロックを渡さずに実行すると、実行するたびに違う Struct::Passwd オブジェクトが順番に返ってきて、最後までいくと nil が返ってくるようになるという挙動に会場はざわ…ざわ…となってました。

Etc.passwd   # 実行するたびに別の Struct::Passwd が返る

「どう書く」初挑戦

どう書く」というイベントの Yokohama.rb 版として、今回は @Nabetani さん作成の問題「Rails on Tiles」に挑戦しました。

40 分の挑戦時間で解けた人は 2 人でした。私は残念ながら時間内に解けず……

挑戦のあと、@Nabetani さんから解説の時間。

考えをコードへ無理なく落とし込めるようにしていきたいという感じです。Yokohama.rb 的には、こういうイベントではペアプログラミングをすることが多いそうなので、機会があれば参加してみたいですね。

追記:当日考えていた方針(すごくナイーブ)で正しく動くところまで書きました。


次回 2016-08-06(土)の Yokohama.rb は以下リンクから申し込めます。

yokohamarb.doorkeeper.jp