From: Kevin Clark Date: Wed, 18 Jun 2008 01:02:14 +0000 (+0000) Subject: Solve the information leak problem between deprecations. Unfortunately this was cause... X-Git-Tag: 0.2.0~619 X-Git-Url: https://source.supwisdom.com/gerrit/gitweb?a=commitdiff_plain;h=de7864e7d5e5db1456c2178d9a764428e1c3ab48;p=common%2Fthrift.git Solve the information leak problem between deprecations. Unfortunately this was caused by a nasty ruby bug. git-svn-id: https://svn.apache.org/repos/asf/incubator/thrift/trunk@668930 13f79535-47bb-0310-9956-ffa450edef68 --- diff --git a/lib/rb/lib/thrift/deprecation.rb b/lib/rb/lib/thrift/deprecation.rb index 68ecb719..094769ba 100644 --- a/lib/rb/lib/thrift/deprecation.rb +++ b/lib/rb/lib/thrift/deprecation.rb @@ -31,74 +31,91 @@ class Module end end -module Thrift::DeprecationProxy +module Thrift::DeprecationProxy # :nodoc: + # there's a really weird bug in Ruby where class variables behave wrong + # when used in a Class.new or #class_eval rather than in a class foo block. + CLASS_MAPPING = {} + MODULE_MAPPING = {} def self.new_class(obj, name) - Class.new(obj) do + klass = Class.new(obj) do klass = self - @@self = klass - @@obj = obj instance_methods.sort.reject { |x| [:__id__,:__send__].include? x.to_sym }.each do |sym| undef_method sym end + define_method :__thrift_deprecation_proxy_klass do + klass + end def method_missing(sym, *args, &block) - @@obj.instance_method(sym).bind(self).call(*args, &block) + klass = __thrift_deprecation_proxy_klass + obj, name, warned = CLASS_MAPPING[klass.__id__] + obj.instance_method(sym).bind(self).call(*args, &block) end (class << self;self;end).class_eval do - @@self = klass - @@obj = obj - @@name = name - @@warned = false instance_methods.sort.reject { |x| [:__id__,:__send__].include? x.to_sym }.each do |sym| undef_method sym end + define_method :__thrift_deprecation_proxy_klass do + klass + end def method_missing(sym, *args, &block) - unless @@warned - STDERR.puts "Warning: class #{@@name} is deprecated" + klass = __thrift_deprecation_proxy_klass + obj, name, warned = CLASS_MAPPING[klass.__id__] + unless warned + STDERR.puts "Warning: class #{name} is deprecated" STDERR.puts " from #{caller.first}" - @@warned = true + CLASS_MAPPING[__thrift_deprecation_proxy_klass.__id__][2] = true end - if @@self.__id__ == self.__id__ - @@obj.send sym, *args, &block + if klass.__id__ == self.__id__ + obj.send sym, *args, &block else - @@obj.method(sym).unbind.bind(self).call(*args, &block) + obj.method(sym).unbind.bind(self).call(*args, &block) end end end end + CLASS_MAPPING[klass.__id__] = [obj, name, false] + klass end def self.new_module(obj, name) - Module.new do - @@obj = obj - @@warned = false - @@name = name + mod = Module.new do include obj instance_methods.sort.reject { |x| [:__id__,:__send__].include? x.to_sym }.each do |sym| undef_method sym end + define_method :__thrift_deprecation_proxy_module do + mod + end def method_missing(sym, *args, &block) - unless @@warned - STDERR.puts "Warning: module #{@@name} is deprecated" + mod = __thrift_deprecation_proxy_module + obj, name, warned = MODULE_MAPPING[mod.__id__] + unless warned + STDERR.puts "Warning: module #{name} is deprecated" STDERR.puts " from #{caller.first}" - @@warned = true + MODULE_MAPPING[mod.__id__][2] = true end - @@obj.instance_method(sym).bind(self).call(*args, &block) + obj.instance_method(sym).bind(self).call(*args, &block) end (class << self;self;end).class_eval do - @@obj = obj - @@warned = false instance_methods.sort.reject { |x| [:__id__,:__send__].include? x.to_sym }.each do |sym| undef_method sym end + define_method :__thrift_deprecation_proxy_module do + mod + end def method_missing(sym, *args, &block) - unless @@warned - STDERR.puts "Warning: module #{@@name} is deprecated" + mod = __thrift_deprecation_proxy_module + obj, name, warned = MODULE_MAPPING[mod.__id__] + unless warned + STDERR.puts "Warning: module #{name} is deprecated" STDERR.puts " from #{caller.first}" - @@warned = true + MODULE_MAPPING[mod.__id__][2] = true end - @@obj.send sym, *args, &block + obj.send sym, *args, &block end end end + MODULE_MAPPING[mod.__id__] = [obj, name, false] + mod end end diff --git a/lib/rb/spec/deprecation_spec.rb b/lib/rb/spec/deprecation_spec.rb index 6c83ccd1..6c3bdc9c 100644 --- a/lib/rb/spec/deprecation_spec.rb +++ b/lib/rb/spec/deprecation_spec.rb @@ -176,8 +176,8 @@ end describe "deprecate_class!" do it_should_behave_like "deprecation" - def stub_stderr(callstr, offset=1) - STDERR.should_receive(:puts).with("Warning: class #{callstr} is deprecated") + def stub_stderr(klass, offset=1) + STDERR.should_receive(:puts).with("Warning: class #{klass} is deprecated") line = caller.first[/\d+$/].to_i + offset STDERR.should_receive(:puts).with(" from #{__FILE__}:#{line}") end @@ -259,8 +259,8 @@ end describe "deprecate_module!" do it_should_behave_like "deprecation" - def stub_stderr(callstr, offset=1) - STDERR.should_receive(:puts).with("Warning: module #{callstr} is deprecated") + def stub_stderr(mod, offset=1) + STDERR.should_receive(:puts).with("Warning: module #{mod} is deprecated") line = caller.first[/\d+$/].to_i + offset STDERR.should_receive(:puts).with(" from #{__FILE__}:#{line}") end @@ -344,4 +344,27 @@ describe "deprecate_module!" do klass.new.foo.should == "foo" end end + + it "should not bleed info between deprecations" do + ensure_const_removed :DeprecationSpecOldModule do + ensure_const_removed :DeprecationSpecOldModule2 do + mod = Module.new do + def self.foo + "foo" + end + end + deprecate_module! :DeprecationSpecOldModule => mod + mod2 = Module.new do + def self.bar + "bar" + end + end + deprecate_module! :DeprecationSpecOldModule2 => mod2 + stub_stderr(:DeprecationSpecOldModule) + ::DeprecationSpecOldModule.foo.should == "foo" + stub_stderr(:DeprecationSpecOldModule2) + ::DeprecationSpecOldModule2.bar.should == "bar" + end + end + end end