niftp 1.0.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.
- data/.gitignore +5 -0
- data/Gemfile +4 -0
- data/MIT-LICENSE +20 -0
- data/README.md +39 -0
- data/Rakefile +23 -0
- data/lib/niftp/version.rb +3 -0
- data/lib/niftp.rb +37 -0
- data/niftp.gemspec +37 -0
- data/test/niftp_test.rb +113 -0
- data/test/test_helper.rb +7 -0
- metadata +154 -0
data/Gemfile
ADDED
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Christopher R. Murphy
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,39 @@
|
|
1
|
+
NiFTP, a Ruby gem, makes Ruby's decidedly un-nifty Net::FTP library easier to
|
2
|
+
use. It abstracts away the FTP plumbing, such as establishing and closing
|
3
|
+
connections. Options include retrying your commands on flakey FTP servers, and
|
4
|
+
forced timeouts. FTP Secure (FTPS) is also supported.
|
5
|
+
|
6
|
+
## Examples
|
7
|
+
|
8
|
+
# get a file with no username, password or other options
|
9
|
+
ftp("localhost") { |ftp| ftp.get("some_file.txt") }
|
10
|
+
|
11
|
+
# put a file to an FTP Secure (FTPS) server
|
12
|
+
ftp("localhost", { username: "anonymous", password: "FTP_FTL", ftps: true }) do |ftp|
|
13
|
+
ftp.put("some_file.txt")
|
14
|
+
end
|
15
|
+
|
16
|
+
## Options
|
17
|
+
|
18
|
+
* **username**: The user name, if required by the host (default: "").
|
19
|
+
* **password**: The password, if required by the host (default: "").
|
20
|
+
* **port**: The port for the host (default: 21).
|
21
|
+
* **ftps**: Set to true if connecting to a FTP Secure server (default: false).
|
22
|
+
* **retries**: The number of times to re-try the given FTP commands upon any
|
23
|
+
exception, before raising the exception (Default: 1).
|
24
|
+
* **timeout**: The number of seconds to wait before timing out (default: 5).
|
25
|
+
Use 0 to disable the timeout.
|
26
|
+
* **passive**: Set to false to prevent a connection in passive mode (default:
|
27
|
+
true).
|
28
|
+
|
29
|
+
## Caveats
|
30
|
+
|
31
|
+
Based on the way the [retryable]("https://github.com/nfedyashev/retryable")
|
32
|
+
gem works, any FTP commands will be retried at least once upon any
|
33
|
+
exception. Setting the :retries option to 0 will raise a runtime error. I'm
|
34
|
+
fine with this for now as I prefer this behavior.
|
35
|
+
|
36
|
+
## Testing
|
37
|
+
|
38
|
+
Tests are written with Shoulda and Mocha. This gem is tested in Ruby 1.8.7
|
39
|
+
(REE) and 1.9.2.
|
data/Rakefile
ADDED
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'bundler'
|
2
|
+
require 'rake/testtask'
|
3
|
+
require 'rake/rdoctask'
|
4
|
+
|
5
|
+
desc 'Default: run unit tests.'
|
6
|
+
task :default => :test
|
7
|
+
|
8
|
+
Bundler::GemHelper.install_tasks
|
9
|
+
|
10
|
+
Rake::TestTask.new(:test) do |test|
|
11
|
+
test.libs << 'lib' << 'test'
|
12
|
+
test.pattern = 'test/**/*_test.rb'
|
13
|
+
test.verbose = true
|
14
|
+
end
|
15
|
+
|
16
|
+
Rake::RDocTask.new do |rdoc|
|
17
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
18
|
+
|
19
|
+
rdoc.rdoc_dir = 'rdoc'
|
20
|
+
rdoc.title = "service_helpers #{version}"
|
21
|
+
rdoc.rdoc_files.include('README*')
|
22
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
23
|
+
end
|
data/lib/niftp.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require "net/ftp"
|
2
|
+
require "ftpfxp"
|
3
|
+
require "retryable"
|
4
|
+
require "timeout"
|
5
|
+
require "active_support/core_ext"
|
6
|
+
|
7
|
+
# Abstracts away File Transfer Protocol plumbing, such as establishing and
|
8
|
+
# closing connections.
|
9
|
+
module NiFTP
|
10
|
+
|
11
|
+
# Connects to the +host+ FTP server, executes the given block then closes
|
12
|
+
# the connection.
|
13
|
+
#
|
14
|
+
# See the README for available options and examples.
|
15
|
+
def ftp(host, options = {}, &block)
|
16
|
+
options.reverse_merge!(:username => "", :password => "", :port => 21,
|
17
|
+
:ftps => false, :retries => 1, :timeout => 5,
|
18
|
+
:passive => true)
|
19
|
+
raise "The :retries option must be > 0." if options[:retries] < 1
|
20
|
+
retryable(:tries => options[:retries]) do
|
21
|
+
ftp = options[:ftps] ? Net::FTPFXPTLS.new : Net::FTP.new
|
22
|
+
ftp.passive = options[:passive]
|
23
|
+
begin
|
24
|
+
Timeout::timeout(options[:timeout]) do
|
25
|
+
ftp.connect host, options[:port]
|
26
|
+
ftp.login options[:username], options[:password]
|
27
|
+
end
|
28
|
+
yield ftp if ftp.present? && block_given?
|
29
|
+
ensure
|
30
|
+
ftp.try(:close)
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# Alias for those that prefer a conventional module name.
|
37
|
+
Niftp = NiFTP
|
data/niftp.gemspec
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
$:.push File.expand_path("../lib", __FILE__)
|
3
|
+
require "niftp/version"
|
4
|
+
|
5
|
+
Gem::Specification.new do |s|
|
6
|
+
s.name = "niftp"
|
7
|
+
s.version = NiFTP::VERSION
|
8
|
+
s.platform = Gem::Platform::RUBY
|
9
|
+
s.authors = ["Christopher R. Murphy"]
|
10
|
+
s.email = ["chmurph2+git@gmail.com"]
|
11
|
+
s.homepage = "http://www.blogobaggins.net"
|
12
|
+
s.summary = %q{NiFTP abstracts away the ceremony from Ruby's Net::FTP class.}
|
13
|
+
s.description = %q{Please see this project's README.}
|
14
|
+
|
15
|
+
s.rubyforge_project = "niftp"
|
16
|
+
|
17
|
+
# files
|
18
|
+
s.files = `git ls-files`.split("\n")
|
19
|
+
s.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
20
|
+
s.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
21
|
+
s.require_paths = ["lib"]
|
22
|
+
|
23
|
+
# RDoc
|
24
|
+
s.has_rdoc = true
|
25
|
+
s.rdoc_options = '--include=examples --main README.md'
|
26
|
+
s.extra_rdoc_files = ["README.md"] + Dir.glob("doc/*")
|
27
|
+
|
28
|
+
# Dependencies
|
29
|
+
s.add_dependency "ftpfxp", ">= 0.0.4"
|
30
|
+
s.add_dependency "retryable", ">= 1.2"
|
31
|
+
s.add_dependency "activesupport", ">= 2.0"
|
32
|
+
s.add_dependency "i18n", ">= 0.5"
|
33
|
+
s.add_development_dependency "shoulda", ">= 2.11"
|
34
|
+
s.add_development_dependency "mocha", ">= 0.9"
|
35
|
+
s.add_development_dependency "xml-simple", ">= 1.0"
|
36
|
+
s.add_development_dependency "rake", ">= 0.8"
|
37
|
+
end
|
data/test/niftp_test.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
require "test_helper"
|
2
|
+
require File.expand_path('../../lib/niftp', __FILE__)
|
3
|
+
|
4
|
+
class NiFTPTest < Test::Unit::TestCase
|
5
|
+
context "An object mixing in the NiFTP module" do
|
6
|
+
setup do
|
7
|
+
@object = Object.new.extend NiFTP
|
8
|
+
@options = {}
|
9
|
+
@host = "localhost"
|
10
|
+
@ftp = stub_everything
|
11
|
+
end
|
12
|
+
|
13
|
+
should "be accessible via the Niftp shortcut" do
|
14
|
+
assert_equal Niftp, NiFTP
|
15
|
+
end
|
16
|
+
|
17
|
+
should "raise a runtime errors if the :retries option is less than 1" do
|
18
|
+
assert_raise(RuntimeError) { @object.ftp(@host, { :retries => 0 }) }
|
19
|
+
end
|
20
|
+
|
21
|
+
should "connect to the FTP server with the default port" do
|
22
|
+
stub_ftp
|
23
|
+
@ftp.expects(:connect).with(@host, 21).once.returns(stub_everything)
|
24
|
+
@object.ftp(@host)
|
25
|
+
end
|
26
|
+
|
27
|
+
should "connect to the FTP server with the optional port" do
|
28
|
+
stub_ftp
|
29
|
+
@ftp.expects(:connect).with(@host, 2121).once.returns(stub_everything)
|
30
|
+
@object.ftp(@host, { :port => 2121 })
|
31
|
+
end
|
32
|
+
|
33
|
+
should "login to the FTP server with the default username and password" do
|
34
|
+
stub_ftp
|
35
|
+
@ftp.expects(:login).with("", "")
|
36
|
+
@object.ftp(@host)
|
37
|
+
end
|
38
|
+
|
39
|
+
should "login to the FTP server with the optional username" do
|
40
|
+
stub_ftp
|
41
|
+
@ftp.expects(:login).with("anonymous", "")
|
42
|
+
@object.ftp(@host, { :username => "anonymous" })
|
43
|
+
end
|
44
|
+
|
45
|
+
should "login to the FTP server with the optional password" do
|
46
|
+
stub_ftp
|
47
|
+
@ftp.expects(:login).with("", "some password")
|
48
|
+
@object.ftp(@host, { :password => "some password" })
|
49
|
+
end
|
50
|
+
|
51
|
+
should "execute any arbitrary FTP code (i.e. the block)" do
|
52
|
+
stub_ftp
|
53
|
+
block_output = nil
|
54
|
+
@object.ftp(@host) do |ftp|
|
55
|
+
block_output = "block was executed"
|
56
|
+
end
|
57
|
+
assert_equal "block was executed", block_output
|
58
|
+
end
|
59
|
+
|
60
|
+
should "close the FTP connection" do
|
61
|
+
stub_ftp
|
62
|
+
@ftp.expects(:close).once
|
63
|
+
@object.ftp(@host)
|
64
|
+
end
|
65
|
+
|
66
|
+
should "retry once (by default) when an exception is raised" do
|
67
|
+
Net::FTP.expects(:new).once.returns(@ftp)
|
68
|
+
assert_raise(RuntimeError) do
|
69
|
+
@object.ftp(@host) { |ftp_client| raise "testing retryable gem"}
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|
73
|
+
should "use the :retries option instead of the default" do
|
74
|
+
Net::FTP.expects(:new).times(5).returns(@ftp)
|
75
|
+
assert_raise(RuntimeError) do
|
76
|
+
@object.ftp(@host, {:retries => 5 }) do |ftp_client|
|
77
|
+
raise "testing retryable gem"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
|
82
|
+
should "close the FTP connection when there is an exception" do
|
83
|
+
Net::FTP.expects(:new).once.returns(@ftp)
|
84
|
+
@ftp.expects(:close).times(1)
|
85
|
+
assert_raise(RuntimeError) do
|
86
|
+
@object.ftp(@host) { |ftp_client| raise "testing close"}
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
should "use a five second (default) timeout when connecting" do
|
91
|
+
stub_ftp
|
92
|
+
Timeout.expects(:timeout).with(5)
|
93
|
+
@object.ftp(@host)
|
94
|
+
end
|
95
|
+
|
96
|
+
should "use the :timeout option instead of the default" do
|
97
|
+
stub_ftp
|
98
|
+
Timeout.expects(:timeout).with(1)
|
99
|
+
@object.ftp(@host, { :timeout => 1 })
|
100
|
+
end
|
101
|
+
|
102
|
+
should "use the FTPFXP (FTPS) library when instructed" do
|
103
|
+
Net::FTPFXPTLS.expects(:new).once.returns(@ftp)
|
104
|
+
@object.ftp(@host, options = { :ftps => true })
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
|
110
|
+
def stub_ftp
|
111
|
+
Net::FTP.stubs(:new => @ftp)
|
112
|
+
end
|
113
|
+
end
|
data/test/test_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,154 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: niftp
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 1.0.0
|
6
|
+
platform: ruby
|
7
|
+
authors:
|
8
|
+
- Christopher R. Murphy
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
|
13
|
+
date: 2011-05-18 00:00:00 -04:00
|
14
|
+
default_executable:
|
15
|
+
dependencies:
|
16
|
+
- !ruby/object:Gem::Dependency
|
17
|
+
name: ftpfxp
|
18
|
+
prerelease: false
|
19
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
20
|
+
none: false
|
21
|
+
requirements:
|
22
|
+
- - ">="
|
23
|
+
- !ruby/object:Gem::Version
|
24
|
+
version: 0.0.4
|
25
|
+
type: :runtime
|
26
|
+
version_requirements: *id001
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: retryable
|
29
|
+
prerelease: false
|
30
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
31
|
+
none: false
|
32
|
+
requirements:
|
33
|
+
- - ">="
|
34
|
+
- !ruby/object:Gem::Version
|
35
|
+
version: "1.2"
|
36
|
+
type: :runtime
|
37
|
+
version_requirements: *id002
|
38
|
+
- !ruby/object:Gem::Dependency
|
39
|
+
name: activesupport
|
40
|
+
prerelease: false
|
41
|
+
requirement: &id003 !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: "2.0"
|
47
|
+
type: :runtime
|
48
|
+
version_requirements: *id003
|
49
|
+
- !ruby/object:Gem::Dependency
|
50
|
+
name: i18n
|
51
|
+
prerelease: false
|
52
|
+
requirement: &id004 !ruby/object:Gem::Requirement
|
53
|
+
none: false
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
version: "0.5"
|
58
|
+
type: :runtime
|
59
|
+
version_requirements: *id004
|
60
|
+
- !ruby/object:Gem::Dependency
|
61
|
+
name: shoulda
|
62
|
+
prerelease: false
|
63
|
+
requirement: &id005 !ruby/object:Gem::Requirement
|
64
|
+
none: false
|
65
|
+
requirements:
|
66
|
+
- - ">="
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: "2.11"
|
69
|
+
type: :development
|
70
|
+
version_requirements: *id005
|
71
|
+
- !ruby/object:Gem::Dependency
|
72
|
+
name: mocha
|
73
|
+
prerelease: false
|
74
|
+
requirement: &id006 !ruby/object:Gem::Requirement
|
75
|
+
none: false
|
76
|
+
requirements:
|
77
|
+
- - ">="
|
78
|
+
- !ruby/object:Gem::Version
|
79
|
+
version: "0.9"
|
80
|
+
type: :development
|
81
|
+
version_requirements: *id006
|
82
|
+
- !ruby/object:Gem::Dependency
|
83
|
+
name: xml-simple
|
84
|
+
prerelease: false
|
85
|
+
requirement: &id007 !ruby/object:Gem::Requirement
|
86
|
+
none: false
|
87
|
+
requirements:
|
88
|
+
- - ">="
|
89
|
+
- !ruby/object:Gem::Version
|
90
|
+
version: "1.0"
|
91
|
+
type: :development
|
92
|
+
version_requirements: *id007
|
93
|
+
- !ruby/object:Gem::Dependency
|
94
|
+
name: rake
|
95
|
+
prerelease: false
|
96
|
+
requirement: &id008 !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ">="
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: "0.8"
|
102
|
+
type: :development
|
103
|
+
version_requirements: *id008
|
104
|
+
description: Please see this project's README.
|
105
|
+
email:
|
106
|
+
- chmurph2+git@gmail.com
|
107
|
+
executables: []
|
108
|
+
|
109
|
+
extensions: []
|
110
|
+
|
111
|
+
extra_rdoc_files:
|
112
|
+
- README.md
|
113
|
+
files:
|
114
|
+
- .gitignore
|
115
|
+
- Gemfile
|
116
|
+
- MIT-LICENSE
|
117
|
+
- README.md
|
118
|
+
- Rakefile
|
119
|
+
- lib/niftp.rb
|
120
|
+
- lib/niftp/version.rb
|
121
|
+
- niftp.gemspec
|
122
|
+
- test/niftp_test.rb
|
123
|
+
- test/test_helper.rb
|
124
|
+
has_rdoc: true
|
125
|
+
homepage: http://www.blogobaggins.net
|
126
|
+
licenses: []
|
127
|
+
|
128
|
+
post_install_message:
|
129
|
+
rdoc_options:
|
130
|
+
- --include=examples --main README.md
|
131
|
+
require_paths:
|
132
|
+
- lib
|
133
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
134
|
+
none: false
|
135
|
+
requirements:
|
136
|
+
- - ">="
|
137
|
+
- !ruby/object:Gem::Version
|
138
|
+
version: "0"
|
139
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
140
|
+
none: false
|
141
|
+
requirements:
|
142
|
+
- - ">="
|
143
|
+
- !ruby/object:Gem::Version
|
144
|
+
version: "0"
|
145
|
+
requirements: []
|
146
|
+
|
147
|
+
rubyforge_project: niftp
|
148
|
+
rubygems_version: 1.6.2
|
149
|
+
signing_key:
|
150
|
+
specification_version: 3
|
151
|
+
summary: NiFTP abstracts away the ceremony from Ruby's Net::FTP class.
|
152
|
+
test_files:
|
153
|
+
- test/niftp_test.rb
|
154
|
+
- test/test_helper.rb
|