2016-04-03 40 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') 
相关问题