2009-10-05 71 views
0

爲什麼在軌道上的遷移語法紅寶石看起來像這樣:爲什麼遷移需要表格塊參數?

create_table :my_table do |t| 
    t.integer :col 
    t.integer :col2 
    t.integer :col3 
end 

而不是:

create_table :my_table do 
    integer :col 
    integer :col2 
    integer :col3 
end 

個人而言,我找到第二個片段更可讀,還有什麼原因導致實現使用第一?

回答

0

我的理解是ruby是詞法範圍的,這意味着「整數」必須引用在代碼中出現的點上定義的內容。你需要動態範圍來完成你所要求的。

這可能是我錯了,至少有一個特效塊,塊和lambdas是動態範圍的,但你仍然有你的答案 - 範圍行爲的模糊細節不是一件好事情,期望程序員知道。

+0

我不知道怎麼回答這個問題。 – 2009-10-05 01:04:30

+0

塊的存在定義了一個範圍...您可以在create_table中訪問它,併爲該表提供整數上下文。我不明白爲什麼不... – 2009-10-05 01:04:33

+0

您可以將塊(或多或少)放入使用'instance_eval'調用的作用域中。 – Chuck 2009-10-05 01:15:36

3

這兩種方法的基本實現是不同的。 在第一個(和實際)情況下,create_table調用yieldTableDefinition對象。因此您的示例塊中的t指向TableDefinition。另一種方法是使用instance_eval。這看起來是這樣的:

def create_table(name, &block) 
    table_definition = TableDefinition.new 
    # Other setup 
    table_definition.instance_eval(&block) 
    # More work 
end 

你用哪種方式做的部分是偏好問題。但是,有些人不是eval的粉絲,所以他們喜歡避免這種情況。此外,使用yield方法可以更清楚地說明您正在使用的對象。

+0

您可以使用像mixico github.com/coderrr/mixico這樣的技術,並避免自我重新映射和instance_eval。儘管如此,我並沒有關注爲什麼你需要在你的專欄中使用自我。 – 2009-10-05 01:30:42

+0

但是我認爲它的人民不喜歡導致這個決定的instance_eval,所以會爲你+1。 – 2009-10-05 01:34:53

+0

我自己就是那種圍牆。我被吸引到了instance_eval選項的清潔,但同時我感覺到避免它是個好主意。這是我需要考慮更多的東西。 – 2009-10-05 01:42:37

0

基本上界面設計師應該選擇這樣做,因爲有關範圍這個小動作,以及如何evalinstance_eval工作,檢查這個例子:

有2類FooBoo以下定義:

class Foo 
    def speak(phrase) 
    puts phrase 
    end 
    def self.generate(&block) 
    f = Foo.new 
    f.instance_eval(&block) 
    end 
end 

class Boo 
    attr_reader :name 
    def initialize(name) ; @name = name ; end 
    def express 
    Foo.generate { speak name} 
    end 
end 

一般來說,這應該能正常運行於大多數情況,但是像下面的語句某些情況下將發出一個錯誤:

Boo.new("someone").express #`express': undefined local variable or method `name' for #<Foo:0xb7f582fc> (NameError) 

我們用不上這裏BooFoo情況下,這是因爲我們使用instance_eval的實例方法,所以這是Boo情況下定義的方法name不在範圍爲Foo實例。

爲了克服這些問題,最好重新定義產生如下:

class Foo 
    def speak(phrase) 
    puts phrase 
    end 
    def self.generate(&block) 
    f = Foo.new 
    block.arity < 1 ? f.instance_eval(&block) : block.call(f) 
    end 
end 

這是要評估取決於通過塊PARAMS代碼塊一個靈活的接口。現在,我們要通過當前Foo對象爲PARAM時,我們需要調用它實例的方法,讓我們重新定義Boo,檢查expresstalk

class Boo 
    attr_reader :name 
    def initialize(name) ; @name = name ; end 
    def express 
    Foo.generate { |f| f.speak name} 
    end 
    def talk(anything) 
    Foo.generate { speak anything} 
    end 
end 

Boo.new("someone").express #=> someone 
Boo.new("someone").talk("whatever") #=> whatever 
相關問題