class Test def initialize(value) @x = value end
def my_method @x end end test = Test.new(1) m = test.method :my_method puts "test.my_method is #{m.call}"
unbind = m.unbind test_2 = Test.new(2) m = unbind.bind(test_2) puts "-"*30 puts "test_2.my_method is #{m.call}"
** 这里我有一个疑问 **
bind 和 unbind 使用场景是什么?
#6 楼 @zgm 用 block 的话 self 也有问题,所以说是为了支持 sinatra 语法的
#5 楼 @meeasyhappy 幸亏你问得不是 fiber...
#9 楼 @jjym block 的用法是为了 Sinatra 的 DSL 特性,这个很多软件都这么写。
但是 sinatra 内部又把这个 block 实际上转换成一个 unbound_method, 然后每次请求 绑定在 当前的 app 上面。
所以我说是为了利用上下文。不是性能。而支持 DSL 语法是 block 做的,与 unbound_method 关系不大。
# https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L869
# Rack call interface.
def call(env)
dup.call!(env)
end
# https://github.com/sinatra/sinatra/blob/master/lib/sinatra/base.rb#L974
def process_route(pattern, keys, conditions, block = nil, values = [])
route = @request.path_info
route = '/' if route.empty? and not settings.empty_path_info?
return unless match = pattern.match(route)
values += match.captures.to_a.map { |v| force_encoding URI.unescape(v) if v }
if values.any?
original, @params = params, params.merge('splat' => [], 'captures' => values) keys.zip(values) { |k,v| Array === @params[k] ? @params[k] << v : @params[k] = v if v }
end
catch(:pass) do
conditions.each { |c| throw :pass if c.bind(self).call == false }
block ? block[self, values] : yield(self, values)
end
ensure
@params = original if original
end
如果不用这个方式,这里该怎么处理?