kaeruspoon

Erlangの勉強その2

すべての関数はモジュールに属している。

-module(restaurant).


関数は以下のように定義する。

menu(coffee) -> 190;
menu(burger) -> 290;
menu(coke) -> 100.

これをシェル(つまり外部)から使うにはexport定義をしてやる必要がある。

-export([menu/1]).

関数名のあとのスラッシュの後ろは引数の数を表している(これをアリティと呼ぶ)。
実際にシェルから使ってみる。

1> c(restaurant).
{ok,restaurant}
2> restaurant:menu(coffee).
190
3> restaurant:menu(coke).
100


無名関数はfunという名前で定義する。

1> SubTotal = fun(Item, Count) -> restaurant:menu(Item) * Count end.
#Fun<erl_eval.12.115169474>
2> SubTotal(coffee,3).
570
3> SubTotal(burger,2).
580


listsモジュールには、RubyでいうEnumerableモジュールのような便利な関数がそろっている。

4> lists:map(fun({Item, Count}) -> restaurant:menu(Item) * Count end, [{coffee, 3}, {burger, 2}]).
[570,580]

map関数の第一引数に、リストの各要素に適用される関数を指定してあげる。第二引数はそのリストだ。
funを返す関数も定義できる。

5> Member = fun(Count) -> (fun(Item) -> restaurant:menu(Item) * Count end) end.
#Fun<erl_eval.6.56006484>
6> ItemValue = Member(3).
#Fun<erl_eval.6.56006484>
7> ItemValue(coffee).
570
8> ItemValue(burger).
870


リスト内包表記を使うと、もっと簡潔にリスト処理が行える。

9> [{restaurant:menu(Item), Count} || {Item, Count} <- [{coffee, 3}, {burger, 2}]].
[{190,3},{290,2}]
10> lists:sum([restaurant:menu(Item) * Count || {Item, Count} <- [{coffee, 3}, {burger, 2}]]).
1150

へぼ将棋にいそしむ

最近、将棋がおもしろくてよくやるのだけど、下手くそなへぼ将棋なので、コンピュータ相手になかなか勝てない。頭の悪さを認識する今日この頃である。Erlangの勉強をしていてもよく思うのだけど、二十歳の頃は本を一度読めばだいたい理解できたのに、今は何度か同じところを読み返してさらに動かしてみたりしないとなかなか理解できない。大人になるほど阿呆になるんだな。

MXTVでガッチャッマンをやっているのだけど、意外とおもいろくてみてしまう。コンドルのジョーがシブい。

ガード - Erlangの勉強

ガードは、パターン照合に条件を付与することができる。カンマ区切りで論理積になり、セミコロン区切りで論理和となる。

cource(X) when is_integer(X), X > 0 -> "cource No." ++ integer_to_list(X);
cource(X) when is_integer(X), X =:= 0 -> "cource is ALL";
cource(X) -> "cource is bad!".

こうしておけば、

1> restaurant:cource(1).
"cource No.1"
2> restaurant:cource(0).
"cource is ALL"
3> restaurant:cource(aa).
"cource is bad!"

となる。
論理和で上記の関数を定義していると結果は当然、

1> restaurant:cource(1).
"cource No.1"
2> restaurant:cource(0).
"cource No.0"
3> restaurant:cource(aa).

=ERROR REPORT==== 4-Jan-2009::23:03:07 ===
Error in process <0.30.0> with exit value: {badarg,[{erlang,integer_to_list,[aa]},{restaurant,cource,1},{erl_eval,do_apply,5},{shell,exprs,6},{shell,eval_loop,3}]}

** exited: {badarg,[{erlang,integer_to_list,[aa]},
                    {restaurant,cource,1},
                    {erl_eval,do_apply,5},
                    {shell,exprs,6},
                    {shell,eval_loop,3}]} **

こうなる。最後の、引数がアトムのときの例外は、integer_to_list()の部分で発生している。

RMagickのメモリばか喰いを解決する方法その2

以前、「RMagickのメモリばか喰いを解決する方法」という記事を書いたけど、同じくらい馬鹿馬鹿しい方法がある。
それはRMagickを使わないという方法だ。

def create_thumbnail(in_file)
  out_file = generate_thumbnail_name(in_file)
  `/usr/local/bin/convert #{in_file} -thumbnail 50x50 #{out_file}`
end

これでメモリリークとはおさらばである。
まあ、サムネイル画像を作る程度の機能でいいのなら、ImageScienceとかを使うのがおすすめです。実際のところ、RMagickほどの機能が必要なことってwebアプリではあまりないと思う。

Rails2.1.2でActsAsReadonlyableが動かないときの対処

Railsのバージョンを2.1.2にあげたらvalidates_uniquness_ofでActiveRecord::StatementInvalid例外が出るようになった。

TypeError: wrong argument type Hash (expected String): .......

vendor/rails/activerecord/lib/active_record/connection_adapters/abstract_adapter.rb:147:in `log'
vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb:302:in `execute'
vendor/rails/activerecord/lib/active_record/connection_adapters/mysql_adapter.rb:537:in `select'
vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/database_statements.rb:7:in `select_all_without_query_cache'
vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:59:in `select_all'
vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:80:in `cache_sql'
vendor/rails/activerecord/lib/active_record/connection_adapters/abstract/query_cache.rb:59:in `select_all'
vendor/rails/activerecord/lib/active_record/validations.rb:651:in `validates_uniqueness_of'

vendor/rails/activerecord/lib/active_record/validations.rbの651行目を見てみる。

results = finder_class.with_exclusive_scope do
  connection.select_all(
    construct_finder_sql(
      :select     => "#{connection.quote_column_name(attr_name)}",
      :from       => "#{finder_class.quoted_table_name}",
      :conditions => [condition_sql, *condition_params]
    )
  )
end

どうも、select_allに文字列のSQLを渡さなきゃいけないのに、Hashが渡っていることでエラーになっている。
なので、construct_finder_sqlメソッドを見てみる。

        def construct_finder_sql(options)
          scope = scope(:find)
          sql  = "SELECT #{options[:select] || (scope && scope[:select]) || ((options[:joins] || (scope && scope[:joins])) && quoted_table_name + '.*') || '*'} "
          sql << "FROM #{(scope && scope[:from]) || options[:from] || quoted_table_name} "

          add_joins!(sql, options, scope)
          add_conditions!(sql, options[:conditions], scope)

          add_group!(sql, options[:group], scope)
          add_order!(sql, options[:order], scope)
          add_limit!(sql, options, scope)
          add_lock!(sql, options, scope)

          sql
        end

それぞれのメソッドもたどって見たけど、このメソッドはちゃんと文字列のSQLを返していた。どこかで悪さをしているやつがいるらしい。
と思ってプラグインを調べたらActsAsReadonlyableが犯人だった。


      def construct_finder_sql(options)
        options.merge(:sql => super)
      end

こんなことしている。なので、select_allをオーバライドして仮対処してみた。

module ActiveRecord
  module ConnectionAdapters
    class AbstractAdapter
      def select_all(sql, name = nil)
        sql = sql[:sql] if sql.is_a?(Hash)
        select(sql, name)
      end
    end
  end
end

Lenovo ThinkPlus USBトラベルキーボード ウルトラナビ付 [31P9514]: 家電・カメラ

Lenovo ThinkPlus USBトラベルキーボード ウルトラナビ付 31P9514

会社のキーボードを特に気にせず使っているけど、マウスをさわるためにキーボードから手を離すのがメンドくさいので「Lenovo ThinkPlus USBトラベルキーボード ウルトラナビ付 31P9514」なんかでも来月のおこづかいで買おうかと思っている。Thinkpadのキーボードとトラックポイントは最高だから。ただ高いんだよね、これ。なんでこのキーボードこんなに高くなってるんだろう。

ドライブに行く

日曜日は東名高速で沼津までドライブしました。田子の浦にうち出でてみて富士の高嶺に雪が積もっているのを眺めてから、富士宮市でラーメンを食べます。このラーメン、油がすごくて、ユルさんはダブルクオーターパウンダーを食べたぼくみたいにやられていました。
朝霧高原で一面の雪化粧を堪能してから都内に戻って夜景を楽しみました。レインポーブリッジから見える夜景は、自分が世界三大都市のひとつに住んでいることを実感させてくれておすすめです。おもしろかった。

ハードディスクから異音

今朝早く、リビングに置いてあるサーバから異音が響いてきて目がさめます。ガラガラという音はどうもハードディスクっぽい感じだったけど、とりあえず電源を落として会社に行きました。
ところが、帰ってきてからひとつづつハードディスクを確かめてみたけどなんの異常もなく起動してしまった。またすぐに異音が出るようになりそうだけど、どのハードディスクが原因なのか見極めができてないので外すこともできません。ログにも何も吐かれてないのでお手上げ状態。もうちょっと様子見しましょう。

飫肥の城下町に住む

http://www.nichinan-uji.jp/modules/myalbum32/photo.php?lid=70&cid=71#top1
この前、ユルさんと九州へのUターンの話をしていていろいろ調べていたら、宮崎県のサイトにUターンしたい人のためのページが用意されていて、そこで飫肥の街の空き家が紹介されていました。
飫肥の街は古い町並みが残る静かな観光地で、ぼくとユルさんは何度も訪れているのですが、とても住みやすそうないいところです。そこでこんな家があったのでふたりで盛り上がってしまいました。
土地が293.51坪で、建物の面積が43.94坪なので相当に庭は広いです。バイクや工作のためのガレージを建てたり庭園鉄道を走らせたりできそう。さらに外装のリフォームには自治体から補助が8割も出るようです。内装が幽霊が出そうな感じなので古民家風なカッコいいものにしたりとかいろいろと想像を楽しみました。

merbでFATAL: The gem dm-core (= 0.9.8, runtime), [] was not foundエラー

merbをちゃんとやろうと、環境を整えてmerbアプリを作ってmerbコマンドで起動しようとしたら、

[tsukasa@ubuntu] $ merb
Loading init file from /home/tsukasa/test/config/init.rb
Loading /home/tsukasa/test/config/environments/development.rb
 ~
 ~ FATAL: The gem dm-core (= 0.9.8, runtime), [] was not found

のようなエラーが出た。dm-coreのバージョンが0.9.9だったので、config/dependencies.rbを以下のように修正する。

dm_gems_version   = "0.9.9"

でもやっぱりダメだ。詳しくみるために--verboseオプションをつけてみた。

[tsukasa@ubuntu] $ merb --verbose                                               [~/test]
 ~ Running bootloaders...
Loading init file from /home/tsukasa/test/config/init.rb
Loading /home/tsukasa/test/config/environments/development.rb
 ~ Loaded DEVELOPMENT Environment...
 ~ Expanding RUBY_PATH...
 ~ loading gem 'merb-action-args' ...
 ~ loading gem 'merb-assets' ...
 ~ loading gem 'merb-cache' ...
 ~ loading gem 'merb-helpers' ...
 ~ loading gem 'merb-mailer' ...
 ~ loading gem 'merb-slices' ...
 ~ loading gem 'merb-auth-core' ...
 ~ loading gem 'merb-auth-more' ...
 ~ Registered slice 'MerbAuthSlicePassword' located at /usr/lib/ruby/gems/1.8/gems/merb-auth-slice-password-1.0.7.1
 ~ loading gem 'merb-auth-slice-password' ...
 ~ loading gem 'merb-param-protection' ...
 ~ loading gem 'merb-exceptions' ...
 ~
 ~ FATAL: The gem dm-core (= 0.9.9, runtime), [] was not found
 ~
 ~ FRAMEWORK_ROOT = /usr/lib/ruby/gems/1.8/gems/merb-core-1.0.7.1/lib
 ~
 ~ Gem::LoadError: Could not find RubyGem launchy (>= 0.3.2)

 ~ ./config/dependencies.rb:18
 ~ /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31:in `gem_original_require'
 ~ /usr/local/lib/site_ruby/1.8/rubygems/custom_require.rb:31:in `require'
 ~ /home/tsukasa/test/config/init.rb:3
 ~ FRAMEWORK_ROOT/merb-core/bootloader.rb:520:in `load'
 ~ FRAMEWORK_ROOT/merb-core/bootloader.rb:520:in `load_initfile'
 ~ FRAMEWORK_ROOT/merb-core/bootloader.rb:388:in `run'
 ~ FRAMEWORK_ROOT/merb-core/bootloader.rb:99:in `run'
 ~ FRAMEWORK_ROOT/merb-core/server.rb:172:in `bootup'
 ~ FRAMEWORK_ROOT/merb-core/server.rb:42:in `start'
 ~ FRAMEWORK_ROOT/merb-core.rb:170:in `start'
 ~ /usr/lib/ruby/gems/1.8/gems/merb-core-1.0.7.1/bin/merb:11
 ~ /usr/bin/merb:19:in `load'
 ~ /usr/bin/merb:19

お? launchy といえものがないらしい。なので入れてみた。

sudo gem install launchy

そしてmerb起動。

Loading init file from /home/tsukasa/test/config/init.rb
Loading /home/tsukasa/test/config/environments/development.rb
 ~ Connecting to database...
 ~ Loaded slice 'MerbAuthSlicePassword' ...
 ~ Parent pid: 6331
 ~ Compiling routes...
 ~ Activating slice 'MerbAuthSlicePassword' ...
merb : worker (port 4000) ~ Starting Mongrel at port 4000
merb : worker (port 4000) ~ Successfully bound to port 4000
merb : worker (port 4000) ~ Started request handling: Fri Jan 16 08:29:35 -0500 2009

動いた! やった~。

休日のこと

土曜日はユルさんにつきあって北千住まで。彼女が律さんとコミケの打ち合わせがあったのでした。行く途中の千代田線で、北千住を通り過ぎたと思ってあわてて降りたら次の駅が北千住だったりしました。千代田線は狐に化かされたりするので注意が必要です。北千住ではケーキを食べました。あと、ネコが三匹雪まみれになっているカレンダーがあったのでちょっと欲しかったけど我慢しました。

merbの勉強をちょっとしました。けどなんだか飽きてきていて放置気味です。Railsもちょっと飽きてきているので困りものであります(ホントは困っていない)。Erlangの勉強もしました。こっちはおもしろいですね。全然違うものをすると脳が活性化する感覚が顕著で、とても気持ちがいいのです。

景虎という日本酒ユルさんに買ってもらいました。おかげで土日の晩はのんびり楽しみます。焼き魚が欲しいな。

近所を散歩しました。しろさん(近所のネコです)を最近見ないので探しにいったのでした。しかし見つからず。あんなにいっぱいネコがいるのに、まったく見かけないときもあるのが不思議です。どこかで暖をとっているのでしょうか。

ひさしぶりにエースコンバット4をしています。今さらです。サラ・コナーです。ターミネーター3はなかったことにされそうですね。なんの話でしょうか。

tokyobikeのブルホーンハンドル化計画の構想を練っていました。去年はストイックに自転車に乗っていたのですが今年は方向転換しておしゃれに気軽に自転車とつきあっていこうと思います。自転車通勤したいなあ。

after_createが2回呼ばれる謎

AR の古いバージョンだけなのかもしれないけど、今日、after_createが連続して2回コールされる現象に出会いました。レコードはひとつしか作られていないのです。でもafter_createが2回コールされ、両方とも同一のインスタンスのもので、コールされる時間もほぼ連続的といっていいのです。
after_createのブロック群はStringやProcの形で配列に保存されていて、コールされるタイミングでその配列のそれぞれのブロックが順繰りに呼ばれます。そこに同じProcがふたつ存在しているのではないかと疑ったのだけど、そうではありませんでした。いろいろ調べたのだけど結局原因はわからず。
仕方なくafter_createを使うのをあきらめたのだけど、ヒマを見ては原因追跡をやっていこうと思います。