我有以下内容:
class Test
@@a = 10
def show_a()
puts "a: #{@@a}"
end
class << self
@@b = '40'
def show_b
puts "b: #{@@b}"
end
end
end
Run Code Online (Sandbox Code Playgroud)
为什么以下工作:
Test.instance_eval{show_b}
b: 40
=> nil
Run Code Online (Sandbox Code Playgroud)
但我无法@@b直接访问?
Test.instance_eval{ @@b }
NameError: uninitialized class variable @@b in Object
Run Code Online (Sandbox Code Playgroud)
同样,以下工作
t = Test.new
t.instance_eval{show_a}
a: 10
=> nil
Run Code Online (Sandbox Code Playgroud)
但是以下失败了
t.instance_eval{ @@a }
NameError: uninitialized class variable @@a in Object
Run Code Online (Sandbox Code Playgroud)
我不明白为什么我不能直接从instance_eval块访问类变量.
除了工作class_eval和instance_eval工作有什么不同def吗?内部class_eval块def定义了类本身的方法(即实例方法),内部instance_eval def定义了类的本征类的方法(即类方法).据我所知其他所有功能在这两种情况下(例如相同的工作define_method,attr_accessor,class << self; end,定义常量).这是真的吗?
答案是:def,undef并且alias有不同的背景class_eval和instance_eval.
我知道send接受带有参数的字符串或符号,而instance_eval接受字符串或块,并且给定接收器它们的区别可能很明显.
我的问题是下面的例子中"引擎盖下 "的区别是什么?
1234.send 'to_s' # '1234'
1234.instance_eval 'to_s' # '1234'
Run Code Online (Sandbox Code Playgroud) 这就是我想要做的:
def call_block(in_class = "String", &block)
instance = eval("#{in_class}.new")
puts "instance class: #{instance.class}"
instance.instance_eval{ block.call }
end
# --- TEST EXAMPLE ---
# This outputs "class: String" every time
"sdlkfj".instance_eval { puts "class: #{self.class}" }
# This will only output "class: Object" every time
# I'm trying to get this to output "class: String" though
call_block("String") { puts "class: #{self.class}" }
Run Code Online (Sandbox Code Playgroud)
在它说"instance.instance_eval {block.call}"的行上,我试图找到另一种方法使新的实例变量在块上运行实例eval.我能想到的唯一方法是将instance_eval传递给原始块,而不是作为变量或任何东西传递,而是像测试示例中那样作为实际块传递.
有小费吗?
原谅我的无知,但我必须在这里遗漏一些东西.我可以在类中找到ruby 1.8.7的instance_eval文档Object,但我无法在1.9.2的任何地方找到它.我知道自从我使用它以来仍然支持该功能.是否有一些秘密的父类已被移至?
我正在研究一个内部的Ruby DSL并让它看起来尽可能漂亮,我需要修补Symbol类并添加一些运算符.我想对我如何做到这一点负责,并希望将补丁的范围和生命周期限制在特定的代码块中.这样做有标准模式吗?这里有一些伪代码来展示我的想法:
class SomeContext
def self.monkey_patch_region(&block)
context = SomeContext.new
context.monkey_patch_Symbol
context.instance_eval(&block)
context.unmonkey_patch_Symbol
end
# magical method
def monkey_patch_Symbol
#...
end
# another magical method
def unmonkey_patch_Symbol
#...
end
Run Code Online (Sandbox Code Playgroud)
结束
我理解instance_eval和之间的基本区别class_eval.我玩的时候发现的东西是奇怪的attr_accessor.这是一个例子:
A = Class.new
A.class_eval{ attr_accessor :x }
a = A.new
a.x = "x"
a.x
=> "x" # ... expected
A.instance_eval{ attr_accessor :y }
A.y = "y"
=> NoMethodError: undefined method `y=' for A:Class
a.y = "y"
=> "y" # WHATTT?
Run Code Online (Sandbox Code Playgroud)
怎么样:
如果我有课:
class KlassWithSecret
def initialize
@secret = 99
end
end
Run Code Online (Sandbox Code Playgroud)
并运行:
puts KlassWithSecret.new.instance_eval { @secret }
Run Code Online (Sandbox Code Playgroud)
它打印99,但如果我运行:
puts KlassWithSecret.new.instance_eval do
@secret
end
Run Code Online (Sandbox Code Playgroud)
它返回一个错误: `instance_eval': wrong number of arguments (0 for 1..3) (ArgumentError)
为什么我不能使用do/end块instance_eval?
PS我正在使用Ruby 2.1.0.
我对Ruby块和触发器的理解是它们都是闭包.现在我已经看到它与instance_eval一起使用,我有点困惑.什么是魔术酱,在查看裸机时的工作量不足,与使用instance_eval相比,它改变了块在大多数常见用途下的作用范围?
以下是您可以在IRB中转储以查看我的意思的示例.我已经包含了proc.call和block yield版本示例.令人高兴的是,他们的行为都是一样的.
# Testing block/proc and eval
class Example
def initialize(value)
# value defined in the instance
@value = value
end
def call_a_proc(proc)
proc.call self
end
def yield_to_block
yield self
end
end
# Value defined in the global object
@value = 1
example = Example.new 'a'
# the block/proc that prints @value
proc1 = -> instance { puts @value }
# instance calling/yielding the block/proc that prints @value
proc2 = -> instance { instance.call_a_proc proc1 }
proc3 = -> …Run Code Online (Sandbox Code Playgroud) 任何人都可以说我,为什么这不起作用:
class A
attr_accessor :b
end
a = A.new
a.instance_eval do
b = 2
end
a.b
=> nil
Run Code Online (Sandbox Code Playgroud)
我在做什么错了?
instance-eval ×10
ruby ×10
block ×2
class-eval ×2
class ×1
dsl ×1
proc ×1
scope ×1
send ×1
variables ×1