普段仕事で使っているRuby on Railsですが、ソースコードを読む機会もなかなかないので、試しにやってみることにしました
読めるようにするまで
以前書いた記事で読めるようにするまでの設定を画像キャプチャ付きで解説しましたので、よろしければこちらをご参照ください
shitake4.hatenablog.com
読んだ箇所
to_query
を今日は読んでみようと思います
どんな使い方だっけ?
読んでみる前にまずは使い方を調べてみます
RailsGuidesの日本語ドキュメントを見てみると
このメソッドは、エスケープされていないkeyを受け取ると、そのキーをto_paramが返す値に対応させるクエリ文字列の一部を生成します
引用:Active Support コア拡張機能:present
使い方はこんな感じのようです
current_user.to_query('user') # => "user=357-john-smith"
引数=レシーバを変換した値
という文字列を生成します
ソースコードを読んでみる
1. railsプロジェクトのactivesupportにある機能ですので、activesupportディレクトリのlib配下で def to_query
を探してみます
2. 該当箇所が3個ほどあったので、それぞれみてみます
activesupport > lib > active_support > core_ext > object > to_query.rb
1. class Object
class Object 省略 # Converts an object into a string suitable for use as a URL query string, # using the given <tt>key</tt> as the param name. def to_query(key) "#{CGI.escape(key.to_param)}=#{CGI.escape(to_param.to_s)}" end end
まず CGI.escape()
を見てみます
与えられた文字列を URL エンコードした文字列を新しく作成し返します。
[PARAM] string:
URL エンコードしたい文字列を指定します。
文字列の引数を1つ取り、それに対してURLエンコードする処理です
CGI.escape()
の引数部分 key.to_param
で何をやっているのかは以前書いたこちらを参照ください
続いて、 CGI.escape(to_param.to_s)
を見ます
CGI.escape
はさきほどと同様です
to_param.to_s
はレシーバを to_param
し、その戻り値を to_s
しています
to_s
はレシーバを文字列に変換するメソッドです
次のクラスに実装されています
ここまでをまとめると
key=value
という文字列を生成するメソッドになります
key部分を生成する際には to_query
の引数に対して to_param
し、それをHTMLエスケープして作ります
value部分を生成する際には レシーバを to_param
し、それをHTMLエスケープするということです
2. class Array
class Array 省略 # Converts an array into a string suitable for use as a URL query string, # using the given +key+ as the param name. # # ['Rails', 'coding'].to_query('hobbies') # => "hobbies%5B%5D=Rails&hobbies%5B%5D=coding" def to_query(key) prefix = "#{key}[]" if empty? nil.to_query(prefix) else collect { |value| value.to_query(prefix) }.join "&" end end end
変数prefixの値の例を見てみます
仮にkeyがrubyMineだとすると
prefix = "rubyMine[]"
という文字列になります
次にif empty?
を見てみます
empty?はRubyの標準メソッドです
使い方を見てみると
empty?メソッドは、配列が空であればtrue、1つ以上の要素があればfalseを返します。
引用:Rubyリファレンス:empty?
if empty?
はレシーバである配列の中身が空であるかを判定しています
次の処理nil.to_query(prefix)
を見てみます
どんな挙動かというと
最後に collect { |value| value.to_query(prefix) }.join "&"
を見ます
collect { |value| value.to_query(prefix) }
では
レシーバに対して collect
を実行しています
collectとはどういうものかというと
collectメソッドは、要素の数だけ繰り返しブロックを実行し、ブロックの戻り値を集めた配列を作成して返します。ブロック引数itemには各要素が入ります。
mapメソッドはcollectメソッドの別名です。
次の例では、16進数を表す文字列を数値に変換した配列を作成しています。
引用: Rubyリファレンス:collect
numbers = ["68", "65", "6C", "6C", "6F"] p numbers.collect {|item| item.to_i(16) } => [104, 101, 108, 108, 111]
レシーバの中身1つずつに対して、value.to_query(prefix)
を実行しています
そして戻り値を配列にしています
実行例としてはこちらになります
.join "&"
では配列中身を&で連結し文字列生成しています
joinの挙動はこちらです
joinメソッドは、配列の各要素を文字列に変換し、引数sepを区切り文字として結合した文字列を返します。
引用:Rubyリファレンス:join
読んでみて
HTTPGetメソッドでパラメータを生成する際の使用するメソッドはWebサービスを作る上で欠かせないものだったりするので、 他のフレームワークや言語で作る際にはここで読んだ内容が活かせるなと思いました