旧版本的Net :: FTP存在一个错误:
f = Net::FTP.new
f.close
Net::FTPConnectionError: not connected
from /usr/local/lib/ruby/1.9.1/net/ftp.rb:1032:in `method_missing'
from /usr/local/lib/ruby/1.9.1/net/ftp.rb:908:in `close'
from (irb):17
from /usr/local/bin/irb:12:in `<main>'
通过向NullSocket添加null方法#close但仍在1.9.3
中,已在Ruby 2+中修复了此错误我想像这样修补内部类NullSocket:
if defined?(Net::FTP::NullSocket) and !Net::FTP::NullSocket.instance_methods.include?(:close)
class Net::FTP::NullSocket
def close
# Do nothing 'cause it's a null-method in a null-object
end
end
end
但它不起作用。我得到完全相同的错误,就像调用method_missing而不是我的新关闭方法一样。
如果我获得对内部私有@sock变量的引用,我可以调用close而不会引发异常,这有多奇怪。
irb(main):010:0* f = Net::FTP.new
=> #<Net::FTP:0x00000000f5d048 @mon_owner=nil, @mon_count=0, @mon_mutex=#<Mutex:0x00000000f5cff8>, @binary=true, @passive=false, @debug_mode=false, @resume=false, @sock=#<Net::FTP::NullSocket:0x00000000f5cfd0>, @logged_in=false>
irb(main):011:0> z = f.instance_variable_get('@sock')
=> #<Net::FTP::NullSocket:0x00000000f5cfd0>
irb(main):012:0> z.methods
=> [:method_missing, :close, :nil?, :===, :=~, :!~, :eql?, :hash, :<=>, :class, :singleton_class, :clone, :dup, :initialize_dup, :initialize_clone, :taint, :tainted?, :untaint, :untrust, :untrusted?, :trust, :freeze, :frozen?, :to_s, :inspect, :methods, :singleton_methods, :protected_methods, :private_methods, :public_methods, :instance_variables, :instance_variable_get, :instance_variable_set, :instance_variable_defined?, :instance_of?, :kind_of?, :is_a?, :tap, :send, :public_send, :respond_to?, :respond_to_missing?, :extend, :display, :method, :public_method, :define_singleton_method, :object_id, :to_enum, :enum_for, :==, :equal?, :!, :!=, :instance_eval, :instance_exec, :__send__, :__id__]
irb(main):013:0> z.close
有没有办法修补这样的内部类?
更新
我最后通过修补Net :: FTP #close
来解决问题class Net::FTP
def close
@sock.close if @sock && !@sock.is_a?(NullSocket) && !@sock.closed?
end
end
但这个问题的真正答案是修正David所解释的正确方法:
if defined?(Net::FTP::NullSocket) and !Net::FTP::NullSocket.instance_methods.include?(:'closed?')
class Net::FTP::NullSocket
def closed?
true
end
end
end
答案 0 :(得分:1)
Ruby提供的回溯显示了ftp.rb的第908行引发的异常,其中包含:
def close
@sock.close if @sock and not @sock.closed?
end
您可以在堆栈跟踪中指示的路径上看到代码on GitHub或本地计算机。
@sock
对象是一个NullSocket对象,因此当调用@sock.closed?
时,它只会引发异常。您应该使用closed?
修补程序返回true
,然后可能不需要修补close
,因为它不会被调用。
回答你的问题:是的,可以使用Ruby标准库中包含的monkeypatch类。