絶対R領域

2011-12-06

[][][]Cucumber + CapybaraでUserAgentを設定してテストを行う

jpmobileで作成されたRailsプロジェクトをテストする必要があったので調べてみました。

ちょっとググると次のサイトが出てきます。

Ruby 1.9 + Rails3 + jpmobileで構築したサイトをcucumberでテストするためのTips

Capybara::Driver::RackTestに細工をしてUserAgentを偽装する方法です。

ただし、手元にインストールされているCapybara1.1.2はCapybara::Driver::RackTestは無くなっており代わりにCapybara::RackTest::Driverが実装されていて、上記の偽装を行うことができません。

他の手を探してみたところ次の記事が見つかりました。

Creating a custom Capybara driver

この方法は新しいCapybaraのDriverを設定してしまう方法です。

features/support/env.rbに次を設定します。

  Capybara.register_driver :mobile do |app|
    Capybara::RackTest::Driver.new(app, 
      :headers => {'HTTP_USER_AGENT' => 'KDDI-CA39 UP.Browser/6.2.0.13.1.5 (GUI) MMP/2.0'})
  end

次にfeatures/step_definitions/web_steps_ja.rbに次を追記します。

前提 /^携帯端末でアクセスしている$/ do
  Capybara.current_driver = :mobile
end

これでモバイルサイト向けのfeaturesが書けますね。

各キャリア毎にDriverを設定しておけばテストの幅が広がっていい感じです。

2011-11-23

[]Ruby標準添付CSVライブラリCSV::Convertersについて調べてみた

CSVの書き出しでちょっとやりたいことがあって標準添付のCSVライブラリについて調べてたんだけど、結局標準のままだと出来なそうという結論に至りました。その際にCSV::Convertersについて色々ほじったのでメモがわりに残しておきます。

CSV::Convertersって何?

ドキュメントを読むと「このハッシュは名前でアクセスできる組み込みの変換器を保持しています。」と書かれています。変換器と言われてもどう使えばいいのかピンと来ませんでした。ググッてもサンプルとかあんまり無いし。

とりあえず使ってみる

まぁ、こんな感じで使えます。

require 'csv'
CSV.parse("2011-11-23,123,456",:converters => :date) do |csv|
  p csv
end

実行すると

[#<Date: 2011-11-23 (4911777/2,0,2299161)>, "123", "456"]

って感じで自動的にDate型に変換されてますね。ここではparseメソッドでconvertersを指定していますがforeachとかでも同じように使えますよ。

convertersの種類

csv.rbの中で定義されてます。


  Converters  = { integer:   lambda { |f|
                    Integer(f.encode(ConverterEncoding)) rescue f
                  },
                  float:     lambda { |f|
                    Float(f.encode(ConverterEncoding)) rescue f
                  },
                  numeric:   [:integer, :float],
                  date:      lambda { |f|
                    begin
                      e = f.encode(ConverterEncoding)
                      e =~ DateMatcher ? Date.parse(e) : f
                    rescue  # encoding conversion or date parse errors
                      f
                    end
                  },
                  date_time: lambda { |f|
                    begin
                      e = f.encode(ConverterEncoding)
                      e =~ DateTimeMatcher ? DateTime.parse(e) : f
                    rescue  # encoding conversion or date parse errors
                      f
                    end
                  },
                  all:       [:date_time, :numeric] }

rescueとか書かれてるので見ていただければ分かるんですが、この変換ルールって「変換できそうなら変換して、ムリならそのまま返す」っての基本なんですね。ちなみに:dateの箇所で定義されてるDateMatcherってRegexpなんですがかなりキツめに書かれていてハイフン区切りじゃないとdate型に変換してくれません。後ろに書かれてるDate.parseはスラッシュ区切りでも変換してくれるのにね。

独自の変換器を定義してみる。

たとえば「3列目の数字の後ろにyenを付ける」って変換器を書いてみます。

proc = Proc.new do |field,field_info|
  if field_info.index == 2
    "#{field}yen"
  else
    field
  end
end

CSV.parse("100,200,300",:converters => proc) do |csv|
  p csv
end

実行すると

["100", "200", "300yen"]

って感じです。

CSV::Convertersに登録してみよう

さっき作ったprocオブジェクトCSV::Convertersに登録してみましょう。

CSV::Converters[:yen] = proc

一度登録してしまえば次からは :convertersに:yenを指定するだけで使えます。

CSV.parse("100,200,300",:converters => :yen) do |csv|
  p csv
end

複数の変換器を適用してみよう

convertersと複数形になっているので当然配列も指定できます。配列を指定すると頭から順番に変換器が適用されます。

hoge = Proc.new do |v|
  "hoge#{v}"
end
fuga = Proc.new do |v|
  "fuga#{v}"
end
CSV.parse("100,200,300",:converters =>[hoge,fuga]) do |csv|
  p csv
end

実行すると

["fugahoge100", "fugahoge200", "fugahoge300"]

ですね。ではhogeとfugaを逆にすると

CSV.parse("100,200,300",:converters =>[fuga,hoge]) do |csv|
  p csv
end
["hogefuga100", "hogefuga200", "hogefuga300"]

となるわけです。

まとめ

CSV::Convertersを使うと特定のルールに従ってCSVに格納されているテキストを加工したり、特定のオブジェクトに変換したりできます。テキストからデータを読み込んだタイミングで変換されていると無駄なループが減って良い感じですね。

私が本当にやりたかったこと(余談)

本当は特定の列の値は必ずダブルクォートで囲んで出力するってのがやりたかったんだけど、この変換器は出力の対応はしてないみたい。モンキーパッチするしかないのかな...

2011-11-19

[][]世界でもっとも美しいポインティングデバイスMagic Mouse」を購入した

f:id:tech-kazuhisa:20111119235459j:image

▲イカの寿司

先日会社でiMacを購入して頂いたんですが、それに付属していたMagic Mouseの虜になったので個人的にも購入してしまいました。Macを使用している人は私の周辺にも多いのですがMagic Mouseを使っている人は少ないんでレビューしようと思います。

ファーストインプレッション

「最悪」の一言です。触った瞬間に「こりゃねぇよ。トラックパッドをマウスの上でやるのはムリがありすぎる」と思いました。ウチに余ってたマウスあったっけ?

10分後

「いや、意外とイケるかも?」と思い出しました。私はMacBookProのトラックパッド設定はアップルの思想に従い「ナチュラル」に設定していたものの、あるフリーウェアを導入してマウスの設定は従来通りのスクロール方向に設定していました。しかし、Magic Mouseでは「ナチュラル」な方向指定で全く違和感ありません。

そして虜に

「magick」とか間違えてますが、とにかく虜になりました。

先ほど書いた「ナチュラル」なスクロール方向指定で違和感を感じない理由ですが、人差し指で弾くように慣性スクロールできることが理由のような気がします。

あと、便利なのが指2本で軽く「タンタン」と叩く(クリックではない)とmission controlが起動するところです。トラックパッドだと指が3本必要なのですがmagic mouseではマウスから手を離すこと無く起動することができます。

ビミョウな点

Appleの紹介ページに書いてあるような横方向のスワイプは難しいです。もっと小さい動きで2本指で左右に弾くように操作するとうまくいくのですが慣れが必要です。

あと、見た目より重い感じがします。単3電池を使ってるので、単4を単3にするアダプタとか使えば少しは軽くなるかな?

まとめ

と、いうことで全ての人に薦められる商品ではないのですが、店頭でちょっと操作した程度では評価できない商品でもあります。

11月26日の岡山Ruby, Ruby on Rails勉強会に持って行きますので興味がある人はぜひ声をかけてください。

2011-11-03

[][]railsで必須入力項目にマークを付けるneed_labelを公開しました

railsでform_forを使ってフォームを作ったときに、必須入力項目を目立たせるのってめんどくないですか?

せっかくmodelに必須入力である情報が入っているのに、Viewでイチイチ指定するのは二度手間です。

そんな方のためにneed_labelというgemを作成しました。

インストール方法

Gemfileに次の一文を追加してください。

gem "need_label"

使い方

まず、modelに必須入力項目の設定を行なってください。

class User < ActiveRecord::Base
  validates :name, :presence => true
end

これで必須入力項目のlabelにneed-labelというclassが出力されるようになります。

例として次のようなcssを指定しておけば下線で目立たせることができます。

label.need-label{
  border-bottom: inset 2px red;
}

f:id:tech-kazuhisa:20111103221505p:image

苦労話

今回はじめてrubygemsパッケージを作成したのですが、テストを書くのが大変でした。need_labelはActionView::Helpers::FormHelperを改造したものですが、テストを行うにはActiveRecordも使う必要がありMVCを考慮したテストコードを書く必要があります。railsであればrspec-railsが良い感じに処理してくれるのですが、テストのためだけにrailsプロジェクトを作るのもナンセンスです。

他のプロジェクトはどうやってるのかな?という時に頼りになるのがgithub!イロイロなプロジェクトをcloneしまくって調査しました。似たような処理だとwill_paginateかなと思いコードを追っていたところ、知り合いから「kaminariの方がよくない?」と助言をいただきそちらを参考にすることに。

kaminariはfake_app.rbという1ファイルでmodelやcontrollerを定義しており非常にシンプルです。コレを参考にしてcapybara + nokogiriでhtmlをチェックすることでテストを無事書くことができました。

うーん。勉強になった。

2011-10-10

[][]Emacsrubyを使う

先日参加したオープンソースカンファレンス広島でお話しした @eielh さんに影響されてEmacsrubyを書きたくなりました。

ちなみに普段Railsの開発で使用しているのはRubyMineというRails用のIDEメソッドジャンプやコード補完などRailsに特化しているだけの事はあり満足度は高いです。ただ、勉強会でコードを見せ合う際にIDEを立ち上げるのはなんともかっこ悪い...(僕だけかな?)ここはviEmacsを華麗に使いこなしたいのです。つまりミエだけですw

突発的に思いつきtwitterで @ore_public さんに声をかけたところ時間を空けてくれました。ついでにATNDを立てたら中国GTUGのイケメンマネージャー(@ttyokoyama)も来てくれるとのこと。ありがてぇありがてぇ。

目標

Emacsを日常使える程度のショートカットキーを学習する。

EmacsRuby on Railsのコード補完およびメソッドジャンプを実現すること。

環境

MacOSX Lion

home brewインストールしたGNU Emacs 23.3.1

ショートカットキー

とりあえず次のキーで日常使用する作業はできそうな感じです。

ctrl + space で範囲選択

ctrl + w でカット

esc + w でコピー

ctrl + y でペースト(ヤンク)

ctrl + _ でアンドゥ

ctrl + kでカーソル行から行末までカット

ctrl + a で行頭(safariのTextAreaでも使用できる)

ctrl + e で行末(safariのTextAreaでも使用できる)

ctrl + g でコマンドを中断(こまったら押すこと!)

ctrl + o でバッファ間を移動

ctrl + 2 で上下分割

ctrl + 3 で左右分割

ctrl + 1で分割解除

ctrl + vでページダウン

esc + v でページアップ

ctrl + s でファイル内検索

grep検索

esc + x でgrep-findと入力してEnter

.の箇所をディレクトリに書き換え、-e の後に検索文字列を入力する。

Ruby on Railsのコード補完およびメソッドジャンプを実現

rsenseを組み込むことでコード補完ができるようになりました。

余談ですが、初めrsenseのオフィシャルサイトに書いてあるとおりに.emacsファイルを設定してもうまく動作させることができませんでした。

同じ現象の人は、.emacsの行頭に

(require 'cl)

って入れるとうまく動くかも。(Thanks > @eielh)

達成度

日常よく使う操作についてはショートカットキーを教えてもらったので多分大丈夫です。

rsenseによるメソッドの補完は良い感じ。これはRubyMineと同等だと思います。

メソッドやクラスの定義元へのジャンプは残念ながらうまく動作せず。ファイルをまたいだ場合とか全くジャンプしないので致命的です。

rsenseとは別にauto-completeによる擬似補完もいい感じなんだけど、cssの補完がおかしいです。color: redとか入力して;を押したタイミングでまた補完が走ってしまいます。cssについては補完をoffにしたほうがいいかも。

感想

と、いうことで、半分ぐらいの達成度でしょうか。最後は「RubyMineは良くできてる」って結論に落ち着いてしまいました。

自分のEmacsについてのレベルは多少上がったと思うので、gitのコミットメッセージを書いたり、ruby単体のソースを書く際は積極的に使っていこうと思います。