Created
July 2, 2012 05:34
-
-
Save kachick/3031285 to your computer and use it in GitHub Desktop.
昔お勉強したこと - 2010年 Module#define_method
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#! ruby -Ks | |
# -*- coding: Shift_JIS -*- | |
# メタプログラミング / Module#define_method | |
# test / Ruby 1.8.7 | |
# 下準備 | |
def self.border | |
@border_num ||= 1 | |
puts "---------------#{@border_num}---------------" | |
@border_num += 1 | |
end | |
# define_methodについてもうちょい突っ込みます | |
# このメソッド気楽に使ってたんですが、ちょっと考えてみるとブロックスコープの扱いがかなり特殊でした。 | |
class MettaMeta | |
names = [:メタ男, :メタ女, :メタ介] | |
define_method :name do | |
names.choice | |
end | |
end | |
border | |
person1 = MettaMeta.new | |
5.times do | |
p person1.name | |
end | |
#=>p いろいろ | |
# こんな感じで、ローカル変数はブロック呼び出し時のスコープから持ってきます。 | |
# これは一般的なブロックの扱いと同じ | |
# 問題は次 | |
class MettaMeta | |
# MettaMetaクラスのインスタンス用アクセサ | |
attr_accessor :age | |
class << self | |
# MettaMetaクラスオブジェクトの特異メソッド | |
def age | |
99 | |
end | |
end | |
# MettaMetaクラスオブジェクトのインスタンス変数 | |
@age = 20 | |
define_method :secret do | |
age | |
end | |
define_method :機密事項 do | |
@age | |
end | |
end | |
border | |
person1.age = 50 | |
p person1.secret | |
#=>p 50 | |
p person1.機密事項 | |
#=>p 50 | |
# 自然に感じられるし、実際書く時はこう動いてくれるほうがうれしい | |
# でもこれはフツーのブロックとスコープの扱いが全然違ってる | |
# フツーのブロックスコープで考えると、person1.secretは99を、person1.機密事項は20を返すべき | |
# このように動く理由はブロック内でinstance_evalを叩いているかららしいのだけれど・・・慣れるまでちょっと戸惑うなぁ | |
# とりあえず、「define_method時。ローカル変数以外のスコープは、クラスでなくインスタンスがselfになる」と覚えておく感じですかね。 | |
# 最後に、ふつーに書いたときと比較して、selfの扱いを覗いてみます。 | |
class MettaMeta | |
define_method :僕が悪いんじゃないんです do | |
self | |
end | |
oresama = self | |
define_method :言われてやっただけなんです do | |
oresama | |
end | |
# フツーのブロックスコープ挙動例 | |
my_proc = Proc.new do | |
self | |
end | |
eval " | |
def そっかー・・・ | |
#{my_proc.call} | |
end | |
" | |
end | |
border | |
p MettaMeta.__id__ | |
p person1.__id__ | |
border | |
p person1.僕が悪いんじゃないんです.__id__ | |
#=>person1.__id__と同じ | |
p person1.言われてやっただけなんです.__id__ | |
#=>MettaMeta.__id__と同じ | |
p person1.そっかー・・・.__id__ | |
#=>MettaMeta.__id__と同じ |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment