ftp_service 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/.gitignore CHANGED
@@ -19,5 +19,7 @@ rdoc
19
19
  doc
20
20
  pkg
21
21
  .yardoc
22
+ tmp
22
23
 
23
24
  ## PROJECT::SPECIFIC
25
+ test_keys/random_seed
@@ -1,8 +1,16 @@
1
+ # v0.3.0 (2010-03-18)
2
+
3
+ * `FtpService#write_request` and `FtpService#read_response` support
4
+ encryption/decryption with gpg.
5
+ * `FtpService#write_request` uses an intermediate temp file while
6
+ uploading to avoid case where server might try and respond to an
7
+ in-progress upload of a large request.
8
+ * `FtpService#read_response` polls for a response.
9
+
1
10
  # v0.2.0 (2010-03-08)
2
11
 
3
12
  * Add `FtpService#write_request` and `FtpService#read_response` methods,
4
13
  making this thing actually usable.
5
-
6
14
  * Switch to Markdown + Yardoc for rdocs.
7
15
 
8
16
  # v0.1.1 (2010-03-08)
@@ -3,7 +3,7 @@
3
3
  An FTP Service is like a web service except stupid. You send your
4
4
  request by uploading an xml file and get your response by downloading
5
5
  another xml file. Have you ever had to deal with something like that? I
6
- have.
6
+ have. It sucks.
7
7
 
8
8
  RDocs on [rdoc.info](http://rdoc.info/projects/blaix/ftp_service).
9
9
 
@@ -18,20 +18,15 @@ Source code on [github](http://github.com/blaix/ftp_service).
18
18
  require 'ftp_service'
19
19
 
20
20
  FtpService.open('host', 'user', 'pass') do |service|
21
- path = '/the/remote/path'
22
- service.write_request("#{path}/request.xml", '<foo>bar</foo>')
23
- response = service.read_response("#{path}/response.xml")
21
+ service.write_request('<foo>bar</foo>', "/request/path.xml")
22
+ response = service.read_response("/response/path.xml")
24
23
  end
25
24
 
26
- * `read_response` will block while it polls the server waiting for a
27
- response.
28
- * Temp files are created for the local request and response files and
29
- deleted when no longer needed.
30
-
31
25
  For more details, see the
32
- [RDocs](http://rdoc.info/projects/blaix/ftp_service) (sike they are
33
- really yardocs!).
26
+ [RDocs](http://rdoc.info/projects/blaix/ftp_service).
34
27
 
35
28
  ## Copyright
36
29
 
37
- Copyright (c) 2010 Justin Blake. See LICENSE for details.
30
+ Copyright (c) 2010 Justin Blake. See
31
+ [LICENSE](http://github.com/blaix/ftp_service/raw/master/LICENSE) for
32
+ details.
data/Rakefile CHANGED
@@ -10,9 +10,11 @@ begin
10
10
  gem.email = "justin@megablaix.com"
11
11
  gem.homepage = "http://github.com/blaix/ftp_service"
12
12
  gem.authors = ["Justin Blake"]
13
+ gem.add_dependency "ruby_gpg", ">= 0.2.0"
13
14
  gem.add_development_dependency "rspec", ">= 1.2.9"
14
15
  gem.add_development_dependency "mocha", ">= 0.9.8"
15
- gem.add_development_dependency "yard", ">= 0"
16
+ gem.add_development_dependency "yard", ">= 0.5.3"
17
+ gem.add_development_dependency "cucumber", ">= 0.6.3"
16
18
  # gem is a Gem::Specification... see http://www.rubygems.org/read/chapter/20 for additional settings
17
19
  end
18
20
  Jeweler::GemcutterTasks.new
@@ -26,6 +28,9 @@ Spec::Rake::SpecTask.new(:spec) do |spec|
26
28
  spec.spec_files = FileList['spec/**/*_spec.rb']
27
29
  end
28
30
 
31
+ require 'cucumber/rake/task'
32
+ Cucumber::Rake::Task.new(:features)
33
+
29
34
  namespace :spec do
30
35
  Spec::Rake::SpecTask.new(:doc) do |spec|
31
36
  spec.libs << 'lib' << 'spec'
@@ -47,7 +52,7 @@ task :default => :spec
47
52
  begin
48
53
  require 'yard'
49
54
  YARD::Rake::YardocTask.new do |y|
50
- y.files << '-' << 'CHANGELOG.*'
55
+ y.files << '-' << 'CHANGELOG.*' << 'TODO.*'
51
56
  end
52
57
  rescue LoadError
53
58
  task :yardoc do
@@ -0,0 +1,4 @@
1
+ # For v1.0.0
2
+
3
+ * Log everything
4
+ * Cleanup remote files on close
data/VERSION CHANGED
@@ -1 +1 @@
1
- 0.2.0
1
+ 0.3.0
@@ -0,0 +1 @@
1
+ default: features
@@ -0,0 +1,19 @@
1
+ # To run, you must have an FTP server running and accessible by the
2
+ # credentials defined in features/support/ftp_helper.rb
3
+
4
+ Feature: Making a request
5
+ In order to take advantage of a web service over FTP
6
+ As a poor unfortunate soul
7
+ I want to make a request
8
+
9
+ Background:
10
+ Given I connect to an FTP service
11
+
12
+ Scenario: send a request
13
+ When I send the request "request" to the path "request_path"
14
+ Then the request "request" should exist at "request_path"
15
+
16
+ Scenario: read a response
17
+ When the server responds with "response" at the path "response_path"
18
+ Then I can read the response at the path "response_path"
19
+ And the response should be "response"
@@ -0,0 +1,25 @@
1
+ # To run, you must have an FTP server running and accessible by the
2
+ # credentials defined in features/support/ftp_helper.rb
3
+
4
+ # The encryption uses the gpg keys in the test_keys dir.
5
+
6
+ Feature: GPG Encryption
7
+ In order to keep my request secure over insecure FTP
8
+ As a user
9
+ I want to use gpg to encrypt and decrypt my request and response files
10
+
11
+ Background:
12
+ Given I connect to an FTP service
13
+
14
+ Scenario: send a request
15
+ When I send the request "secret content" to the path "request_path.gpg" with gpg recipient "Slow Joe Crow"
16
+ Then a binary request should exist at "request_path.gpg"
17
+ And the binary request at "request_path.gpg" should not contain "secret content"
18
+ When I download the binary request at "request_path.gpg" to "downloaded_request.gpg"
19
+ And I decrypt the file "downloaded_request.gpg" with passphrase "test"
20
+ Then the file "downloaded_request" should contain "secret content"
21
+
22
+ Scenario: read a response
23
+ When the server responds with "secret response" encrypted for "Slow Joe Crow" at the path "response_path.gpg"
24
+ Then I can read the response at the path "response_path.gpg" with the passphrase "test"
25
+ And the response should be "secret response"
@@ -0,0 +1,68 @@
1
+ Given /^I connect to an FTP service$/ do
2
+ @service = FtpService.new(FtpHelper::SERVER, FtpHelper::USER, FtpHelper::PASS)
3
+ end
4
+
5
+ When /^I send the request "([^\"]*)" to the path "([^\"]*)"$/ do |request, remote_path|
6
+ @service.write_request(request, remote_path)
7
+ end
8
+
9
+ When /^I send the request "([^\"]*)" to the path "([^\"]*)" with gpg recipient "([^\"]*)"$/ do |request, remote_path, gpg_recipient|
10
+ @service.write_request(request, remote_path, :gpg_recipient => gpg_recipient)
11
+ end
12
+
13
+ When /^the server responds with "([^\"]*)" at the path "([^\"]*)"$/ do |response, remote_path|
14
+ response = StringIO.new(response)
15
+ ftp.storlines("STOR #{remote_path}", response)
16
+ end
17
+
18
+ When /^the server responds with "([^\"]*)" encrypted for "([^\"]*)" at the path "([^\"]*)"$/ do |response, gpg_recipient, remote_path|
19
+ # Cheating a bit here to mimic a ftp service response by sending a request...
20
+ @service.write_request(response, remote_path, :gpg_recipient => gpg_recipient)
21
+ end
22
+
23
+ When /^I download the binary request at "([^\"]*)" to "([^\"]*)"$/ do |remote_path, local_path|
24
+ File.delete(local_path) if File.exist?(local_path)
25
+ ftp.getbinaryfile(remote_path, "#{TMP_PATH}/#{local_path}")
26
+ end
27
+
28
+ When /^I decrypt the file "([^\"]*)" with passphrase "([^\"]*)"$/ do |filename, passphrase|
29
+ RubyGpg.decrypt("#{TMP_PATH}/#{filename}", passphrase)
30
+ end
31
+
32
+ Then /^the request "([^\"]*)" should exist at "([^\"]*)"$/ do |request, remote_path|
33
+ actual_request = ""
34
+ ftp.retrlines("RETR #{remote_path}") { |line| actual_request << line }
35
+ actual_request.should == request
36
+ end
37
+
38
+ Then /^a binary request should exist at "([^\"]*)"$/ do |remote_path|
39
+ lambda {
40
+ ftp.retrbinary("RETR #{remote_path}", 128) {}
41
+ }.should_not raise_error
42
+ end
43
+
44
+ Then /^the binary request at "([^\"]*)" should not contain "([^\"]*)"$/ do |remote_path, request|
45
+ actual = ""
46
+ ftp.retrbinary("RETR #{remote_path}", 128) { |chunk| actual << chunk }
47
+ actual.strip.should_not == request.strip
48
+ end
49
+
50
+ Then /^I can read the response at the path "([^\"]*)"$/ do |remote_path|
51
+ @actual_response = @service.read_response(remote_path)
52
+ end
53
+
54
+ Then /^I can read the response at the path "([^\"]*)" with the passphrase "([^\"]*)"$/ do |remote_path, gpg_passphrase|
55
+ @actual_response = @service.read_response(remote_path, :gpg_passphrase => gpg_passphrase)
56
+ end
57
+
58
+ Then /^the response should be "([^\"]*)"$/ do |response|
59
+ @actual_response.strip.should == response
60
+ end
61
+
62
+ Then /^the file "([^\"]*)" should contain "([^\"]*)"$/ do |filename, contents|
63
+ File.read("#{TMP_PATH}/#{filename}").strip.should == contents.strip
64
+ end
65
+
66
+ After do
67
+ @service.close if @service
68
+ end
@@ -0,0 +1,6 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../../lib')
2
+ require 'ftp_service'
3
+
4
+ RubyGpg.config.homedir = File.dirname(__FILE__) + '/../../test_keys'
5
+
6
+ TMP_PATH = File.dirname(__FILE__) + '/../../tmp'
@@ -0,0 +1,13 @@
1
+ require 'net/ftp'
2
+
3
+ module FtpHelper
4
+ SERVER = 'localhost'
5
+ USER = 'cucumber'
6
+ PASS = 'cucumber_pass123'
7
+
8
+ def ftp
9
+ @connection ||= Net::FTP.new(SERVER, USER, PASS)
10
+ end
11
+ end
12
+
13
+ World(FtpHelper)
@@ -5,11 +5,11 @@
5
5
 
6
6
  Gem::Specification.new do |s|
7
7
  s.name = %q{ftp_service}
8
- s.version = "0.2.0"
8
+ s.version = "0.3.0"
9
9
 
10
10
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
11
  s.authors = ["Justin Blake"]
12
- s.date = %q{2010-03-08}
12
+ s.date = %q{2010-03-18}
13
13
  s.description = %q{An FTP Service is like a web service except stupid. You send your request by uploading an xml file and get your response by downloading another xml file.}
14
14
  s.email = %q{justin@megablaix.com}
15
15
  s.extra_rdoc_files = [
@@ -22,14 +22,25 @@ Gem::Specification.new do |s|
22
22
  "LICENSE",
23
23
  "README.markdown",
24
24
  "Rakefile",
25
+ "TODO.markdown",
25
26
  "VERSION",
27
+ "cucumber.yml",
28
+ "features/basic_request.feature",
29
+ "features/encrypted_request.feature",
30
+ "features/step_definitions/ftp_request_steps.rb",
31
+ "features/support/env.rb",
32
+ "features/support/ftp_helper.rb",
26
33
  "ftp_service.gemspec",
27
34
  "lib/ftp_service.rb",
35
+ "lib/ftp_service/encryption.rb",
28
36
  "lib/tempfile_helper.rb",
29
37
  "spec/ftp_service_spec.rb",
30
38
  "spec/spec.opts",
31
39
  "spec/spec_helper.rb",
32
- "spec/tempfile_helper_spec.rb"
40
+ "spec/tempfile_helper_spec.rb",
41
+ "test_keys/pubring.gpg",
42
+ "test_keys/secring.gpg",
43
+ "test_keys/trustdb.gpg"
33
44
  ]
34
45
  s.homepage = %q{http://github.com/blaix/ftp_service}
35
46
  s.rdoc_options = ["--charset=UTF-8"]
@@ -47,18 +58,24 @@ Gem::Specification.new do |s|
47
58
  s.specification_version = 3
48
59
 
49
60
  if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
61
+ s.add_runtime_dependency(%q<ruby_gpg>, [">= 0.2.0"])
50
62
  s.add_development_dependency(%q<rspec>, [">= 1.2.9"])
51
63
  s.add_development_dependency(%q<mocha>, [">= 0.9.8"])
52
- s.add_development_dependency(%q<yard>, [">= 0"])
64
+ s.add_development_dependency(%q<yard>, [">= 0.5.3"])
65
+ s.add_development_dependency(%q<cucumber>, [">= 0.6.3"])
53
66
  else
67
+ s.add_dependency(%q<ruby_gpg>, [">= 0.2.0"])
54
68
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
55
69
  s.add_dependency(%q<mocha>, [">= 0.9.8"])
56
- s.add_dependency(%q<yard>, [">= 0"])
70
+ s.add_dependency(%q<yard>, [">= 0.5.3"])
71
+ s.add_dependency(%q<cucumber>, [">= 0.6.3"])
57
72
  end
58
73
  else
74
+ s.add_dependency(%q<ruby_gpg>, [">= 0.2.0"])
59
75
  s.add_dependency(%q<rspec>, [">= 1.2.9"])
60
76
  s.add_dependency(%q<mocha>, [">= 0.9.8"])
61
- s.add_dependency(%q<yard>, [">= 0"])
77
+ s.add_dependency(%q<yard>, [">= 0.5.3"])
78
+ s.add_dependency(%q<cucumber>, [">= 0.6.3"])
62
79
  end
63
80
  end
64
81
 
@@ -1,5 +1,6 @@
1
1
  require 'net/ftp'
2
2
  require 'tempfile_helper'
3
+ require 'ftp_service/encryption'
3
4
 
4
5
  # Class for dealing with a service that acts like a web service, except
5
6
  # over FTP. Meaning an xml request is uploaded as a file, and the
@@ -21,6 +22,7 @@ require 'tempfile_helper'
21
22
  # response = service.read_response("#{path}/response.xml")
22
23
  # service.close
23
24
  class FtpService
25
+ include Encryption
24
26
 
25
27
  # Open a connection to the FTP server and return an FtpService object.
26
28
  # The object must be closed explicitely. See FtpServier#open for a
@@ -42,18 +44,49 @@ class FtpService
42
44
  end
43
45
  end
44
46
 
45
- # Write `request` to a local temp file and upload it to `remote_path`
47
+ # Write +request+ to a local temp file and upload it to +remote_path+
46
48
  # on the FTP server.
47
- def write_request(request, remote_path)
48
- tmp = TempfileHelper.write(request, 'request')
49
- @ftp.puttextfile(tmp.path, remote_path)
49
+ #
50
+ # ftp_service.write_request('<foo>bar</foo>', '/remote/path.xml')
51
+ #
52
+ # You can encrypt the request using GPG:
53
+ #
54
+ # ftp_service.write_request('<secret>stuff</secret>', '/remote/path.xml.gpg', :gpg_recipient => 'recipient@email.com')
55
+ #
56
+ # You must have +gpg+ installed and have a public key available for
57
+ # the intended recipient. This uses the +ruby_gpg+ gem. To configure
58
+ # the gpg settings, see {http://rdoc.info/projects/blaix/ruby_gpg}.
59
+ def write_request(request, remote_path, options = {})
60
+ request = TempfileHelper.write(request, 'request')
61
+ remote_temp_path = remote_path + ".tmp"
62
+ if options[:gpg_recipient]
63
+ encrypt(request, options[:gpg_recipient])
64
+ @ftp.putbinaryfile(request.path, remote_temp_path)
65
+ else
66
+ @ftp.puttextfile(request.path, remote_temp_path)
67
+ end
68
+ @ftp.rename(remote_temp_path, remote_path)
50
69
  end
51
70
 
52
- # Download the file at `remote_path` from the FTP server to a local
53
- # temp file and return its contents.
54
- def read_response(remote_path)
55
- TempfileHelper.read('response') do |tmp|
56
- @ftp.gettextfile(remote_path, tmp.path)
71
+ # Download the file at +remote_path+ from the FTP server to a local
72
+ # temp file and return its contents. If +remote_path+ doesn't exist,
73
+ # keep trying for 2 minutes before raising a Timeout::Error.
74
+ #
75
+ # response = ftp_service.read_response('/remote/path.xml')
76
+ #
77
+ # If you expect the response to be encrypted for you with gpg:
78
+ #
79
+ # response = ftp_service.read_response('/remote/path.xml.gpg', :gpg_passphrase => "my_passphrase")
80
+ #
81
+ # You must have +gpg+ installed and have the necessarry private key.
82
+ # This uses the +ruby_gpg+ gem. To configure the gpg settings, see
83
+ # {http://rdoc.info/projects/blaix/ruby_gpg}.
84
+ def read_response(remote_path, options = {})
85
+ response = download_and_read_response(remote_path, options)
86
+ if options[:gpg_passphrase]
87
+ RubyGpg.decrypt_string(response, options[:gpg_passphrase])
88
+ else
89
+ response
57
90
  end
58
91
  end
59
92
 
@@ -61,4 +94,38 @@ class FtpService
61
94
  def close
62
95
  @ftp.close
63
96
  end
97
+
98
+ private
99
+
100
+ def download_and_read_response(remote_path, options = {})
101
+ TempfileHelper.read('response') do |tmp|
102
+ Timeout::timeout(120) do
103
+ loop_until_downloaded(remote_path, tmp.path, options)
104
+ end
105
+ end
106
+ end
107
+
108
+ def loop_until_downloaded(remote_path, local_path, options = {})
109
+ loop do
110
+ begin
111
+ download(remote_path, local_path, options)
112
+ break
113
+ rescue Net::FTPPermError => e
114
+ raise unless e.message.include?("No such file")
115
+ rest_between_requests
116
+ end
117
+ end
118
+ end
119
+
120
+ def download(remote_path, local_path, options = {})
121
+ if options[:gpg_passphrase]
122
+ @ftp.getbinaryfile(remote_path, local_path)
123
+ else
124
+ @ftp.gettextfile(remote_path, local_path)
125
+ end
126
+ end
127
+
128
+ def rest_between_requests
129
+ sleep(2)
130
+ end
64
131
  end
@@ -0,0 +1,17 @@
1
+ begin
2
+ require 'ruby_gpg'
3
+ rescue LoadError
4
+ require 'rubygems'
5
+ require 'ruby_gpg'
6
+ end
7
+
8
+ class FtpService
9
+ module Encryption
10
+ private
11
+ # Expects a tempfile object and a string for the recipient.
12
+ def encrypt(file, recipient)
13
+ RubyGpg.encrypt(file.path, recipient)
14
+ file.path << ".gpg"
15
+ end
16
+ end
17
+ end
@@ -54,9 +54,28 @@ describe "FtpService" do
54
54
  @service.write_request('request', '/remote/path')
55
55
  end
56
56
 
57
- it "uploads the request to `path` on the FTP server" do
57
+ it "encrypts the request if passed a gpg recipient" do
58
58
  TempfileHelper.stubs(:write).returns(@tempfile)
59
- @ftp.expects(:puttextfile).with('/local/path', '/remote/path')
59
+ RubyGpg.expects(:encrypt).with('/local/path', 'recipient')
60
+ @service.write_request('request', '/remote/path.gpg', :gpg_recipient => 'recipient')
61
+ end
62
+
63
+ it "uploads the request to a temp path on the FTP server" do
64
+ TempfileHelper.stubs(:write).returns(@tempfile)
65
+ @ftp.expects(:puttextfile).with('/local/path', '/remote/path.tmp')
66
+ @service.write_request('request', '/remote/path')
67
+ end
68
+
69
+ it "uploads the request as binary if passed a gpg recipient" do
70
+ TempfileHelper.stubs(:write).returns(@tempfile)
71
+ RubyGpg.stubs(:encrypt)
72
+ @ftp.expects(:putbinaryfile).with('/local/path.gpg', '/remote/path.gpg.tmp')
73
+ @service.write_request('request', '/remote/path.gpg', :gpg_recipient => 'recipient')
74
+ end
75
+
76
+ it "renames the temp path on the FTP server to the passed `path`" do
77
+ TempfileHelper.stubs(:write).returns(@tempfile)
78
+ @ftp.expects(:rename).with('/remote/path.tmp', '/remote/path')
60
79
  @service.write_request('request', '/remote/path')
61
80
  end
62
81
  end
@@ -65,7 +84,10 @@ describe "FtpService" do
65
84
  before do
66
85
  tempfile = stub('tempfile', :path => '/local/path')
67
86
  TempfileHelper.stubs(:read).returns('response').yields(tempfile)
87
+
68
88
  @service = FtpService.new('host', 'user', 'pass')
89
+ # No need to be nice to the "server" during testing...
90
+ @service.stubs(:rest_between_requests)
69
91
  end
70
92
 
71
93
  it "downloads the response at `path` from the FTP server" do
@@ -73,9 +95,45 @@ describe "FtpService" do
73
95
  @service.read_response('/remote/path')
74
96
  end
75
97
 
98
+ it "downloads the response as binary if passed a gpg passphrase" do
99
+ RubyGpg.stubs(:decrypt_string)
100
+ @ftp.expects(:getbinaryfile).with('/remote/path.gpg', '/local/path')
101
+ @service.read_response('/remote/path.gpg', :gpg_passphrase => "my_passphrase")
102
+ end
103
+
104
+ it "decrypts the response if passed a gpg passphrase" do
105
+ RubyGpg.expects(:decrypt_string).with('response', 'my_passphrase')
106
+ @service.read_response('/remote/path.gpg', :gpg_passphrase => "my_passphrase")
107
+ end
108
+
76
109
  it "returns the contents of the downloaded response" do
77
110
  @service.read_response('/remote/path').should == "response"
78
111
  end
112
+
113
+ it "polls until response shows up" do
114
+ error = Net::FTPPermError.new("No such file")
115
+ # Raise error on the first two calls...
116
+ @ftp.expects(:gettextfile).times(3).raises(error).then.raises(error).then.returns(nil)
117
+ lambda {
118
+ @service.read_response('/remote/path')
119
+ }.should_not raise_error
120
+ end
121
+
122
+ it "times out if response takes longer than 2 minutes to show up" do
123
+ # TODO: Less brittle way to test this?
124
+ # Currently depends on inner workings of Timeout.
125
+ Timeout.expects(:sleep).with(120)
126
+ lambda {
127
+ @service.read_response('/remote/path')
128
+ }.should raise_error(Timeout::Error)
129
+ end
130
+
131
+ it "doesn't gobble up every FTP exception" do
132
+ @ftp.stubs(:gettextfile).raises(Net::FTPPermError.new("Permission denied")).then.returns(nil)
133
+ lambda {
134
+ @service.read_response('/remote/path')
135
+ }.should raise_error(Net::FTPPermError, "Permission denied")
136
+ end
79
137
  end
80
138
 
81
139
  describe '#close' do
Binary file
Binary file
Binary file
metadata CHANGED
@@ -4,9 +4,9 @@ version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
6
  - 0
7
- - 2
7
+ - 3
8
8
  - 0
9
- version: 0.2.0
9
+ version: 0.3.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Justin Blake
@@ -14,13 +14,27 @@ autorequire:
14
14
  bindir: bin
15
15
  cert_chain: []
16
16
 
17
- date: 2010-03-08 00:00:00 -05:00
17
+ date: 2010-03-18 00:00:00 -04:00
18
18
  default_executable:
19
19
  dependencies:
20
20
  - !ruby/object:Gem::Dependency
21
- name: rspec
21
+ name: ruby_gpg
22
22
  prerelease: false
23
23
  requirement: &id001 !ruby/object:Gem::Requirement
24
+ requirements:
25
+ - - ">="
26
+ - !ruby/object:Gem::Version
27
+ segments:
28
+ - 0
29
+ - 2
30
+ - 0
31
+ version: 0.2.0
32
+ type: :runtime
33
+ version_requirements: *id001
34
+ - !ruby/object:Gem::Dependency
35
+ name: rspec
36
+ prerelease: false
37
+ requirement: &id002 !ruby/object:Gem::Requirement
24
38
  requirements:
25
39
  - - ">="
26
40
  - !ruby/object:Gem::Version
@@ -30,11 +44,11 @@ dependencies:
30
44
  - 9
31
45
  version: 1.2.9
32
46
  type: :development
33
- version_requirements: *id001
47
+ version_requirements: *id002
34
48
  - !ruby/object:Gem::Dependency
35
49
  name: mocha
36
50
  prerelease: false
37
- requirement: &id002 !ruby/object:Gem::Requirement
51
+ requirement: &id003 !ruby/object:Gem::Requirement
38
52
  requirements:
39
53
  - - ">="
40
54
  - !ruby/object:Gem::Version
@@ -44,19 +58,35 @@ dependencies:
44
58
  - 8
45
59
  version: 0.9.8
46
60
  type: :development
47
- version_requirements: *id002
61
+ version_requirements: *id003
48
62
  - !ruby/object:Gem::Dependency
49
63
  name: yard
50
64
  prerelease: false
51
- requirement: &id003 !ruby/object:Gem::Requirement
65
+ requirement: &id004 !ruby/object:Gem::Requirement
52
66
  requirements:
53
67
  - - ">="
54
68
  - !ruby/object:Gem::Version
55
69
  segments:
56
70
  - 0
57
- version: "0"
71
+ - 5
72
+ - 3
73
+ version: 0.5.3
58
74
  type: :development
59
- version_requirements: *id003
75
+ version_requirements: *id004
76
+ - !ruby/object:Gem::Dependency
77
+ name: cucumber
78
+ prerelease: false
79
+ requirement: &id005 !ruby/object:Gem::Requirement
80
+ requirements:
81
+ - - ">="
82
+ - !ruby/object:Gem::Version
83
+ segments:
84
+ - 0
85
+ - 6
86
+ - 3
87
+ version: 0.6.3
88
+ type: :development
89
+ version_requirements: *id005
60
90
  description: An FTP Service is like a web service except stupid. You send your request by uploading an xml file and get your response by downloading another xml file.
61
91
  email: justin@megablaix.com
62
92
  executables: []
@@ -72,14 +102,25 @@ files:
72
102
  - LICENSE
73
103
  - README.markdown
74
104
  - Rakefile
105
+ - TODO.markdown
75
106
  - VERSION
107
+ - cucumber.yml
108
+ - features/basic_request.feature
109
+ - features/encrypted_request.feature
110
+ - features/step_definitions/ftp_request_steps.rb
111
+ - features/support/env.rb
112
+ - features/support/ftp_helper.rb
76
113
  - ftp_service.gemspec
77
114
  - lib/ftp_service.rb
115
+ - lib/ftp_service/encryption.rb
78
116
  - lib/tempfile_helper.rb
79
117
  - spec/ftp_service_spec.rb
80
118
  - spec/spec.opts
81
119
  - spec/spec_helper.rb
82
120
  - spec/tempfile_helper_spec.rb
121
+ - test_keys/pubring.gpg
122
+ - test_keys/secring.gpg
123
+ - test_keys/trustdb.gpg
83
124
  has_rdoc: true
84
125
  homepage: http://github.com/blaix/ftp_service
85
126
  licenses: []