2016-04-03 55 views
2

我想動態定義方法並向它傳遞一個參數。這是我到目前爲止有:動態定義方法的默認參數

class Commands 
end 

@commands = Commands.new 

def route(name, &block) 
    Commands.send(:define_method, name, &block) 
end 

route 'foo' do 
    puts 'oh hai' 
    puts data 
end 

route被調用,這是我所期望的要執行:

data = {name: 'foo', optional: 'bar'} 
@commands.send(data['name'].to_sym, data) 

失敗的原因data沒有定義,除非我做這樣的事情:

route 'foo' do |data| 
    puts 'oh hai' 
    puts data 
end 

有沒有辦法傳遞一個默認參數?似乎它是sinatrarb做的,但我還沒有能夠從代碼中做出正面或反面。

+1

我不明白你的意思是「傳遞默認參數」。 –

+0

清澈如泥? :),對不清楚的問題感到抱歉。部分問題肯定是我不知道我應該問什麼是根本問題。 答案顯示在目標上,所以我會試驗並更新我的問題 – Dishcandanty

回答

3

你的問題不是很清楚,但我懷疑你尋找的功能通常是通過instance_eval和朋友來實現的。 instance_eval評估給定塊在其被調用者的上下文中,以便被調用者的實例方法和實例變量在塊內可用。

這裏是一個非常基本的例子:

"foo".instance_eval do 
    puts size 
    puts upcase 
end 
# -> 3 
# -> FOO 

sizeupcase不是我們給塊參數,它們是那些已經在String對象的情況下可用的方法。

class Route 
    attr_reader :data 

    def initialize(name) 
    @data = { name: name, optional: "bar" } 
    end 
end 

rt = Route.new("foo") 

rt.instance_eval do 
    puts 'oh hai' 
    puts data 
end 
# -> oh hai 
# -> {:name=>"foo", :optional=>"bar"} 

這裏我們定義的路由類,其實例可以作爲其評估給予route方法塊上下文:

考慮到這一點,你可能會像這樣開始:

def route(name, &block) 
    rt = Route.new(name) 
    Commands.send(:define_method, name) do 
    rt.instance_eval(&block) 
    end 
end 

route 'foo' do 
    puts 'oh hai' 
    puts data 
end 

route 'qux' do 
    puts "My name is %{name} and optional is %{optional}" % data 
end 

@commands = Commands.new 
@commands.foo 
# -> oh hai 
# -> {:name=>"foo", :optional=>"bar"} 

@commands.qux 
# -> My name is qux and optional is bar 
1

該塊是你傳遞給route方法的東西;你可以自由地通過任何你想要的,因此紅寶石不會抱怨反對任何數量的參數

有人可能會指定一個默認值,以塊參數(直到@commands.foo實際上是所謂的):

λ = lambda do |data = 'hello'| 
    puts data 
end 

這拉姆達傳遞給route

route 'foo', &λ 
#⇒ "hello" 

據我所知,沒有辦法明確指定國外binding局部變量使用某種類似黑客:

block.binding.local_variable_set(:data, 'hello')