MySQL/Rubyのバージョン確認方法
gemでインストールするMySQL/Rubyのバージョンは2.7と少々古いので、念の為に2.7.4にバージョンアップしておく。
require 'mysql' Mysql.const_get(:VERSION) => 20704
でバージョンをチェックする。
20704だと2.7.4になる。
今見てみたら1.9対応の2.8pre1がリリースされている。Railsが対応できているかどうか怪しいので2.7系に留めておくのが無難か。
MySQL/Ruby
Rubyでの正規表現についての覚書
- /pattern/option
- %r{pattern}option
- Regexp.new('pattern', option)
通常扱うのは/pattern/option。所謂正規表現リテラルで、リテラル内には式展開を含める事ができる。
/hoge#{"foo"}/ # => /hogefoo/
ただし、optionには式展開を適用することができない。これはコンパイルエラーにもならないので注意が必要。
/hoge#{"foo"}/#{"ni"} # => /hogefoo/ #式展開でくっつけたoption値が無視されている。
この問題は%r記法でも同様だった。
optionを動的にしたい場合はRegexp.newメソッドを使う。
Regexp.new("hoge", "i") # => /hoge/i Regexp.new("hoge", "o") # => /hoge/i
……あれ?
どんな値を入れても何故かignore caseがオプションになってしまう。
Regexpのrdocを見て謎が解明。
第二引数が Fixnum であった場合、その値は
Regexp::IGNORECASE
Regexp::MULTILINE
Regexp::EXTENDED
の論理和でなければなりません。第二引数が Fixnum 以外であれば真偽値の指定として見なされ、真 (nil, false 以外)であれば Regexp::IGNORECASE の指定と同じになります。
第三引数が与えられた時には、$KCODE の値にかかわらず、指定された文字コードでマッチを行います。文字コードは $KCODE への代入と同様に文字列引数の最初の一文字で決定されます。
http://www.ruby-lang.org/ja/man/?cmd=view;name=Regexp
つまり、文字コードの取り扱いは第3引数で、第2引数はそれ以外のオプションになるようだ。今回は文字コードを動的に変えたかったので、最終的には以下のようなコードとなった。
charset = "o" Regexp.new("hoge", nil, charset) # => /hoge/o charset = "u" Regexp.new("hoge", Regexp::MULTILINE , charset) # => /hoge/mu
csvからのインポート
インストールモジュールを確認する
bin/httpd -M 2>&1 | sort actions_module (static) alias_module (static) asis_module (static) auth_basic_module (static) authn_default_module (static) authn_file_module (static) authz_default_module (static) authz_groupfile_module (static) authz_host_module (static) authz_user_module (static) autoindex_module (static) cgid_module (static) core_module (static) dir_module (static) env_module (static) expires_module (static) filter_module (static) headers_module (static) http_module (static) include_module (static) log_config_module (static) mime_module (static) mpm_worker_module (static) negotiation_module (static) proxy_ajp_module (static) proxy_balancer_module (static) proxy_connect_module (static) proxy_ftp_module (static) proxy_http_module (static) proxy_module (static) rewrite_module (static) setenvif_module (static) so_module (static) status_module (static) userdir_module (static) Loaded Modules: Syntax OK
Apacheのコマンドよりも標準エラーを標準出力にリダイレクトさせるコマンドが覚えられない…。
adv_attr_accessorの実装から感じるRailsの哲学
ActionMailerのソースを読んでいたら、
adv_attr_accessor :bcc
と言うコードが合ったので、このadv_attr_accessorという謎のメソッドを調べてみた。
短かいコードだったので全文引用してしまう。
module ActionMailer module AdvAttrAccessor #:nodoc: def self.included(base) base.extend(ClassMethods) end module ClassMethods #:nodoc: def adv_attr_accessor(*names) names.each do |name| ivar = "@#{name}" define_method("#{name}=") do |value| instance_variable_set(ivar, value) end define_method(name) do |*parameters| raise ArgumentError, "expected 0 or 1 parameters" unless parameters.length <= 1 if parameters.empty? if instance_variables.include?(ivar) instance_variable_get(ivar) end else instance_variable_set(ivar, parameters.first) end end end end end end end
setterはCで書かれたデフォルトのアクセッサをそのままRuby版に置き換えたようなコードだ。
一方、getterは独自実装になっており、引数がある場合はその引数を変数にセットすると言う内容。
つまり、目的は#=の代わりに
class C adv_attr_accessor :bcc def do_something bcc "hoge@hoge.com" #== bcc = "hoge@hoge.com" end
と書きたい、と言う事のようだ。
ActionMailerのサンプルでは以下のようなコードがよく出てくる。
def mail(message) recipients message[:address] from message[:from] subject message[:subject] body message[:body] end
DSLっぽいインターフェースを実現したい、と言う為だけに新しいアクセッサを用意する辺りがRailsらしい。こう言った強引さがRails以前からのRubyistからすると不満なのだろう。Railsがフレームワークと言う枠を飛び越えて、Rubyをimproveした新しい言語になろうとしているかのようで。
必要に迫られてRailsのコードを読む事もあるが、Railsのコードは一行一行から思想が滲み出ていて、読んでいて単純に楽しい。勉強にもなる。RailsだってやっぱりRubyで出来ているんだよな、なんて事を思った。
BackgrounDRbのWorkerオブジェクト削除タイミングについての悩み
BackgrounDRbのサンプルでよく見かけるのが以下のようなソース。
def start_background_task session[:KEY] = MiddleMan.new_worker(:class => :foo_worker, :args => "hoge") end #start_background_task.rhtmlから非同期で呼ばれるアクション def update_progress if request.xhr? worker = MiddleMan.worker(session[:KEY]) progress_percent = worker.progress_percent render :update do |page| page.call('progressPercent', 'progressbar', progress_percent) page.redirect_to(:action => 'done') if progress_percent >= 100 end end end def done MiddleMan.delete_worker(session[:KEY]) end
分かりやすい例なのだけれど、肝心な点が抜けている。
それは、「処理中にブラウザを閉じたらどうなるのか?」と言う事。
このソースだと、処理の完了後に表示されるアクションでワーカーオブジェクトの削除処理を実装している為、途中でブラウザを閉じたりするとワーカーオブジェクトが削除されなくなってしまう。
じゃあどうしよう、という事で悩んでいたのだが、タイミングよくWEB+DB PRESS 40号のRails連載記事でBackgrounDRbが紹介されていた。
記事では、ワーカーの作成時のオプションにttlとexpire_typeと言う値を指定できるとの事。
例えば以下のように書くと、最後にアクセスした時刻から300秒経過するとワーカーオブジェクトが削除されるらしい。
MiddleMan.new_worker(:class => :foo_worker, :args => "foo", :ttl => 300, :expire_type => :accessed)
キタコレと思ったものの、BackgrounDRbのソースを読んだ時にはttlとexpire_typeオプションを処理している箇所が見当たらなかった。
再度見なおしても、やっぱりない…。
記事内ではBackgrounDRbのバージョンについて何も言及されていなかったのだけれど、WEB+DB PRESSのサポートページにソースがアップされていた。このソースだと、BackgrounDRb起動時に削除用のスレッドが生成され、それがttlとexpire_typeオプションを見てワーカーオブジェクトを削除するように実装されていた。
今のBackgrounDRbの最新版は0.21だが、過去のバージョンは0.20までしかない。
どちらのバージョンにも上記の処理がなかったところを見ると、WEB+DB PRESSで使用したBackgrounDRbのバージョンはかなり古いものなのだと思う。
うーんどうしよう…。
古いバージョンに戻すのも怖いし、かと言ってそれなりに巨大化した今のBackgrounDRbを勝手に拡張して問題が起こらない自信もなし。
そもそもあって然るべきの削除用のスレッド周りの処理が何故削除されたのか、という事情も分からないからなあ。
もうちょっと調べてみよう。
Ctrl + Cで終了しないRubyプログラム
バッチ用のRubyプログラムをちょっと動かしてからCtrl + Cで終了させたものの、止まってくれなくて焦る。標準出力にガンガン出力されていく…。
kill -s 9
で強制的にKillするが、そもそもCtrl + Cで止まらないことが問題。
ちょっと考えてみたところ、原因は簡単だった。
例外処理のところでJava時代の癖が残っていて、Exceptionクラスをキャッチしてしまっていたのだ。
Ctrl+Cを押下した際にRuby側に例外として投げられるのはInterruptクラス。スーパークラスを辿って行くとSignalException -> Exceptionクラスとなる。
プログラミング言語 Ruby リファレンスマニュアル
つまり、例外が発生して終了すべきところを、プログラム内でキャッチして吸収してしまったと言う事。最低だ…。
教訓:
例外を明示的にキャッチする時は一番粗い粒度はStandardErrorクラスとする事。
Exceptionクラスはキャッチしちゃダメ、絶対。