ftpmock 0.0.0 → 0.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.gitignore +3 -0
- data/.rubocop.yml +60 -2
- data/.travis.yml +19 -2
- data/Gemfile +1 -1
- data/Gemfile.lock +30 -11
- data/README.md +136 -12
- data/ftpmock.gemspec +6 -1
- data/images/ftpmock.png +0 -0
- data/images/ruby.png +0 -0
- data/lib/ftpmock.rb +19 -1
- data/lib/ftpmock/core/cache.rb +186 -0
- data/lib/ftpmock/core/configuration.rb +33 -0
- data/lib/ftpmock/helpers/get_helper.rb +46 -0
- data/lib/ftpmock/helpers/list_helper.rb +53 -0
- data/lib/ftpmock/helpers/path_helper.rb +24 -0
- data/lib/ftpmock/helpers/put_helper.rb +39 -0
- data/lib/ftpmock/proxies/method_missing_mixin.rb +9 -0
- data/lib/ftpmock/proxies/net_ftp_proxy.rb +287 -0
- data/lib/ftpmock/proxies/net_sftp_proxy.rb +50 -0
- data/lib/ftpmock/utils/color_utils.rb +27 -0
- data/lib/ftpmock/utils/string_utils.rb +29 -0
- data/lib/ftpmock/utils/verbose_utils.rb +19 -0
- data/lib/ftpmock/version.rb +1 -1
- metadata +74 -3
| @@ -0,0 +1,33 @@ | |
| 1 | 
            +
            module Ftpmock
         | 
| 2 | 
            +
              module_function
         | 
| 3 | 
            +
             | 
| 4 | 
            +
              def configure
         | 
| 5 | 
            +
                yield configuration
         | 
| 6 | 
            +
              end
         | 
| 7 | 
            +
             | 
| 8 | 
            +
              def configuration
         | 
| 9 | 
            +
                @configuration ||= Configuration.new
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              class Configuration
         | 
| 13 | 
            +
                attr_writer :path
         | 
| 14 | 
            +
                attr_accessor :verbose
         | 
| 15 | 
            +
             | 
| 16 | 
            +
                def initialize(path: nil, verbose: true)
         | 
| 17 | 
            +
                  @path = path
         | 
| 18 | 
            +
                  @verbose = verbose
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def path
         | 
| 22 | 
            +
                  @path ||= "#{test_dir}/ftp_records"
         | 
| 23 | 
            +
                end
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                def test_dir
         | 
| 26 | 
            +
                  rspec? ? 'spec' : 'test'
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def rspec?
         | 
| 30 | 
            +
                  defined?(RSpec)
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
            end
         | 
| @@ -0,0 +1,46 @@ | |
| 1 | 
            +
            module Ftpmock
         | 
| 2 | 
            +
              module GetHelper
         | 
| 3 | 
            +
                module_function
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                # reads from cache to localfile
         | 
| 6 | 
            +
                #
         | 
| 7 | 
            +
                # true/false
         | 
| 8 | 
            +
                def read(cache_path, chdir, remotefile, localfile)
         | 
| 9 | 
            +
                  # chdir =
         | 
| 10 | 
            +
                  remotefile = PathHelper.join(PathHelper.simplify(chdir), remotefile).to_s
         | 
| 11 | 
            +
                  # localfile = PathHelper.join(chdir, localfile).to_s
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                  cached_path = path_for(cache_path, remotefile)
         | 
| 14 | 
            +
             | 
| 15 | 
            +
                  File.exist?(cached_path) && FileUtils.cp(cached_path, localfile)
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                  fetched?(localfile)
         | 
| 18 | 
            +
                end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
                # writes to cache from localfile
         | 
| 21 | 
            +
                def write(cache_path, chdir, remotefile, localfile)
         | 
| 22 | 
            +
                  return false unless File.exist?(localfile)
         | 
| 23 | 
            +
             | 
| 24 | 
            +
                  # chdir =
         | 
| 25 | 
            +
                  remotefile = PathHelper.join(PathHelper.simplify(chdir), remotefile).to_s
         | 
| 26 | 
            +
                  # localfile = PathHelper.join(chdir, localfile).to_s
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                  cached_path = path_for(cache_path, remotefile)
         | 
| 29 | 
            +
                  FileUtils.cp(localfile, cached_path)
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                  File.exist?(cached_path)
         | 
| 32 | 
            +
                end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                def fetched?(localfile)
         | 
| 35 | 
            +
                  File.exist?(localfile)
         | 
| 36 | 
            +
                end
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                def path_for(cache_path, remotefile)
         | 
| 39 | 
            +
                  path = cache_path.join('get')
         | 
| 40 | 
            +
                  remotefile = PathHelper.simplify(remotefile)
         | 
| 41 | 
            +
                  ret = path.join(remotefile)
         | 
| 42 | 
            +
                  FileUtils.mkdir_p(ret.dirname.to_s)
         | 
| 43 | 
            +
                  ret
         | 
| 44 | 
            +
                end
         | 
| 45 | 
            +
              end
         | 
| 46 | 
            +
            end
         | 
| @@ -0,0 +1,53 @@ | |
| 1 | 
            +
            require 'psych'
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            module Ftpmock
         | 
| 4 | 
            +
              module ListHelper
         | 
| 5 | 
            +
                module_function
         | 
| 6 | 
            +
             | 
| 7 | 
            +
                def read(cache_path, chdir, key)
         | 
| 8 | 
            +
                  key = PathHelper.join(chdir, key).to_s if chdir
         | 
| 9 | 
            +
                  dataset = read_dataset(cache_path)
         | 
| 10 | 
            +
                  dataset[key]
         | 
| 11 | 
            +
                end
         | 
| 12 | 
            +
             | 
| 13 | 
            +
                def write(cache_path, chdir, key, list)
         | 
| 14 | 
            +
                  key = PathHelper.join(chdir, key).to_s if chdir
         | 
| 15 | 
            +
                  dataset = read_dataset(cache_path)
         | 
| 16 | 
            +
                  dataset[key] = list
         | 
| 17 | 
            +
                  write_dataset(cache_path, dataset)
         | 
| 18 | 
            +
                  true
         | 
| 19 | 
            +
                end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                def read_dataset(cache_path)
         | 
| 22 | 
            +
                  path = path_for(cache_path)
         | 
| 23 | 
            +
                  string = path.read
         | 
| 24 | 
            +
                  load(string)
         | 
| 25 | 
            +
                end
         | 
| 26 | 
            +
             | 
| 27 | 
            +
                def write_dataset(cache_path, dataset)
         | 
| 28 | 
            +
                  path = path_for(cache_path)
         | 
| 29 | 
            +
                  content = dump(dataset)
         | 
| 30 | 
            +
                  path.write(content)
         | 
| 31 | 
            +
                end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def path_for(cache_path)
         | 
| 34 | 
            +
                  cache_path = PathHelper.clean(cache_path)
         | 
| 35 | 
            +
                  cache_path.exist? || FileUtils.mkdir_p(cache_path)
         | 
| 36 | 
            +
                  path = PathHelper.clean("#{cache_path}/list.yml")
         | 
| 37 | 
            +
                  path.exist? || path.write(dump(new_list))
         | 
| 38 | 
            +
                  path
         | 
| 39 | 
            +
                end
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                def new_list
         | 
| 42 | 
            +
                  {}
         | 
| 43 | 
            +
                end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
                def load(string)
         | 
| 46 | 
            +
                  Psych.load(string)
         | 
| 47 | 
            +
                end
         | 
| 48 | 
            +
             | 
| 49 | 
            +
                def dump(data)
         | 
| 50 | 
            +
                  Psych.dump(data)
         | 
| 51 | 
            +
                end
         | 
| 52 | 
            +
              end
         | 
| 53 | 
            +
            end
         | 
| @@ -0,0 +1,24 @@ | |
| 1 | 
            +
            module Ftpmock
         | 
| 2 | 
            +
              module PathHelper
         | 
| 3 | 
            +
                module_function
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def clean(path)
         | 
| 6 | 
            +
                  path = path.to_s
         | 
| 7 | 
            +
                  path = path[1..-1] if path[0] == '/'
         | 
| 8 | 
            +
                  path = Pathname(path).cleanpath
         | 
| 9 | 
            +
                  return Pathname('') if path.to_s == '.'
         | 
| 10 | 
            +
             | 
| 11 | 
            +
                  path
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def join(path_a, path_b)
         | 
| 15 | 
            +
                  clean Pathname(path_a.to_s).join(path_b.to_s)
         | 
| 16 | 
            +
                end
         | 
| 17 | 
            +
             | 
| 18 | 
            +
                def simplify(path)
         | 
| 19 | 
            +
                  path.to_s
         | 
| 20 | 
            +
                      .tr('/', '-')
         | 
| 21 | 
            +
                      .tr('..', '__')
         | 
| 22 | 
            +
                end
         | 
| 23 | 
            +
              end
         | 
| 24 | 
            +
            end
         | 
| @@ -0,0 +1,39 @@ | |
| 1 | 
            +
            module Ftpmock
         | 
| 2 | 
            +
              module PutHelper
         | 
| 3 | 
            +
                module_function
         | 
| 4 | 
            +
             | 
| 5 | 
            +
                def cached?(cache_path, remotefile)
         | 
| 6 | 
            +
                  path = path_for(cache_path, remotefile)
         | 
| 7 | 
            +
                  path.exist?
         | 
| 8 | 
            +
                end
         | 
| 9 | 
            +
             | 
| 10 | 
            +
                def exist?(localfile)
         | 
| 11 | 
            +
                  File.exist?(localfile)
         | 
| 12 | 
            +
                end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                def write(cache_path, localfile, remotefile)
         | 
| 15 | 
            +
                  path = path_for(cache_path, remotefile)
         | 
| 16 | 
            +
                  FileUtils.cp(localfile, path)
         | 
| 17 | 
            +
                end
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                # Array
         | 
| 20 | 
            +
                def compare(cache_path, localfile, remotefile)
         | 
| 21 | 
            +
                  return [] unless cached?(cache_path, remotefile)
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                  path = path_for(cache_path, remotefile)
         | 
| 24 | 
            +
                  diff = StringUtils.diff(localfile, path)
         | 
| 25 | 
            +
                  diff.split("\n")
         | 
| 26 | 
            +
                end
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                # def expire(cache_path, remotefile)
         | 
| 29 | 
            +
                #   path = path_for(cache_path, remotefile)
         | 
| 30 | 
            +
                #   path.exist? && path.delete
         | 
| 31 | 
            +
                # end
         | 
| 32 | 
            +
             | 
| 33 | 
            +
                def path_for(cache_path, remotefile)
         | 
| 34 | 
            +
                  path = cache_path.join('put')
         | 
| 35 | 
            +
                  FileUtils.mkdir_p(path)
         | 
| 36 | 
            +
                  path.join(remotefile.tr('/', '-'))
         | 
| 37 | 
            +
                end
         | 
| 38 | 
            +
              end
         | 
| 39 | 
            +
            end
         | 
| @@ -0,0 +1,287 @@ | |
| 1 | 
            +
            # https://apidock.com/ruby/Net/FTP
         | 
| 2 | 
            +
            require 'net/ftp'
         | 
| 3 | 
            +
             | 
| 4 | 
            +
            module Ftpmock
         | 
| 5 | 
            +
              class NetFtpProxy
         | 
| 6 | 
            +
                # Stubbers
         | 
| 7 | 
            +
             | 
| 8 | 
            +
                Real = begin
         | 
| 9 | 
            +
                         Net::FTP
         | 
| 10 | 
            +
                       rescue NameError
         | 
| 11 | 
            +
                         nil
         | 
| 12 | 
            +
                       end
         | 
| 13 | 
            +
             | 
| 14 | 
            +
                # inspired by https://github.com/bblimke/webmock/blob/master/lib/webmock/http_lib_caches/net_http.rb
         | 
| 15 | 
            +
                def self.on!
         | 
| 16 | 
            +
                  unless Real
         | 
| 17 | 
            +
                    yield
         | 
| 18 | 
            +
                    return
         | 
| 19 | 
            +
                  end
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                  Net.send(:remove_const, :FTP)
         | 
| 22 | 
            +
                  Net.const_set(:FTP, self)
         | 
| 23 | 
            +
                  if block_given?
         | 
| 24 | 
            +
                    yield
         | 
| 25 | 
            +
                    off!
         | 
| 26 | 
            +
                  end
         | 
| 27 | 
            +
                end
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                def self.off!
         | 
| 30 | 
            +
                  return unless Real
         | 
| 31 | 
            +
             | 
| 32 | 
            +
                  Net.send(:remove_const, :FTP)
         | 
| 33 | 
            +
                  Net.const_set(:FTP, Real)
         | 
| 34 | 
            +
                end
         | 
| 35 | 
            +
             | 
| 36 | 
            +
                PORT = 21
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                # Instance Methods
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                # inspired by https://apidock.com/ruby/v2_6_3/Net/FTP/open/class
         | 
| 41 | 
            +
                def self.open(host, *args)
         | 
| 42 | 
            +
                  if block_given?
         | 
| 43 | 
            +
                    proxy = new(host, *args)
         | 
| 44 | 
            +
                    begin
         | 
| 45 | 
            +
                      yield proxy
         | 
| 46 | 
            +
                    ensure
         | 
| 47 | 
            +
                      proxy.close
         | 
| 48 | 
            +
                    end
         | 
| 49 | 
            +
                  else
         | 
| 50 | 
            +
                    new(host, *args)
         | 
| 51 | 
            +
                  end
         | 
| 52 | 
            +
                end
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                # inspired by https://apidock.com/ruby/v2_6_3/Net/FTP/new/class
         | 
| 55 | 
            +
                def initialize(host = nil, *args)
         | 
| 56 | 
            +
                  @options = args.last.is_a?(Hash) ? args.pop : {}
         | 
| 57 | 
            +
                  @host = host
         | 
| 58 | 
            +
                  @configuration = @options[:configuration] || Ftpmock.configuration
         | 
| 59 | 
            +
             | 
| 60 | 
            +
                  if args.size == 2
         | 
| 61 | 
            +
                    @options[:username] ||= args[0]
         | 
| 62 | 
            +
                    @options[:password] ||= args[1]
         | 
| 63 | 
            +
                  end
         | 
| 64 | 
            +
             | 
| 65 | 
            +
                  if host
         | 
| 66 | 
            +
                    connect(host, @options[:port] || PORT)
         | 
| 67 | 
            +
                    login(@options[:username], @options[:password]) if @options[:username]
         | 
| 68 | 
            +
                  end
         | 
| 69 | 
            +
                end
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                def real
         | 
| 72 | 
            +
                  @real ||= Real.new
         | 
| 73 | 
            +
                end
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                attr_writer :cache, :real
         | 
| 76 | 
            +
                attr_reader :configuration,
         | 
| 77 | 
            +
                            :host,
         | 
| 78 | 
            +
                            :port,
         | 
| 79 | 
            +
                            :username,
         | 
| 80 | 
            +
                            :password
         | 
| 81 | 
            +
             | 
| 82 | 
            +
                # connection methods
         | 
| 83 | 
            +
             | 
| 84 | 
            +
                def connect(host, port = PORT)
         | 
| 85 | 
            +
                  @real_connected = false
         | 
| 86 | 
            +
                  @host = host
         | 
| 87 | 
            +
                  @port = port
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                  StringUtils.all_present?(host, port) || _raise_not_connected
         | 
| 90 | 
            +
             | 
| 91 | 
            +
                  @cache_connected = true
         | 
| 92 | 
            +
                  true
         | 
| 93 | 
            +
                end
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                def login(username, password)
         | 
| 96 | 
            +
                  @cache = nil
         | 
| 97 | 
            +
                  @real_logged = false
         | 
| 98 | 
            +
                  @username = username
         | 
| 99 | 
            +
                  @password = password
         | 
| 100 | 
            +
             | 
| 101 | 
            +
                  _init_cache
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                  @cache_logged = true
         | 
| 104 | 
            +
                  true
         | 
| 105 | 
            +
                end
         | 
| 106 | 
            +
             | 
| 107 | 
            +
                def _real_connect_and_login
         | 
| 108 | 
            +
                  @cache_connected || _raise_not_connected
         | 
| 109 | 
            +
                  @cache_logged || _raise_not_connected
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                  @real_connected || real.connect(*_real_connect_args)
         | 
| 112 | 
            +
                  @real_connected = true
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                  @real_logged || real.login(*_real_login_args)
         | 
| 115 | 
            +
                  @real_logged = true
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                  if @chdir
         | 
| 118 | 
            +
                    @real.chdir(@chdir)
         | 
| 119 | 
            +
                    @chdir = nil
         | 
| 120 | 
            +
                  end
         | 
| 121 | 
            +
                end
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                def _real_connect_args
         | 
| 124 | 
            +
                  [host, port]
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
             | 
| 127 | 
            +
                def _real_login_args
         | 
| 128 | 
            +
                  [username, password].select { |string| StringUtils.present?(string) }
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                def _init_cache
         | 
| 132 | 
            +
                  credentials = [host, port, username, password]
         | 
| 133 | 
            +
                  @cache = Cache.new(configuration, credentials)
         | 
| 134 | 
            +
                end
         | 
| 135 | 
            +
             | 
| 136 | 
            +
                def cache
         | 
| 137 | 
            +
                  @cache || _raise_not_connected
         | 
| 138 | 
            +
                end
         | 
| 139 | 
            +
             | 
| 140 | 
            +
                def _raise_not_connected
         | 
| 141 | 
            +
                  raise(Net::FTPConnectionError, 'not connected')
         | 
| 142 | 
            +
                end
         | 
| 143 | 
            +
             | 
| 144 | 
            +
                # directory methods
         | 
| 145 | 
            +
             | 
| 146 | 
            +
                # https://docs.ruby-lang.org/en/2.0.0/Net/FTP.html#method-i-chdir
         | 
| 147 | 
            +
                def chdir(dirname = nil)
         | 
| 148 | 
            +
                  cache.chdir(dirname)
         | 
| 149 | 
            +
                end
         | 
| 150 | 
            +
             | 
| 151 | 
            +
                def pwd
         | 
| 152 | 
            +
                  chdir
         | 
| 153 | 
            +
                end
         | 
| 154 | 
            +
             | 
| 155 | 
            +
                def getdir
         | 
| 156 | 
            +
                  chdir
         | 
| 157 | 
            +
                end
         | 
| 158 | 
            +
             | 
| 159 | 
            +
                # list methods
         | 
| 160 | 
            +
             | 
| 161 | 
            +
                def list(*args)
         | 
| 162 | 
            +
                  cache.list(*args) do
         | 
| 163 | 
            +
                    _real_connect_and_login
         | 
| 164 | 
            +
                    real.list(*args)
         | 
| 165 | 
            +
                  end
         | 
| 166 | 
            +
                end
         | 
| 167 | 
            +
             | 
| 168 | 
            +
                # get methods
         | 
| 169 | 
            +
             | 
| 170 | 
            +
                def get(remotefile, localfile = File.basename(remotefile))
         | 
| 171 | 
            +
                  cache.get(remotefile, localfile) do
         | 
| 172 | 
            +
                    _real_connect_and_login
         | 
| 173 | 
            +
                    real.get(remotefile, localfile)
         | 
| 174 | 
            +
                  end
         | 
| 175 | 
            +
             | 
| 176 | 
            +
                  true
         | 
| 177 | 
            +
                end
         | 
| 178 | 
            +
             | 
| 179 | 
            +
                def gettextfile(remotefile, localfile = File.basename(remotefile))
         | 
| 180 | 
            +
                  cache.get(remotefile, localfile) do
         | 
| 181 | 
            +
                    _real_connect_and_login
         | 
| 182 | 
            +
                    real.gettextfile(remotefile, localfile)
         | 
| 183 | 
            +
                  end
         | 
| 184 | 
            +
             | 
| 185 | 
            +
                  true
         | 
| 186 | 
            +
                end
         | 
| 187 | 
            +
             | 
| 188 | 
            +
                def getbinaryfile(remotefile, localfile = File.basename(remotefile))
         | 
| 189 | 
            +
                  cache.get(remotefile, localfile) do
         | 
| 190 | 
            +
                    _real_connect_and_login
         | 
| 191 | 
            +
                    real.getbinaryfile(remotefile, localfile)
         | 
| 192 | 
            +
                  end
         | 
| 193 | 
            +
             | 
| 194 | 
            +
                  true
         | 
| 195 | 
            +
                end
         | 
| 196 | 
            +
             | 
| 197 | 
            +
                # put methods
         | 
| 198 | 
            +
             | 
| 199 | 
            +
                # TODO: block
         | 
| 200 | 
            +
                # https://docs.ruby-lang.org/en/2.0.0/Net/FTP.html#method-i-put
         | 
| 201 | 
            +
                def put(localfile, remotefile = File.basename(localfile))
         | 
| 202 | 
            +
                  cache.put(localfile, remotefile) do
         | 
| 203 | 
            +
                    _real_connect_and_login
         | 
| 204 | 
            +
                    real.put(localfile, remotefile)
         | 
| 205 | 
            +
                  end
         | 
| 206 | 
            +
             | 
| 207 | 
            +
                  true
         | 
| 208 | 
            +
                end
         | 
| 209 | 
            +
             | 
| 210 | 
            +
                # TODO: block
         | 
| 211 | 
            +
                def puttextfile(localfile, remotefile = File.basename(localfile))
         | 
| 212 | 
            +
                  cache.put(localfile, remotefile) do
         | 
| 213 | 
            +
                    _real_connect_and_login
         | 
| 214 | 
            +
                    real.puttextfile(localfile, remotefile)
         | 
| 215 | 
            +
                  end
         | 
| 216 | 
            +
             | 
| 217 | 
            +
                  true
         | 
| 218 | 
            +
                end
         | 
| 219 | 
            +
             | 
| 220 | 
            +
                # TODO: block
         | 
| 221 | 
            +
                def putbinaryfile(localfile, remotefile = File.basename(localfile))
         | 
| 222 | 
            +
                  cache.put(localfile, remotefile) do
         | 
| 223 | 
            +
                    _real_connect_and_login
         | 
| 224 | 
            +
                    real.putbinaryfile(localfile, remotefile)
         | 
| 225 | 
            +
                  end
         | 
| 226 | 
            +
             | 
| 227 | 
            +
                  true
         | 
| 228 | 
            +
                end
         | 
| 229 | 
            +
             | 
| 230 | 
            +
                # TODO: Methods Not Implemented
         | 
| 231 | 
            +
             | 
| 232 | 
            +
                # abort
         | 
| 233 | 
            +
                # acct
         | 
| 234 | 
            +
                # binary
         | 
| 235 | 
            +
                # binary=
         | 
| 236 | 
            +
                # close
         | 
| 237 | 
            +
                # closed?
         | 
| 238 | 
            +
                # debug_mode
         | 
| 239 | 
            +
                # debug_mode=
         | 
| 240 | 
            +
                # delete
         | 
| 241 | 
            +
                # help
         | 
| 242 | 
            +
                # last_response
         | 
| 243 | 
            +
                # last_response_code
         | 
| 244 | 
            +
                # mdtm
         | 
| 245 | 
            +
                # mkdir
         | 
| 246 | 
            +
                # mlsd
         | 
| 247 | 
            +
                # mlst
         | 
| 248 | 
            +
                # mon_enter
         | 
| 249 | 
            +
                # mon_exit
         | 
| 250 | 
            +
                # mon_locked?
         | 
| 251 | 
            +
                # mon_owned?
         | 
| 252 | 
            +
                # mon_synchronize
         | 
| 253 | 
            +
                # mon_try_enter
         | 
| 254 | 
            +
                # mtime
         | 
| 255 | 
            +
                # new_cond
         | 
| 256 | 
            +
                # nlst
         | 
| 257 | 
            +
                # noop
         | 
| 258 | 
            +
                # open_timeout
         | 
| 259 | 
            +
                # open_timeout=
         | 
| 260 | 
            +
                # passive
         | 
| 261 | 
            +
                # passive=
         | 
| 262 | 
            +
                # quit
         | 
| 263 | 
            +
                # read_timeout
         | 
| 264 | 
            +
                # read_timeout=
         | 
| 265 | 
            +
                # rename
         | 
| 266 | 
            +
                # resume
         | 
| 267 | 
            +
                # resume=
         | 
| 268 | 
            +
                # retrbinary
         | 
| 269 | 
            +
                # retrlines
         | 
| 270 | 
            +
                # return_code
         | 
| 271 | 
            +
                # return_code=
         | 
| 272 | 
            +
                # rmdir
         | 
| 273 | 
            +
                # sendcmd
         | 
| 274 | 
            +
                # set_socket
         | 
| 275 | 
            +
                # site
         | 
| 276 | 
            +
                # size
         | 
| 277 | 
            +
                # ssl_handshake_timeout
         | 
| 278 | 
            +
                # ssl_handshake_timeout=
         | 
| 279 | 
            +
                # status
         | 
| 280 | 
            +
                # storbinary
         | 
| 281 | 
            +
                # storlines
         | 
| 282 | 
            +
                # system
         | 
| 283 | 
            +
                # voidcmd
         | 
| 284 | 
            +
                # welcome
         | 
| 285 | 
            +
                include MethodMissingMixin
         | 
| 286 | 
            +
              end
         | 
| 287 | 
            +
            end
         |