2011-09-27 46 views
8

我知道我可以使用define_method動態地定義一個類的方法,並且我使用塊的arity指定了這個方法所需的參數。我可以動態地定義一個帶塊的Ruby方法嗎?

我想動態定義一個方法,它既接受可選參數又接受一個塊。在Ruby 1.9中,這很容易,因爲現在允許將塊傳遞給塊。

不幸的是,Ruby 1.8中不允許這樣,所以下面將不工作:

#Ruby 1.8 
class X 
    define_method :foo do |bar, &baz| 
    puts bar 
    baz.call if block_given? 
    end 
end 

x = X.new 
x.foo("foo") { puts "called!"} #=> LocalJumpError: no block given 

yield更換明確block.call沒有任何解決問題。
不幸的是,升級到Ruby 1.9並不適合我。這是一個難以解決的問題,還是存在解決方法?

回答

6

這個工程使用Ruby 1.8.7,而不是1.8.6:

class X 
    define_method(:foo) do |bar, &baz| 
    puts bar 
    baz.call if baz 
    end 
end 

測試用:

X.new.foo("No block") 
X.new.foo("With block") { puts " In the block!"} 
p = proc {puts " In the proc!"} 
X.new.foo("With proc", &p) 

給出:

No block 
With block 
    In the block! 
With proc 
    In the proc! 

(與1.8.6它給出syntax error, unexpected tAMPER, expecting '|'。)

如果你想可選參數以及塊,你可以嘗試這樣的事:

class X 
    define_method(:foo) do |*args, &baz| 
    if args[0] 
     bar = args[0] 
    else 
     bar = "default" 
    end 
    puts bar 
    baz.call if baz 
    end 
end 

測試用:

X.new.foo 
X.new.foo { puts " No arg but block"} 

給出:

default 
default 
    No arg but block 
4

你可以做的是使用class_eval而不是define_method。這個缺點(除了不那麼優雅)是你失去了詞彙範圍。但這通常不是必需的。

+0

我需要傳遞一個字符串到class_eval?我不能通過一個塊,這將保持範圍界定? – andrewdotnich

+2

@andrewdotnich好吧,那麼你又回到瞭如何動態定義方法的問題。 –

+1

https://github.com/agrimm/zombie-chaser/blob/master/lib/zombie-chaser/chaser.rb有一個例子和一個鏈接到文件中間的博客文章。 –

相關問題