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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 6a2714d624206cbe24807a0bcc79669622477c00e6c0940c0935b339acaced40
4
- data.tar.gz: 10063104b716fa5a937926b00d351897310d270d9fbe442854ff9b9e0b9af29c
3
+ metadata.gz: c9fcde1b94eb86b0f144b748def95e77104d92bd45a024527a3a33dd9445e5ca
4
+ data.tar.gz: ac31e623824872dd372e65233d9d4a1de3277a248beda3b18cba8442b5054bcd
5
5
  SHA512:
6
- metadata.gz: 7ef4fe9824f4ed0f195d7d511321a6e247e37ec64a85c76082125cacb63c3815ef64393cec661714a1c703b6cd8d1163d6c614c55bedeed1f1e05f3193ef7d37
7
- data.tar.gz: 8476bcb8358b326632f6fab4c634773f13b18458124625193af5dc87af1995fc242c92ef158641c264c6dbed3a6064b161b111d50993fc9417824ad83741e2ae
6
+ metadata.gz: e9fe1e4d12970f57eb15d7ed68d76fc278460360de769526f58f7ed2a093a0fe294a4f59cc69c7dff4596cf664a2a80537ae490e89b62fe4f8165e6e6fcc948b
7
+ data.tar.gz: 48d26252d595a84ab33252c223508a059397145d57a61422b47d1da45a844a191b3610bdc2feaecf16b9f2669ff5726ba69343660ae8256596d91bbcd7aacc68
data/.gitignore CHANGED
@@ -9,3 +9,6 @@
9
9
 
10
10
  # rspec failure tracking
11
11
  .rspec_status
12
+
13
+ # OS
14
+ .DS_Store
data/.rubocop.yml CHANGED
@@ -9,7 +9,7 @@ AllCops:
9
9
  EnabledByDefault: false
10
10
  UseCache: true
11
11
  CacheRootDirectory: ~
12
- TargetRubyVersion: 2.6
12
+ TargetRubyVersion: 2.7
13
13
  Exclude:
14
14
  - 'a/*'
15
15
  - 'bin/*'
@@ -43,11 +43,69 @@ Naming:
43
43
  Style:
44
44
  Enabled: true
45
45
 
46
+ # Undefaulted
47
+
48
+ Style/HashEachMethods:
49
+ Enabled: true
50
+ Style/HashTransformKeys:
51
+ Enabled: true
52
+ Style/HashTransformValues:
53
+ Enabled: true
54
+
46
55
  # Custom
47
56
 
48
- Metrics/LineLength:
57
+ Layout/LineLength:
49
58
  Max: 80
59
+ Exclude:
60
+ - 'spec/ftpmock/proxies_net_ftp/integration_spec.rb'
50
61
 
51
62
  # If you think this should be true, reach out!
52
63
  Style/FrozenStringLiteralComment:
53
64
  Enabled: false
65
+
66
+ Style/Documentation:
67
+ Enabled: false
68
+
69
+ Style/GuardClause:
70
+ Enabled: false
71
+
72
+ Style/MethodMissingSuper:
73
+ Exclude:
74
+ - 'lib/ftpmock/proxies/method_missing_mixin.rb'
75
+ Style/MissingRespondToMissing:
76
+ Exclude:
77
+ - 'lib/ftpmock/proxies/method_missing_mixin.rb'
78
+
79
+ Metrics/BlockLength:
80
+ Exclude:
81
+ - 'spec/**/*.rb'
82
+
83
+ Naming/ConstantName:
84
+ Exclude:
85
+ - 'lib/ftpmock/proxies/*_proxy.rb'
86
+
87
+ Naming/MethodParameterName:
88
+ Exclude:
89
+ - 'spec/ftpmock/helpers/*.rb'
90
+
91
+ # http://c2.com/cgi/wiki?AbcMetric, https://en.wikipedia.org/wiki/ABC_Software_Metric
92
+ Metrics/AbcSize:
93
+ # Max: 15 (default)
94
+ Max: 20
95
+ Exclude:
96
+ - 'spec/ftpmock/helpers/*.rb'
97
+
98
+ # https://rubystyle.guide#short-methods
99
+ Metrics/MethodLength:
100
+ # Max: 10 (default)
101
+ Max: 15
102
+ Exclude:
103
+ - 'spec/ftpmock/helpers/*.rb'
104
+
105
+ Metrics/ClassLength:
106
+ # Max: 100 (default)
107
+ Max: 200
108
+
109
+ Metrics/CyclomaticComplexity:
110
+ Exclude:
111
+ - 'lib/ftpmock/proxies/*_proxy.rb'
data/.travis.yml CHANGED
@@ -1,7 +1,24 @@
1
1
  ---
2
2
  sudo: false
3
3
  language: ruby
4
- cache: bundler
4
+
5
5
  rvm:
6
- - 2.6.3
6
+ - 2.3
7
+ - 2.4
8
+ - 2.5
9
+ - 2.6
10
+ - 2.7
11
+ - ruby-head
12
+
7
13
  before_install: gem install bundler -v 2.0.2
14
+
15
+ cache:
16
+ - bundler
17
+ - apt
18
+
19
+ addons:
20
+ code_climate:
21
+ repo_token: e91dbff92783b09f531028ccb33b372a03b8ee2ec0b15bf8e250359c80e06838
22
+
23
+ after_success:
24
+ - bundle exec codeclimate-test-reporter
data/Gemfile CHANGED
@@ -3,4 +3,4 @@ source 'https://rubygems.org'
3
3
  # Specify your gem's dependencies in ftpmock.gemspec
4
4
  gemspec
5
5
 
6
- gem 'rubocop', '0.75.0'
6
+ gem 'rubocop', '0.80.0' # February 18, 2020
data/Gemfile.lock CHANGED
@@ -2,50 +2,69 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  ftpmock (0.1.0)
5
+ diffy (~> 3.0)
5
6
 
6
7
  GEM
7
8
  remote: https://rubygems.org/
8
9
  specs:
9
10
  ast (2.4.0)
11
+ codeclimate-test-reporter (1.0.9)
12
+ simplecov (<= 0.13)
10
13
  diff-lcs (1.3)
11
- jaro_winkler (1.5.3)
12
- parallel (1.18.0)
13
- parser (2.6.5.0)
14
+ diffy (3.3.0)
15
+ docile (1.1.5)
16
+ jaro_winkler (1.5.4)
17
+ json (2.3.0)
18
+ net-sftp (2.1.2)
19
+ net-ssh (>= 2.6.5)
20
+ net-ssh (5.2.0)
21
+ parallel (1.19.1)
22
+ parser (2.7.0.2)
14
23
  ast (~> 2.4.0)
15
24
  rainbow (3.0.0)
16
25
  rake (10.5.0)
26
+ rexml (3.2.4)
17
27
  rspec (3.9.0)
18
28
  rspec-core (~> 3.9.0)
19
29
  rspec-expectations (~> 3.9.0)
20
30
  rspec-mocks (~> 3.9.0)
21
- rspec-core (3.9.0)
22
- rspec-support (~> 3.9.0)
31
+ rspec-core (3.9.1)
32
+ rspec-support (~> 3.9.1)
23
33
  rspec-expectations (3.9.0)
24
34
  diff-lcs (>= 1.2.0, < 2.0)
25
35
  rspec-support (~> 3.9.0)
26
- rspec-mocks (3.9.0)
36
+ rspec-mocks (3.9.1)
27
37
  diff-lcs (>= 1.2.0, < 2.0)
28
38
  rspec-support (~> 3.9.0)
29
- rspec-support (3.9.0)
30
- rubocop (0.75.0)
39
+ rspec-support (3.9.2)
40
+ rubocop (0.80.0)
31
41
  jaro_winkler (~> 1.5.1)
32
42
  parallel (~> 1.10)
33
- parser (>= 2.6)
43
+ parser (>= 2.7.0.1)
34
44
  rainbow (>= 2.2.2, < 4.0)
45
+ rexml
35
46
  ruby-progressbar (~> 1.7)
36
47
  unicode-display_width (>= 1.4.0, < 1.7)
37
48
  ruby-progressbar (1.10.1)
38
- unicode-display_width (1.6.0)
49
+ simplecov (0.13.0)
50
+ docile (~> 1.1.0)
51
+ json (>= 1.8, < 3)
52
+ simplecov-html (~> 0.10.0)
53
+ simplecov-html (0.10.2)
54
+ unicode-display_width (1.6.1)
39
55
 
40
56
  PLATFORMS
41
57
  ruby
42
58
 
43
59
  DEPENDENCIES
44
60
  bundler (~> 2.0)
61
+ codeclimate-test-reporter
45
62
  ftpmock!
63
+ net-sftp
46
64
  rake (~> 10.0)
47
65
  rspec (~> 3.0)
48
- rubocop (= 0.75.0)
66
+ rubocop (= 0.80.0)
67
+ simplecov
49
68
 
50
69
  BUNDLED WITH
51
70
  2.0.2
data/README.md CHANGED
@@ -1,38 +1,162 @@
1
1
  # Ftpmock
2
2
 
3
- Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/ftpmock`. To experiment with that code, run `bin/console` for an interactive prompt.
3
+ Test your FTP calls offline.
4
4
 
5
- TODO: Delete this and the text above, and describe your gem
5
+ ## Status
6
+
7
+ | Is It Working? | Is It Tested? | Code Quality | **# of Downloads** | **Get Involved!** |
8
+ |:---|:---|:---|:---|:---|
9
+ | [![Master Build Status](https://api.travis-ci.org/thejamespinto/ftpmock.svg?branch=master)](https://travis-ci.org/thejamespinto/ftpmock) | [![Test Coverage](https://api.codeclimate.com/v1/badges/25ac02fa4774e3fcb569/test_coverage)](https://codeclimate.com/github/thejamespinto/ftpmock/test_coverage) | [![Maintainability](https://api.codeclimate.com/v1/badges/25ac02fa4774e3fcb569/maintainability)](https://codeclimate.com/github/thejamespinto/ftpmock/maintainability) | [![Downloads](http://img.shields.io/gem/dt/ftpmock.svg)](https://rubygems.org/gems/ftpmock) | [![GitHub Issues](https://img.shields.io/github/issues/thejamespinto/ftpmock.svg)](https://github.com/thejamespinto/ftpmock/issues) |
10
+
11
+ ## Compatibility
12
+
13
+ | <image width=16 src='./images/ruby.png'> Ruby 2.3 | <image width=16 src='./images/ruby.png'> Ruby 2.4 | <image width=16 src='./images/ruby.png'> Ruby 2.5 | <image width=16 src='./images/ruby.png'> Ruby 2.6 | <image width=16 src='./images/ruby.png'> Ruby 2.7 |
14
+ | :--- | :--- | :--- | :--- | :--- |
6
15
 
7
16
  ## Installation
8
17
 
9
18
  Add this line to your application's Gemfile:
10
19
 
11
20
  ```ruby
12
- gem 'ftpmock'
21
+ group :test do
22
+ gem 'ftpmock'
23
+ end
13
24
  ```
14
25
 
15
- And then execute:
26
+ ## Usage
16
27
 
17
- $ bundle
28
+ If you know your way around tests
18
29
 
19
- Or install it yourself as:
30
+ ```ruby
31
+ require 'ftpmock'
32
+
33
+ RSpec.configure do |config|
34
+ config.around(:example) do |example|
35
+ Ftpmock.on! do
36
+ example.run
37
+ end
38
+ end
39
+ end
40
+ ```
20
41
 
21
- $ gem install ftpmock
42
+ If you need to see a full example
22
43
 
23
- ## Usage
44
+ ```ruby
45
+ require 'rubygems'
46
+ require 'test/unit'
47
+ require 'ftpmock'
48
+
49
+ # Optional (default values)
50
+ Ftpmock.configure do |c|
51
+ c.path = 'test/ftp_records'
52
+ c.verbose = true
53
+ end
54
+
55
+ class FtpmockTest < Test::Unit::TestCase
56
+ def test_ubuntu_mirror
57
+ Ftpmock.on! do
58
+ # Ubuntu Download - University of Pittsburgh
59
+ ftp = Net::FTP.new
60
+ assert_equal(Ftpmock::NetFtpProxy, ftp.class)
61
+ assert ftp.connect('mirror.cs.pitt.edu', 21)
62
+ assert ftp.login('', '')
63
+
64
+ t = Time.now
65
+ 3.times do |i|
66
+ list = ftp.list('/ubuntu/releases')
67
+ assert list.size.positive?
68
+
69
+ ftp.get('/ubuntu/releases/robots.txt', 'tmp/ubuntu_robots.txt')
70
+ assert File.exist?('tmp/ubuntu_robots.txt')
71
+
72
+ puts "[Take #{i+1}] #{(Time.now-t).round(3)}s"
73
+ end
74
+ end
75
+ end
76
+ end
77
+ ```
78
+
79
+ Run this test once, and Ftpmock will record the FTP requests to __test/ftp\_records/mirror-cs-pitt-edu\_21\_\_/__
80
+
81
+ Run it again, and Ftpmock will replay the responses from __mirror.cs.pitt.edu__ when the FTP request is made.
82
+
83
+ Your tests are now blazing fast because no real FTP requests are made anymore.
84
+
85
+ The test will continue to pass, even if you are offline, or if the University of Pittsburgh FTP servers are down for maintenance.
86
+
87
+ The responses will be accurate since they will contain the same list and files you get from a real request.
24
88
 
25
- TODO: Write usage instructions here
89
+ Unlike VCR, Ftpmock combines your four credentials _(address + port + username + password)_ and caches onto the exact same directory, optimizing for both storage and readability.
26
90
 
27
91
  ## Development
28
92
 
29
- After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
93
+ After checking out the repo, run `bin/setup` to install dependencies.
94
+
95
+ Then, run `bundle exec rake spec` to run the tests.
96
+
97
+ You can also run `bin/console` for an interactive prompt that will allow you to experiment.
98
+
99
+ To install this gem onto your local machine, run `bundle exec rake install`.
100
+
101
+ ## Documentation
102
+
103
+ ![Chart](./images/ftpmock.png)
104
+
105
+ - Core
106
+ - [x] Stubber
107
+ - [x] Configuration
108
+ - [x] Cache
109
+ - [x] Helpers
110
+ - Proxies
111
+ - [x] Proxy for Ruby's native Net::FTP library
112
+ - [ ] Proxy for Jamis Buck's gem 'net-sftp'
113
+
114
+ ### Core instantiable classes & procedural modules
115
+
116
+ links: [lib/ftpmock/core](./lib/ftpmock/core)
117
+
118
+ - [x] stubber for proxies
119
+ - [x] configuration class
120
+ - [x] cache class
121
+ - [x] cache path helper
122
+ - [x] cache list helper
123
+ - [x] cache get helper
124
+ - [x] cache put helper
125
+
126
+ ### Proxy for Ruby's native Net::FTP library (Ftpmock::NetFtpProxy)
127
+
128
+ links: [lib/ftpmock/proxies/net_ftp_proxy.rb](./lib/ftpmock/proxies/net_ftp_proxy.rb) , https://apidock.com/ruby/Net/FTP & https://github.com/ruby/ruby/tree/master/lib/net
129
+
130
+ - [x] proxy class
131
+ - [x] stubbers
132
+ - [x] address & port forwarding
133
+ - [x] username & password forwarding
134
+ - [x] chdir forwarding
135
+ - [x] pwd
136
+ - [x] list
137
+ - [x] get
138
+ - [x] put
139
+ - [ ] ssl support
140
+ - [x] unit tests
141
+ - [x] integration tests
142
+
143
+ ### Proxy for Jamis Buck's gem 'net-sftp' (Ftpmock::NetSftpProxy)
144
+
145
+ links: [lib/ftpmock/proxies/net_sftp_proxy.rb](./lib/ftpmock/proxies/net_sftp_proxy.rb) , https://rubygems.org/gems/net-sftp & https://github.com/net-ssh/net-sftp
30
146
 
31
- To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
147
+ - [x] proxy class
148
+ - [x] stubbers
149
+ - [ ] address & port forwarding
150
+ - [ ] username & password forwarding
151
+ - [ ] list
152
+ - [ ] get
153
+ - [ ] put
154
+ - [ ] unit tests
155
+ - [ ] integration tests
32
156
 
33
157
  ## Contributing
34
158
 
35
- Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/ftpmock.
159
+ Bug reports and pull requests are welcome on GitHub at https://github.com/thejamespinto/ftpmock.
36
160
 
37
161
  ## License
38
162
 
data/ftpmock.gemspec CHANGED
@@ -8,7 +8,7 @@ Gem::Specification.new do |spec|
8
8
  spec.authors = ['James Pinto']
9
9
  spec.email = ['thejamespinto@gmail.com']
10
10
 
11
- spec.summary = 'Record and Replay FTP requests in Ruby tests.'
11
+ spec.summary = 'Test your FTP calls offline.'
12
12
  spec.description = 'Just like VCR and WebMock, but for FTP.'
13
13
  spec.homepage = 'https://github.com/thejamespinto/ftpmock'
14
14
  spec.license = 'MIT'
@@ -31,6 +31,11 @@ Gem::Specification.new do |spec|
31
31
  spec.require_paths = ['lib']
32
32
 
33
33
  spec.add_development_dependency 'bundler', '~> 2.0'
34
+ spec.add_development_dependency 'codeclimate-test-reporter'
35
+ spec.add_development_dependency 'net-sftp'
34
36
  spec.add_development_dependency 'rake', '~> 10.0'
35
37
  spec.add_development_dependency 'rspec', '~> 3.0'
38
+ spec.add_development_dependency 'simplecov'
39
+
40
+ spec.add_dependency 'diffy', '~> 3.0'
36
41
  end
Binary file
data/images/ruby.png ADDED
Binary file
data/lib/ftpmock.rb CHANGED
@@ -1,6 +1,24 @@
1
+ require 'pathname'
1
2
  require 'ftpmock/version'
2
3
 
4
+ Dir['lib/ftpmock/{utils,core,helpers,proxies}/*.rb'].each do |f|
5
+ load f
6
+ end
7
+
3
8
  module Ftpmock
4
9
  class Error < StandardError; end
5
- # Your code goes here...
10
+ class GetNotFetched < StandardError; end
11
+ class PutFileNotFound < Error; end
12
+ class PutLocalDiffersFromCache < Error; end
13
+
14
+ def self.on!(&block)
15
+ NetFtpProxy.on! do
16
+ NetSftpProxy.on!(&block)
17
+ end
18
+ end
19
+
20
+ def self.off!
21
+ NetFtpProxy.off!
22
+ NetSftpProxy.off!
23
+ end
6
24
  end
@@ -0,0 +1,186 @@
1
+ module Ftpmock
2
+ class Cache
3
+ attr_reader :credentials, :configuration
4
+
5
+ def initialize(configuration, credentials)
6
+ @configuration = configuration
7
+ @credentials = credentials
8
+ @chdir = nil
9
+ end
10
+
11
+ def path
12
+ @path ||= Pathname("#{configuration.path}/#{path_dir}")
13
+ end
14
+
15
+ def path_dir
16
+ StringUtils.parameterize(credentials.map(&:to_s).join('_'))
17
+ end
18
+
19
+ def _alert(tag, content, color = :green)
20
+ configuration.verbose && VerboseUtils.alert(tag, content, color)
21
+ end
22
+
23
+ def chdir(dirname = nil)
24
+ return @chdir if dirname.nil?
25
+
26
+ original = @chdir
27
+ @chdir = PathHelper.join(@chdir, dirname)
28
+
29
+ _chdir_alert(dirname, original, @chdir)
30
+ @chdir
31
+ end
32
+
33
+ def _chdir_alert(dirname, old_chdir, new_chdir)
34
+ tag = "ftpmock.cache.chdir '#{dirname}'"
35
+
36
+ _alert tag, "changed from '#{old_chdir}' to '#{new_chdir}'", :green
37
+ end
38
+
39
+ def list(*args)
40
+ key = args.join(',')
41
+ tag = _list_tag_for(key)
42
+
43
+ list = ListHelper.read(path, chdir, key)
44
+ _list_alert_hit(tag, list)
45
+ return list if list
46
+
47
+ _list_alert_miss(tag)
48
+ list = yield
49
+
50
+ _list_alert_storing(tag, list)
51
+ ListHelper.write(path, chdir, key, list)
52
+
53
+ list
54
+ end
55
+
56
+ def _list_tag_for(key)
57
+ tag = "ftpmock.cache.list '#{key}'"
58
+ tag += ", chdir: '#{chdir}'" if chdir
59
+ tag
60
+ end
61
+
62
+ def _list_alert_hit(tag, list)
63
+ list.nil? || _alert(tag, "hit! (#{list.size} lines)")
64
+ end
65
+
66
+ def _list_alert_miss(tag)
67
+ _alert tag, 'miss!', :yellow
68
+ end
69
+
70
+ def _list_alert_storing(tag, list)
71
+ _alert tag, "storing #{list.size} lines!"
72
+ end
73
+
74
+ def get(remotefile, localfile = File.basename(remotefile))
75
+ tag = _get_tag_for(remotefile)
76
+
77
+ if GetHelper.read(path, chdir, remotefile, localfile)
78
+ _get_alert_hit(tag, localfile)
79
+ return
80
+ end
81
+
82
+ _get_alert_miss(tag)
83
+ yield
84
+
85
+ if GetHelper.fetched?(localfile)
86
+ _get_alert_storing(tag, localfile)
87
+ GetHelper.write(path, chdir, remotefile, localfile)
88
+ else
89
+ _get_raise_localfile_not_fetched(remotefile, localfile)
90
+ end
91
+ end
92
+
93
+ def _get_tag_for(remotefile)
94
+ tag = "ftpmock.cache.get '#{remotefile}'"
95
+ tag += ", chdir: '#{chdir}'" if chdir
96
+ tag
97
+ end
98
+
99
+ def _get_alert_hit(tag, localfile)
100
+ _alert tag, "hit! (#{localfile})"
101
+ end
102
+
103
+ def _get_alert_miss(tag)
104
+ _alert tag, 'miss!', :yellow
105
+ end
106
+
107
+ def _get_alert_storing(tag, localfile)
108
+ _alert tag, "storing #{localfile}"
109
+ end
110
+
111
+ def _get_raise_localfile_not_fetched(remotefile, localfile)
112
+ msg = "FTP GET '#{remotefile}' should have created '#{localfile}'"
113
+ msg = "#{msg}, but didn't."
114
+ raise GetNotFetched, msg
115
+ end
116
+
117
+ def put(localfile, remotefile = File.basename(localfile))
118
+ tag = _put_tag_for(localfile)
119
+
120
+ _put_alert_exists(tag)
121
+ PutHelper.exist?(localfile) || _put_raise_not_found(remotefile, localfile)
122
+
123
+ if PutHelper.cached?(path, remotefile)
124
+ _put_cached(tag, path, localfile, remotefile)
125
+ else
126
+ _put_alert_miss(tag)
127
+ yield
128
+
129
+ _put_alert_storing(tag, remotefile)
130
+ PutHelper.write(path, localfile, remotefile)
131
+ end
132
+
133
+ true
134
+ end
135
+
136
+ def _put_tag_for(localfile)
137
+ tag = "ftpmock.cache.put '#{localfile}'"
138
+ tag += ", chdir: '#{chdir}'" if chdir
139
+ tag
140
+ end
141
+
142
+ def _put_alert_exists(tag)
143
+ _alert tag, 'file exists?'
144
+ end
145
+
146
+ def _put_alert_miss(tag)
147
+ _alert tag, 'miss!', :yellow
148
+ end
149
+
150
+ def _put_alert_storing(tag, remotefile)
151
+ _alert tag, "storing #{remotefile}"
152
+ end
153
+
154
+ def _put_cached(tag, path, localfile, remotefile)
155
+ diff = PutHelper.compare(path, localfile, remotefile)
156
+
157
+ _put_alert_hit(tag, diff.size)
158
+
159
+ diff.any? && _put_raise_localfile_differs(remotefile, localfile, diff)
160
+ end
161
+
162
+ def _put_alert_hit(tag, size)
163
+ color = size.zero? ? :green : :red
164
+ _alert tag, "hit! (#{size} differing lines)", color
165
+ end
166
+
167
+ def _put_raise_not_found(remotefile, localfile)
168
+ msg = "FTP PUT '#{remotefile}' has failed"
169
+ msg = "#{msg} because '#{localfile}' does not exist."
170
+ raise PutFileNotFound, msg
171
+ end
172
+
173
+ def _put_raise_localfile_differs(remotefile, localfile, diff)
174
+ spaces = ' ' * 20
175
+ VerboseUtils.puts
176
+ VerboseUtils.puts ColorUtils.highlight "#{spaces}Diffy Begin#{spaces}"
177
+ VerboseUtils.puts diff
178
+ VerboseUtils.puts ColorUtils.highlight "#{spaces} Diffy End #{spaces}"
179
+ VerboseUtils.puts
180
+
181
+ msg = "FTP PUT '#{remotefile}' has failed because"
182
+ msg = "#{msg} '#{localfile}' contents don't match #{path}/#{remotefile}"
183
+ raise PutLocalDiffersFromCache, msg
184
+ end
185
+ end
186
+ end