( ꒪⌓꒪) ゆるよろ日記

( ゚∀゚)o彡°オパーイ!オパーイ! ( ;゚皿゚)ノシΣ フィンギィィーーッ!!!

表参道.rb #4で「本当は怖い オープンクラスと Duck Typing」というLTをやった話

スライドです

f:id:yuroyoro:20150904130822p:plain
本当は怖いオープンクラスとDuckTyping - 表参道.rb #4

まぁたいした話じゃないんですが、マッドマックスの画像をスクリーンに大写しできたのでその点だけで個人的には満足しています

「型を讃えよ」

ぼくのかんがえたさいきょうのGit Repository Browser: Gitterb をRuby2.1.2/Rails4にupgradeしてDockerImage作った話

3年ほど前に、GitterbというGitリポジトリのコミットログを可視化するツールを作った。


このアプリケーションはRuby1.9/Rails3.2 で書かれていて、今となってはもう動かないので、Ruby2.1/Rails4へupgradeした。

デモサイトはこちら http://gitterb.yuroyoro.net/


依存しているGritというRubyからGitリポジトリをホゲるGemがRuby2系では動かないので、libgit2のRubyバインディングであるRuggedに移行している。

あと、せっかくなのでCentOS7で動くDockerImageを作った。Docker Hubにおいてある。

以下のようにdocker pullした後にrunすると、port3000でサンプルが起動する。

docker pull yuroyoro/gitterb
docker run -d -p 3000:3000 -t yuroyoro/gitterb


macでboot2dcoker使ってる人は、port forwardingしてくだされ。

ssh -N -L 3000:127.0.0.1:3000 docker@localhost -p 2022

( ꒪⌓꒪) あばばばばばばばば

Rails3でMultiJsonのBackendをyajlに変更してJSONのエンコード/デコードのパフォーマンスを改善する

yajl(Yet Another JSON Library)っていう高速なJSONライブラリがあって、

yajl


こいつをrubyから使えるようにするyajl-rubyってgemがあって、これをMultiJsonのBackendに変更することで、RailsにおけるJSON処理の高速化が期待できるデス。

brianmario/yajl-ruby · GitHub


素のjson.gemと、yajl-rubyとで適当なActiveRecordオブジェクトからJSONへのエンコードと、その逆のデコードで簡単にベンチってみると、約2倍の差があることが分かる。

--------------------------------------------------------------------------------
Benchmark of json encoding/decoding
  json_gem vs yajl
--------------------------------------------------------------------------------

                                            | json_gem |    yajl | json_gem/yajl |
--Single ActiveRecord Object -----------------------------------------------------
encode                               x10000 |   12.130 |   6.167 |         1.97x |
decode                               x10000 |    1.085 |   0.437 |         2.48x |
--Array  ActiveRecord Objects-----------------------------------------------------
encode                               x10000 |  508.319 | 225.235 |         2.26x |
decode                               x10000 |   39.069 |  19.869 |         1.97x |

MultiJsonのBackendをyajlに変えたら素のjson.gemの2倍のパフォーマンスになった件


MultiJsonは、yajl-rubyがあると自動的にそっちを見るようになってるので、gem 'yajl-ruby'するだけでjsonの処理が高速化する、とおもいきや……


ActiveSupport::JSONのコードを見てみると、JSONのデコード時にはMultiJsonを利用するようになっているが、エンコードする際にはActiveSupport独自の実装でエンコードするようになっている。この理由としては、ActiveSupportAPIと他のライブラリの実装で互換性がないかもしれない、という話みたいだ。

Endoding with yajl-ruby for rails 3 · Issue #40 · brianmario/yajl-ruby · GitHub


とはいえ、オブジェクトをActiveSupportのas_jsonでHashにしてしまって、それをyajlでJSONにエンコードすれば問題ないはず。ということで、このようなパッチを書いた。

MultiJson.engine = :yajl unless MultiJson.engine == MultiJson::Adapters::Yajl

module ActiveSupport
  module JSON
    def self.encode(value, options = nil)
      hash = ActiveSupport::JSON::Encoding::Encoder.new(options).as_json(value)
      MultiJson.encode(hash)
    end
  end
end

JSONを大量にやりとりする系のアプリケーションには多少のパフォーマンス改善が期待できる、はず。

Railsで今いるブランチによってデータベースを切り替える

ブランチングモデルとしてgit-flowを使っていて、メインラインとして、本番適用中のmasterブランチと、次期リリース用のrelease/9999ブランチと、メイン開発ブランチのdevelopがある。


ところが、開発中は頻繁にブランチを移動するし、ブランチによってDBのスキーマが異なるなんてザラにあるし、ブランチ切り替える度にconfig/database.ymlを書き換えるのもタルいので、こんな風に書いた。

development:
  adapter: postgresql
  database: my_app_<%=
    case `git symbolic-ref --short HEAD`
      when 'master'  then 'master'
      when 'develop' then 'develop'
      when /release\/.*/ then 'release'
      when /hotfix\/.*/  then 'master'
      when /feature\/.*/ then 'develop'
      else 'develop'
    end
  %>
 
  username: yuroyoro
  password: yuroyoro
  host: localhost
  encoding: utf8

これで、masterブランチにいるときはmy_app_masterというDBを使い、release/9999ブランチの時はmy_app_releaseってDBを使うようになる。migrationが入り乱れたり、アプリケーションとスキーマが合わないので500るとかなくなって凄惨性あがる.

ちょっとの手間でRSpecの出力をキレイにするためにnamed_letというのを書いてみた

RSpecの話です。


RSpecは、テストコードがそのまま仕様を記述するドキュメントになる、というのが大きな利点の一つです。
しかし、rspecコマンドに-dオプションを渡して出力されるドキュメントは、必ずしも読める文章になっているとは限りません。


例として、以下のようなCanCanのspecを見てみます。

require 'spec_helper'
require "cancan/matchers"

describe Ability do
  context 'an user' do
    let(:user)          { Factory.create(:user) }

    let(:article)     { Factory.create(:article) }
    let(:own_article) { Factory.create(:article, :user => user) }

    subject { Ability.new(user) }

    it { should be_able_to(:read, article) }
    it { should be_able_to(:update, own_article) }
  end
end

Userは、ある記事をreadする権限を持っていて、自分が書いた記事はupdateすることができる、という記述です。
'should be_able_to(:read, article)'や' should be_able_to(:update, own_article) 'は、そのままの文章になってます。


では、これをrspec -dで実行してみます。


f:id:yuroyoro:20120110174348p:image:w640


アルェ?
'should be able to :read #

describe Ability do
  context 'an user' do
    let(:user)          { Factory.create(:user) }

    named_let(:article) { Factory.create(:article) }
    named_let(:own_article, "own article") { Factory.create(:article, :user => user) }

    subject { Ability.new(user) }

    it { should be_able_to(:read,  article) }
    it { should be_able_to(:update, own_article) }
  end
end


さっきのspecで、letで定義されていたarticleを、named_letを利用するように変更しました。named_letでは、第一引数のSymbolを表示の際に利用します。第二引数に別名を渡すことも出来ます。

    named_let(:article) { Factory.create(:article) }
    named_let(:own_article, "own article") { Factory.create(:article, :user => user) }


あらためて実行してみます。


f:id:yuroyoro:20120110174349p:image:w640


ちゃんと意図した文章になって出力されていますね。やったー。


ぼくのかんがえたさいきょうのGit Repository Browser

こんなヤツ

デモサイトはこちら http://gitterb.yuroyoro.net/


f:id:yuroyoro:20110707204302p:image:w360

Gitである程度運用してると、ブランチがいっぱいになっていつどこから生えたのかわからなくなったり、どのブランチがマージされてるか把握できなかったりとかがあると思う。
たとえばgit log --graph とかgit merge-baseとかコマンドで頑張ればいいんだけど、俺はあまり頭良くないし記憶力もないので、コミットのつながりをグラフィカルに表示してほしいと常々思っていたわけ。

たとえばGitXとかgitkとかGit Towerとかのツリー表示って、こんな感じじゃないですか。

f:id:yuroyoro:20110707204305p:image:w360

これはこれでまぁいいんだけど、この程度ならlog --graphやtigを使えばいいのでわざわざGUI起動するまでもないし、そもそもあんまりグラフィカルじゃない。見たいのは、Pro Gitとかにあるようなコミットを○と矢印でつないだ有向グラフな図なんだよ。


で、あんまりにもないので作った。

yuroyoro/gitterb · GitHub


Ruby1.9.2とRails3.0.9で動作確認してる。多分Ruby1.8.7/Rails2.3でも動くと思うけど確認してない。

LGPLなライセンスで。テストは、書いてない。pull request歓迎します。

セットアップ

pygementが必要なのでeasy_installでいれろ

 sudo easy_install pygments

Bundler使って依存Gem入れろ

    gem install bundler # if you haven't
    bundle install ./vendor/bundle

config/database.ymlに表示するgitリポジトリを絶対パスで指定しる

    development:
      repository: '/home/your_name/your_repository'

サーバ起動して、'http://localhsost:3000'で表示させり

    script/rails server

使い方的なアレ

とりあえず最初はmasterからさかのぼって100件分のコミットを出す。一緒に、表示されているコミットに到達可能なブランチとそのコミットもだす。これは'all'チェックボックスをoffると消える。
赤い時の四角がブランチで、青いのがtagな。
git log --graph --all的なイメージで表示してると思え。思え。

f:id:yuroyoro:20110707204303p:image


フォーカスするブランチを切り替えたいならプルダウンから選べばいいんじゃない?好きにすれば?


○で表示してるのがコミットオブジェクトな。マウス乗せるとコミットログをポップアップさせる。させる。

f:id:yuroyoro:20110707204304p:image

クリックすると、そのコミットの詳細が出る。ダブルクリックすると消える。以上。

できないこと

  • 複数のリポジトリを切り替えたり
  • リモートのブランチを出したり(fetchしろ)
  • comitしたりpullしたりrebaseしたりpushしたり(そういうのはもっと高機能なGUIツールでやるのがいいとおもいます)