tkawachi Blog

ActiveSupport 日時計算の罠

ActiveSupport の日時計算はとても便利です。直感的な記法でスラスラ書けちゃいます。 でもハマるポイントもありますので注意してください。 というか昨日僕がやらかしたことの告白です。

下のコードを見てください。

1
2
3
4
5
6
7
t1 = Time.new(2012, 12, 1)

t2 = t1 + 1.day
t2 - t1 == 1.day # => true

t3 = t1 + 1.month
t3 - t1 == 1.month # => false

a = b + c だったら普通 a - b = c だろうと思うのですが、最後の式は false を返します。 なぜだかわかりますか?

Rails の JavaScript (CoffeeScript) でローカライゼーションを簡単に

Rails 3.2 のプロジェクトで作業していて JavaScript (CoffeeScript) でのローカライゼーションをしたくなりました。 調べてみたところ i18n-js が簡単につかえてよさそうな感じです。

まずは Gemfile に追加して bundle install

Gemfile
1
gem "i18n-js"

続いて application.js に以下の行を追加。

app/assets/javascripts/application.js
1
2
//= require i18n
//= require i18n/translations

app/views/layouts/application.html.erb に以下の行を追加。 指定した言語で訳が存在しない時にデフォルト言語の訳を参照したいので I18n.fallbacks = true; を指定しています。

app/views/layouts/application.html.erb
1
2
3
4
5
<script type="text/javascript">
    I18n.defaultLocale = "<%= I18n.default_locale %>";
    I18n.locale = "<%= I18n.locale %>";
    I18n.fallbacks = true;
</script>

最後に rake i18n:js:setup を実行すると config/i18n-js.yml が生成されます。

これで config/locales/*.yml に書いてある Rails (Ruby) 側で利用できる情報と同じものが利用できるようになります。

ローカライゼーションは I18n.t() 関数で実行します。

1
I18n.t("hello");

デフォルト値を指定したい場合はこんな感じ。

1
I18n.t("hello", {defaultValue: "こんちは"});

便利に使わせていただきます。

Octopress に Facebook Recommendations Bar を設置

この blog は Octopress を使って github pages で書いています。

Facebook recommendations bar を追加してみました。 Facebook の Recommendations Bar のページから blog 用の Facebook application をひとつ作って、code snippet を吐き出します。

あとは このように source/_layouts/post.html を書き換えます。 Github pages だと何を変更したかも github で見られるのが嬉しいですね。

Blog の like 数が少なすぎるのでしょう。まだおすすめがちゃんと出ないようですが、 like 数が増えると出るようになるのでしょうか。

sessanの日記 - はてなブログにFacebookのRecommendations Barを設置する を参考にしました。

Facebook Promoted Posts

Facebook で投稿したときに右下に表示される「宣伝する」を試してみました。 大学時代の仲間内で作ったアプリをリリースしたのでそのお知らせということで。

「宣伝する」ボタンを押すとこんな画面が表示されます。

支払画面1

674円とのことです。 うーん。高いのか安いのか? よくわかりませんが、何事も経験なので勉強代だと思ってクレジットカードを入力します。

支払画面2

どうやら 81 Facebookポイント を 674円で購入し、それを使って「大切な投稿を宣伝」を購入したようです。 1 Facebook ポイントは 8.32 円ですか。 キリが悪いように感じますが、為替相場を考えると 10 Facebook ポイントが $1 なのでしょう。

購入後しばらくは何も変化が感じられません。 結果が見えるようになるまで1日近くかかります。

結果表示

1日後くらいから上の画像のような結果が表示されます。 どうやら通常見られるより2倍以上の露出があったようです。

投稿からの流入だけではありませんが、投稿内に書いた AmbientPlayer の紹介動画は72回再生がありました。

Facebook のヘルプ によれば、そもそも自分の投稿の読者のみにしか表示されないことが書いてあります。 私のフレンド数がおおよそ180ですので、最大露出がこの程度なのでしょう。 今回の宣伝がフレンドの全域に行き渡ったと仮定すれば、普段の投稿の露出はこの半分程度になっていると言えます。

雑感ですが、「宣伝する」はあくまで露出を高めるだけで、それを見た人に何かしら訴えるのは投稿内容ですから、どれくらいアクションを起こしてもらえるかは投稿の内容が肝になりそうです。 が、大きな反響を呼ぶ投稿であれば「宣伝する」しなくても、ライクを集めタイムラインへの露出は増えるように思います。 もちろん露出を増幅する効果はあるでしょうが、効果は微妙かなという感じを私は受けました。

Generating HTML From DocBook

これまで DocBook には縁がなかったのですが、とある DocBook 形式の .xml ファイルを HTML に変換したくなりました。 DocBook project で用意されている xslt を xlstproc コマンドであててあげれば良いようです。

今作業している MacOS X (Mountain Lion) には xsltproc が /usr/bin/ にインストールされているようです。 DocBook 用の xslt をインストールするのに Homebrew を使います。

1
2
3
4
$ brew install docbook
$ xsltproc -o book.html \
  /usr/local/Cellar/docbook/5.0/docbook/xsl-ns/1.77.1/xhtml5/docbook.xsl \
  book.xml

こんなかんじで無事に book.xml から book.html を生成することができました。 DocBook って難しくて怖いイメージがあったんですが意外に簡単にでした。

IAMユーザのS3アクセスをフォルダレベルで制限する

AWS の IAM でユーザを作り、S3 bucket の特定の path 以下にのみアクセスを与えるということを設定したかったのですが、情報を見つけられず時間をつかってしまったので共有しておきます。 (参考: Giving a user permission to acceess just a folder within a bucket)

現状 AWS では bucket 数上限が 100, IAM ユーザ数制限が 5000 になっています。 利用者1人に 1 IAM ユーザを発行すると 5000 人で使えるわけですが、 bucket 毎に共有設定を行った場合は 100 共有までです。 同一 bucket 内で path を切り替えて共有した場合は bucket 数上限は関係なくなるので嬉しい、というわけです。

まず最初に S3 の IAM policy に関するAWS の公式ドキュメントは Using IAM Policies です。 Bucket レベルの指定は arn:aws:s3:::bucket_name に対して行い、 object レベルの指定は arn:aws:s3:::bucket_name/key_name に対して行います。

同ページ内の Example 5: Allow a partner to drop files into a specific portion of the corporate bucket がやりたいこととほぼ同じ設定になります。

Object レベルの指定で path 以下にアクセスを制限したいときは * が使えます。 my_bucket bucket の shared/ 以下に s3:PutObject を許可するには、以下のような statement を追加します。

1
2
3
4
5
{
  "Effect":"Allow",
  "Action":"s3:PutObject",
  "Resource":"arn:aws:s3:::my_bucket/shared/*"
}

上記は object レベルでの指定になります。 S3を利用するアプリケーションによっては object レベルの API だけではなく bucket レベルでの API も使うものがあります。

Bucket レベルの指定で path 以下にアクセスを制限したいときは Condition, StringLike を使います。 s3:ListBucket, s3:GetBucketLocation を許可するには、以下の様な statement を追加します。

1
2
3
4
5
6
7
8
9
{
  "Effect": "Allow",
  "Action": ["s3:ListBucket", "s3:GetBucketLocation"],
  "Resource": "arn:aws:s3:::my_bucket",
  "Condition": {
    "StringLike": {
    "s3:prefix": "shared/*"
  }
}

上記の方法でアプリケーションが利用する API に応じて object レベル, bucket レベルの action を許可すれば、今回の目的が達成できます。

なお、S3 すべての action についてこれらの指定で動作することを検証したわけではないので、必要に応じてみなさまご確認ください。

Sending Git Revision to Exceptional.io

Exceptional.io は Ruby アプリケーションで起きた例外を集約して管理するサービスだ。

例外が起きた時に困るのが、それってどのバージョンで起きたバグ?ってことがわからないこと。 日付が記録されているので調べればわからなくはないけど、面倒だよね。

Exceptional.io では付加情報を付け加えて送ることができるので、以下の utility class をつかって git の revision 情報を取得し、それを送るようにしてみた。

あとは

1
Exceptional.context({git_revision: GitUtil.revision})

こんな感じのコードを例外送出前に呼んでおくと、付加情報と共に送られていく。

これでどのコミットからどのコミットまで例外が起きてたかわかるようになった。便利便利。

Open Sources Used by Spotify

US などの iTunes store からダウンロードできる Spotify の iOS アプリの出来がとても良い。 アプリ内に用意されている Lisence のページを見ていたら、利用している open source ソフトウェアの一覧が並んでいたので、ちゃんと出来てるアプリに使われているものはきっとちゃんとしているだろうということでメモしておく。

  • Boost
  • Expat
  • FastDelegate C++ の member function pointer に代わる何か?
  • giflib GIF
  • libjpeg JPEG
  • libpng PNG
  • libogg Ogg
  • libvorbis Vorbis
  • Tremolo Tremolo is an ARM optimised version of the Tremor lib from xiph.org. For those that don’t know, the Tremor lib is an integer only library for doing Ogg Vorbis decompression.
  • Mersenne Twister Mersenne Twister(以下MT)は、松本眞 ・西村拓士(アルファベット順)により1996年から1997年に渡って 開発された疑似乱数生成アルゴリズムです。
  • Snd Snd is a sound editor. Spotify では resampling にコードを流量。
  • zlib
  • NSIS Windows のインストーラ作成システム。
  • Windows Template Library Windows Template Library (WTL) is a C++ library for developing Windows applications and UI components. It extends ATL (Active Template Library) and provides a set of classes for controls, dialogs, frame windows, GDI objects, and more.
  • Growl
  • Lua
  • Nu Nu is an interpreted object-oriented language. Its syntax comes from Lisp, but Nu is semantically closer to Ruby than Lisp. Nu is implemented in Objective-C and is designed to take full advantange of the Objective-C runtime and the many mature class libraries written in Objective-C.
  • SBJSON
  • ASIHTTPRequest
  • MAObjCRuntime MAObjCRuntime is an ObjC wrapper around the Objective-C runtime APIs. If that’s confusing, it provides a nice object-oriented interface around (some of) the C functions in /usr/include/objc.
  • Google Breakpad An open-source multi-platform crash reporting system
  • iCarousel iCarousel is an open source (free) javascript tool for creating carousel like widgets.
  • MBProgressHUD MBProgressHUD is an iOS drop-in class that displays a translucent HUD with an indicator and/or labels while work is being done in a background thread
  • KKGridView High-performance iOS grid view (MIT license). iOS6 では iOS SDK に類似の view controller を入れたので不要に。
  • KissXML KissXML provides a drop-in replacement for Apple’s NSXML class culster in environments without NSXML (e.g. iOS).
  • ProtobufObjc
  • Facebook
  • Chronium
  • CEF The Chromium Embedded Framework (CEF) is an open source project founded by Marshall Greenblatt in 2008 to develop a Web browser control based on the Google Chromium project. CEF currently supports a range of programming languages and operating systems and can be easily integrated into both new and existing applications.

Mac 版 Spotify のブラウザっぽいものは CEF なのかな。

Google Breakpad, Nu, MAObjCRuntime, KKGridView あたりはすぐ使うかも。要調査。

Run Rspec Faster for Rails 3.1

個人プロジェクトで Rails 3.1 のアプリケーションを書いていたのだが、rake spec の 実行が遅くてイライラしていた。 1回の実行に 10 秒程度が掛かっていた。 テスト実行は 0.5 ms 以下で終了していたので、残りの 9.5 s 以上は framework の開始 などに費やされていると想像される。

この状態で皆が満足するはずが無いと思い、少し調べたところ spork が求めるもののようだ。 これはテスト用サーバを別プロセスで起動しておき、drb で rspec などによるテスト実行を キックできるもののようだ。

また guard-spork を使えば、 spork を用いたテストの実行をファイル書き換え時に行うことができるようだ。 またテスト結果の通知を Growl で行うことも出来るようだ。