rbook-pacstream 0.6 → 0.7

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/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