それをinjectでやる方法
`inject`でもこんな感じに書けばシンプルにできますよ。 ruby>> >> [:name, :yomi].inject({}){|h,k| h.merge(k => "maiha")} => {:name=>"maiha", :yomi=>"maiha"} <最初に思いついたのは、inject
array = [:name, :yomi] array.inject({}){|h,i| h[i] = "maiha"; h} => {:name=>"maiha", :yomi=>"maiha"}"; h" が冗長で悔しいのよね。
ensureのreturning的な使い方
ActiveSupportでは、メソッドの途中で戻り値を指定するためのreturningというメソッドがObjectクラスに定義されています。
これを使うと、以下のようにメソッドの最後の式の値が何になるかを
気にせずに記述することができます。
rails>>
def foo
returning Article.find(parmas[:id]) do |article|
article.foo = 'bar'
article.save
end
end
<<--
これと同様のことを、Rubyにあらかじめ用意されているensure
を使っても実現可能です。
ruby>>
def foo
article = Article.find(params[:id])
ensure
article.foo = 'bar'
article.save
end
<<--
ブロックの値がensureの値を無視する事を利用しています。
RubyでBase64URLを使う方法のメモ
RubyでバイナリデータをBase64エンコードする場合、require 'base64'をしてからBase64.encode64(binary)をするか、
以下のようにpackのmテンプレートを使うことができます。
ruby>>
[binary].pack('m') #=> Base64 encoded string
<<--
しかし、アップロードしたファイル用のテンポラリなファイル名
などに使用する場合、Base64でエンコードした文字列は
ファイル名に使えない(可能性が高い)文字を含んでいるため、
そのような場合にはbase64url形式でエンコードします。
base64url とは、base64 を基に RFC4648 で規定された変換方式で、url とファイル名に使用しても安全になるように設計されています。変更点は、base64 では + と / が使用されていますが、それを - と _ を使用するようにします。具体的には、base64では「ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/」の表で変換しますが、base64url では「ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_」を使用します。
ということで、通常のBase64エンコードした結果に対して、+を-に、/を_に置き換えればいいだけなので、
以下のようにすればOKです。
ruby>>
[binary].pack('m').tr('+/', '-_')
<<--
annotate_modelsにindexの情報を付加する
annotate_models
は、テーブルの情報をModelとFixtureのファイルに
コメントとして書き込んでくれる非常に便利なプラグインです。
永く愛用しているプラグインの一つなのですが、
しばらくメンテナンスされていないようなので、
欲しいと思っていたindexに関する情報も出力するようにしてみました。
http://svn.s21g.com/public/rails/plugins/annotate_models_with_index/
こんな感じに、インデックス情報をカラムごとに付加します。
rails>>
== Schema Information
Schema version: 48
Table name: users
id :integer(11) not null, primary key
(* snip *)
mobile_email :string(255) index_users_on_mobile_email(unique)
<<--
irbでメソッド一覧を探す方法のTips
irbを使っているときに、オブジェクトにどんなメソッドが
定義されているのかをpublic_methodsなどで調べることが
出来ますが、たいていの場合大量のメソッドがリストアップされて
わかりにくくなってしまいます。
今回は、そんなときに良くやる方法を紹介します。
ruby>>
Time.public_methods.sort - Object.public_methods
=> ["_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からObjectのpublic_methodsを取り除いたものを
表示しています。Objectの代わりに適当な親クラスを指定することで、
クラス階層の特定の領域で定義されたメソッドを表示することも
できますね。
ShootingStar: Road to 4.0.0
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.
Genki Takiuchi
- Blog: http://blog.s21g.com/genki
- Twitter: http://twitter.com/takiuchi
- Facebook: http://www.facebook.com/profile.php?id=701866760
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!
Hash#only and Hash#only!
以前紹介したHash#only
にちょっとした修正。
lib/hash_ext.rb
ruby>>
class Hash
def only(*args)
args = *args if args[0].is_a? Array
args.inject({}){|hash, key| hash[key] = self[key] if include? key; hash}
end
def only!(*args)
args = *args if args[0].is_a? Array
args.inject({}){|hash, key| hash[key] = self[key]; hash}
end
<<--
以前のHash#onlyは、指定したキーが存在しない場合でも
ruby>>
{:foo => 1}.only(:bar) #=> {:bar => nil}
<<--
というように、nilを指すHashを返していましたが、
キーが存在しない場合に空のHashを返すようにしてみました。
従来の挙動をするメソッドは、Hash#only!と感嘆符付きの
メソッドにしています。
修正後の挙動は以下の通り。
ruby>>
{:foo => 1}.only(:bar) #=> {}
{:foo => 1}.only!(:bar) #=> {:bar => nil}
<<--
ActiveRecordをさらに便利にする方法の紹介
最近は、自分用にRailsの挙動を拡張するために書いたlib/xxxx_ext.rbが増えてきました。
こういったファイルはconfig/initializer/の直下に
置いても良いのですが、ON/OFFを切り替えやすいので、config/initializer/libs.rbの中から、require "xxxx_ext"
を呼ぶようにしています。
さて、今回はActiveRecordをさらに便利に使うために、
僕が行っている拡張を紹介します。
lib/active_record_ext.rb
rails>>
module ActiveRecord
class Base
def self.[](arg, *args)
case arg
when Range
find arg.to_a
when Hash
find :all, arg
when :first, :all
find arg, *args
when :last
find(:all, *args).last
when Symbol
send "find_#{arg}", *args
else
find arg, *args
end
end
def update_counters(counters)
self.class.update_counters id, counters
end
end
end
<<--
どうでしょう、お分かりだと思いますが、ARクラスに
インデクサ (rb_aref) を定義しています。こんな感じに動作します。
pre>>
Site[1].uri
=> "http://www.google.com/"Site[1,2].map &:uri
=> ["http://www.google.com/", "http://www.wikipedia.org/"]Site[1..2].map &:uri
=> ["http://www.google.com/", "http://www.wikipedia.org/"]Site[:last].title
=> "Ruby/Tk チュートリアル"Site[:by_uri, "http://www.google.com/"].uri
=> "http://www.google.com/"
<<--
実際のアプリケーションコードの中ではあまり使っていないですが、script/consoleの中で使うのには大変便利です。
最後に、update_countersは、インスタンスメソッドとして
欲しかったので追加しています。
Rails 2.0から仕様が変わった counter_cache については、
日比さんがこちらに記事
「既存のモデル/テーブルでcounter_cacheを使う:update_counters」
を書いているので参照してみてください。
lighttpd-1.4.8でmod_deflateを使う
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のソースと、パッチを
ダウンロードし、パッチを適用します。
shell>>
cd /usr/local/src
wget http://www.lighttpd.net/download/lighttpd-1.4.18.tar.bz2
tar xvjf lighttpd-1.4.18.tar.bz2
cd lighttpd-1.4.18
curl http://poocs.net/files/lighttpd-1.4.18.mod_deflate.scoop.patch.gz | gzip -d | patch -p1
<<--
あとは、通常通りソースからインストールすれば完了です。
shell>>
./configure --with-bzip2
~ (snip) ~
enabled:
auth-crypt
compress-bzip2
compress-deflate
~ (snip) ~
make
make install
<<--
mod_deflateの使い方は、こちらのサイトをご覧ください。
キャッシュされたcssやjsを更新する手順
javascript_include_tagやstylesheets_link_tag
の:cache => trueオプションは、複数のassetsファイルを
ひとつのファイルにまとめる事で、サーバへのリクエスト
数を減らすことができる機能です。
何度か実験してみたところ、生成されたキャッシュファイルを
削除して更新するためには、単純にファイルを削除するだけ
ではだめで、APサーバのプロセスを再起動する必要があるようです。
このためには、./script/process/reaper -a graceful
を使う必要があります。タイプするのが面倒なので、
Rakeタスクを作ってみました。
lib/tasks/cache.rake
rails>>
namespace :tmp do
namespace :cache do
desc 'Delete cached asset files'
task :update do
patterns = [
'public/stylesheets/cached_*.css',
'public/javascripts/cached_*.js']
Dir.glob(patterns).each do |path|
rm_rf path
puts "deleted: #{path}"
end
./script/process/reaper -a graceful 2>&1 > /dev/null
puts "script/process/reaper -a graceful"
end
end
end
<<--
生成されるキャッシュファイルの名前を:cache => "cached_#{controller.controller_name}"
と指定しているため、こんな感じになります。
デフォルトでは、all.cssやall.jsとなりますので
適宜読みかえてください。
Rails 2.0でデバッグをする新しいやり方
比嘉さんからciteされたみたいなので、取り急ぎ新しい情報を吐き出しておこうと思います。
後、デバッグの環境は、Javaに比べて貧弱だと思う。Railsでデバッグをする7つの方法を見てほしい。IDEでソースにブレークポイントを設定(ソースコードを書き換えるのではなく)して、ステップイン、ステップオーバー、メモリの状態を見たりなんてのに慣れているJavaから比べると、すっごく大変に見える。
喜ばしいことに、Rails 2.0ではruby-debugを使ったdebuggerが正式に採用されました。
これの使い方は非常に簡単です。
まずは、以下のようにブレークポイントをコード中に書き込みます。
rails>>
def some_method
debugger # breakpoint
end
<<--
続いて、Webサーバをデバッグモードで実行します。
shell>>
% ./script/server -u
<<--
これだけです。あとは、実際にブレークポイントを仕掛けた
場所が実行されるようにすれば、gdbライクなruby-debugの
セッションが開始されます。
ruby-debugは、gdbと同じように、ステップ実行、ステップオーバー等の逐次実行を行うインターフェイスがあるので、
コードの動作を確認しながらデバッグを行うことができます。
gdbになれていない人には、irbコマンドを実行することで、
その場でirbを立ち上げることができます。これは非常に便利ですね。
参考までに、debuggerから実行できるコマンドのリストを
載せておきます。
pre>>
backtrace break catch cont delete display down eval exit finish frame help irb list method next p pp quit reload restart save script set step thread trace undisplay up var where
<<--
Have a good debugging life!
See Also
更新履歴
- 2008/01/21 See Alsoに1点追加
cache_fuやmemcachedを使うときに、cacheメソッドがオプションを
受け取ってくれないので不便だなと思っていたのですが、
EdgeRailsでは以下のようなパッチが当たっていて
この問題は解決されているようです。
[PATCH] Rails have poor support to work with memcached
Let's assume we have a caching installation with Nginx used as a frontend. Nginx attempts to get page body by key from memcached. If it succeeds (meaning that the page is in memcached), Rails doesn't get control, making this schema extremely fast, up to 3K requests per second. In case memcached doesn't contain cached page by url as a key, Rails receive control, render page and cache it in memcached in order for the next request to be retrieved from memcached.
現状のリリースバージョンのコードでは、以下のようになっています。
vendor/rails/actionpack/lib/action_view/helpers/cache_helper.rb
rails>>
def cache(name = {}, &block)
@controller.cache_erb_fragment(block, name)
end
<<--
これが、EdgeRailsでは以下のように変更されています。
vendor/rails/actionpack/lib/action_view/helpers/cache_helper.rb
rails>>
def cache(name = {}, options = nil, &block)
template_extension = first_render[/.(\w+)$/, 1].to_sym
case template_extension
when :erb, :rhtml
@controller.cache_erb_fragment(block, name, options)
when :rjs
@controller.cache_rjs_fragment(block, name, options)
when :builder, :rxml
@controller.cache_rxml_fragment(block, name, options)
else
# do a last ditch effort for those brave souls using
# different template engines. This should give plugin
# writters a simple hook.
unless @controller.respond_to?("cache_#{template_extension}_fragment")
raise "fragment caching not supported for #{template_extension} files."
end
@controller.send!("cache_#{template_extension}_fragment", block, name, options)
end
end
<<--
script/consoleからドキュメントを読む方法
helpコマンドを使うと、script/consoleから非常に簡単に
ドキュメントを参照することができます。
使い方は以下の通り。
pre>>
help CGI
------------------------------------------------------------- Class: CGI
Wrapper around the CGIMethods that have been secluded to allow
testing without an instantiated CGI object
TODO: document how this differs from stdlib CGI::Cookie
TODO: document how this differs from stdlib CGI::Cookie
Wrapper around the CGIMethods that have been secluded to allow
testing without an instantiated CGI object
TODO: document how this differs from stdlib CGI::Cookie
(END)
<<--
引数としてクラスや文字列を渡すと、riと同じようにドキュメントを
照会することができます。ちょっと便利ですね。
How To Use Conditional RJS
RJSテンプレートは、RubyコードからJavaScriptコードを生成
するための仕組みです。
今回は、RJSテンプレートの中でJavaScriptの条件分岐を
簡潔に記述するために、PrototypeHelperを拡張する方法を紹介します。
以下のようなファイルを作成して、config/initializersの下に
設置します(Rails 2.0以降の場合)
prototype_helper_ext.rb
rails>>
module ActionView
module Helpers
module PrototypeHelper
class JavaScriptGenerator
def if(condition, &block)
page << "if(#{condition}){"
block.call if block
page << '}'
end
def elsif(condition, &block)
page << "else if(#{condition}){"
block.call if block
page << '}'
end
def else(&block)
page << "else{"
block.call if block
page << '}'
end
end
end
end
end
<<--
これによって、こんな感じに条件分岐を記述できるようになります。
rails>>
render :update do |page|
page.if "$$('#posts .post').length == 0" do
page.remove 'posts'
end
end
<<--
最初から用意されててもいい気がする。
You can see also http://blog.s21g.com/articles/212, the article written about the same theme for
comparison, if you are familiar to Japanese.
1. p/pp
This is a very popular method used not only in Rails but also in other
debugging. In Rails this method should be used on web server which is in the states of foreground process.
shell>>
$ ./script/server
<<--
If you are familiar with p/pp, it should be simple and easy.
2. logger.debug
For logger.debug, the following example will explain fully.
rails>>
logger.debug "something interesting information"
<<--
Calling logger.debug, you can create a log file oflog/$RAILS_ENV.log such as log/development.log.
By configuring the output file to:
shell>>
$ tail -f log/development.log
<<--
you can check the debug output log in the same manner as in p/pp debugging.
Furthermore, as the result is output in a log-file format, you can
refer it later on.
3. script/console
script/console comes in handy when you check the DB contents during
the operation. Executing "script/console" command, irb
launches after confirming Rails environment.
You can change DB as you like by using ActiveRecord, such as find,
create and destroy_all.This is very tactful feature.
4. script/breakpointer
As previously described, although script/console
comes in very handy and tactful, it can not check session status
during the action.
In that case, you can use "script/breakpointer" for it.
shell>>
$ ./script/breakpointer
<<--
Please make sure to launch a breakpointer initially.
Then locate a "breakpoint" to the position where you want to check
the status.
rails>>
class FooController < ApplicationController
def bar
# something
breakpoint
# something
end
<<--
Then you execute bar action through brower access and check and
manupulate the necessary information
after the launch of irb at the set breakpointer.
5. better rails debugger
script/breakpointer is very useful but it has a weak point
as it cannot operate step execution.
We understand you rarely experience the need for step execution,
however, it's better to have a method than nothing. The ruby-debug
Gem, informed by yugui in the last Rails meeting, will meet the need.
First of all, make sure to install ruby-debug in advance.
shell>>
gem install ruby-debug
<<--
Then, add a breakpoint.
rails>>
class FooController < ApplicationController
def bar
# something
debugger
# something
end
<<--
After launching Web server such as Webrick or Mongrel on foreground,
which is used in p/pp debugging,
you make an access to execute targeted code through the browser. Then
something similer to debug.rb launches in Web server process.
Now you can start debuggin in the same manner as you do with
general ruby script.
6. test/autotest
In Ruby on Rails, test framework is ready to use by default.
Generally, specification is designed after writing a test code in test
operation development.
However, you can write a test code for
verification of desired behavior and also utilize it for debugging.
It takes time to operate every test by using "rake" command, I
recommend to use autotest in ZenTest.This autotest operates only
related tests for modified files, and can provide quicker response
than using "rake" command.
If you use a redgreen as a combination, the smooth operation will
please you while debuggin.
7. tail -f log/development.log&; autotest
Lastly, let me intriduce my current method.I launch a separate
terminal other than for development, and operate following command in
RAILS_ROOT.
shell>>
$ tail -f log/development.log&; autotest
<<--
This arrangement enables to display the autotest output in editing
program and test code
and the logger output when there is an access from the browser.
Basically, those two runs asynchronously, you can fully use one
terminal.
HAPPY NEW YEAR!
ruby>>
class Happy
def year!
sleep 4.hours
end
end
Happy.new.year!
<<--
I wish you a happy new year.