Hatena::Grouprubyist

うんたらかんたらRuby RSSフィード

2010-04-22クックパッドの開発の裏側見せます に参加してきた

クックパッドの開発の裏側見せます に参加してきた

| クックパッドの開発の裏側見せます に参加してきた - うんたらかんたらRuby を含むブックマーク はてなブックマーク - クックパッドの開発の裏側見せます に参加してきた - うんたらかんたらRuby

先週土曜日の話ですが

クックパッドの開発の裏側見せます in 京都 vol.2(4/17)

に参加してきました。


開発者ブログを見たのか、誰かのつぶやきを見たのか

このイベントを知ったきっかけがはっきり思い出せませんが、

cookpadといえばrailsamazonガシガシなイメージがあって

そんなお話が聞けるならと思って、行ってきました。


お話の内容

クックパッドのデータ処理、たった5万円:日経ビジネスオンライン

釣りタイトルですが、クラウドの話としては上記内容に関するお話でした。

あと、elastic mapreduceは実用性が低いとか

yahooが開発したPIGがよさそう(hiveは上限があって、スケールしなくなる)とか

hiveとmap reduceを使用しているとか(明確な使い分けはしていないらしい)。

効果的に使用している印象。


「コンフィデンシャルなデータをクラウドに置くことに社内の反対は無かったか?」という質問がありましたが

(それに対する答えは「特に無い」。自分もここは気になっていたのでwktkしながら聞いていたのですが)、

このあたりは、クラウド導入を検討している多くの日本企業にとって

障壁の一つであるとは言えると思いますが、

cookpadさんがやってるという事実がハードルを低くしてくれるのかも。

(まぁ金融系は、、、わかんないですが)


他には、非エンジニアのリテラシを上げて(firefox greasemonkeyを全社員にインストール)

社内ツール作って生産性アップ、というお話がありました。

このあたりは、参考にしたいですが

非エンジニアの要望を集約するのが難しいなぁと思ったりします。

きっと社内の風通しがいいんだろうな。いろんな人とコミュニケートができてる感じがします。


最後は、技術部長の方がエンジニア募集(cookpadの環境)についてお話されていました。

・開発環境はmacbookpro + 英語keyboard(他の方も仰られてましたが)

・週2回シェフによるまかない(+ エンジニアよるまかない)

この2点はすごく羨ましい。

特にmacによる開発。

最近、少しずつですが会社でwindowsrubyいれてscript書いたりrailsやったりしてるんですが

windowsってのが結構ネックと感じることがあります(遅かったり、使えないものがあったりpassengerなど)。

しかも、家では英語keyboard使ってるので、

家と会社往復すると、記号入力間違えまくりで凄いストレス。

jis keyboardに変えようかと思い直しているところだったりします。


あと、技術部長の方が楽しそうな方で

何度か「はてなおすすめです」と仰ってました。

(余談ですが、twitterの写真が怖くてfollowを断念しました。)

ただ、技術やサービスに対する思いは持っておられると感じました。


元はてなバイトの濱崎さんも入社に至った経緯などお話されていて

今すごく勢いのある会社だなぁと感じました。

cookpad良さそうです。


あと、

本いただきました。

本の内容は詳しく書きませんが、面白かったです。

ユーザにしっかり向いてると感じました。ブレてないです。cookpad



残念だったこと

ustやってるって知りませんでした。ATNDに書いておいて欲しかった。

・懇親会の食事を多少期待していたのですが、ホテルのポテトやサラダでした。

 →ま、仕方ないか。

・情報共有をうまくやってると濱崎さんが仰られてましたが、その辺りのノウハウ(redmine、codereviewなど)聞いておけばよかったな

トラックバック - http://rubyist.g.hatena.ne.jp/rochefort/20100422

2010-04-14autospecの結果をgrowlで通知〜windows編

autospecの結果をgrowlで通知〜windows編

| autospecの結果をgrowlで通知〜windows編 - うんたらかんたらRuby を含むブックマーク はてなブックマーク - autospecの結果をgrowlで通知〜windows編 - うんたらかんたらRuby

↓はmacの話なんですが、

autospecの結果をgrowlで通知 - うんたらかんたらRuby - Rubyist


職場ではwindowsも使うので、楽しくTDDBDD)するために

チャレンジしてみました。


インストール

Growl for Windows

をインストール。


macと同じように gem install autotest-growl としましたが

動きません。


調べてみるとautotest-growlforkして動くようにしてくれた

karl-autotest-growlというのがありました。

gem install karl-autotest-growl --source http://gems.github.com

これで難なくgrowlできました。

ありがたく使用させていだきます。

トラックバック - http://rubyist.g.hatena.ne.jp/rochefort/20100414

2010-04-13autospecの結果をgrowlで通知

autospecの結果をgrowlで通知

| autospecの結果をgrowlで通知 - うんたらかんたらRuby を含むブックマーク はてなブックマーク - autospecの結果をgrowlで通知 - うんたらかんたらRuby

インストール

growl

こちらからGrowl


autotest-growl

ZenTestからautotest及びautotest用のモジュールが

それぞれ別gemになった模様。

(ZenTest入れてない人は、gem install ZenTestで入れてください。)

$ sudo gem install autotest-growl

In order to use autotest-growl, the following line has to be added to your
~/.autotest file:

require 'autotest/growl'

Make sure the notification service installed on your computer:

http://growl.info (Growl for Mac OS X)
http://growlforwindows.com (Growl for Windows)
http://www.galago-project.org (libnotify for Linux)

If Growl notifications are not always displayed, take a look at the README
for assistance.

For more information, feedback and bug submissions, please visit:

http://www.bitcetera.com/products/autotest-growl

If you like this gem, please consider to recommend me on Working with
Rails, thank you!

http://workingwithrails.com/recommendation/new/person/11706-sven-schwyn

+-------------------------------------------------------------------------+
| UPGRADING USERS please take a look at the README now for important news |
| related to modified dependencies since 0.1.x and Rails compatibility.   |
+-------------------------------------------------------------------------+

上記は、インストール時に表示されるメッセージですが

なんとwindowsgrowlも開発されているというメッセージが。

近々使ってみたいと思います。


設定

メッセージ通り

~/.autotestを作成し下記を保存します。

require 'autotest/growl'


稼働確認

#~/.autotest
require 'autotest/growl'

autotest(autospec)を実行。

f:id:rochefort:20100413080951p:image

f:id:rochefort:20100413080952p:image

こ、これは楽しい。


画像は

下記に格納されています。

/opt/local/lib/ruby/gems/1.8/gems/autotest-growl-0.2.3/img/ruby


あと.autotestのsampleは下記。

/opt/local/lib/ruby/gems/1.8/gems/ZenTest-4.3.1/example_dot_autotest.rb


補足

以前は、growlnotify が必要なようでしたが

現在は無しでも動きます。(素晴らしい!)

(探せば結構情報がありますが、旧バージョンの情報が多いようです。)

masashi_fujimasashi_fuji2010/11/03 13:07autotest + growlに関しては古い記事が多くて混乱していましたが、この記事のおかげですんなりと環境構築できました。ありがとうございました。

rochefortrochefort2010/11/03 16:15お役に立ててよかったです。
ruby / rails 周りは進化が早いですからね〜。readmeやらdocumentは必ず読むようにしてます。

2010-04-12autospecでテストを自動化

autospecでテストを自動化

| autospecでテストを自動化 - うんたらかんたらRuby を含むブックマーク はてなブックマーク - autospecでテストを自動化 - うんたらかんたらRuby

zen testのautotestという機能を使うと

テストコードを修正して保存する度に

自動的にテストが実行されます。


↓の実演動画内で稼働していて、便利そうだなと思ったので

使ってみました。

(growlでの通知はまた次回)

簡単で便利で最高です。

スはスペックのス~RSpecによるテスト駆動開発の実演 - うんたらかんたらRuby - Rubyist


install

$ sudo gem install ZenTest


autospec

rspec入れるとついてくるautospecコマンドを実行すれば

自動でテストされるようになります。


$ autospec
loading autotest/rspec
/opt/local/bin/ruby /Users/rochefort/.gem/ruby/1.8/gems/rspec-1.3.0/bin/spec --autospec /Users/rochefort/work/ruby/rspec/bowling/spec/game_spec.rb 
.........

Finished in 0.020817 seconds

9 examples, 0 failures

rspecのオプションは

spec.optsに書いておけばOKです。

#spec.opts
--colour
--format specdoc

spec/game_spec.rbを更新する度に、テストが自動実行される

$ autospec
loading autotest/rspec
/opt/local/bin/ruby /Users/rochefort/.gem/ruby/1.8/gems/rspec-1.3.0/bin/spec --autospec /Users/rochefort/work/ruby/rspec/bowling/spec/game_spec.rb -O spec/spec.opts 

Game すべてガターの場合
- スコアは0点

Game すべて1ピンの場合
- スコアは20点

Game ストライクの場合
- スコアは24点

Game パーフェクトゲーム場合
- スコアは300点

Game Game スペアの場合
- スコアは21点

Game Uncle Bobの受け入れゲームの場合
- スコアは133点

Game 10フレーム目の場合 1投目がストライクの場合
- スコアは17点

Game 10フレーム目の場合 2投目がストライクの場合
- スコアは14点

Game 10フレーム目の場合 スペアの場合
- スコアは14点

Finished in 0.024603 seconds

9 examples, 0 failures

終了は

ctrl + C を2回

トラックバック - http://rubyist.g.hatena.ne.jp/rochefort/20100412

2010-04-11RE: スはスペックのス~RSpecによるテスト駆動開発の実演

RE: スはスペックのス~RSpecによるテスト駆動開発の実演

| RE: スはスペックのス~RSpecによるテスト駆動開発の実演 - うんたらかんたらRuby を含むブックマーク はてなブックマーク - RE: スはスペックのス~RSpecによるテスト駆動開発の実演 - うんたらかんたらRuby

20110216追記

すいません、修正後ソースが見えなくなってました。



前回の続き(スはスペックのス~RSpecによるテスト駆動開発の実演 - うんたらかんたらRuby - Rubyist)。

テストコードをリファクタリングしてみた。

余談だけど、gitで随時コミットするのがいいと思った。


describeのnest

全てGameに対するテストなのでnestしてみた。

対象を説明する時は describe, 状況を説明する時は context。


beforeを一纏め

#修正前抜粋
  context "すべてガターの場合" do 
    before do
      @game = Game.new
      20.times { roll_gutter }
    end

    it "スコアは0点" do
      @game.score.should == 0
    end
  end

beforeセクションは、Game.newが重複しまくっているので

これを一纏めに。

beforeセクションの内容は、テストの準備という位置づけの方が

いいような気がする(あとでもう少し調べる)ので

各beforeセクションで実行しているテスト条件の設定をitセクションへ移動してみた。


subjectを設定

#修正前
@game.score.should == 0

全テストで比較する対象が@game.scoreなので

subjectを設定

#修正後
  subject{ @game.score }


  should == 0

contextをさらにnest

(ここは余計かも)group化した方が見やすいかもと思ったので

10フレーム目の3つのテストを

contextで更にnestしてみた。

#修正後
  context "10フレーム目の場合" do
    context "1投目がストライクの場合" do
      it "スコアは17点" do
        18.times { roll_gutter }
        roll_strike
        @game.roll(3)
        @game.roll(4) # 17
        should == 17
      end
    end

    context "2投目がストライクの場合" do
      it "スコアは14点" do
        19.times { roll_gutter }
        roll_strike
        @game.roll(4) # 14
        should == 14
      end
    end

    context "スペアの場合" do
      it "スコアは14点" do
        18.times { roll_gutter }
        roll_spare
        @game.roll(4) # 14
        @game.score.should == 14
      end
    end
  end

修正前全部

require File.expand_path(File.dirname(__FILE__) + "/../game.rb")
#[1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6] => 133

describe Game, "すべてガターの場合" do
  before do
    @game = Game.new
    20.times { roll_gutter }
  end

  it "スコアは0点" do
    @game.score.should == 0
  end
end

describe Game, "すべて1ピンの場合" do
  before do
    @game = Game.new
    20.times { @game.roll(1) }
  end

  it "スコアは20点" do
    @game.score.should == 20
  end
end

describe Game, "ストライクの場合" do
  before do
    @game = Game.new
    roll_strike
    @game.roll(3)
    @game.roll(4)
    18.times { roll_gutter }
  end

  it "スコアは24点" do
    @game.score.should == 24
  end
end

describe Game, "パーフェクトゲーム場合" do
  before do
    @game = Game.new
    12.times { roll_strike }
  end

  it "スコアは300点" do
    @game.score.should == 300
  end
end

describe Game, "スペアの場合" do
  before do
    @game = Game.new
    roll_spare
    @game.roll(4)
    @game.roll(3) # 21
    16.times { roll_gutter }
  end

  it "スコアは21点" do
    @game.score.should == 21
  end
end

#[1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6] => 133
describe Game, "Uncle Bobの受け入れゲームの場合" do
  before do
    @game = Game.new
    [1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6].each {|pin| @game.roll pin}
  end

  it "スコアは133点" do
    @game.score.should == 133
  end
end

describe Game, "10フレーム目の1投目がストライクの場合" do
  before do
    @game = Game.new
    18.times { roll_gutter }
    roll_strike
    @game.roll(3)
    @game.roll(4) # 17
  end

  it "スコアは17点" do
    @game.score.should == 17
  end
end

describe Game, "10フレーム目の2投目がストライクの場合" do
  before do
    @game = Game.new
    19.times { roll_gutter }
    roll_strike
    @game.roll(4) # 14
  end

  it "スコアは14点" do
    @game.score.should == 14
  end
end

describe Game, "10フレーム目でスペアの場合" do
  before do
    @game = Game.new
    18.times { roll_gutter }
    roll_spare
    @game.roll(4) # 14
  end

  it "スコアは14点" do
    @game.score.should == 14
  end
end

private
def roll_gutter
  @game.roll(0)
end

def roll_strike
  @game.roll(10)
end

def roll_spare
  @game.roll(5)
  @game.roll(5)
end

修正後全部

多少見やすくなったかな。

require File.expand_path(File.dirname(__FILE__) + "/../game.rb")
#require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
#[1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6] => 133

describe Game do
  before do
    @game = Game.new
  end

  subject{ @game.score }

  context "すべてガターの場合" do
    it "スコアは0点" do
      20.times { roll_gutter }
      should == 0
    end
  end

  context "すべて1ピンの場合" do
    it "スコアは20点" do
      20.times { @game.roll(1) }
      should == 20
    end
  end

  context "ストライクの場合" do
    it "スコアは24点" do
      roll_strike
      @game.roll(3)
      @game.roll(4)
      18.times { roll_gutter }
      should == 24
    end
  end

  context "パーフェクトゲーム場合" do
    it "スコアは300点" do
      12.times { roll_strike }
      should == 300
    end
  end

  context Game, "スペアの場合" do
    it "スコアは21点" do
      roll_spare
      @game.roll(4)
      @game.roll(3) # 21
      16.times { roll_gutter }
      should == 21
    end
  end

  #[1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6] => 133
  context "Uncle Bobの受け入れゲームの場合" do
    it "スコアは133点" do
      [1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6].each {|pin| @game.roll pin}
      should == 133
    end
  end

  context "10フレーム目の場合" do
    context "1投目がストライクの場合" do
      it "スコアは17点" do
        18.times { roll_gutter }
        roll_strike
        @game.roll(3)
        @game.roll(4) # 17
        should == 17
      end
    end

    context "2投目がストライクの場合" do
      it "スコアは14点" do
        19.times { roll_gutter }
        roll_strike
        @game.roll(4) # 14
        should == 14
      end
    end

    context "スペアの場合" do
      it "スコアは14点" do
        18.times { roll_gutter }
        roll_spare
        @game.roll(4) # 14
        @game.score.should == 14
      end
    end
  end
end

private
def roll_gutter
  @game.roll(0)
end

def roll_strike
  @game.roll(10)
end

def roll_spare
  @game.roll(5)
  @game.roll(5)
end


テスト結果

spec -c -fs spec/game_spec.rb

Game すべてガターの場合
- スコアは0点

Game すべて1ピンの場合
- スコアは20点

Game ストライクの場合
- スコアは24点

Game パーフェクトゲーム場合
- スコアは300点

Game Game スペアの場合
- スコアは21点

Game Uncle Bobの受け入れゲームの場合
- スコアは133点

Game 10フレーム目の場合 1投目がストライクの場合
- スコアは17点

Game 10フレーム目の場合 2投目がストライクの場合
- スコアは14点

Game 10フレーム目の場合 スペアの場合
- スコアは14点

Finished in 0.007972 seconds

9 examples, 0 failures

kakutanikakutani2010/04/14 15:25動画を丁寧に観ていただけて嬉しいです。ありがとうございます。あれは2年前のセッションなのと入門的な内容なので、いまやるならもうちょっと違う書き方がありそうですね。subjectとかnested contextはすでに使われているので、ちょっと違う感じでまとめてみました。 http://gist.github.com/365496 こっちのほうが読みやすいというつもりは無いのですが、共通処理の括り出しかたの一例として参考になれば幸いです。実行結果はこんな感じです。さいきんは --format は s よりも n がおすすめです。 http://gist.github.com/365501

rochefortrochefort2010/04/14 23:41おおお、角谷さんコメントありがとうございます!
しかもテストまで書き直してくださったなんて。
ブロック渡してテストするなんて、全く思いつきませんでした。
これはすっきりですね。
--format n もいいです。
t_wadaさんやmoroさんやるびまの記事を拝見して、最近rspec始めたところなので本当に勉強になります。

kakutanikakutani2010/04/15 01:03書き直しとか滅相もないです。ありがたいなあ、と思ったので自分でもちょっとやってみただけなので。ブロック渡し云々も、id:rochefort のリファクタした後のコードを見て「なんか他にないかなー」と無理矢理考えたところでもあるので、あんまり間に受けないでください(いつもこう書いてるわけではないです!)。 自分の日記にも感想を書いてみました: http://kakutani.com/20100414.html#p03

トラックバック - http://rubyist.g.hatena.ne.jp/rochefort/20100411

2010-04-10スはスペックのス~RSpecによるテスト駆動開発の実演

スはスペックのス~RSpecによるテスト駆動開発の実演

| スはスペックのス~RSpecによるテスト駆動開発の実演 - うんたらかんたらRuby を含むブックマーク はてなブックマーク - スはスペックのス~RSpecによるテスト駆動開発の実演 - うんたらかんたらRuby

スはスペックのス~RSpecによるテスト駆動開発の実演~ - 角谷信太郎 (1/3)‐ニコニコ動画(9)

スはスペックのス~RSpecによるテスト駆動開発の実演~ - 角谷信太郎 (2/3)‐ニコニコ動画(9)

スはスペックのス~RSpecによるテスト駆動開発の実演~ - 角谷信太郎 (3/3)‐ニコニコ動画(9)

を見ながらテストしてみた。

スライドはこちら。S is for Spec


追記

RE: スはスペックのス~RSpecによるテスト駆動開発の実演 - うんたらかんたらRuby - Rubyist


追記その2

autospecの結果をgrowlで通知 - うんたらかんたらRuby - Rubyist


感想

凄くいい動画・資料でした。

いやぁ、いい時代だ。


1本目は、TDDについての解説です。

2、3本目はボーリングのスコア算出プログラムの実演です。

1本目で解説した内容をテストを書くという「プロセス」を通して実演しています。

この「プロセス」がいいし、TDDって素晴らしいと思えます。


動画自体は1.5時間くらいあって長いし、

実演部は随時止めながら手動かしたので

全部で2時間ちょっとくらいかかりましたが

見る価値、やる価値は十分ありました。


一応ソース

#spec/game_spec.rb
require File.expand_path(File.dirname(__FILE__) + "/../game.rb")
#require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
#[1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6] => 133

describe Game, "すべてガターの場合" do
  before do
    @game = Game.new
    20.times { roll_gutter }
  end

  it "スコアは0点" do
    @game.score.should == 0
  end
end

describe Game, "すべて1ピンの場合" do
  before do
    @game = Game.new
    20.times { @game.roll(1) }
  end

  it "スコアは20点" do
    @game.score.should == 20
  end
end

describe Game, "ストライクの場合" do
  before do
    @game = Game.new
    roll_strike
    @game.roll(3)
    @game.roll(4)
    18.times { roll_gutter }
  end

  it "スコアは24点" do
    @game.score.should == 24
  end
end

describe Game, "パーフェクトゲーム場合" do
  before do
    @game = Game.new
    12.times { roll_strike }
  end

  it "スコアは300点" do
    @game.score.should == 300
  end
end

describe Game, "スペアの場合" do
  before do
    @game = Game.new
    roll_spare
    @game.roll(4)
    @game.roll(3) # 21
    16.times { roll_gutter }
  end

  it "スコアは21点" do
    @game.score.should == 21
  end
end

#[1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6] => 133
describe Game, "Uncle Bobの受け入れゲームの場合" do
  before do
    @game = Game.new
    [1,4,4,5,6,4,5,5,10,0,1,7,3,6,4,10,2,8,6].each {|pin| @game.roll pin}
  end

  it "スコアは133点" do
    @game.score.should == 133
  end
end

private
def roll_gutter
  @game.roll(0)
end

def roll_strike
  @game.roll(10)
end

def roll_spare
  @game.roll(5)
  @game.roll(5)
end
#game.rb
class Game
  FRAMES_OF_A_GAEME = 10
  def initialize
    @rolls = []
  end

  def roll(pins)
    @rolls << pins
  end
  
  def score
    roll_idx = 0
    score = 0
    FRAMES_OF_A_GAEME.times do |frame|
      if strike?(roll_idx)
        # strike
        score += strike_bounus(roll_idx)
        roll_idx += 1
      elsif spare?(roll_idx)
        # spare
        score += spare_bounus(roll_idx)
        roll_idx += 2
      else
        score += score_of_frame(roll_idx)
        roll_idx += 2        
      end
    end
    score
  end

  private
  def strike?(roll_idx)
    @rolls[roll_idx] == 10
  end
  
  def spare?(roll_idx)
    @rolls[roll_idx] + @rolls[roll_idx + 1] == 10
  end
  
  def score_of_frame(roll_idx)
    @rolls[roll_idx] + @rolls[roll_idx + 1]
  end
  
  def strike_bounus(roll_idx)
    10 + @rolls[roll_idx + 1] + @rolls[roll_idx + 2]
  end
  
  def spare_bounus(roll_idx)
    10 + @rolls[roll_idx + 2]
  end
end

10フレーム目が特殊な気がするので

追加で書いてみた。

describe Game, "10フレーム目の1投目がストライクの場合" do
  before do
    @game = Game.new
    18.times { roll_gutter }
    roll_strike
    @game.roll(3)
    @game.roll(4) # 17
  end

  it "スコアは17点" do
    @game.score.should == 17
  end
end

describe Game, "10フレーム目の2投目がストライクの場合" do
  before do
    @game = Game.new
    19.times { roll_gutter }
    roll_strike
    @game.roll(4) # 14
  end

  it "スコアは14点" do
    @game.score.should == 14
  end
end

describe Game, "10フレーム目でスペアの場合" do
  before do
    @game = Game.new
    18.times { roll_gutter }
    roll_spare
    @game.roll(4) # 14
  end

  it "スコアは14点" do
    @game.score.should == 14
  end
end

あとで

テスト自体は、もう少しきれいになるので、修正しよう。

autotestについて調べよう。


以下、自分用メモ

1つのゴール

"clean code that works"

動作するきれいなコード

1つのテーマ

"The translation of a feeling into a test is a common theme of TDD."

感情をテストにすることが、TDDのテーマである。

不安だ

何かがおかしい

これでいい

退屈だ

→テストを構造化する

→書くのを止める


2つの主張

設計の技法

開発の進め方

2つのルール

テストに失敗した時だけコードを書く

重複を取り除く

3つのモード

Red

Green

Refactoring

3つの技法

"Fake It"

いんちき

"Triangulate"

三角測量

"Obvious implementation"

ふつうに実装する

4つのモード

Think+3つのモード

2010-04-09イケテルRails勉強会 第1部Rails編

イケテルRails勉強会 第1部Rails編

| イケテルRails勉強会 第1部Rails編 - うんたらかんたらRuby を含むブックマーク はてなブックマーク - イケテルRails勉強会 第1部Rails編 - うんたらかんたらRuby

20090418 イケテルRails勉強会 第1部Rails編

をやってみた。


準備

↓一通り読んで、API利用登録。

食べログAPI サービス案内[食べログ]


やってみた感想

ActiveResource凄い。

apiの処理が簡単に扱える。

Hash.from_xmlでxmlhashにして扱う。)


注意事項

資料上、APIのリクエストパラメータが小文字で記載されてますが

実際は、先頭大文字なので注意。

詳細は下記。

食べログAPI マニュアル[食べログ]


一応ソース

prefectureモデルはscaffoldで作成するので略。

#models/restaurant.rb
class Restaurant < ActiveResource::Base
  self.site = "http://api.tabelog.com/"
  
  def self.find_restaurants(restaurant_params={})
    restaurant_params[:Key] = "取得したAPIアクセスキー"
    Hash.from_xml(
      self.find(
      :one,
      :from => "/Ver2.1/RestaurantSearch/",
      :params => restaurant_params
      ).to_xml
    )
  end
end

#models/bookmark.rb
class Bookmark < ActiveRecord::Base
  has_attached_file :photo
end

#controllers/restaurants_controller
class RestaurantsController < ApplicationController
  def index
    @prefectures = Prefecture.find(:all)
    @pages = Array.new(100){ |i| i+1 }
    
    @restaurants = Restaurant.find_restaurants(request.query_parameters)["restaurant"]
    @restaurants["Item"].each do |item|
      bookmark = Bookmark.find_by_rcd item["Rcd"]
      if bookmark
        item["Memo"] = bookmark.memo
        item["image_url"] = bookmark.photo_file_name ? request.protocol + request.host_with_port + bookmark.photo.url : nil
      end
    end
    
    #xmlの仕様にあわせるため、ItemをItemsに変更
    @restaurants["Items"] = @restaurants["Item"]
    @restaurants.delete "Item"

    respond_to do |format|
      format.html # index.html.erb
      format.xml  { render :xml => @restaurants.to_xml(:root => "restaurant", :dasherize => false ) }
    end
  end
  
  def create
    if params[:create] && params[:Rcd]
      bookmark_params = {
        :rcd  => params[:Rcd],
        :memo => params[:Memo],
        :photo => params[:photo]
      }
      bookmark = Bookmark.find_or_initialize_by_rcd bookmark_params
      bookmark.attributes = bookmark_params
      bookmark.save
    end
    restaurants_params = {
      :Prefecture  => params[:Prefecture],
      :PageNum => params[:PageNum].to_i
    }
    redirect_to :controller => :restaurants, :action => :index, :params => restaurants_params
  end
end

#views/restaurants/index.html.erb
<h1>RBC食べログ</h1>
<% form_tag({}, {:multipart => true}) do -%>
<p>
  都道府県:<%= select_tag :Prefecture, 
           options_from_collection_for_select(@prefectures, :en, :ja, params[:Prefecture]) %>
</p>
<p>
  ページ:<%= select_tag :PageNum, options_for_select(@pages, params[:PageNum].to_i) %>
</p>
<%= submit_tag "検索", {:name => "search"} %>
<ul>
  <% @restaurants["Items"].each do |item| -%>
  <li>
    <%= radio_button_tag :Rcd, item["Rcd"] %>
    <%= link_to item["RestaurantName"], item["TabelogUrl"], {:target => '_blank'} %>
    <%= item["Memo"] %>
    <% unless item["image_url"].blank? -%>
      <br /><%= image_tag item["image_url"] %>
    <% end -%>
  </li>
  <% end -%>
</ul>
<p>
  メモ:<%= text_field_tag :Memo %>
</p>
<p>
  イメージ:<%= file_field_tag :photo %>
</p>
<%= submit_tag "登録", { :name => "create" } %>
<% end -%>

資料では、初期マスタデータである都道府県情報の登録を

migrationファイル内に記載しているが、seedの方が適切と判断し

seeds.rbに記載した。

#db/seeds.rb
Prefecture.delete_all
prefs = [
["全国","japan"],
["北海道","hokkaido"],
["青森","aomori"],
["岩手","iwate"],
["宮城","miyagi"],
["秋田","akita"],
["山形","yamagata"],
["福島","fukushima"],
["東京","tokyo"],
["神奈川","kanagawa"],
["埼玉","saitama"],
["千葉","chiba"],
["茨城","ibaraki"],
["栃木","tochigi"],
["群馬","gunma"],
["山梨","yamanashi"],
["長野","nagano"],
["新潟","niigata"],
["富山","toyama"],
["石川","ishikawa"],
["福井","fukui"],
["愛知","aichi"],
["岐阜","gifu"],
["静岡","shizuoka"],
["三重","mie"],
["大阪","osaka"],
["兵庫","hyogo"],
["京都","kyoto"],
["滋賀","shiga"],
["奈良","nara"],
["和歌山","wakayama"],
["鳥取","tottori"],
["島根","shimane"],
["岡山","okayama"],
["広島","hiroshima"],
["山口","yamaguchi"],
["徳島","tokushima"],
["香川","kagawa"],
["愛媛","ehime"],
["高知","kochi"],
["福岡","fukuoka"],
["佐賀","saga"],
["長崎","nagasaki"],
["熊本","kumamoto"],
["大分","oita"],
["宮崎","miyazaki"],
["鹿児島","kagoshima"],
["沖縄","okinawa"]
]
prefs.each do |pref|
  Prefecture.create!(:ja => pref[0], :en => pref[1])
end


あとで

paperclipは調べよう。

トラックバック - http://rubyist.g.hatena.ne.jp/rochefort/20100409

2010-04-04RSpec入門

RSpec入門

| RSpec入門 - うんたらかんたらRuby を含むブックマーク はてなブックマーク - RSpec入門 - うんたらかんたらRuby

t-wadaさんのRSpecの記事を読んでやってみた。

RSpec の入門とその一歩先へ - t-wadaの日記

RSpec の入門とその一歩先へ、第2イテレーション - t-wadaの日記


個人的には

特に第2イテレーションが参考になりました。

    • share_examples_for it_should_behave_like
    • describeのnest
    • 対象を説明する時は describe, 状況を説明する時は context
トラックバック - http://rubyist.g.hatena.ne.jp/rochefort/20100404