rbook-pacstream 0.6 → 0.7

Sign up to get free protection for your applications and to get access to all the features.
data/Rakefile CHANGED
@@ -6,7 +6,7 @@ require 'rake/testtask'
6
6
  require "rake/gempackagetask"
7
7
  require 'spec/rake/spectask'
8
8
 
9
- PKG_VERSION = "0.6"
9
+ PKG_VERSION = "0.7"
10
10
  PKG_NAME = "rbook-pacstream"
11
11
  PKG_FILE_NAME = "#{PKG_NAME}-#{PKG_VERSION}"
12
12
  RUBYFORGE_PROJECT = 'rbook'
@@ -24,7 +24,13 @@ task :cruise => [ :spec, :spec_report, :doc ]
24
24
  desc "Run all rspec files"
25
25
  Spec::Rake::SpecTask.new("spec") do |t|
26
26
  t.spec_files = FileList['specs/**/*.rb']
27
- t.rcov = true
27
+
28
+ if RUBY_VERSION >= "1.8.6" && RUBY_PATCHLEVEL >= 110
29
+ t.rcov = false
30
+ else
31
+ t.rcov = true
32
+ end
33
+
28
34
  t.rcov_dir = (ENV['CC_BUILD_ARTIFACTS'] || 'doc') + "/rcov"
29
35
  t.rcov_opts = ["--exclude","spec.*\.rb"]
30
36
  end
@@ -5,21 +5,131 @@ require 'tempfile'
5
5
 
6
6
  module RBook
7
7
 
8
+ # an error indicating pacstream authentication issues
9
+ class PacstreamAuthError < RuntimeError; end
10
+
11
+ # an error indocating a problem with executing a pacstream command
12
+ class PacstreamCommandError < RuntimeError; end
13
+
14
+ # an error indicating a problem connecting to the pacstream server
15
+ class PacstreamConnectionError < RuntimeError; end
16
+
8
17
  # Ruby class for sending and retrieving electronic orders
9
18
  # via pacstream, a service run by the ECN Group
10
19
  # (http://www.ecngroup.com.au/)
11
20
  #
12
21
  # = Basic Usage
13
22
  #
14
- # RBook::Pacstream.get(:orders, :username => "myusername", :password => "mypass") do |order|
23
+ # pac = RBook::Pacstream.new(:username => "myusername", :password => "mypass")
24
+ # pac.login
25
+ # pac.get(:orders) do |order|
15
26
  # puts order
16
27
  # end
28
+ # pac.get(:poacks) do |poa|
29
+ # puts poa
30
+ # end
31
+ # pac.put(:order, 1000, order_text)
32
+ # pac.quit
33
+ #
34
+ # = Alternative Usage
35
+ # RBook::Pacstream.open(:username => "myusername", :password => "mypass") do |pac|
36
+ # pac.get(:orders) do |order|
37
+ # puts order
38
+ # end
39
+ # pac.put(:order, 1000, order_text)
40
+ # end
17
41
  class Pacstream
18
42
 
19
43
  FILE_EXTENSIONS = { :orders => "ORD", :invoices => "ASN", :poacks => "POA" }
44
+ FILE_EXTENSIONS_SINGULAR = { :order => "ORD", :invoice => "ASN", :poack => "POA" }
45
+
46
+ def initialize(*args)
47
+ if args[0][:username].nil? && args[0][:password].nil?
48
+ raise ArgumentError, 'username and password must be specified'
49
+ end
50
+
51
+ @server = args[0][:servername].to_s || "pacstream.tedis.com.au"
52
+ @username = args[0][:username].to_s
53
+ @password = args[0][:password].to_s
54
+ end
20
55
 
21
- # Iterate over each document waiting on the pacstream server, returning
22
- # it as a string
56
+ # download all documents of a particular type from the pacstream server
57
+ #
58
+ # pac.get(:orders) do |order|
59
+ # puts order
60
+ # end
61
+ #
62
+ # WARNING: as soon as you download the order, the file is deleted from the server
63
+ # and cannot be retrieved again
64
+ def get(type, &block)
65
+ raise PacstreamCommandError, "No current session open" unless @ftp
66
+ raise ArgumentError, 'unrecognised type' unless FILE_EXTENSIONS.include?(type.to_sym)
67
+
68
+ # determine the filename pattern we're searching for
69
+ file_regexp = Regexp.new(".*\.#{FILE_EXTENSIONS[type.to_sym]}$", Regexp::IGNORECASE)
70
+ @ftp.chdir("outgoing/")
71
+
72
+ # loop over each file in the outgoing dir and check if it matches the file type we're after
73
+ @ftp.nlst.each do |file|
74
+ if file.match(file_regexp)
75
+
76
+ # for all matching files, download to a temp file, return the contents, then delete the file
77
+ tempfile = Tempfile.new("pacstream")
78
+ tempfile.close
79
+ @ftp.getbinaryfile(file, tempfile.path)
80
+ yield File.read(tempfile.path)
81
+ tempfile.unlink
82
+ end
83
+ end
84
+
85
+ @ftp.chdir("..")
86
+ end
87
+
88
+ # logs into to the pacstream server. Can raise several exceptions
89
+ # RBook::PacstreamConnectionError - Can't connect to server
90
+ # RBook::PacstreamAuthError - Invalid username or password
91
+ def login
92
+ begin
93
+ @ftp = Net::FTP.open(@server)
94
+ @ftp.login(@username, @password)
95
+ rescue Net::FTPPermError => e
96
+ raise PacstreamAuthError, e.message
97
+ rescue SocketError => e
98
+ raise PacstreamConnectionError, e.message
99
+ rescue Errno::ECONNREFUSED => e
100
+ raise PacstreamConnectionError, e.message
101
+ end
102
+ end
103
+
104
+ # upload a file to the pacstream server
105
+ # type - :order, invoice or :poack
106
+ # ref - a reference number, used to name the file
107
+ # content - the content to upload
108
+ def put(type, ref, content)
109
+ raise PacstreamCommandError, "No current session open" unless @ftp
110
+ raise ArgumentError, 'unrecognised type' unless FILE_EXTENSIONS_SINGULAR.include?(type.to_sym)
111
+
112
+ remote_filename = "#{ref}.#{FILE_EXTENSIONS_SINGULAR[type.to_sym]}"
113
+ @ftp.chdir("incoming/")
114
+
115
+ tempfile = Tempfile.new("pacstream")
116
+ tempfile.write(content)
117
+ tempfile.close
118
+
119
+ @ftp.putbinaryfile(tempfile.path, remote_filename)
120
+
121
+ tempfile.unlink
122
+
123
+ @ftp.chdir("..")
124
+ end
125
+
126
+ # logout from the pacstream server
127
+ def quit
128
+ raise PacstreamCommandError, "No current session open" unless @ftp
129
+ @ftp.quit
130
+ end
131
+
132
+ # Deprecated way to download files from the pacstream server
23
133
  #
24
134
  # Document types available:
25
135
  #
@@ -31,38 +141,20 @@ module RBook
31
141
  # puts order
32
142
  # end
33
143
  def self.get(type = :orders, *args, &block)
34
- if args[0][:username].nil? && args[0][:password].nil?
35
- raise ArgumentError, 'username and password must be specified'
144
+ pac = RBook::Pacstream.new(args[0])
145
+ pac.login
146
+ pac.get(type) do |content|
147
+ yield content
36
148
  end
149
+ pac.quit
150
+ end
37
151
 
38
- raise ArgumentError, 'unrecognised type' unless FILE_EXTENSIONS.include?(type.to_sym)
39
-
40
- server = args[0][:servername] || "pacstream.tedis.com.au"
41
-
42
- begin
43
- transaction_complete = false
44
- Net::FTP.open(server) do |ftp|
45
-
46
- file_regexp = Regexp.new(".*\.#{FILE_EXTENSIONS[type.to_sym]}$", Regexp::IGNORECASE)
47
- ftp.login(args[0][:username].to_s, args[0][:password].to_s)
48
- ftp.chdir("outgoing/")
49
- ftp.nlst.each do |file|
50
- if file.match(file_regexp)
51
- tempfile = Tempfile.new("pacstream")
52
- tempfile.close
53
- ftp.getbinaryfile(file, tempfile.path)
54
- yield File.read(tempfile.path)
55
- tempfile.unlink
56
- end
57
- end
58
- transaction_complete = true
59
- #ftp.quit
60
- end
61
- rescue EOFError
62
- raise "Connection terminated by remote server" unless transaction_complete
63
- rescue Net::FTPPermError
64
- raise "Error while communicating with the pacstream server"
65
- end
152
+ # Alternative, block syntax. See notes at the top of the class for usage
153
+ def self.open(*args, &block)
154
+ pac = RBook::Pacstream.new(args[0])
155
+ pac.login
156
+ yield pac
157
+ pac.quit
66
158
  end
67
159
  end
68
160
  end
@@ -0,0 +1,167 @@
1
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../lib')
2
+ $LOAD_PATH.unshift(File.dirname(__FILE__) + '/../vendor')
3
+
4
+ require 'rbook/pacstream'
5
+ require 'not_a_mock'
6
+ require 'rubygems'
7
+ require 'spec'
8
+
9
+ Spec::Runner.configure do |config|
10
+ config.mock_with NotAMock::RspecMockFrameworkAdapter
11
+ end
12
+
13
+ context "The pacstream class" do
14
+
15
+ setup do
16
+ @options = {:servername => "127.0.0.1",
17
+ :username => "test",
18
+ :password => "pass"}
19
+
20
+ end
21
+
22
+ specify "should open and close an ftp connection when login and logout are called in the right order" do
23
+ # prevent a real ftp session from being opened. If the lib attempts to open
24
+ # a connection, just return a stubbed class
25
+ ftp = Net::FTP.stub_instance(:login => true, :quit => true)
26
+ Net::FTP.stub_method(:new => ftp, :open => ftp)
27
+
28
+ pac = RBook::Pacstream.new(@options)
29
+ pac.login
30
+ pac.quit
31
+
32
+ Net::FTP.should have_received(:open).once.with(@options[:servername])
33
+ ftp.should have_received(:login).once.with(@options[:username], @options[:password])
34
+ ftp.should have_received(:quit).once.without_args
35
+ end
36
+
37
+ specify "should return the contents of a invoice when looping over all available invoices's" do
38
+ # prevent a real ftp session from being opened. If the lib attempts to open
39
+ # a connection, just return a stubbed class
40
+ # this stub will allow the user to call chdir, and pretends that there is a single invoice available
41
+ # for download
42
+ ftp = Net::FTP.stub_instance(:login => true, :chdir => true, :nlst => ["1.ASN"], :getbinaryfile => true, :quit => true)
43
+ Net::FTP.stub_method(:new => ftp, :open => ftp)
44
+ File.stub_method(:read => "this is an invoice")
45
+
46
+ pac = RBook::Pacstream.new(@options)
47
+ pac.login
48
+ pac.get(:invoices) do |ord|
49
+ ord.should eql("this is an invoice")
50
+ end
51
+ pac.quit
52
+
53
+ ftp.should have_received(:chdir).twice
54
+ ftp.should have_received(:nlst).once.without_args
55
+ ftp.should have_received(:getbinaryfile).once
56
+ end
57
+
58
+ specify "should return the contents of an order when looping over all available orders" do
59
+ # prevent a real ftp session from being opened. If the lib attempts to open
60
+ # a connection, just return a stubbed class
61
+ # this stub will allow the user to call chdir, and rpretends that there is a single order available
62
+ # for download
63
+ ftp = Net::FTP.stub_instance(:login => true, :chdir => true, :nlst => ["1.ORD"], :getbinaryfile => true, :quit => true)
64
+ Net::FTP.stub_method(:new => ftp, :open => ftp)
65
+ File.stub_method(:read => "this is an order")
66
+
67
+ pac = RBook::Pacstream.new(@options)
68
+ pac.login
69
+ pac.get(:orders) do |ord|
70
+ ord.should eql("this is an order")
71
+ end
72
+ pac.quit
73
+
74
+ ftp.should have_received(:chdir).twice
75
+ ftp.should have_received(:nlst).once.without_args
76
+ ftp.should have_received(:getbinaryfile).once
77
+ end
78
+
79
+ specify "should return the contents of a POA when looping over all available poa's" do
80
+ # prevent a real ftp session from being opened. If the lib attempts to open
81
+ # a connection, just return a stubbed class
82
+ # this stub will allow the user to call chdir, and pretends that there is a single poa available
83
+ # for download
84
+ ftp = Net::FTP.stub_instance(:login => true, :chdir => true, :nlst => ["1.POA"], :getbinaryfile => true, :quit => true)
85
+ Net::FTP.stub_method(:new => ftp, :open => ftp)
86
+ File.stub_method(:read => "this is a poa")
87
+
88
+ pac = RBook::Pacstream.new(@options)
89
+ pac.login
90
+ pac.get(:poacks) do |ord|
91
+ ord.should eql("this is a poa")
92
+ end
93
+ pac.quit
94
+
95
+ ftp.should have_received(:chdir).twice
96
+ ftp.should have_received(:nlst).once.without_args
97
+ ftp.should have_received(:getbinaryfile).once
98
+ end
99
+
100
+ specify "should download a file correctly when the alternative, block syntax is used" do
101
+ # prevent a real ftp session from being opened. If the lib attempts to open
102
+ # a connection, just return a stubbed class
103
+ ftp = Net::FTP.stub_instance(:login => true, :chdir => true, :nlst => ["1.ORD"], :getbinaryfile => true, :quit => true)
104
+ Net::FTP.stub_method(:new => ftp, :open => ftp)
105
+ File.stub_method(:read => "this is an order")
106
+
107
+ RBook::Pacstream.open(@options) do |pac|
108
+ pac.get(:orders) do |ord|
109
+ ord.should eql("this is an order")
110
+ end
111
+ end
112
+
113
+ Net::FTP.should have_received(:open).once.with(@options[:servername])
114
+ ftp.should have_received(:login).once.with(@options[:username], @options[:password])
115
+ ftp.should have_received(:chdir).twice
116
+ ftp.should have_received(:nlst).once.without_args
117
+ ftp.should have_received(:getbinaryfile).once
118
+ ftp.should have_received(:quit).once.without_args
119
+ end
120
+
121
+ specify "should raise an exception if incorrect login details are provided" do
122
+ # prevent a real ftp session from being opened. If the lib attempts to open
123
+ # a connection, just return a stubbed class
124
+ ftp = Net::FTP.stub_instance(:login => Net::FTPPermError.new("530 incorrect login. not logged in."))
125
+ Net::FTP.stub_method(:new => ftp, :open => ftp)
126
+
127
+ pac = RBook::Pacstream.new(@options)
128
+ lambda { pac.login }.should raise_error(RBook::PacstreamAuthError)
129
+ end
130
+
131
+ specify "should raise an exception if an invalid server is provided" do
132
+ # prevent a real ftp session from being opened. If the lib attempts to open
133
+ # a connection, just return a stubbed class
134
+ ftp = Net::FTP.stub_instance(:login => SocketError.new("getaddrinfo: Name or service not known"))
135
+ Net::FTP.stub_method(:new => ftp, :open => ftp)
136
+
137
+ pac = RBook::Pacstream.new(@options)
138
+ lambda { pac.login }.should raise_error(RBook::PacstreamConnectionError)
139
+ end
140
+
141
+ specify "should save an order to the server" do
142
+ # prevent a real ftp session from being opened. If the lib attempts to open
143
+ # a connection, just return a stubbed class
144
+ # this stub will allow the user to call chdir, and pretends that there is a single poa available
145
+ # for download
146
+ ftp = Net::FTP.stub_instance(:login => true, :chdir => true, :putbinaryfile => true, :quit => true)
147
+ Net::FTP.stub_method(:new => ftp, :open => ftp)
148
+
149
+ pac = RBook::Pacstream.new(@options)
150
+ pac.login
151
+ pac.put(:order, 1, "order content")
152
+ pac.quit
153
+
154
+ ftp.should have_received(:chdir).twice
155
+ ftp.should have_received(:putbinaryfile).once
156
+ end
157
+
158
+ specify "should raise an exception if quit is called before login" do
159
+ # prevent a real ftp session from being opened. If the lib attempts to open
160
+ # a connection, just return a stubbed class
161
+ ftp = Net::FTP.stub_instance(:login => true, :quit => true)
162
+ Net::FTP.stub_method(:new => ftp, :open => ftp)
163
+
164
+ pac = RBook::Pacstream.new(@options)
165
+ lambda { pac.quit }.should raise_error(RBook::PacstreamCommandError)
166
+ end
167
+ end
metadata CHANGED
@@ -3,8 +3,8 @@ rubygems_version: 0.9.4
3
3
  specification_version: 1
4
4
  name: rbook-pacstream
5
5
  version: !ruby/object:Gem::Version
6
- version: "0.6"
7
- date: 2007-10-10 00:00:00 +10:00
6
+ version: "0.7"
7
+ date: 2007-10-24 00:00:00 +10:00
8
8
  summary: A library for interaction with the PACSTREAM service
9
9
  require_paths:
10
10
  - lib
@@ -32,12 +32,13 @@ files:
32
32
  - examples/pacstream.rb
33
33
  - lib/rbook
34
34
  - lib/rbook/pacstream.rb
35
+ - specs/pacstream_spec.rb
35
36
  - Rakefile
36
37
  - README
37
38
  - COPYING
38
39
  - LICENSE
39
- test_files: []
40
-
40
+ test_files:
41
+ - specs/pacstream_spec.rb
41
42
  rdoc_options:
42
43
  - --title
43
44
  - pacstream Documentation