Core Ext Object

目次

ActiveSupport 拡張で追加される Object のメソッド

試した環境

$ ruby -v
ruby 2.0.0p0 (2013-02-24 revision 39474) [x86_64-darwin12.2.1]
$ bundle exec ruby -r active_support -e 'puts ActiveSupport::VERSION::STRING'
4.0.0.rc2

Object へ機能を追加する方法

require 'active_support/core_ext/object'

Acts Like

acts_like? を定義しています。

この機能だけ読み込む方法

require 'active_support/core_ext/object/acts_like'

#acts_like?

ダックタイピングをアシストするためのメソッド。 このメソッドは acts_linke_date? のようなメソッドが定義されていれば、 acts_like? :date が true を返します。

require 'active_support/core_ext'
Date.new.acts_like? :date       # => true
Date.new.acts_like? :time       # => false
DateTime.new.acts_like? :date   # => true
DateTime.new.acts_like? :time   # => true

のように使えます。

Blank

中身があるかどうかを判定する blank? メソッドやそれに関係するメソッドが実装されています。

この機能だけ読み込む方法

require 'active_support/core_ext/object/blank'

#blank?

空のようなものは true を変えします。該当するものは

です。

実装的には empty? メソッドが存在するかどうか。empty? が true を返すかどうかによって変わります。

基本的なクラスには empty? が実装されます。

presenct?

blankの逆に何か有効な値は True を返します。

presence

空ではない場合、値を返すバージョンです。

Conversions

オブジェクトを別の型に変換する。他のファイルを読み込みするだけ。

あたりを読み込む。

これだけ読み込むには:

require 'active_support/core_ext/object/conversions'

Deep Dup

深いコピーを提供する deep_dup メソッドが実装されています。 deep_dup メソッド は ObjectArrayHash へ追加されます。 コピーできないシングルトンなオブジェクトなどはコピーをせずに参照を渡します。

この機能だけ読み込むには:

require 'active_support/core_ext/object/deep_dup'

#deep_dup

深いコピーを提供します。 dup と動作比較をします。

a = ["a","b","c"]
b = a.dup
b[1] << "b"
b     # => ["a","bb","c"]
a     # => ["a","bb","c"]

a = ["a","b","c"]
b = a.deep_dup
b[1] << "b"
b     # => ["a","bb","c"]
a     # => ["a","b","c"]

前者は 配列の要素は同じオブジェクトを指しています。 後者は 配列の要素は新しいオブジェクトになっています。

Duplicable

オブジェクトのコピーができるかどうかを確認する duplicable? メソッドを実装します。

この機能だけ読み込みする方法:

require 'active_support/core_ext/object/duplicable'

#duplicable?

オブジェクトのコピーができるかどうか確認するメソッドです。 Object を継承しているオブジェクトは基本的に true を返します。

以下のクラスのインスタンスは false を返します。

Inclusion

オブジェクトが対象に含まれているか確認するメソッド in? が定義されています。 4.0.0.rc2 で Deprecated になりました。変わりに Object#include? を利用しましょう。

この機能だけ読み込みする方法

require 'active_support/core_ext/object/inclusion'

#in?

self が args に含まれているか確認します。

Array#include? を利用して実装されています。

:hoge.in? :hoge, :goro  # => true
:mogu.in? :hoge, :goro  # => false

引数がひとつの場合はそのオブジェクトの include? メソッドを利用して動作します。 include? メソッドを持たないオブジェクトを渡した場合 ArgumentError が発生します。

:hoge.in? hoge: 1 , goro: 2  # => true
:mogu.in? hoge: 1 , goro: 2  # => flase

:hoge.in? 1      # raise: ArgumentError: The single parameter passed to #in? must respond to #include?

Instance Variables

インスタンス変数に関する情報を取得するメソッドが実装されちます。

この機能だけ読み込みたい場合:

require 'active_support/core_ext/object/instance_variables'

#instance_values

インスタンス変数の一覧を Hash で返すメソッドです。 key にインスタンス変数名 value に値が入ります。 key には @ のつかない名前が入ります。

class Hoge
  def initialize
    @x, @y = 1, 2
  end
end

Hoge.new.instance_values # => {"x"=>1, "y"=>2}

#instance_variable_names

インスタンス変数名の一覧を文字列で返します。 @ がついている変数名が返ります。

似たメソッドとして Object#instance_variables があります。 こちら文字列ではなく、シンボルを返します。

class Hoge
  def initialize
    @x, @y = 1, 2
  end
end

Hoge.new.instance_variable_names # => ["@x", "@y"]

To JSON

Object に to_json メソッドを実装します。 実際のJSON への エンコード は ActiveSupport::JSONで実装されています。

json ライブラリを読込み後に Object, Array, FalseClass, Float, Hash, Integer, NilClass, String, TrueClass クラスで to_json メソッドを上書きするという少しトリッキーなことをしていました。

また to_json するための hash は as_json というメソッドを利用するようです。

この機能だけ読込むには:

require 'active_support/json/encoding'

依存関係の問題で、‘active_support/json/encoding’ を読込むことになります。

#to_json

オブジェクトを JSON に変換します。 処理自体は ActiveSupport::JSON.encode へ委譲することになります。

option は ActiveSupport::JSON のインスタンス変数となります。as_jsonメソッド などにも伝搬されます。

Process::Status#as_json

Process::Status を encode_json メソッドが実装されているオブジェクトに変換します。 ここに定義されてる理由は謎。

To Param

オブジェクトを URL や QUERY_STRING へ変換するメソッド to_param が実装されています。 url_for などのメソッドを利用して URL を作成する場合に利用されます。

この機能だけ読み込みする方法

require 'active_support/core_ext/object/to_param'

ただし、 Hash#to_param が to_guery を利用するため、

require 'active_support/core_ext/object/to_query'

とするほうが気兼ねなく使えます。

#to_param

Object, Nilclass, TrueClass, FalseClass, Array, Hash に to_param メソッドが提供されています。 Objectの to_param の実装は、to_s のエイリアスとなっています。to_s とは挙動を変えたい場合は、サブクラスで to_param をオーバーライドすることになります。 自然なURLを作成したい場合にオーバーライドすることになります。

Object.new.to_param # => "#<Object:0x007ff263abf600>"
nil.to_param        # => nil
true.to_param       # => true
false.to_param      # => false

Arrayの場合は / で区切られます。

[].to_param         # => ""
[:hoge,:mogu].to_param # => "hoge/mogu"

Hashの場合は key=value 形式になります。key でソートされるため、パーマリンクも作りやすい。 引数にオプションとして namespace を設定することができます。 うまく使うとモデルのないフォームも扱いやすくなりそうです。

{}.to_param                 # => ""
{hoge: 0}.to_param          # => "hoge=0"
{hoge: 0, mogu:1}.to_param  # => "hoge=0&mogu=1"
{mogu:1, hoge: 0}.to_param  # => "hoge=0&mogu=1"

To Query

オブジェクトを QUERY_STRING で利用する文字列に変換します。key1=value2&key2=value2 のような構造をとります。

この機能だけ読み込みする方法

require 'active_support/core_ext/object/to_query'

#to_query

QUERY_STRING を構築します。 key を指定することで key-value の関係を作成します。 この形式である必要があるので key は必須になります。

レシーバがHash の場合は key が必須でなくなります。 Hash はすでに key-value の形式になっているからです。 また、この時は to_param メソッドのエイリアスになっているだです。key を指定した場合は Hash#to_param と同じ動作をします。

Try

self が nil の場合、なにもせず、nilじゃない場合は 指定したメソッドを呼びだす try メソッドが実装されています。

この機能だけ読込みをする方法:

require 'active_support/core_ext/object/try'

#try

nil に対し必ず nil を呼び、それ以外のオブジェクトの場合は 引数a の名前のメソッドを呼びだします。

nil になる可能性があるオブジェクトに対して、nilの場合はなにもしないという状況では if などを使用せずに完結に書けます。

1.try(:to_s)    # => "1"
nil.try(:to_s)  # => nil

blockは 呼び出すメソッドに渡します。ただいそうa 引数aがない場合は ブロックが実行されます。

1.try { |n| n * 2}   # => 2
nil.try { |n| n * 2} # => nil

NilClass と Object に try にメソッドを実装することで実現しています。

#try!

tryメソッドとほとんど同じ道斎をしますが、指定したメソッドがない場合は `NoMethodError`` が発生します。

With Options

同じオプションをメソッドに指定する場合、まとめることができる with_options というメソッドが実装されています。

この機能だけ読み込みする方法

require 'active_support/core_ext/object/with_options'

#with_options

同じオプションをメソッドへのオプションを指定するのに便利するメソッドです。ブロックは必須です。

普通に記述すると

hoge aaa: 1, bbb: 2, zzz: 3
hoge aaa: 1, bbb: 2, zzz: 4

となる場合、この with_optionsを使用して

with_options aaa: 1, bbb:2 do |this|
  this.hoge zzz: 3
  this.hoge zzz: 4
end

と書くことができます。

ブロックの引数には、with_options の self のような感覚で使えばよさそうです。 実際には ActiveSupport::OptionMerger のインスタンスで、処理もこのクラスに記述されています。