diff --git a/lib/sinatra/base.rb b/lib/sinatra/base.rb index 3b17cf76..4df83f98 100644 --- a/lib/sinatra/base.rb +++ b/lib/sinatra/base.rb @@ -1490,6 +1490,14 @@ module Sinatra methods.each do |method_name| eval <<-RUBY, binding, '(__DELEGATE__)', 1 def #{method_name}(*args, &b) + arity = ::Sinatra::Delegator.target.method(#{method_name.inspect}).arity + if arity < 0 ? args.size < -arity - 1 : args.size != arity + begin + return super + rescue NameError => e + raise e unless e.message.include? #{method_name.to_s.inspect} + end + end ::Sinatra::Delegator.target.send(#{method_name.inspect}, *args, &b) end private #{method_name.inspect} diff --git a/test/delegator_test.rb b/test/delegator_test.rb index a898748c..cbaa24f6 100644 --- a/test/delegator_test.rb +++ b/test/delegator_test.rb @@ -1,6 +1,13 @@ class DelegatorTest < Test::Unit::TestCase class Mirror attr_reader :last_call + + Sinatra::Delegator.private_instance_methods.each do |method| + define_method(method) do |*a, &b| + method_missing(method, *a, &b) + end + end + def method_missing(*a, &b) @last_call = [*a.map(&:to_s)] @last_call << b if b @@ -100,13 +107,62 @@ class DelegatorTest < Test::Unit::TestCase assert_equal app.last_call, ["helpers", mixin.to_s ] end - it "registers helpers with the delegation target" do app, mixin = mirror, Module.new Sinatra.use mixin assert_equal app.last_call, ["use", mixin.to_s ] end + it "should work with method_missing proxies for options" do + mixin = Module.new do + def method_missing(method, *args, &block) + return super unless method.to_sym == :options + {:some => :option} + end + end + + app = mirror + def app.options(arg, *rest) "yay" end + + a = b = c = nil + delegate do + extend mixin + a, b, c = options, options(1), options(1, 2) + end + + assert_equal({:some => :option}, a) + assert_equal("yay", b) + assert_equal("yay", c) + end + + it "should work with method_missing proxies for methods arity > 0" do + mixin = Module.new do + def method_missing(method, *args, &block) + return super unless method.to_sym == :options + {:some => :option} + end + end + + app = mirror + def app.options(arg) "yay" end + + a = b = c = nil + delegate do + extend mixin + a, b, c = options, options(1), options(1, 2) + end + + assert_equal({:some => :option}, a) + assert_equal("yay", b) + assert_equal({:some => :option}, c) + end + + it "should not raise a NameError for methods not handled by a proxy" do + app = mirror + def app.options(arg) "yay" end + assert_raises(ArgumentError) { delegate { options }} + end + delegates 'get' delegates 'patch' delegates 'put'