4. 表参道.rb #29 発表資料 「Module での名前解決について」
定数の名前解決
親クラスの定数は子クラスからも参照できる
外側のモジュールの定数は内側からも参照できる
3
class Base
A = 1
end
class Sub<Base
def self.a
A
end
end
puts Sub.a #=> 1
module Outer
B = 10
class Sub<Base
def self.b
B
end
end
end
puts Outer::Sub.b #=> 10
5. 表参道.rb #29 発表資料 「Module での名前解決について」
Q: 定数の名前解決
継承関係とモジュールのネスト、
名前が衝突した場合、どちらが優先されるか?
4
class Base
A = 1
def self.a
A
end
end
module Outer
A = 2
class Sub<Base
def self.a2
A
end
end
end
puts Base.a #=> 1
puts Outer::Sub.a #=> ?
puts Outer::Sub.a2 #=> ?
6. 表参道.rb #29 発表資料 「Module での名前解決について」
A: 定数の名前解決
両方が見える場所では継承関係よりもネストの外側にあ
る方が優先されます。
5
module Outer
A = 2
class Sub<Base
def self.a2
A
end
end
end
puts Base.a #=> 1
puts Outer::Sub.a #=> 1
puts Outer::Sub.a2 #=> 2
class Base
A = 1
def self.a
A
end
end
7. 表参道.rb #29 発表資料 「Module での名前解決について」
定数の名前解決(こぼれ話)
ネストしていない場合、外側の定数は参照できません
6
class Base
A = 1
end
module Outer
A = 2
class Sub<Base
end
end
class Outer::Sub
def a3
A
end
end
puts Outer::Sub.a3 #=> 1
8. 表参道.rb #29 発表資料 「Module での名前解決について」
Q: クラス変数
クラス変数は、継承関係をまたいでアクセスできる
子クラスで、値を更新したとき、
親クラスに影響するか?
7
class Base
@@a = 1
def self.a
@@a
end
end
class Sub<Base
def self.set_a
@@a = 2
end
end
puts Base.a #=> 1
puts Sub.a #=> 1
Sub.set_a
puts Base.a #=> ?
puts Sub.a #=> 2
9. 表参道.rb #29 発表資料 「Module での名前解決について」
A: クラス変数
クラス変数は名前空間がクラスの継承関係で、スコープ
が区切られたグローバル変数と思うと理解しやすい
子クラスでの更新は
親クラスにも影響する
8
class Base
@@a = 1
def self.a
@@a
end
end
class Sub<Base
def self.set_a
@@a = 2
end
end
puts Base.a #=> 1
puts Sub.a #=> 1
Sub.set_a
puts Base.a #=> 2
puts Sub.a #=> 2
10. 表参道.rb #29 発表資料 「Module での名前解決について」
補足:クラス変数
Ruby on Rails ではクラス変数の利用を避け、
class_attribute を使うことが推奨される
class_attribute では、
子クラスで更新しても
親クラスには影響しない
9
require 'active_support' +
'/core_ext/class/attribute'
class Base
class_attribute :a
self.a = 1
end
class Sub<Base
def self.set_a
self.a = 2
end
end
puts Base.a #=> 1
puts Sub.a #=> 1
Sub.set_a #=> 2
puts Base.a #=> 1
puts Sub.a #=> 2
11. 表参道.rb #29 発表資料 「Module での名前解決について」
Q: クラスインスタンス変数
Ruby はすべてがオブジェクト。クラスもオブジェクト
クラスのインスタンス変数がクラスインスタンス変数
子クラスから親クラスのクラスインスタンス変数にアク
セスできるか?
10
class Base
@a = 1
def self.a1
@a
end
end
class Sub<Base
def self.a2
@a
end
end
p Base.a1 #=> 1
p Sub.a1 #=> ?
p Sub.a2 #=> ?
12. 表参道.rb #29 発表資料 「Module での名前解決について」
A: クラスインスタンス変数
子クラスからは親クラスのクラスインスタンス変数には
アクセスできない
クラスインスタンス変数はより狭いスコープとなる
そのクラスでしか使わないときは有用
クラス変数はスコープが広すぎるので、狭くしても問題ないとき
はクラスインスタンス変数を使うとベター。
11
class Base
@a = 1
def self.a1
@a
end
end
class Sub<Base
def self.a2
@a
end
end
p Base.a1 #=> 1
p Sub.a1 #=> nil
p Sub.a2 #=> nil
13. 表参道.rb #29 発表資料 「Module での名前解決について」
Q: クラスコンテキストでのローカル変数
ローカル変数と同じ名前のメソッドがあったとき、
どちらが優先されるか?
クラスを再度開きなおしたとき、ローカル変数のスコー
プはどうなるか?
12
class Base
a = 1
def a
10
end
def a1
a
end
define_method :a2 do
a
end
end
class Base
define_method :a3 do
a
end
end
base = Base.new
puts base.a #=> 10
puts base.a1 #=> ?
puts base.a2 #=> ?
puts base.a3 #=> ?
14. 表参道.rb #29 発表資料 「Module での名前解決について」
A: クラスコンテキストでのローカル変数
def は、新しいスコープを作り、その外側のローカル変
数は参照できない。
ブロックからは外側のローカル変数も参照できる
ローカル変数があれば、メソッド呼び出しより優先される
新たに開きなおすとスコープが区切られ、その中で定義
したローカル変数しか参照できない
13
class Base
a = 1
def a
10
end
def a1
a
end
define_method :a2 do
a
end
end
class Base
define_method :a3 do
a
end
end
base = Base.new
puts base.a #=> 10
puts base.a1 #=> 10
puts base.a2 #=> 1
puts base.a3 #=> 10
15. 表参道.rb #29 発表資料 「Module での名前解決について」
(こぼれ話)class_eval と instance_eval
class_eval の中での def はインスタンスメソッドで、
instance_eval での def はクラスメソッドとなる
言葉と逆になるので、
ときおり混乱する
14
class Base
class_eval do
def a
"class_eval"
end
end
instance_eval do
def a
"instance_eval"
end
end
end
puts Base.a #=> instance_eval
puts Base.new.a #=> class_eval