2012-02-12 62 views
1

我有一个关于Ruby块的问题。 比如我有一个Ruby类:块黑客,如何简化块

class NewClass 
    def initialize 
    @a = 1 
    end 

    def some_method 
    puts @a 
    end 
end 

当我做这样的事情:

NewClass.new do |c| 
    c.some_method 
end 

一切都很好,但没有任何可能性做,不知怎的,喜欢:

NewClass.new do 
    some_method 
end 

任何想法?

+3

相关问题:http://stackoverflow.com/questions/9225946/dsl-block-without-argument-in-ruby – 2012-02-12 14:22:34

回答

1

因为您没有yield,您当前的代码将忽略该块。对于你在第一个例子中你想要做的事情,你需要成语initialize

为什么您首先需要一个块变量,请考虑一下some_method的接收器在您的第二个示例中。没有一个明确的接收者,它是顶级main(除非这个代码是某个其他类的一部分,封闭类将是self)。请参阅Dave Thomas的博文Changing self in Ruby(或Niklas B.在评论中指出的Yehuda Katz' post)以获得关于该主题的更多信息(评论清除了“proc调用”部分)。

编辑:所有的说,这似乎工作,但我更喜欢yield self版本和实例1:

class NewClass 
    def initialize 
    @a = 1 
    end 

    def some_method 
    puts "Hello: #@a" 
    end 

    def self.build(&block) 
    x = self.new 
    x.instance_eval(&block) 
    x 
    end 
end 

NewClass.build do 
    some_method 
end 

这可以让你不用块变量执行块并且将返回的新实例分配给变量的类别等。

+1

+1,这是唯一的很好的答案,IMO。不过,我建议你链接到[Yehuda Katz的博客文章,介绍元编程中'self'的作用](http://yehudakatz.com/2009/11/15/metaprogramming-in-ruby-its-all-about-该自我/)而不是戴夫托马斯的相当无知的帖子:) – 2012-02-12 14:50:41

+0

更新,感谢您的建议。 – 2012-02-12 17:22:28

0

使用instance_eval应该完成这项工作。但是,除非你知道自己在做什么(而不仅仅是懒惰),否则我会建议反对,并采用原来的方法。

def initialize(&block) 
    @a = 1 
    self.instance_eval(&block) if block_given? 
end 
+0

除原来的方法不起作用。 – 2012-02-12 14:27:32

2
class NewClass 
    def initialize(&block) 
    @a = 1 
    instance_eval(&block) 
    end 

    def some_method 
    puts @a 
    end 
end 



NewClass.new do 
    some_method 
end 
+2

这将失败'除非block_given?' – 2012-02-12 14:48:07