Home > Programming > Ruby
Ruby Archive
RSpecでMacro?を書く。
- 2010-01-08 (Fri)
- Ruby
RSpecを使ってSpecを書いていると何度も同じことを書くことが多いです。
たとえばパラメータに応じてページタイトルを変えたい場合とか、validationがきちんと行われているかとか。。。
毎回、 it “should have hoge” do … end と書いているのは大変です。
RSpecではいくつかの方法を使用して、もっと簡単に書くことができます。
クラスメソッドを使う
一つのspecファイルで何度も使うものであればクラスメソッドにします。
[$RAILS_ROOT/spec/views/articles/index.html.erb_spec.rb]
describe "/articles" do
def self.it_should_have_tag(selector, content)
it "should have '#{content}' at '#{selector}'" do
response.should(have_tag(selector, content))
end
end
end
と書いておけば、以下のような書き方が可能になります。
[$RAILS_ROOT/spec/views/articles/index.html.erb_spec.rb]
describe "/articles" do
def self.it_should_have_tag(selector, content)
it "should have '#{content}' at '#{selector}'" do
response.should(have_tag(selector, content))
end
end
it_should_have_tag('tr>td', 'MyString')
end
it_should_have_tag(’tr>td’, ‘MyString’) の部分だけで適切なspecに展開されます。
1行で簡潔に書けますので、理解する時間も短くてすみます。
自分はページタイトル、meta description、meta keywords、RSSのスペックに以下のコードを使用しています。
[$RAILS_ROOT/spec/views/articles/index.html.erb_spec.rb]
describe "/articles" do
def self.it_should_have_tag(selector, content)
it "should have '#{content}' at '#{selector}'" do
response.should(have_tag(selector, content))
end
end
def self.it_should_have_page_title(title)
it_should_have_tag('head>title', title)
end
def self.it_should_have_meta_description(meta_description)
it_should_have_tag('head>meta[name=description][content=?]', meta_description)
end
def self.it_should_have_meta_keywords(meta_keywords)
it_should_have_tag('head>meta[name=keywords][content=?]', meta_keywords)
end
def self.it_should_have_rss_link(link)
it_should_have_tag('head>link[rel=alternate][type=application/rss+xml][href=?]', link)
end
end
モジュールに追い出す
さらによく使う項目、上記のhtmlに関するspecなどはたくさんのところに書かれるであろうことが推測されます。
そういう場合には、モジュールに追い出してしまうということが可能だということを同僚のquekさんに教えていただきました。1
$RAILS_ROOT/spec/support フォルダにモジュールのファイルを書きます。
上記の例であれば
[$RAILS_ROOT/spec/support/tag_macros.rb]
module TagMacros
def self.included(base)
base.extend(ClassMethods)
end
module ClassMethods
def it_should_have_tag(selector, content)
it "should have '#{content}' at '#{selector}'" do
response.should(have_tag(selector, content))
end
end
def it_should_have_page_title(title)
it_should_have_tag('head>title', title)
end
def it_should_have_meta_description(meta_description)
it_should_have_tag('head>meta[name=description][content=?]', meta_description)
end
def it_should_have_meta_keywords(meta_keywords)
it_should_have_tag('head>meta[name=keywords][content=?]', meta_keywords)
end
def it_should_have_rss_link(link)
it_should_have_tag('head>link[rel=alternate][type=application/rss+xml][href=?]', link)
end
end
end
使用する際には include TagMacros を書いておきます。
[$RAILS_ROOT/spec/views/articles/index.html.erb_spec.rb]
describe "/articles" do
include TagMacros
it_should_have_tag('tr>td', 'MyString')
end
自分のような include 〜 を書くのもものぐさだという人は、 $RAILS_ROOT/spec/spec_helper.rb に config.include メソッドを使用すれば、自動的に読み込まれるようになります。
[$RAILS_ROOT/spec/spec_helper.rb]
Spec::Runner.configure do |config| # ... config.include(TagMacros, :type => [:views]) # ... end
上記のように :type を指定すれば view だけで読み込まれるというような指定も可能です。
参考
Railscasts – RSpec Matchers & Macros
Writing Macros in RSpec • Blog Archive • Ben Mabey
P.S.
参考にしたサイトではMacroと書いてありますが、どうもこれをMacroと読んでいいものなのかどうかかなり謎なので、タイトルはMacro?と?付きにしてみましたwww
- quekさんによると、下の「参考」のところに書いた Railscasts に同様のことが書いてあり、そのアドレスを過去の自分は社内のチケットに書いていたらしいのですが、モジュールに出すことは全く知りませんでしたwww [↩]
- Comments: 0
- Trackbacks: 0
ssl_requirement pluginでssl_required(:all)と書きたい!
- 2009-08-27 (Thu)
- Ruby
Ruby on RailsでSSLで通信する必要があるページには、DHH謹製らしい?ssl_requirement pluginを使用すると、以下のようにに簡単にhttpsにリダイレクトしてくれるようにできます。
class Hoge < ApplicationController
ssl_required(:index) # インデックスページだけSSLで通信する。
def index
# some crazy codes ...
end
def show
# some rotten codes ...
end
end
残念ながら、このssl_requiredはアクションに:allとか書いてコントローラ全部を対象にするというようなことができません。
allというアクションを定義する場合もあるからこうなっているのかもしれません。
コントローラ全体にSSL通信をさせるようにするための方法については、コントローラ全体をssl強制に – 車輪の再発明というサイトに、trueを返すssl_required?メソッドを定義する方法が書かれています。
現在書いているRailsアプリでも同様のことが行われているものの、いかんせんたびたび見る気がしてきて、クラスメソッドにしようかと思いました。
でも、すでにssl_requiredというメソッドがあるところに、さらなる同じようなメソッドを作るのは避けたいし、やっぱりssl_required(:all)と書きたいと思いました。
そこでalias_method_chainを使用して、ApplicationControllerをこんな風にしてみました。
class ApplicationController < ActionController::Base
include SslRequirement
# some codes...
class << self
def ssl_required_with_all(*actions)
if actions.include?(:all)
class_eval do
def ssl_required?
true
end
end
else
class_eval do
ssl_required_without_all(*actions)
end
end
end
alias_method_chain(:ssl_required, :all)
end
end
まともにclass_evalとかがわかっていないので、かなり怪しいです!!!
- Comments: 0
- Trackbacks: 0
Apple Push Notification Serviceを利用した、iPhone クライアントと、Rubyによるサーバの作成。
[とりあえず表示しましたが、これからコードをアップロードしたり改変していきます。]
先週から、システム部で何か動くものを作って発表するという企画?が始まりました。
プログラムプレゼンテーションを始めてみたら意外に良かった
第一弾は自分だったので、1週間しかなかったので、ちょこっとやればできそうで今までやってみたかったiPhone OS 3.0の目玉機能の一つ、Push Notification Serviceの実装をやってみることにしてみました。
iPhoneクライアントはほぼObjective-Cしかありませんのでそれを使い、サーバはRubyで実装しました。
以下が発表したスライドを少し改変したものになります。
コードは今回はbitbucket.orgにアップロードすることにしました!
コードはこちらになります。
http://bitbucket.org/milkcocoa/apns-test/
ただしサーバのファイルに関しては
- デバイスIDとかの部分はxでマスクしています。
- キーに関してはスライドで指定した方法で記述してください。
[ポイントを書く。]
- Comments: 0
- Trackbacks: 2
mislav-will_paginate pluginを使用したページをRSpecでテストする。
- 2009-07-19 (Sun)
- Ruby
Webアプリケーションでは、たくさんの項目を一覧表示する場合、1ページに全部見せるのではなくpaginate処理をして数ページに分ける場合があります。
たとえばGoogleの検索結果は通常、1ページに10件しか表示されません。
そういうページをRuby on Railsで作成する場合には、mislav-will_paginate pluginというプラグインを使用するということは割とよく知られていることです。
先日もそういうページを作成する必要があり、作成していましたが、RSpecでテストを作成しようとしたところやり方がわからず詰まりました。
そのため、その方法をここに記しておこうと思います。
ドキュメントを読もう!
実はGitHubのpluginのWikiページに最低限必要なことは書いてありました。
気がついていればもっと早く解決していたところでした。
「I’m getting “undefined method `total_pages’” error when rendering in the view!」という部分ですね。
ポイントはpaginateやtotal_pagesというメソッドをstub!で定義してあげることです。
実際のコード
- Controller: ArticlesController
- Model: Article
- title: string
- body: text
Controllerのテスト(の一部)
[$RAILS_ROOT/spec/controllers/articles_controller_spec.rb]
require File.expand_path(File.dirname(__FILE__) + '/../spec_helper')
describe ArticlesController do
describe "handling GET /articles" do
before(:each) do
article = mock_model(Article)
article.stub!(:find).and_return([article])
@articles = [article]
@articles.stub!(:total_pages).and_return(1)
@articles.stub!(:paginate).and_return(@articles)
end
def do_get
get(:index)
end
it "should be successful" do
do_get
response.should be_success
end
it "should render index template" do
do_get
response.should render_template('index')
end
it "should find all articles" do
Article.should_receive(:paginate).with(:page => nil, :per_page => 100).and_return(@articles)
do_get
end
it "should assign the found articles for the view" do
do_get
assigns[:articles].should == @articles
end
end
end
ちなみに29行目の:page => nilになっているのは、たぶんassingsとかでparameterを指定していないからこうなるのだと思います。
まだshould_receiveをきちんと理解していないで、まともな説明が書けません。
Viewのテスト(の一部)
[$RAILS_ROOT/spec/views/articles/index.html.erb_spec.rb]
require File.expand_path(File.dirname(__FILE__) + '/../../spec_helper')
describe "/articles/index.html.erb" do
include ArticlesHelper
before(:each) do
article_98 = mock_model(Article)
article_98.stub!(:id).and_return(1)
article_98.stub!(:title).and_return('MyString')
article_98.stub!(:body).and_return('MyText')
article_99 = mock_model(Article)
article_99.stub!(:id).and_return(2)
article_99.stub!(:title).and_return('MyString')
article_99.stub!(:body).and_return('MyText')
@articles = [article_98, article_99]
@articles.stub!(:total_pages).and_return(1)
@articles.stub!(:paginate).and_return(@articles)
assigns[:articles] = @articles
end
it "should render list of articles" do
render "/articles/index.html.erb"
response.should have_tag("tr>td", "MyString", 2)
response.should have_tag("tr>td", "MyText", 2)
end
end
- Comments: 0
- Trackbacks: 0
RubyでArrayの部分集合を作成する。
- 2009-07-10 (Fri)
- Ruby
Arrayの部分集合を作成する必要があったので、作ってみました。
class Array
def subset
rec = Proc.new do |univ|
# subset!でポインタが循環しないようにcloneを使う。
(ret = []) << univ.clone
univ.each do |e|
ret += rec.call(univ - [e])
end
ret
end
rec.call(self).uniq
end
def subset!
self.replace(self.subset)
end
end
他には同じサイズの配列を作成して、その要素を使用するかどうかtrueかfalseのフラグを立てていくという手法もあるようです。
irbで実行するとこうなります。
>> a = %w(1 2 3 4) => ["1", "2", "3", "4"] >> a.subset => [["1", "2", "3", "4"], ["2", "3", "4"], ["3", "4"], ["4"], [], ["3"], ["2", "4"], ["2"], ["2", "3"], ["1", "3", "4"], ["1", "4"], ["1"], ["1", "3"], ["1", "2", "4"], ["1", "2"], ["1", "2", "3"]]
2009/7/20 追記
twitterですばらしい方法を教えていただきました!
ただしRuby 1.8.7で追加されたcombinationというメソッドを使用しているので1.8.7以降限定です。
cf. Ruby 1.8.7で使えるようになったRuby 1.9のメソッドたち – (rubikitch loves (Emacs Ruby CUI))
class Array
def subset
(0..self.length).inject([]) do |ret, n|
ret.push(*self.combination(n))
end
end
end
irbでの実行結果。
>> a = %w(1 2 3 4) => ["1", "2", "3", "4"] >> a.subset => [[], ["1"], ["2"], ["3"], ["4"], ["1", "2"], ["1", "3"], ["1", "4"], ["2", "3"], ["2", "4"], ["3", "4"], ["1", "2", "3"], ["1", "2", "4"], ["1", "3", "4"], ["2", "3", "4"], ["1", "2", "3", "4"]]
すごくすっきりしました!
- Comments: 0
- Trackbacks: 0
レセプトオンライン送信で請求ができたかを確認するRubyスクリプト
- 2009-05-08 (Fri)
- Pharmaceutical sciences | Ruby
すごいニッチなところをすみませんwww。
レセプトオンライン送信について知っている人だけをまずは対象にしています。
複数の店舗のレセプトを一括してオンライン請求するときにきちんと請求済みになっているかどうか1 を(念のため)確認するのは2(社保、国保) × 店舗数分やらないといけないので大変です。
特にEeePCを使っていると遅いので、だいぶん大変度が増します。
ということで、Rubyでオートマティックに確認するスクリプトを書いてみました。
神奈川県の事例しか知らないので神奈川県限定です。
スクリプト中の神奈川県に関する部分を修正すれば、ほかの県でももしかしたら利用できるかもしれません。
またHTMLを解析して、やっていますのでサイトの構成やHTML等が変わってしまった場合には利用ができません。
共有はしますが、ノーサポートです。
私はこのスクリプトを使用して生じた一切の責任を負いません。
ライセンスをどうしようかと思いましたが、どのみちスクリプトですから改変しても公開せざるを得ないと思うので、GPLv3にしておきます。2
動作環境は
- Windows3
- Ruby 1.8.7
- RubyGems 1.3.2
RubyGemsによってインストールした- WWW::Mechanize 0.9.2
- Term::ANSIColor 1.0.3
- Win32Console 1.2.0
- およびそれらの依存ライブラリ(Nokogiri等)
です。
これらのインストールに関する質問はお答えできませんので、あらかじめご了承を。
さらにopenssl(UNIX系だと普通にあると思われる4 )を用いて配布されているp12形式の証明書ファイルからcerファイルとkeyファイル(この二つをいまいちわかっていない)を作成します。
パスワードの入力を求められますが、これは証明書発行時に発行されたパスワードになります。
openssl pkcs12 -in hoge.p12 -clcerts -out hoge.cer -nokeys openssl pkcs12 -in hoge.p12 -clcerts -out hoge.key -nocerts -nodes
さらに店舗情報としてYAMLファイルを作成します。
名前は適当につけていただいて、ファイルの中身は
- name: hoge id: 0120444444 password: hogepass cert: hoge.cer key: hoge.key - name: piyo id: 0120888888 password: piyopass cert: piyo.cer key: piyo.key
とかしてください。
nameは任意の区別できる名前にします。
id, passwordはその薬局がログインするときのIDとパスワードです。
certとkeyは上記で作成したcertファイルとkeyファイルのパスを指定します。
後のオプションはきっとわかると思います。
このときWindowsでパス区切りに使われるバックスラッシュ(\)はうまく動いてくれなかったように思えるので、スラッシュでパスを区切りました。
あとは
ruby receipt_check.rb hoge.yaml
とでも打ち込めば、請求済みであれば緑色の字で[OK]、請求済みになっていない場合には[Failed]と表示されます。
ruby receipt_check.rb -t hoge.yaml
のように -t オプションをつけると、確認試験で実行します。
さらに自分は上記コマンドを呼び出すバッチファイルを作成し、それをcmd.exeで呼び出すリンクファイルを作ってリンクファイルをクリックするだけで確認できるようにしてあります。
TODOはそこにも書いてありますが、エラー処理を全くしていません。
そのため運用時間外などに実行すると、運用時間外ですとか知らせることなく、思い切りスクリプトのエラーが出ます。
もしやる気があれば、未請求になっていた場合にはスクリプトで請求できるようにしたり、もうスクリプトだけで請求するということも考えています(こちらは実現が難しそう)。
あと、できるだけ修正はしたいと思いますが、最終的なデバッグはレセプトオンライン送信の端末でしかできないので、修正まで非常に時間がかかる場合、修正しない場合があります。
ということで、以上を理解した方のみダウンロードはこちらから。
- Comments: 0
- Trackbacks: 0
Ultraviolet Syntax Highlighting Engineをさくらインターネットのサーバにインストールする
- 2009-01-04 (Sun)
- Programming | Ruby | UN*X | Web
UltravioletはRubyによって書かれた様々なSyntax(文法)に対応したSyntax Highlighting Engineです。
今回はこれをさくらインターネットのサーバにインストールしてみましょう。
RubyGemsを使ってインストールをするのですが、以前RubyGemsのインストール方法については書きました。
cocoa*life – ブログをさくらインターネットへ移行しました。
ということで、RubyGemsのインストールが終わっている状態で書き始めます。
Ultravioletのインストール
正規表現ライブラリOniguruma(鬼車)のインストール
まずは正規表現ライブラリであるOnigurumaをインストールします。
普通にconfigureしてmakeしてinstallすれば良いだけです。
wget http://www.geocities.jp/kosako3/oniguruma/archive/onig-5.9.1.tar.gz tar zxf onig-5.9.1.tar.gz cd onig-5.9.1 ./configure --prefix=$HOME/local make make install
RubyGemsを使ってUltravioletのインストール
一直線に答えを書いてしまってもいいのですが、問題解決法を書くのも忘れてしまう自分のためになると思うので、書きます。
gem install -r ultraviolet
とすればいいと思いきや、こんなエラーが出て止まります。
oregexp.c:2:23: oniguruma.h: No such file or directory
どうも標準ではない/home/hoge/local/以下にインストールしてあるので、oniguruma.hなどが見つからないようです。
さらに、エラーの最後を見ていると
Stop in /home/hoge/local/gems/oniguruma-1.1.0/ext.
なんて書いてあって、 どうも依存関係によりまず他のライブラリをインストールしているよう。
調べてみるとOniguruma for Rubyというものらしい。
そこでまず~/local/gems/oniguruma-1.1.0というフォルダを見てみると、Rakefileがある。
さらに中身を読んでみると、30 〜 36行目に以下のような記述があります。
if ENV['PLATFORM'] =~ /win32/ p.lib_files = ["win/oregexp.so"] p.spec_extras[:require_paths] = ["win", "lib", "ext" ] p.spec_extras[:platform] = Gem::Platform::WIN32 else p.spec_extras[:extensions] = ["ext/extconf.rb"] end
どうも、ext/extconf.rbがくさそうだという気がしたので、ext/extconf.rbを見てみます。
require 'mkmf'
have_library("onig")
$CFLAGS='-Wall'
create_makefile( "oregexp" )
たった4行!
ですがcreate_makefileでMakefileを作成しているというのは読み取れますので、何かありそうです。
そしてどうも、require ’mkmf’というのが鍵を握っている様な気がしました。
mkmf – Rubyリファレンスマニュアル
Ruby の拡張ライブラリのための Makefile を作成するライブラリです。
ということで、ビンゴでしょうか?
さらに読み進めると
- –with-opt-dir=directory
- ヘッダファイル、ライブラリファイルを探索するディレクトリ directory/include、directory/lib をそれぞれ追加します。
と書いてあるので、これを指定できればいいということになります。
ということで、
gem install -r oniguruma -- --with-opt-dir=$HOME/local gem install -r ultraviolet
として、これでめでたくインストールが完了します。1
RubyGemsに慣れている人であれば当たり前のことなのかもしれませんが、自分は初めてだったので良い経験になりました。
Ultravioletの使い方
uvというコマンドがUltravioletのコマンドになりますが、uv –helpでヘルプを見てみると
uv -t amy -h ~/.bashrc > bashrc.html
なんてのがサンプルとして書いてあります。
amyというのはテーマの名前のようです。
テーマはUltraviolet Theme Galleryで見ることができます。
-sでSyntaxを指定することができますが、ある程度は自動的に認識されるのかもしれません。
uv -l syntax
で利用可能なSyntax一覧を表示することが可能です。
自分は.zshrcをやってみました。
Syntaxが認識されないので、-s shell-unix-genericというのを指定しました。
uv -t blackboard -s shell-unix-generic -h ~/.zshrc > zshrc.html
生成されたzshrc.htmlはcssを参照しているところがあるのですが、そのcssは
/home/hoge/local/gems/ultraviolet-0.10.2/render/xhtml/files/cssにあります。
Rubyからもライブラリとして使うことができるようです。
Usageのところを見ると書いてあります。
- 試してはいないけれど、gem install -r ultraviolet — –with-opt-dir=$HOME/localでうまくいくのかなぁ? [↩]
- Comments: 0
- Trackbacks: 0
RSRubyでRubyのArrayをRのMatrixに変換する
- 2008-09-03 (Wed)
- Ruby
題名の通りです。
以前ご紹介したように、RSRubyはRubyでRのスクリプトを実行するためのものです。
RのオブジェクトをRubyのオブジェクトに変換することは簡単です。
というのはeval_Rをした結果がArrayとして扱うのが適当であればArrayに、Hashとして扱うのが適当であれば、Hashに変換してくれます。
問題はRubyのArrayをRの中で使いたいときです。
たとえば
[1, 2, 3, 4, 5]
というArrayをRの行列にしたい場合。
ruby_data = [1, 2, 3, 4, 5]
r = RSRuby::instance
r.eval_R <<-RCOMMANDS
r_data <- matrix(c(#{ruby_data.join(",")}), 1, #{ruby_data.size})
<<-RCOMMANDS
などとしてうまくjoinを使ってやればできます。
- Comments: 0
- Trackbacks: 0
Ruby de R
- 2008-07-23 (Wed)
- Programming | Ruby
RでRubyではなく、RubyでR。
Rubyが本当に便利なので、できる限りRubyで作業をしたいなぁと思っています。
そんなことを助けてくれるのにrurubyというライブラリがあります。
MacBookでのインストールは
sudo gem install rsruby -- --with-R-dir=/Library/Frameworks/R.framework/Resources
としました。
このままでは $R_HOMEが見つからないと怒られるようです。
私はzshを使っているので、~/.zshrcに
export R_HOME=/Library/Frameworks/R.framework/Resources
を追加しておきました。
使い方はとりあえずeval_Rコマンドを使えばRのコマンドはなんでも実行できるので、特にRubyのデータ構造を使う必要がなければこれだけでもいけます。
ちなみにヒアドキュメントを使えばいいと
require 'rubygems' require 'rsruby' r = RSRuby.instance r.eval_R <<-RCOMMAND # 何かしらのRのコマンド RCOMMAND
これで使いなれたRubyの正規表現が使えるので自分としてはとても嬉しい。
- Comments: 0
- Trackbacks: 1
鯖の方に移らなきゃ
- 2008-07-05 (Sat)
- Programming | Ruby | Web
Crêpeで使うデータ更新用のサーバーを作らないといけないのですが、今までやったことがないことなので(スタンドアロンアプリケーションしか作ったことがない)、何からやらなきゃいけないかがわかりません。
まずは、言語およびフレームワークの選択?
PHPを使うか、 Ruby on Railsを使うか、それとも単純にRubyだけで・・・。
とりあえず昔買ったRails本を引っ張り出して斜め読みをしています。
いつの間にか第2版が出ていたようで、というか第2版でもRails 2系とは違うらしいという驚くべき開発スピードなんですが(汗)。
著者: Dave Thomas, David Heinemeier Hansson, Leon Breedt, Mike Clark, Andreas Schwarz, James Duncan Davidson, Justin Gehtland
出版社: オーム社
発売日: 2007年10月20日
ちなみに本国?の方では第3版の準備がされているようです。1
Agile Web Development with Rails, Third Edition
2ヶ月前はSQLもさっぱりだったし、Objective-Cもさっぱりだったし(最近ようやく参照カウンタに慣れてきた)、ある程度頑張ればそこからはある程度わかるようになるでしょうと思っているのですが・・・。
SQLがわかったあとなので、少しは頭に入ってきていますが、まだ全体的な繋がりがよく見えない。
ちょろちょろとテストアプリを作ってみて掴んでいくしかないな。
でも、ここでの開発の経験はあとに生かせるはず!!!
- 上記サイトでBeta版のPDFが出ているのだから、日本語版も2, 3ヶ月遅れでできないかしら?なんてわがまま放題なことを発言してみます。 [↩]
- Comments: 0
- Trackbacks: 0
Home > Programming > Ruby



