rails3 + rspec + helper method
まだ疑問に思っている程度の事。
rails3の複数のhelperに同じ名前のメソッドを作るとrspecできちんとテストできない様子。
以下のコードは実際に試したコードとは異なる名前なので、動作が異なるかもしれない。
ただ、このような状況が発生している事は残しておきたい。
例 ) こんな構成になっているとき。
# app/helper/top_helper.rb module TopHelper def my_helper_method "top helper method" end end # app/helper/second_helper.rb module SecondHelper def my_helper_method "second helper method" end end
rspec
# spec/helpers/top_helper_spec.rb require 'rspec_helper' describe TopHelper do describe :my_helper_method do it { expect(helper.my_helper_method).to eq("top helper method") } end end
これで動かしてみるとrspecがfailedな状態になる。
表示されるスタックトレースを見ると、どうやらSecondHelperの方が呼ばれている様子。
helper毎にmodule名が違うんだから、同じ名前のメソッド名つけてもきちんと使い分けてほしい。
まだ勉強不足でどこが原因なのか調べきれてないので、とりあえず状況をメモしてみた。
git pre-pushで ユーザの入力を受け付ける方法
https://raw.github.com/git/git/master/Documentation/RelNotes/1.8.2.txt
git 1.8.2からpre-push hookが追加されたので、早速使ってみた。
このとき、ユーザからの入力を受け付けるところで少し工夫が必要だったのでメモ。
ユーザからの入力が拾えない?
ユーザに yes/no ? と確認してから動作するようなスクリプトを書いたのだけど、単純に $stdin.gets とすると入力待ちしてくれない様子。
また、pre-pushは $stdinからはpushされる対象の情報が渡ってくるとのこと。
# Information about the commits which are being pushed is supplied as lines to # the standard input in the form: # # <local ref> <local sha1> <remote ref> <remote sha1> # # This sample shows how to prevent push of commits where the log message starts # with "WIP" (work in progress).
解決方法
https://gist.github.com/ebihara/5948590#file-pre-push-py-L10
こちらの10行目が解決方法になってた。
まずスクリプトの先頭で $stdinから拾えるだけ入力を拾ってきておく。
その後は、$stdinを open("/dev/tty") で置き換えて利用。
これで解決できた。
今日の発見
Expecta
AFNetworkingのtestcaseをチラ見してて気がついたもの。
SenTestCaseで使ってるmatcherがさくっと書けてしまう優れもの。
expect(@"foo").to.equal(@"foo"); // `to` is a syntatic sugar and can be safely omitted. expect(foo).notTo.equal(1); expect([bar isBar]).to.equal(YES); expect(baz).to.equal(3.14159);
非同期テストもシンプルに書けるぽい。
expect(対象).will.to.equal(期待するもの);
とか。
実際の例はAFNetworkingのtestcaseから。
# https://github.com/AFNetworking/AFNetworking/blob/master/Tests/AFHTTPClientTests.m - (void)testPostWithParameters { __block id blockResponseObject = nil; [self.client postPath:@"/post" parameters:@{ @"key": @"value" } success:^(AFHTTPRequestOperation *operation, id responseObject) { blockResponseObject = responseObject; } failure:nil]; expect([self.client.operationQueue operationCount]).will.equal(0); expect(blockResponseObject).notTo.beNil(); expect(blockResponseObject).to.beKindOf([NSData class]); NSError *error = nil; NSDictionary *responseDictionary = [NSJSONSerialization JSONObjectWithData:blockResponseObject options:0 error:&error]; expect(responseDictionary[@"form"]).to.equal(@{ @"key": @"value" }); }
httpbin
通信ライブラリとかのテストケースで使えそうなもの。
いろいろとテストで使えそうな予感。
ローカルで動いてないと嫌な人はここからインストールするとかで使えそうな雰囲気。
bundle と mecab-ruby
mecab, mecab-ipadicはcheckinstallで入れたんだけど、mecab-rubyがいい感じに動いてくれなかった。
試行錯誤した結果、こんな風にGemfileを書いたらうまいこといった。
source "https://rubygems.org" # gem "rails" gem 'mecab-ruby', :github => 'hotchpotch/mecab-ruby-gem'
あとデフォルトでinstallするとMeCab.soがロードできなかったので、環境変数を設定
export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/usr/local/lib64
これで動くようにはできた。
rubyのJSON.parseでhashキーをsymbolにしてもらう方法
Ruby JSON parse changes Hash keys
- ruby 1.9.3p393
- json (1.8.0)
$ pry [1] pry(main)> require 'json' => true # hashをjsonへ変換 [2] pry(main)> json = {:key_a => "value2", :key_b => "value3"}.to_json => "{\"key_a\":\"value2\",\"key_b\":\"value3\"}" # 普通にparseしてもらうと keyはString [3] pry(main)> p JSON.parse(json) {"key_a"=>"value2", "key_b"=>"value3"} => {"key_a"=>"value2", "key_b"=>"value3"} # optionを指定すると、keyをSymbolにしてくれる [4] pry(main)> p JSON.parse(json, {:symbolize_names => true}) {:key_a=>"value2", :key_b=>"value3"} => {:key_a=>"value2", :key_b=>"value3"}
rspecのfixturesに指定する名前でひっかかった話
rails3のrspecを書いて動かしていたときの話。
- 環境
- rails (3.2.13)
- rspec (2.13.0)
- activerecord (3.2.13)
- activesupport (3.2.13)
rspecのfixturesに指定する名前によっては、例外がログに出る事があるみたい。
fixtureに :xxx_meta という名前を指定した事が引き金だった。
rspecでfixturesを使ってた
とあるrails3なアプリのrspecでfixtureを使ってみたところ、実行する度にログにstack traceが出てくるようになってた。
# spec/models/blog_meta_spec.rb require 'spec_helper' describe BlogMeta do fixtures :blog_meta # ... spec... end
spec/fixtures/blog_meta.yml にはちゃんとfixtureなデータファイルは置いてて、期待する感じで動いてくれる。
動いてくれるのだけど、なぜか実行の度にstack traceがログに出てくる。
気持ち悪い!
rspecの実行の度にstack traceがログに出る
Unable to load blog_metum, underlying cause No such file to load -- blog_metum (snip)/vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:317:in `rescue in depend_on' (snip)/vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:312:in `depend_on' (snip)/vendor/bundle/ruby/1.9.1/gems/activesupport-3.2.13/lib/active_support/dependencies.rb:225:in `require_dependency' (snip)/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:767:in `try_to_load_dependency' (snip)/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:782:in `block in require_fixture_classes' (snip)/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:779:in `each'(snip)/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:779:in `require_fixture_classes' (snip)/vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.13/lib/active_record/fixtures.rb:762:in `fixtures' (snip)/spec/models/blog_meta_spec.rb:4:in `block in <top (required)>' (snip)/vendor/bundle/ruby/1.9.1/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:242:in `module_eval' (snip)/vendor/bundle/ruby/1.9.1/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:242:in `subclass'(snip)/vendor/bundle/ruby/1.9.1/gems/rspec-core-2.13.1/lib/rspec/core/example_group.rb:228:in `describe' (snip)/vendor/bundle/ruby/1.9.1/gems/rspec-core-2.13.1/lib/rspec/core/dsl.rb:18:in `describe' (snip)/spec/models/blog_meta_spec.rb:3:in `<top (required)>' (...snip...)
(一部省略)
原因
結論からいうと、
ActiveSupport(ここでは3.2.13) - String.singularize
文字列の単数形を作ってくれる便利なメソッドの挙動が原因。
$ bundle exec ./script/rails console Loading development environment (Rails 3.2.13) 1.9.1 :001 > "blog_meta".singularize => "blog_metum" 1.9.1 :002 >
meta の 単数形 が metum になってる。
もう少し細かい話
stack traceを追いかけてみると、少しずつ見えてきた。
activerecordでは、fixturesをロードする前に、指定された名前から必要となりそうなファイル名を推測して先にロードしようとがんばる。
そのときに指定した名前を単数形にして、そのファイルをロードしようとする様子。
まさにこのfixtures.rb:781
# vendor/bundle/ruby/1.9.1/gems/activerecord-3.2.13/lib/active_record/fixtures.rb 778 def require_fixture_classes(fixture_names = nil) 779 (fixture_names || fixture_table_names).each do |fixture_name| 780 file_name = fixture_name.to_s 781 file_name = file_name.singularize if ActiveRecord::Base.pluralize_table_names 782 try_to_load_dependency(file_name)
rspecの "fixtures :blog_meta"という記述の引数にあたる部分が fixture_namesになってわたっていく。
そして、 "blog_meta".singularize => "blog_metum" となり、その"blog_metum"をloadしようとして、そんなファイルないわーと例外を投げる結果になる。
ちなみにここではActiveRecord::Base.pluralize_table_names はdefaultのまま trueでした。
対策
一つの解決方法として、設定で回避する事に。
Railsで単数形をsingularizeすると不可解な変化をする場合の対応
rails3でも同様な対処ができる様子。
# config/initializers/inflections.rb ActiveSupport::Inflector.inflections do |inflect| inflect.singular 'blog_meta', 'blog_meta' end
こんな風に、「"blog_meta"の複数形は "blog_meta"にしてください」とお願いすると回避できた。
$ bundle exec ./script/rails console Loading development environment (Rails 3.2.13) 1.9.1 :001 > "blog_meta".singularize => "blog_meta" 1.9.1 :002 >
すっきりした。
今日の発見
後でこんなのあったなーと自分が振り返れるようにするために、
細かい説明とかは省略して、発見した情報をメモするだけの試み。
aws sdk for iOS
awsのiOS用SDKがある様子。便利そう。
まだ使ってないので雰囲気はAPI referenceをサラッと見た感じだけ...
あとで使ってみる予定。
$ pod search AWSiOS -> AWSiOSSDK (1.5.0) Amazon Web Services SDK for iOS. - Homepage: http://aws.amazon.com/sdkforios - Source: https://github.com/aws/aws-sdk-ios.git - Versions: 1.5.0, 1.4.6, 1.4.5, 1.4.4, 1.4.3, 1.4.2, 1.4.1, 1.4.0, 1.3.3, 1.2.2 [master repo] - Sub specs: - AWSiOSSDK/Runtime (1.5.0) - AWSiOSSDK/AutoScaling (1.5.0) - AWSiOSSDK/CloudWatch (1.5.0) - AWSiOSSDK/DynamoDB (1.5.0) - AWSiOSSDK/EC2 (1.5.0) - AWSiOSSDK/ElasticLoadBalancing (1.5.0) - AWSiOSSDK/S3 (1.5.0) - AWSiOSSDK/SES (1.5.0) - AWSiOSSDK/SNS (1.5.0) - AWSiOSSDK/SQS (1.5.0) - AWSiOSSDK/STS (1.5.0) - AWSiOSSDK/SimpleDB (1.5.0)
image_optim for ruby
mac appのImageOptimはとてもお世話になっているのだけど、rubyから使えるgemもあるぽい。
中身をチラっと見た感じ、最適化用の各種コマンドを呼び分けてくれるものの様子。
たった2行で画像の最適化ができた。(ちょっぴりサイズが減った)
コマンドも付いてて、linuxで手軽に使えるようになってる様子なのはありがたい。