Module での名前解決について
2017/12/7
@cuzic
表参道.rb #29 発表資料 「Module での名前解決について」
1自己紹介
Tomoya Kawanishi a.k.a cuzic
エネチェンジ株式会社 チーフエンジニア
エンジニア、積極採用してます!
Ruby関西の中の人
みなさん、登壇お願いします!
Otemachi.rb 主催
11月28日(火) Otemachi.rb #1 を開催しました。
表参道.rb #29 発表資料 「Module での名前解決について」
モジュールでの名前解決
クラスの継承関係などを通じて、どのように名前解決さ
れるかをします
定数、インスタンス変数、クラス変数、メソッドなど
クイズ形式で進行しますので、お楽しみください
2
表参道.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
表参道.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 #=> ?
表参道.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
表参道.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
表参道.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
表参道.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
表参道.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
表参道.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 #=> ?
表参道.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
表参道.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 #=> ?
表参道.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
表参道.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
表参道.rb #29 発表資料 「Module での名前解決について」
結びとして
Module、Class での名前解決についてクイズ形式で解説
しました
私自身とても勉強になりました
知らないと気づくまで非常に時間がかかる不具合になる
ような仕様もあります。
また、懇親会等で感想を聞かせてください。
15
16
ご清聴ありがとう
ございました

Module での名前解決について

  • 1.
  • 2.
    表参道.rb #29 発表資料「Module での名前解決について」 1自己紹介 Tomoya Kawanishi a.k.a cuzic エネチェンジ株式会社 チーフエンジニア エンジニア、積極採用してます! Ruby関西の中の人 みなさん、登壇お願いします! Otemachi.rb 主催 11月28日(火) Otemachi.rb #1 を開催しました。
  • 3.
    表参道.rb #29 発表資料「Module での名前解決について」 モジュールでの名前解決 クラスの継承関係などを通じて、どのように名前解決さ れるかをします 定数、インスタンス変数、クラス変数、メソッドなど クイズ形式で進行しますので、お楽しみください 2
  • 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
  • 16.
    表参道.rb #29 発表資料「Module での名前解決について」 結びとして Module、Class での名前解決についてクイズ形式で解説 しました 私自身とても勉強になりました 知らないと気づくまで非常に時間がかかる不具合になる ような仕様もあります。 また、懇親会等で感想を聞かせてください。 15
  • 17.