全局思路方法eval 编译并且执行段包含ruby代码片断串这是个很power机制它允许你建造在运行时
执行代码看下面例子:
Ruby代码
parameters = {}
ARGF.each do |line|
name, expr = line.split(/\s*=\s*/, 2)
parameters[name] = eval expr
end
假设输出是这样:
引用
a = 1
b = 2 + 3
c = `date`
然后你parameters 应该是这样{"a"=>1, "b"=>5, "c"=>"Mon Apr 30 21:17:47 CDT 2001\n"}. 不过这样话危
险性很高假设你传入个 "rm *"那么就很郁闷了
ruby有 3个思路方法来做到在运行时evaluate代码_eval, module_eval, 和instance_eval前两个是同义而这 3
个思路方法其实所做事都是样他们都是evaluate 个串或者个block但是在做这件事时候他们会把
self改变为他们自己接收者.如果你想看些例子推荐你去看ruby内置库delegate.rb.
eval 思路方法还能够在局部变量创建域外面evaluate.
你能够使用 Kernel#binding思路方法来将个当前绑定付给个对象而eval第 2个参数就是这个绑定:
Ruby代码
def some_ethod
a = "local variable"
binding
end
the_binding = some_method
eval "a", the_binding # "local variable"
而如果带有block话这个block则是被存储为这个绑定部分:
Ruby代码
def some_method
binding
end
the_binding = some_method { puts "hello" }
eval "yield", the_binding # hello
2 使用const_get
const_get思路方法从类或者模块得到个常量值:
Ruby代码
str = "PI"
Math.const_get(str) # Evaluates to Math::PI
这是种避免使用eval思路方法还有些类似思路方法instance_variable_, instance_variable_get和
_method.
const_get 比eval快而且他更可读更明确
3 通过个名字来动态例子化个类
可以使用const_get思路方法在ruby中所有类通常情况下都被命名为个常量作为Object个全局成员.
Ruby代码
name = "Array"
klass = Object.const_get(name)
x = klass.(4, 1) # [1, 1, 1, 1]
如果类名字嵌套话就会报错:
Ruby代码
Alpha
Beta
Gamma
FOOBAR = 237
end
end
end
str = "Alpha::Beta::Gamma::FOOBAR"
val = Object.const_get(str) # error!
这是const_get思路方法并没有那么智能可是我们可以这么做:
Ruby代码
str = "Alpha::Beta::Gamma::FOOBAR"
val = str.split("::").inject(Object) {|x,y| x.const_get(y) } # 237
4 动态存取例子变量
看下面例子:
Ruby代码
MyClass
attr_reader :alpha, :beta
def initialize(a,b,g)
@alpha, @beta, @gamma = a, b, g
end
end
x = MyClass.(10,11,12)
x.instance_variable_("@alpha",234)
p x.alpha # 234
x.instance_variable_("@gamma",345) # 345
v = x.instance_variable_get("@gamma") # 345
这里要注意是必须用变量全名来作为参数也就是说要带上@符号.
5 使用_method
比起def,_method只是个很平常加个思路方法到个对象或者个类个思路方法.
如果我们想要在个思路方法体内或者其他类似地方重新打开这个类(也就是说增加些思路方法)那么除非这个类是singleton 这时在老版本ruby中我们必须使用eval可是现在我们能够使用_method由于_method是 private所以我们必须这样使用:
Ruby代码
today =~ /Saturday|Sunday/
Object._eval { _method(:activity) { puts "Playing!" } }
Object._eval { _method(:activity) { puts "Working!" } }
end
activity
我们也可以把_method直接插在个类里面:
Ruby代码
MyClass
_method(:mymeth) { puts "This is my method." }
end
然后你可以这样做:
Ruby代码
MyClass
def self._method(name, &block)
_method(name, &block)
end
end
MyClass._method(:mymeth) { puts "This is my method." }
x = MyClass.
x.mymeth # Prs "This is my method."
如果你想要使用在例子级别你可以这么做:
Ruby代码
MyClass
def _method(name, &block)
self..send(:_method,name, &block)
end
end
x = MyClass.
x._method(:mymeth) { puts "This is my method." }
x.mymeth # Prs "This is my method."
这里要注意的所以使用send是send也可以用于私有思路方法而在ruby1.9中send是不能用于私有思路方法.
我们可以看到_method思路方法还带有个block为参数这就意味着我们能够保留定义这个block时上下文:
Ruby代码
MyClass
def self._method(name, &block)
_method(name, &block)
end
end
a,b = 3,79
MyClass._method(:compute) { a*b }
x = MyClass.
puts x.compute # 237
a,b = 23,24
puts x.compute # 552
看下面我们读取个类变量例子:
Ruby代码
SomeClass
@@var = 999
_method(:peek) { @@var }
end
x = SomeClass.
p x.peek # 999
假设这时我们想要读取个例子变量:
Ruby代码
SomeClass
@var = 999
_method(:peek) { @var }
end
x = SomeClass.
p x.peek # prs nil
竟然打印出nil为什么呢?可是修改下又可以打出正确值了:
Ruby代码
SomeClass
@var = 999
x = @var
_method(:peek) { x }
end
x = SomeClass.
p x.peek # 999
原因是新建思路方法上下文是对象例子上下文而不是类因此在这里这个类例子变量会被对象例子变量
所覆盖也就是说这里打印其实是例子变量@var
6 使用const_missing
const_missing 思路方法和method_missing很相似如果你想要得到个你不知道常量这个思路方法就会被:
Ruby代码
Module
def const_missing(x)
"from Module"
end
end
X
end
p X::BAR # "from Module"
p BAR # "from Module"
p Array::BAR # "from Module"
如果想要让他作为个类思路方法你可以这样做:
Ruby代码
Alpha
def self.const_missing(sym)
"Alpha has no #{sym}"
end
end
Beta
def self.const_missing(sym)
"Beta has no #{sym}"
end
end
A < Alpha
end
B < Beta
end
p Alpha::FOO # "Alpha has no FOO"
p Beta::FOO # "Beta has no FOO"
p A::FOO # "Alpha has no FOO"
p B::FOO # "Beta has no FOO"
7 移除定义
比如个思路方法我们想要彻底删除它这时我们就能用到undef(和def刚好相反).你能够undef 思路方法局部变量常量...可以要注意你不能undef个类:
Ruby代码
def asbestos
puts "Now fireproof"
end
tax = 0.08
PI = 3
asbestos
puts "PI=#{PI}, tax=#{tax}"
undef asbestos
undef tax
undef PI
# 下面上面思路方法或者变量就会报错
这里要注意你不能undef个例子变量.
还有remove_method 和 undef_method思路方法他们区别是很细小:remove_method 将会remove掉当前思路方法定义 undef_method 思路方法 将会remove掉所有思路方法定义(比如超类思路方法):
Ruby代码
Parent
def alpha
puts "parent alpha"
end
def beta
puts "parent beta"
end
end
Child < Parent
def alpha
puts "child alpha"
end
def beta
puts "child beta"
end
remove_method :alpha # Remove "this" alpha
undef_method :beta # Remove every beta
end
x = Child.
x.alpha # parent alpha
x.beta # Error!
remove_const 将会remove掉个常量.
Ruby代码
module Math
remove_const :PI
end
# No PI anymore!
我们现在可以利用remove_const来移除掉个类定义(类标识符其实也就是个常量):
Ruby代码
BriefCandle
def test
p "aaa"
end
end
out_out = BriefCandle.
Object
remove_const :BriefCandle
end
out=BriefCandle.
out_out.test
要注意remove_const和remove_method都是私有思路方法.
最新评论