Tag Archives: ruby

Rack::Profilerを使う

Rack::Profilerを使うのに少し躓いたのでメモ。

Gemfile:

gem "ruby-prof"
gem "rack-contrib", :require => "rack/contrib"

app.rbのconfigureブロックあたり:

require "rack/contrib/profiler"
Rack::RubyProf = RubyProf
use Rack::Profiler

Rack::RubyProf = RubyProfをしているのはエラーが出るから。

アクセスする際にURL末尾に

?profile=process_time

を付けるとプロファイル結果がダウンロードできる。

あとはKCacheGrindとかQCacheGrindで解析する、らしい。 (qtのビルドで時間がかかってるのでまだできていない…)

参考


RestClientの返り値はStringとちょっと違う

インターフェースが簡潔で使いやすいRestClientだけれども、各種HTTPメソッドの返り値をto_iするとステータスコードを返すみたいだ。

たとえば次のようなSinatraアプリが起動していたとする。

get '/' do
  "1"
end

このgetルーティングに対してRestClientでアクセスすると、次のような結果が得られる。

require "rest_client"

res = RestClient.get("http://localhost:9292/")
#=> "1"

# Stringなのにto_iはステータスコード200を返す
res.class #=> String
res.to_i  #=> 200

# to_strしても変わらない
str = res.to_str  #=> "1"
str.to_i          #=> 200
res.class         #=> String

# 期待される値はと言うと
"1".to_i  #=> 1

内部でどうやっているかまでは確認できていないけど、 このようにRestClientの返り値のto_iはステータスコードを返す。

で、具体的にどんなときに不具合があるかというと、

  • Web APIからRestClientを使って取得した値をActiveRecord::Base.findに渡す
    • 内部的にto_iしているのか、毎回id=200を探しに行く
  • json gemによるエスケープ処理JSON.generate([val])が無限ループしてしまう

ではどうやっていつものStringとして扱うのかというと、Stringで包みなおせばいい。

res = RestClient("http://localhost:9292")
str = String.new(res)
str.to_i              #=> 1
str.class             #=> String

なんでこんな変な仕様になってるんだろう。 せめて返り値には別のクラスを使用して欲しかった。

そんな感じで、RestClientは変なところではまるので要注意。


Object#presenceが便利

ActiveSupport 2.3で導入されたObject#presenceが便利。

たとえば、

time = options[:timestamp].presence || Time.now

で初期値の代入に使えるし、

time = options[:timestamp].presence && Time.at(options[:timestamp])

で値がある場合に限って加工に使える。

組み合わせれば、

time = (options[:timestamp].presence && Time.at(options[:timestamp])) || Time.now

で値があれば加工して、なければ初期値を代入することができる。

でもこれはさすがにわかりづらいので、三項演算子を使って

time = options[:timestamp].present? ? Time.at(options[:timestamp]) : Time.now

としたほうがカッコが減ってわかりやすい。

ActiveSupportがないと生きていけないゆとりになってしまった…。


Mongoid/MongoDBでauto increment

Auto Increment with MongoDBより、Mongoid/MongoDBでMySQLのauto incrementみたいなことをする方法。

連番を保持するためのCollectionを用意して、新しくDocumentを作る際にそれをfind_and_modifyで1増加させるという方法をとる。 find_and_modifyを使うので、MongoDBは1.3.0以上、Mongoidは2.2.0以上が必要になる。

まずは連番を保持するためのCollectionを用意する。

class Seq
  include Mongoid::Document
  field :collection, type: String
  field :seq,        type: Integer
end

auto increment的なことがしたいCollectionではbefore_validateのタイミングでSeqから採番する。

class User
  include Mongoid::Document
  field :name,  type: String
  field :seq,   type: Integer, default: 0

  before_create :set_seq

  private

  def set_seq
    self.seq = Seq.collection.find_and_collection(
      query:  { "collection" => "users" },
      update: { "$inc" => { "seq" => 1 } },
      new:    true
    )["seq"]
  end
end

連番Collection別に連番を保持するためのDocumentは事前に用意して必要があるので忘れずに。

Seq.create(collection: "users", seq: 0)

yard-sinatraでSinatraのドキュメントにYARDを使う

yardのプラグインであるyard-sinatraを使うとSinatraのアクションごとに記述されたyardocからHTMLドキュメントを生成できる。

インストールと設定

yard-sinatraをインストールすれば必要に応じてyardもインストールされる。 ただしyardはデフォルトではプラグインを読み込まないので、読み込むように設定してやる必要がある。

$ gem install yard-sinatra
$ mkdir ~/.yardoc
$ yard config load_plugins true

ドキュメントの生成

$ cd /path/to/sinatra/project
$ yardoc
$ open doc/index.html # OSXでのみ有効

Class Listからアクションが実装されているClassを選択すると、HTTPメソッド順にアクションが並んでいる。


µ-optparseを使って.rvmrcを生成

optparseのラッパーであるµ-optparseを使って.rvmrcを生成するスクリプトを書いてみた。

オプションは下記の通り。–helpでも見れるし、コードを読むだけでもわかりやすい。

-r, –ruby
Rubyのバージョン。デフォルトはこのスクリプトを実行しているRuby
-g, –gemset
gemset名。デフォルトはカレントディレクトリ名
-f, –force
指定された場合、.rvmrcが存在しようがしまいが書きだす

たとえば次のコマンドでは”rvm use 1.9.2@rails31″を.rvmrcに書きだす。

$ rvmrc -r 1.9.2 -g rails31 -f

µ-optparseは宣言していない引数が指定された場合や、引数の値が条件(正規表現、特定の値、もしくは任意の判定条件を)にマッチしない場合にエラー文を出してくれたりと結構便利。–helpや–versionにも勝手に対応してくれるので、ちょこっとしたスクリプトを書くのに向いている。

まぁこんなコマンドを叩くぐらいなら直接echoした場合のほうが手軽だろうけど、どちらかというとオプション指定ナシで現在の環境の.rvmrcを吐くのが目的なので、実際問題オプションは必要なかったりする…かも


RubyKaigi2011(二日目)に参加してきた

今日も午後から参加してきた。@a_matsudaさん、@yharaさんの話が聞けなくて、寝坊してしまったことを激しく後悔している。

5 years know-how of RSpec driven Rails app. development. / @moro

最近のrspecやfixture-replacementを使ったテストの書き方のノウハウ。 fixture-replacementはFabricationを使ってるみたい。

寝坊して最後の5分しか見られなかったけど、早くもスライドUstが公開されているのでそちらをチェックしよう。

  • shared_context
  • fixtureはマスタ、fixture_replacementはリソース、beforeはイベントが向いてる
    • 適宜使い分けるといい

Rails3レシピブック買いました!

Efficient JavaScript integration testing with Ruby and V8 engine. / -Chris Kowalik

V8エンジンをRubyから呼び出してJavascriptのIntegrational Testをしようという話。

肝心のMustangとMikeの位置関係が理解しきれなかった。CとC++の混在してるMustangじゃなくてC++で統一されたMikeを使おうよ、って話でいいのかな。あとで別の人のレポートを読もう。

  • selenium時間かかりすぎ
  • selenium,watir,phantom 遅い
  • phantomはただのwebkitラッパーで、遅いことにかわりない
  • ヘッドレス
    • HtmlUnit(Java)
      • いち押し
      • 設定が面倒くさい
    • Zombie
    • EnvJS
  • 欲しいのは
    • 速さ
    • javascript support
    • 使いやすいAPI
    • ポータビリティ
  • Mustang – V8 in Ruby
    • nu7hatch/mustang
    • もとはrubyracer
    • スクラッチから設計・実装された
    • パフォーマンス重視
  • V8素敵
    • 世代GC
    • メモリモデルが優れてる
    • 暗黙クラス機能(?
    • インラインキャッシュ
    • ネイティブコードの生成
  • Mike
    • MustangはC/C/C++で書かれてる
      • 全部C++で書けばいいのに
    • https://github.com/nu7hatch/mike
    • 複数ウィンドウのサポート
    • フレームのサポート
    • ユーザの操作のサポート
      • クリック
      • フォーム入力
    • Javascriptの実行
    • アラート・ポップアップ
  • Q&A
    • V8のインスタンスはLinux上だと1個しか作れなかったと思うけど
      • 1つのインスタンスに対して複数のコンテキストを持たせることができるので問題にはならない

Advancing Net::HTTP / @wycats

net/httpは凄くいいライブラリだけど、ほんのちょっと機能が足りなかったのでnet2/httpとしてフォークしたよ、ついでにnet/reactorってのを書いたよ、っていう話だと思う。

IO周りが苦手なので全然ついていけなかった。

  • net/http
    • ブロックが多い
      • socketやレスポンスのリリースに使うからそうなってる
    • rackでリクエストとレスポンスに別のスレッドが必要になった
  • net2/httpにフォークした
    • ブロックの有無の分岐
  • よくわからん!

!RubyKaigi

時間が空いたので、3階で行われてた!RubyKaigi(not RubyKaigi)をチラ見してきた。

  • RubyKaigi会場にはmac多すぎて非macな私は孤独を感じてる! ** macは筐体のデザインが統一されているのでいっぱいいるように見える

実際Mac使ってる人多いよなぁ。Windows持ってきてる人は手元でどうやって作業しているんだろう?(@yuguiさんも「動いたらいいな」と思ってる)Cygwin?

個人的にはpowとか出てきちゃったのでなかなかmacからほかに移れない。でもLinuxもちゃんと勉強しなきゃだよなぁ…。

The Gate / @kakutani

Dave Thomasの基調講演の代理だったらしい。あまりメモを取れなかった。

今振り返ったら、昨日の@ayuminさんの発表ともなんかつながってるんだなぁと思った。 「たのしいRuby」って本が出てる通り、Ruby楽しい。だから仕事でも遊びと別け隔てなくそれをやっていきたい。 でもそれをやるために、「自分じゃない誰かにインスピレーションを与える」必要がある。 で、@ayuminさんの場合はそれが「攻めの人たちにRailsの必要性を説く」ってことだったのかもしれない。 (違ってたらゴメンなさい)

  • 達人プログラマー
    • 10年以上前の本だけど、今読んでも新しい発見がある
  • Pragmatic bookshelfにはいい本がある
  • アジャイルサムライ
    • 初めてアジャイルをやる人とかに、アジャイルの全体像を伝えるための本
  • Rubyが変えるのは会社ではなく人。変わった人が業務や業界を変えて行く。
  • 楽しく仕事をすることが大事
    • 生産性を上げる
    • 誰と仕事をするかが大事
  • 業務と業務外とを分けてたら立ちいかなるんじゃない?
    • 生きることの達人は、仕事と遊び、労働と余暇、心と体、教育と娯楽、愛と宗教の区別を付けない。何をやるにしろ、その道で卓越していることを目指す。仕事か遊びかは周りが決めてくれる。当人に取っては、つねに仕事であり遊びでもあるのだ(要出典)
  • 3つの宿題
    • 自分じゃない誰かにインスピレーションを与える
      • find someone to inspire who’s not like you
    • 自分の中に多様性を持つ
      • diversity
    • 前の人が通った轍から降りる
      • 新しい視点を持つ
    • そして楽しみながらやりなさい
  • Yesterday Is History, Tomorrow Is a Mystery, but Today Is a Gift. That Is Why It Is Called the Present. * 「カンフー・パンダ」からの一節らしい

LT

メモる余裕ナシ!

  • @nagachika
    • 9.2 trunk-commits/day
    • コミット中22%がバグ修正、しかし少なくとも3%が新たなバグを作り出している
  • @_yue_04
    • Ruby OS
  • @pwim
    • 外国人と日本人との壁をなくすために #trbmeetup を主催している
    • とても素晴らしいLTだった!
  • @niku_name
    • gem install myrurema
  • @florere
    • MacRubyで実装されたJamesと会話をする
    • Jamesは寝起きが悪い
  • こんどうようへい
    • Rails3 vs .Net MVC3
    • modernizr
    • .Net MVC3、テストの機能が有料版VisualStudioに依存
  • @ryopeko
    • rubykaigi.orgのソースは永和さん、えにしテックさんの最新の技術トレンドが注ぎ込まれてるのでとても参考になる
    • rubykaigi.com(ちなみにregional.rubykaigi.comも)はgithubベースで管理されてる
  • @stillpedant
    • vimperator : Firefox to vim
    • keysnail : Firefox to emacs
    • インタラクティブCLI
    • Rios::Proxy – gem install rios
      • コマンドライン入力・出力をフック
  • Eloy Durán & Vincent Isambart
    • MacRubyでCocoaを操作できるIRBっぽいものを作った
      • github.com/alloy
    • MacRubyはCocoaとがっちり連携できるから面白そう
  • @m_seki
    • ERB
  • Joseph Wilk
    • Limited Red
    • Work In Progressを減らす
    • 測定して可視化する

RubyKaigi2011(初日)に参加してきた

午後から参加してきた。

とりあえず箇条書きのメモを載せておく。あとで感想を書こう。

Ruby を利用した大規模ウェブサービスの開発・運用 / @hotchpotch

cookpadの中の話。extensionsがとても興味深かった。 この後のgithubとかもそうなんだけど、テスト=CIがもう当たり前なんだな、という感じがした。

  • 1.8.7/2.3
  • varnish
    • 30ms
  • tofu
  • solr
    • 集合を扱う(Facet
    • 重み付け検索(Boost Search
    • 動的なフィールド追加(Dynamicfields
    • 速度は変わらない、検索の柔軟性
      • 空間検索できるらしい
      • amebaの事例http://www.cyberagent.co.jp/news/press/2010/0708_2.html
  • ベストに集中
    • シンプル
    • キャッシュにのりやすい
    • 非同期を活用
      • 共通部分とユーザ固有とを分けることでキャッシュしやすくする
      • ユーザの体感速度的に問題ない
  • テスト
    • rspec 1.x
      • unit
      • functional
      • integration
        • JS周りの重視
          • capybara-webkit
    • リモートサーバ上でテスト
      • http://d.hatena.ne.jp/secondlife/20110410/1302442313
      • CIを通ったコードのみリリース
      • みんなテストを書く
      • CIで動かないテスト→将来的に価値のないテスト
  • extensions
    • 特定の条件下のみで有効になる機能拡張
    • 新機能の試用などに利用
    • 没になったら rm -rf app/extentions/foo_ext
    • specなくてok
      • 仕様の変更が多い
    • 例外が発生したら自動的に無効になる

Shipping at the Speed of Life / @atoms

githubの中の人の話。マシンガントーク。凄くたくさんのツールを使ってるみたい。

  • githubの維持のためにたくさんのツールを作った
    • 単純作業の自動化
  • BrowserdMod
  • collectd
    • 時系列データの収集(mysqlの書き込み時間とか
  • nagios
  • redis counters
    • 何が何回使われたか
  • campfire
    • コミュニケーション
    • http://propaneapp.com/
  • Haystack
    • hoptoadみたいなもの
    • 例外を監視
  • hubot
  • CI/Jenkinsの結果をcampfireに通知
  • new relic
    • http://newrelic.com/
    • パフォーマンスプロファイラ
      • レイヤごとに表示
  • silverline
    • https://silverline.librato.com/
    • アプリケーション別にリソースを監視
  • デプロイ
    • トピックブランチをデプロイすることもある
      • それならmasterにロールバックできる
      • 一部のサーバーに
      • subset deploy
      • heaven というライブラリで、特定のサーバに特定のブランチをデプロイ
  • まとめ
    • 大きなリリースをするときにはブログにポストを書いてユーザの反応を見る
    • 常にデータを集めておく、必要になったときに便利
    • カスタムな機能でプロセスの簡略化、柔軟性
      • プロダクトの成長で変化する
    • いいものをリリースすことを心かける
      • 価値を頻繁に提供する
        • 2週間スプリントとか生ぬるい
  • ユーザを大事にする
  • Q&A
    • マイグレーションどうしてる
      • まずカラム追加
      • それからコードを投入して使う
    • チャットなんでcamfireなん?
      • 安いし十分
    • 物理サーバだけ?
      • 小さなツールはrackspace使ってる
      • puppetとchef knifeで管理してる

Toggleable Mocks and Testing Strategies in a Service Oriented Architecture / EngineYardの中の人

HTTPのテストの仕方。あまり聞けなかった。

  • single responsibility principle
  • コードベースを小さくできる
  • チームで別々の部分を開発できる
  • RESTで通信
  • サーバのテストをするのが難しい
    • 遅い
    • 元の状態に戻せない(変更を受ける側が切り離されている
  • モックを作る
  • mock
    • オブジェクトの偽物
  • stub
    • メソッド(振る舞い)の偽物
  • fake
    • データの偽物
  • fakeweb
    • net/httpに相当するstub
    • fakewebの実装を知っている必要がある
      • テストにfakewebの初期化コードが入ってくるから?
  • Artifice
    • https://github.com/wycats/artifice
    • Rackアプリケーションをnet/httpなテストのつなぎ先として指定できる
      • プロダクションのバックエンドのコードをそのままテストに利用できるかも
  • Q&A
    • mockするだけじゃだめ?
      • integrationalなテストとして
        • unitテストならmockでもいいのかも、適宜
    • 非同期のテストは?
      • あまり経験ない
    • 異常系のテストはどうする?
      • フェイクでエラー状態のデータを作る
      • できないところはユニットテストでカバー

Issues of Enterprise Rubyist ~SIerのなかのRubyistが考えるべきこと~ / @ayumin

今日一番興味深かった発表。Rubyは使いたいけど、リスク回避の回避でその方向に持っていくのは難しい。必要としている場所に必要であるということを提示できないといけない。

  • SIerの顧客がrubyに求めること

    • 安い早い柔軟
    • エンタープライズに耐えられる品質
  • 自分の手元をrubyで変える

  • わざわざやるほど逼迫した需要がない
  • たのしいRubyより仕事の役に立つRuby。役立つRubyより、開発現場に欠かせないRuby。
  • リスク回避の回避は難しい
    • 攻めの部署に、すぐに使えて、柔軟に変更できる。効果をちゃんと測定できるソリューションを提案
      • 攻めの部署
        • 企画、営業
      • まもりの部署
        • 開発、運用
  • Q&A
    • ruby/railsは何が向いてると思います?
      • 定型化されていないもの(営業管理?CRM,SFA

日本の図書館はどのようにRubyを使っているか – 「Next-L Enju」と「国会図書館サーチ」 / -

途中から見たけど、とても面白そうだったようなのでUstでみようと思う。 elispは衝撃的。

  • solr
  • 目録登録がemacs lispで動く

Rubyで作った “critical mission” システムについて / @emorima

TokyoRubyistMeetupでお聞きした、東京ガスでの事例。RubyはWebサービス以外でも使われるべき。

  • 東京ガスの事例
  • リアルタイムにセンサからの情報を得るために、100プロセスx100スレッド/プロセス=10000スレッド
    • ディスクリプタ上限を超えていた
    • できるできないではなく、やらなければならない!
  • 計算量が必要な部分はCで実装
  • 230プロセスを使うプログラム、Cで作りたい?
  • “Rubyすげぇ”
    • 直感的
    • 容易
      • Thread
      • UDP/TCP Socket
    • 便利なメソッド
      • yield
      • instance_eval
    • テストが簡単に書ける
      • 正常系は当たり前
      • 異常系もできる
  • 大規模システムでも使えると思う
    • もったいない
    • ただスピードと信頼性は課題
  • Q&A
    • なんでruby?
      • お客さんがrubyを選んだから
    • rubyのアップグレードする?
      • 基本やらない
      • 安定稼働がなによりも大事
      • やるときは安定性のテストを行う

geminaboxでローカルにgemをホストする

geminaboxを使ってローカルにgemをホストしてみる。

(とりあえずでやってみただけなので、手順等にミスがあるかも)

まずはサーバを立てる

rvmとpowが入っている前提で。 ~/var/geminabox 以下を使うとする。

$ rvm use 1.8.7@geminabox --create
$ gem install geminabox
$ mkdir -p ~/var/geminabox/data
$ echo "rvm use 1.8.7@geminabox" > ~/var/geminabox/.rvmrc
$ echo 'require "rubygems"
require "geminabox"

Geminabox.data = "#{ENV['HOME']}/var/geminabox/data"
run Geminabox
' > ~/var/geminabox/config.ru
$ ln -s $HOME/var/geminabox $HOME/.pow

これで http://geminabox.dev/ にアクセスすればgeminaboxでホストしているgem一覧が表示される。

つぎにgemを追加する

たとえばhello-0.0.1.gemをrubygems.orgから落としてきて追加する。

$ wget http://rubygems.org/downloads/hello-0.0.1.gem
$ gem inabox hello-0.0.1.gem

これをやると http://geminabox.dev/ の一覧に追加される。

使ってみる

$ gem sources -a http://geminabox.dev/

もしくは~/.gemrcのsourcesに手動で追加する。

:sources:
- http://geminabox.dev
- http://rubygems.org

bundlerだったらGemfileに追記する。

source "http://geminabox.dev"
source :rubygems

では実際にインストールしてみる。

$ gem install hello
Successfully installed hello-0.0.1
1 gem installed

できた!

最後に

powとrvmのペアが最強すぎる。サーバをいちいち立ち上げる必要もないし、geminaboxの依存するgemと開発用のgemとが混在することもない。

あとはrubygems.orgから一度落としたやつをgeminaboxにコピーすることができたら完璧だ。 gemコマンドのフックってできないのかな?


rubygemsをバージョンを指定して更新

メモ。

gem install rubygems-update -v <バージョン>
update_rubygems

バージョンの一覧はrubygems.orgなどで確認するとよい。