java で memcached に入れたものを ruby で取り出す (その逆も)
タイトル通り。
memcached つかうほどのものをいじっていないのだけれども面白そうなのでメモ。
以下、java はhttp://www.whalin.com/memcached/
ruby は memcached-client を前提とする*1。
普通につかう。
普通にサンプル通り書くと、java なら
String[] servers = { "localhost:11211", }; SockIOPool pool = SockIOPool.getInstance(); pool.setServers(servers); pool.initialize(); MemCachedClient mcc = new MemCachedClient(); mcc.set("one", 1); mcc.set("two", 2); mcc.get("one");
こんな感じ*2。
ruby だと
require 'rubygems' require 'memcache' mem = MemCache.new("localhost:11211") mem["three"] = 3 mem["four"] = 4 mem["three"]
こんな感じ。
普通に使う分にはこれで十分っぽい*3。
java で入れたものを ruby から取り出す
でも、ここで java で入れたやつを ruby から取ろうとして、
p mem["one"]
とかやっても、
/opt/local/lib/ruby/gems/1.8/gems/memcache-client-1.5.0/lib/memcache.rb:214:in `load': marshal data too short (ArgumentError)
from /opt/local/lib/ruby/gems/1.8/gems/memcache-client-1.5.0/lib/memcache.rb:214:in `[]'
from mem.rb:8
とかそんな感じで、怒られる。
これは、ruby の memcache-client が値がマーシャルであることを期待しているため*4。
該当個所はここらへん。
## # Retrieves +key+ from memcache. If +raw+ is false, the value will be # unmarshalled. def get(key, raw = false) server, cache_key = request_setup key value = if @multithread then threadsafe_cache_get server, cache_key else cache_get server, cache_key end return nil if value.nil? value = Marshal.load value unless raw # ここでエラー!!! return value rescue TypeError, SocketError, SystemCallError, IOError => err handle_error server, err end
ちなみに話がずれるけど、get なんて使ってないのにここでエラーになっているのは、以下のようにエイリアスが定義されているから。
alias [] get
まあということで、
p mem.get["one",true]
とやってあげればOK、とおもいきや、java で入れた値の場合、
"\000\000\000\001"
という値が返ってきてしまう。
これに関しては、java の memcached ライブラリのサイトの http://www.whalin.com/memcached/HOWTO.txt にコメントがあって、
Multi-client Example:
=====================If you need to support multiple clients (i.e. Java, PHP, Perl, etc.)
you need to make a few changes when you are setting things up:// use a compatible hashing algorithm
pool.setHashingAlg( SockIOPool.NEW_COMPAT_HASH );// store primitives as strings
// the java client serializes primitives
//
// note: this will not help you when it comes to
// storing non primitives
mcc.setPrimitiveAsString( true );// don't url encode keys
// by default the java client url encodes keys
// to sanitize them so they will always work on the server
// however, other clients do not do this
mcc.setSanitizeKeys( false );
ということらしい。ということで、java 側を
String[] servers = { "localhost:11211", }; SockIOPool pool = SockIOPool.getInstance(); pool.setServers(servers); pool.setHashingAlg( SockIOPool.NEW_COMPAT_HASH ); // ここと pool.initialize(); MemCachedClient mcc = new MemCachedClient(); mcc.setPrimitiveAsString( true ); // ここと mcc.setSanitizeKeys( false ); // ここ mcc.set("one", 1); mcc.set("two", 2); mcc.get("one");
てな感じでかえてあげると、ruby からも値が取り出せるようになる。
ruby で入れたものをjava からとりだす
ruby の memcache-client の場合、値をマーシャルにして保存しようとするので、そうさせないようにする。
該当部分のコードは以下。
def add(key, value, expiry = 0, raw = false) raise MemCacheError, "Update of readonly cache" if @readonly server, cache_key = request_setup key socket = server.socket value = Marshal.dump value unless raw # ここでマーシャルにしてる!! command = "add #{cache_key} 0 #{expiry} #{value.size}\r\n#{value}\r\n" begin @mutex.lock if @multithread socket.write command socket.gets rescue SocketError, SystemCallError, IOError => err server.close raise MemCacheError, err.message ensure @mutex.unlock if @multithread end end
つまり、ruby で
mem.add("one","1",0,true)
として値を入れてあげれば java から
mcc.get("one");
という形でとりだせる。
ここで、注意しなきゃいけないのは、add の定義のなかで、
command = "add #{cache_key} 0 #{expiry} #{value.size}\r\n#{value}\r\n"
となっている点。ruby の場合、
1.size #=> 4 "1".size #=> 1
なので、値は Fixnum とかじゃまずい*5。
mem.set("one",1,0,true) # 第二引数が String じゃない!
とかやるとエラーになる*6。
サイズがあうものを入れると入れられちゃう分、気がつきにくそうで怖い。
つまり、以下はOK。
mem.set("hoge",1234,0,true) # 第二引数が String じゃないけど、通る!
…。
まとめ
ruby の memcache-client は デフォルトだと値をマーシャルにして入れているということ。
マーシャルじゃなくて保存したいときには、add と get の引数に true を指定してあげればよい。
ruby,php,perlでmemcacheの中身を使い回す | Parse Errorとかをみる限りだと、perl とか php はそのまま入れてるっぽい。
will_paginate について
最近railsはじめた。
で、will_paginate*1を
# sudo gem install will_paginate
で、入れたのだが、これだと古いものが入ってしまうらしい。
これは、Home · mislav/will_paginate Wiki · GitHub に
The name of the will_paginate gem is now “mislav-will_paginate” because it’s being built by GitHub. If you have a gem named “will_paginate”, it is old and you are advised to remove it from your system.
という文章があったため判明した。
そこで、http://github.com/mislav/will_paginate/wikis/installationをみながら、
# sudo gem uninstall will_paginate # sudo gem sources -a http://gems.github.com # sudo gem install mislav-will_paginate
と、やってあげて、ねんがんのwill_paginateをてにいれた。
ニコニコの右上でFortuneのデータつくった
まず、http://www.nicochart.jp/static/comment.htmlから右上の発言集をとってくる。
require 'open-uri' open("http://www.nicochart.jp/static/comment.html") do |f| f.each do |line| line.scan(/<dd>(.*?)<\/dd>/){|a|puts a.first.gsub(/<.*?>/,""); puts "%"} end end
上記のスクリプト(ここではmigiue.rbとする)だと、標準出力にでてくるので適当なファイルにリダイレクト。
ruby migiue.rb > nico
で、nicoの中身は以下のような感じ。
ニコニコしている時のあなたが一番輝いていて、………好き。 % 泣くな!ニコニコしろ!! % たまに空見上げてみるのもいいもんだよ % みんな〜、ニコニコしてるかな? % 右上の夏休みは一日もない。 %
これに対して、strfileする。
strfile nico nico.dat
これで完成。
で、このファイルを指定してfortuneを実行すれば、
bubbles% fortune nico 朝、目を覚まし、横を見るとなぜかニコニコが同じふとんに bubbles%
という感じに。
あとは、ログイン時に表示されるように適当に.zshrcとか.bashrcをいじる。
■
Carbon Emacs の夏版が出たらしいので入れたのだが、前のように(mac-toggle-max-window)では、全画面にならない。
http://www.sooey.com/journal/2008/07/19/ では、起動時に全画面になる設定が書かれていたが、自分は、全画面にしたりもどしたりしたかったので以下のように、.emacs に書いた。
(defun my-mac-toggle-max-window () (interactive) (if (frame-parameter nil 'fullscreen) (set-frame-parameter nil 'fullscreen nil) (set-frame-parameter nil 'fullscreen 'fullboth))) (global-set-key "\C-cm" 'my-mac-toggle-max-window)
はじめは、関数定義して、global-set-keyしてあげればいいのかなー、と思ってたがうまくいかず、いろいろググったところ、http://www.kabipan.com/computer/emacs/ で
(global-set-key "\C-cz" (insert "a"))
よくあるキーバインディングの誤り。
リストの第三要素は任意の式でいいわけではない。(global-set-key "\C-cz" (lambda () (insert "a")))
第三要素をラムダ式にしても、まだ使用時にエラーが出る。
ただの関数では駄目。(global-set-key "\C-cz" (lambda () (interactive )(insert "a")))
http://www.kabipan.com/computer/emacs/
コマンドだと宣言してある関数ならうまくいく。
と書いてあり、関数定義のなかに(interactive) を加えたらうまくいった。超参考になりました。
で、とりあえずC-cmで全画面との切り替えができるようにした。
あんまり自信はないが、とりあず動くのでOKということにする。