[Ruby] [:name, :yomi] から {:name=>"maiha", :yomi=>"maiha"} を作りたい

最初に思いついたのは、inject

array = [:name, :yomi]
array.inject({}){|h,i| h[i] = "maiha"; h}
=> {:name=>"maiha", :yomi=>"maiha"}

"; h" が冗長で悔しいのよね。

injectでもこんな感じに書けばシンプルにできますよ。

   1  >> [:name, :yomi].inject({}){|h,k| h.merge(k => "maiha")}
   2  => {:name=>"maiha", :yomi=>"maiha"}

Hashinjectmergeと相性がいい。

posted by Png genki on Sun 27 Jan 2008 at 06:45

ActiveSupportでは、メソッドの途中で戻り値を指定するための returningというメソッドがObjectクラスに定義されています。 これを使うと、以下のようにメソッドの最後の式の値が何になるかを 気にせずに記述することができます。

   1  def foo
   2    returning Article.find(parmas[:id]) do |article|
   3      article.foo = 'bar'
   4      article.save
   5    end
   6  end

これと同様のことを、Rubyにあらかじめ用意されているensure を使っても実現可能です。

   1  def foo
   2    article = Article.find(params[:id])
   3  ensure
   4    article.foo = 'bar'
   5    article.save
   6  end

ブロックの値がensureの値を無視する事を利用しています。

posted by Png genki on Sat 26 Jan 2008 at 20:13

RubyでバイナリデータをBase64エンコードする場合、 require 'base64'をしてからBase64.encode64(binary)をするか、 以下のようにpackmテンプレートを使うことができます。

   1  [binary].pack('m') #=> Base64 encoded string

しかし、アップロードしたファイル用のテンポラリなファイル名 などに使用する場合、Base64でエンコードした文字列は ファイル名に使えない(可能性が高い)文字を含んでいるため、 そのような場合にはbase64url形式でエンコードします。

base64url って何?

base64url とは、base64 を基に RFC4648 で規定された変換方式で、url とファイル名に使用しても安全になるように設計されています。変更点は、base64 では + と / が使用されていますが、それを - と _ を使用するようにします。具体的には、base64では「ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/」の表で変換しますが、base64url では「ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_」を使用します。

ということで、通常のBase64エンコードした結果に対して、 +-に、/_に置き換えればいいだけなので、 以下のようにすればOKです。

   1  [binary].pack('m').tr('+/', '-_')

posted by Png genki on Thu 24 Jan 2008 at 06:02

annotate_models は、テーブルの情報をModelとFixtureのファイルに コメントとして書き込んでくれる非常に便利なプラグインです。

永く愛用しているプラグインの一つなのですが、 しばらくメンテナンスされていないようなので、 欲しいと思っていたindexに関する情報も出力するようにしてみました。

http://svn.s21g.com/public/rails/plugins/annotate_models_with_index/

こんな感じに、インデックス情報をカラムごとに付加します。

   1  # == Schema Information
   2  # Schema version: 48
   3  #
   4  # Table name: users
   5  #
   6  #  id           :integer(11)   not null, primary key
   7     (* snip *)
   8  #  mobile_email :string(255)   index_users_on_mobile_email(unique)

posted by Png genki on Thu 24 Jan 2008 at 01:09

irbを使っているときに、オブジェクトにどんなメソッドが 定義されているのかをpublic_methodsなどで調べることが 出来ますが、たいていの場合大量のメソッドがリストアップされて わかりにくくなってしまいます。

今回は、そんなときに良くやる方法を紹介します。

   1  >> Time.public_methods.sort - Object.public_methods
   2  => ["_load", "at", "days_in_month", "gm", "httpdate", "iso8601", "local", "local_time", "mktime", "now", "parse", "rfc2822", "rfc822", "time_with_datetime_fallback", "times", "today", "utc", "utc_time", "xmlschema", "yaml_new", "zone_offset"]

public_methodsからObjectpublic_methodsを取り除いたものを 表示しています。Objectの代わりに適当な親クラスを指定することで、 クラス階層の特定の領域で定義されたメソッドを表示することも できますね。

posted by Png genki on Mon 21 Jan 2008 at 14:14

Now, we are working on ShootingStar-4.0.0

It will be working on Windows by using WaitForMultipleObject API. I loved it since more than 10 years ago and thought it as is one of a beautiful aspect of Windows.

It may be shipped on next month.

posted by Png genki on Mon 21 Jan 2008 at 06:46

Rails勉強会@東京#26

Genki Takiuchi

Recent Situation:

  • Founded a small company.
    • And it has already survived 3 months, Yay!
  • Shipped ShootingStar 3.2.6
  • Jogging and swimming.
  • Finally I bought e-mobile (D02HW)
  • And also being with Rails 2.0.2

Favorite Things:

  • C/C++ Template, JavaScript, Ruby.
  • Thinking algorithm, Rendering (CG) and 3D.
  • Vim7, Zsh, GNU screen, rails.vim, ZenTest.

Thank you!

posted by Png genki on Sun 20 Jan 2008 at 14:33

以前紹介した Hash#only にちょっとした修正。

lib/hash_ext.rb

   1  class Hash
   2    def only(*args)
   3      args = *args if args[0].is_a? Array
   4      args.inject({}){|hash, key| hash[key] = self[key] if include? key; hash}
   5    end
   6  
   7    def only!(*args)
   8      args = *args if args[0].is_a? Array
   9      args.inject({}){|hash, key| hash[key] = self[key]; hash}
  10    end

以前のHash#onlyは、指定したキーが存在しない場合でも

   1  {:foo => 1}.only(:bar) #=> {:bar => nil}

というように、nilを指すHashを返していましたが、 キーが存在しない場合に空のHashを返すようにしてみました。 従来の挙動をするメソッドは、Hash#only!と感嘆符付きの メソッドにしています。 修正後の挙動は以下の通り。

   1  {:foo => 1}.only(:bar) #=> {}
   2  {:foo => 1}.only!(:bar) #=> {:bar => nil}

posted by Png genki on Sat 19 Jan 2008 at 13:30

最近は、自分用にRailsの挙動を拡張するために書いた lib/xxxx_ext.rbが増えてきました。 こういったファイルはconfig/initializer/の直下に 置いても良いのですが、ON/OFFを切り替えやすいので、 config/initializer/libs.rbの中から、require "xxxx_ext" を呼ぶようにしています。

さて、今回はActiveRecordをさらに便利に使うために、 僕が行っている拡張を紹介します。

lib/active_record_ext.rb

   1  module ActiveRecord
   2    class Base
   3      def self.[](arg, *args)
   4        case arg
   5        when Range
   6          find arg.to_a
   7        when Hash
   8          find :all, arg
   9        when :first, :all
  10          find arg, *args
  11        when :last
  12          find(:all, *args).last
  13        when Symbol
  14          send "find_#{arg}", *args
  15        else
  16          find arg, *args
  17        end
  18      end
  19  
  20      def update_counters(counters)
  21        self.class.update_counters id, counters
  22      end
  23    end
  24  end

どうでしょう、お分かりだと思いますが、ARクラスに インデクサ (rb_aref) を定義しています。こんな感じに動作します。

   1  >> Site[1].uri
   2  => "http://www.google.com/"
   3  >> Site[1,2].map &:uri
   4  => ["http://www.google.com/", "http://www.wikipedia.org/"]
   5  >> Site[1..2].map &:uri
   6  => ["http://www.google.com/", "http://www.wikipedia.org/"]
   7  >> Site[:last].title
   8  => "Ruby/Tk チュートリアル"
   9  >> Site[:by_uri, "http://www.google.com/"].uri
  10  => "http://www.google.com/"

実際のアプリケーションコードの中ではあまり使っていないですが、 script/consoleの中で使うのには大変便利です。

最後に、update_countersは、インスタンスメソッドとして 欲しかったので追加しています。 Rails 2.0から仕様が変わった counter_cache については、 日比さんがこちらに記事 「既存のモデル/テーブルでcounter_cacheを使う:update_counters」 を書いているので参照してみてください。

posted by Png genki on Tue 15 Jan 2008 at 06:38

lighttpd-1.5.xから導入される予定のmod_deflateは、 static/dynamicを問わず、レンダリング出力を 圧縮してくれる便利なモジュールですが、 残念ながらlighttpd-1.4.x系では使うことができません。

しかし、非常に便利な機能なので、1.5.x系から バックポートするための様々な試みがなされています。 今回は、lighttpd-1.4.8にパッチを当てて mod_deflateを使う方法を紹介します。

以下のようにlighttpd-1.4.8のソースと、パッチを ダウンロードし、パッチを適用します。

   1  # cd /usr/local/src
   2  # wget http://www.lighttpd.net/download/lighttpd-1.4.18.tar.bz2
   3  # tar xvjf lighttpd-1.4.18.tar.bz2
   4  # cd lighttpd-1.4.18
   5  # curl http://poocs.net/files/lighttpd-1.4.18.mod_deflate.scoop.patch.gz  | gzip -d | patch -p1

あとは、通常通りソースからインストールすれば完了です。

   1  # ./configure --with-bzip2
   2  
   3  ~ (snip) ~
   4  
   5  enabled:
   6    auth-crypt
   7    compress-bzip2
   8    compress-deflate
   9  
  10  ~ (snip) ~
  11  
  12  # make
  13  # make install

mod_deflateの使い方は、こちらのサイトをご覧ください。

posted by Png genki on Sun 13 Jan 2008 at 07:33