trackerific 0.3.2 → 0.3.3

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.
Files changed (36) hide show
  1. data/Gemfile +1 -0
  2. data/Gemfile.lock +40 -38
  3. data/README.rdoc +4 -9
  4. data/VERSION +1 -1
  5. data/doc/Trackerific.html +34 -22
  6. data/doc/Trackerific/Base.html +237 -20
  7. data/doc/Trackerific/Details.html +6 -6
  8. data/doc/Trackerific/Error.html +2 -2
  9. data/doc/Trackerific/Event.html +7 -7
  10. data/doc/Trackerific/FedEx.html +190 -3
  11. data/doc/Trackerific/UPS.html +190 -3
  12. data/doc/Trackerific/USPS.html +190 -3
  13. data/doc/_index.html +1 -1
  14. data/doc/file.README.html +6 -24
  15. data/doc/index.html +6 -24
  16. data/doc/method_list.html +68 -4
  17. data/doc/top-level-namespace.html +1 -1
  18. data/lib/trackerific.rb +37 -74
  19. data/lib/trackerific/base.rb +70 -0
  20. data/lib/{trackerific_details.rb → trackerific/details.rb} +0 -0
  21. data/lib/trackerific/error.rb +4 -0
  22. data/lib/{trackerific_event.rb → trackerific/event.rb} +0 -0
  23. data/lib/{fedex.rb → trackerific/services/fedex.rb} +9 -2
  24. data/lib/{ups.rb → trackerific/services/ups.rb} +10 -4
  25. data/lib/{usps.rb → trackerific/services/usps.rb} +10 -3
  26. data/spec/lib/trackerific/base_spec.rb +34 -0
  27. data/spec/lib/{trackerific_details_spec.rb → trackerific/details_spec.rb} +0 -0
  28. data/spec/lib/trackerific/error_spec.rb +5 -0
  29. data/spec/lib/{trackerific_event_spec.rb → trackerific/event_spec.rb} +0 -0
  30. data/spec/lib/{fedex_spec.rb → trackerific/services/fedex_spec.rb} +19 -14
  31. data/spec/lib/{ups_spec.rb → trackerific/services/ups_spec.rb} +20 -14
  32. data/spec/lib/{usps_spec.rb → trackerific/services/usps_spec.rb} +18 -14
  33. data/spec/lib/trackerific_spec.rb +7 -30
  34. data/spec/spec_helper.rb +1 -0
  35. data/trackerific.gemspec +18 -22
  36. metadata +38 -27
@@ -94,7 +94,7 @@
94
94
  </div>
95
95
 
96
96
  <div id="footer">
97
- Generated on Mon Jun 13 16:20:06 2011 by
97
+ Generated on Mon Jun 13 21:28:36 2011 by
98
98
  <a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
99
99
  0.7.1 (ruby-1.9.2).
100
100
  </div>
data/lib/trackerific.rb CHANGED
@@ -1,71 +1,15 @@
1
- # Trackerific is a UPS, FedEx and USPS tracking provider.
1
+ require 'rails'
2
+ require 'trackerific/base'
3
+ require 'trackerific/error'
4
+ require 'trackerific/details'
5
+ require 'trackerific/event'
6
+
7
+ # require all the Trackerific services
8
+ services_path = File.join(File.dirname(__FILE__), "trackerific", "services", "**", "*.rb")
9
+ Dir[File.expand_path(services_path)].each { |file| require file }
10
+
11
+ # Trackerific provides package tracking to Rails apps.
2
12
  module Trackerific
3
- require 'rails'
4
- require 'trackerific_details'
5
- require 'trackerific_event'
6
-
7
- # Raised if something other than tracking information is returned.
8
- class Error < StandardError; end
9
-
10
- # Base class for Trackerific package tracking services.
11
- class Base
12
- # Creates a new instance of Trackerific::Base with required options
13
- # @api private
14
- def initialize(options = {})
15
- required = required_options
16
- # make sure all the required options exist
17
- required.each do |k|
18
- raise ArgumentError.new("Missing required parameter: #{k}") unless options.has_key?(k)
19
- end
20
- # make sure no invalid options exist
21
- options.each do |k, v|
22
- raise ArgumentError.new("Invalid parameter: #{k}") unless required.include?(k)
23
- end
24
- @options = options
25
- end
26
-
27
- # Gets the tracking information for the package from the server
28
- # @param [String] package_id the package identifier
29
- # @return [Trackerific::Details] the tracking details
30
- # @example Override this method in your custom tracking provider to implement tracking
31
- # module Trackerific
32
- # class MyTrackingProvider < Base
33
- # def track_package
34
- # Trackerific::Details.new(
35
- # "summary of tracking events",
36
- # [Trackerific::Event.new(Time.now, "summary", "location")]
37
- # )
38
- # end
39
- # end
40
- # end
41
- # @api public
42
- def track_package(package_id)
43
- @package_id = package_id
44
- end
45
-
46
- protected
47
-
48
- # An array of options that are required to create a new instance of this class
49
- # @return [Array] the required options
50
- # @example Override this method in your custom tracking provider to enforce some options
51
- # module Trackerific
52
- # class MyTrackingProvider < Base
53
- # def required_options
54
- # [:all, :these, :are, :required]
55
- # end
56
- # end
57
- # end
58
- # @api private
59
- def required_options
60
- []
61
- end
62
-
63
- end
64
-
65
- require 'usps'
66
- require 'fedex'
67
- require 'ups'
68
-
69
13
  # Checks a string for a valid package tracking service
70
14
  # @param [String] package_id the package identifier
71
15
  # @return [Trackerific::Base] the Trackerific class that can track the given
@@ -75,14 +19,33 @@ module Trackerific
75
19
  # tracking_service "183689015000001" # => Trackerific::FedEx
76
20
  # @api public
77
21
  def tracking_service(package_id)
78
- case package_id
79
- when /^.Z/, /^[HK].{10}$/ then Trackerific::UPS
80
- when /^96.{20}$/ then Trackerific::FedEx
81
- else case package_id.length
82
- when 13, 20, 22, 30 then Trackerific::USPS
83
- when 12, 15, 19 then Trackerific::FedEx
84
- else nil
22
+ # loop through each constant in Trackerific
23
+ Trackerific.constants.each do |const|
24
+ # get the constant's class
25
+ cls = Trackerific.const_get(const)
26
+ # check if it descends from Trackerific::Base
27
+ if cls.superclass == Trackerific::Base
28
+ # loop through each package id matcher
29
+ cls.package_id_matchers.each do |matcher|
30
+ # return the class if it matches
31
+ return cls if package_id =~ matcher
32
+ end
85
33
  end
86
34
  end
35
+ # if we've made it this far, nothing matched
36
+ nil
87
37
  end
38
+
39
+ # TODO: Tracks a package by determining its service from the package id
40
+ # @param [String] package_id the package identifier
41
+ # @return [Trackerific::Details] the tracking results
42
+ # @raise [Trackerific::Error] raised when the server returns an error (invalid credentials, tracking package, etc.)
43
+ # @example Track a package
44
+ # include Trackerific
45
+ # details = track_package("183689015000001")
46
+ # @api public
47
+ # def track_package(package_id)
48
+ # service = tracking_service(package_id)
49
+ #
50
+ # end
88
51
  end
@@ -0,0 +1,70 @@
1
+ module Trackerific
2
+ # Base class for Trackerific package tracking services.
3
+ class Base
4
+ # Creates a new instance of Trackerific::Base with required options
5
+ # @api private
6
+ def initialize(options = {})
7
+ required = self.class.required_options
8
+ # make sure all the required options exist
9
+ required.each do |k|
10
+ raise ArgumentError.new("Missing required parameter: #{k}") unless options.has_key?(k)
11
+ end
12
+ # make sure no invalid options exist
13
+ options.each do |k, v|
14
+ raise ArgumentError.new("Invalid parameter: #{k}") unless required.include?(k)
15
+ end
16
+ @options = options
17
+ end
18
+
19
+ # Gets the tracking information for the package from the server
20
+ # @param [String] package_id the package identifier
21
+ # @return [Trackerific::Details] the tracking details
22
+ # @example Override this method in your custom tracking service to implement tracking
23
+ # module Trackerific
24
+ # class MyTrackingService < Base
25
+ # def track_package
26
+ # # your tracking code here
27
+ # Trackerific::Details.new(
28
+ # "summary of tracking events",
29
+ # [Trackerific::Event.new(Time.now, "summary", "location")]
30
+ # )
31
+ # end
32
+ # end
33
+ # end
34
+ # @api semipublic
35
+ def track_package(package_id)
36
+ @package_id = package_id
37
+ end
38
+
39
+ # An Array of Regexp that matches valid package identifiers for your service
40
+ # @example Override this method in your custom tracking service
41
+ # module Trackerific
42
+ # class MyTrackingService < Base
43
+ # def self.package_id_matchers
44
+ # [ /^.Z/, /^[HK].{10}$/ ] # matchers for UPS package identifiers
45
+ # end
46
+ # end
47
+ # end
48
+ # @return [Array, Regexp] an array of regular expressions
49
+ # @api semipublic
50
+ def self.package_id_matchers
51
+ nil
52
+ end
53
+
54
+ # An array of options that are required to create a new instance of this class
55
+ # @return [Array] the required options
56
+ # @example Override this method in your custom tracking service to enforce some options
57
+ # module Trackerific
58
+ # class MyTrackingService < Base
59
+ # def self.required_options
60
+ # [:all, :these, :are, :required]
61
+ # end
62
+ # end
63
+ # end
64
+ # @api semipublic
65
+ def self.required_options
66
+ []
67
+ end
68
+
69
+ end
70
+ end
@@ -0,0 +1,4 @@
1
+ module Trackerific
2
+ # Raised if something other than tracking information is returned.
3
+ class Error < StandardError; end
4
+ end
File without changes
@@ -45,16 +45,23 @@ module Trackerific
45
45
  )
46
46
  end
47
47
 
48
- protected
48
+ # A regex that matches valid package identifiers for FedEx package ids
49
+ # @return [Regexp] the regular expression
50
+ # @api private
51
+ def self.package_id_matchers
52
+ [ /^[0-9]{15}$/ ]
53
+ end
49
54
 
50
55
  # Returns an Array of required options used when creating a new instance
51
56
  # @return [Array] required options for tracking a FedEx package are :account
52
57
  # and :meter
53
58
  # @api private
54
- def required_options
59
+ def self.required_options
55
60
  [:account, :meter]
56
61
  end
57
62
 
63
+ protected
64
+
58
65
  # Builds the XML request to send to FedEx
59
66
  # @return [String] a FDXTrack2Request XML
60
67
  # @api private
@@ -37,15 +37,21 @@ module Trackerific
37
37
  end
38
38
  end
39
39
 
40
- protected
41
-
40
+ # A regex that matches valid package identifiers for UPS package ids
41
+ # @return [Regexp] the regular expression
42
+ # @api private
43
+ def self.package_id_matchers
44
+ [ /^.Z/, /^[HK].{10}$/ ]
45
+ end
42
46
  # The required options for tracking a UPS package
43
- # @return [Array] the required options for tracking a UPS package.
47
+ # @return [Array] the required options for tracking a UPS package
44
48
  # @api private
45
- def required_options
49
+ def self.required_options
46
50
  [:key, :user_id, :password]
47
51
  end
48
52
 
53
+ protected
54
+
49
55
  # Parses the response from UPS
50
56
  # @return [Trackerific::Details]
51
57
  # @api private
@@ -56,15 +56,22 @@ module Trackerific
56
56
  )
57
57
  end
58
58
 
59
- protected
59
+ # A regex that matches valid package identifiers for USPS package ids
60
+ # @return [Regexp] the regular expression
61
+ # @api private
62
+ def self.package_id_matchers
63
+ [ /^E\D{1}\d{9}\D{2}$|^9\d{15,21}$/ ]
64
+ end
60
65
 
61
66
  # The required options for tracking a UPS package
62
- # @return [Array] the required options for tracking a UPS package.
67
+ # @return [Array] the required options for tracking a UPS package
63
68
  # @api private
64
- def required_options
69
+ def self.required_options
65
70
  [:user_id]
66
71
  end
67
72
 
73
+ protected
74
+
68
75
  # Builds an XML request to send to USPS
69
76
  # @return [String] the xml request
70
77
  # @api private
@@ -0,0 +1,34 @@
1
+ require 'spec_helper'
2
+
3
+ class TestBaseClass < Trackerific::Base
4
+ def self.required_options
5
+ [:required, :also_required]
6
+ end
7
+ end
8
+
9
+ describe 'Trackerific::Base' do
10
+
11
+ before(:all) do
12
+ @base = Trackerific::Base.new
13
+ end
14
+
15
+ context "with a new Trackerific::Base class that has required options" do
16
+ context "has all the required options" do
17
+ it "should be able to create a new instance" do
18
+ t = TestBaseClass.new(:required => true, :also_required => :yup)
19
+ t.should be_a TestBaseClass
20
+ end
21
+ end
22
+ context "is missing some required options" do
23
+ it "should raise an ArgumentError" do
24
+ lambda { TestBaseClass.new() }.should raise_error(ArgumentError)
25
+ end
26
+ end
27
+ context "has an invalid option" do
28
+ it "should raise an ArgumentError" do
29
+ lambda { TestBaseClass.new(:unknown => :argument ) }.should raise_error(ArgumentError)
30
+ end
31
+ end
32
+ end
33
+
34
+ end
@@ -0,0 +1,5 @@
1
+ require 'spec_helper'
2
+
3
+ describe 'Trackerific::Error' do
4
+ # nothing to do here, yet
5
+ end
@@ -6,19 +6,27 @@ FEDEX_TRACK_URL = "https://gateway.fedex.com/GatewayDC"
6
6
  describe "Trackerific::FedEx" do
7
7
  include Fixtures
8
8
 
9
- before(:all) do
10
- @package_id = "183689015000001"
11
- @fedex = Trackerific::FedEx.new :account => "123456789", :meter => "123456789"
9
+ describe :required_options do
10
+ subject { Trackerific::FedEx.required_options }
11
+ it { should include(:account) }
12
+ it { should include(:meter) }
12
13
  end
13
14
 
14
- describe "track_package" do
15
+ describe :package_id_matchers do
16
+ it "should be an Array of Regexp" do
17
+ Trackerific::FedEx.package_id_matchers.should each { |m| m.should be_a Regexp }
18
+ end
19
+ end
20
+
21
+ describe :track_package do
22
+ before(:all) do
23
+ @package_id = "183689015000001"
24
+ @fedex = Trackerific::FedEx.new :account => "123456789", :meter => "123456789"
25
+ end
26
+
15
27
  context "with a successful response from the server" do
16
28
  before(:each) do
17
- FakeWeb.register_uri(
18
- :post,
19
- FEDEX_TRACK_URL,
20
- :body => load_fixture(:fedex_success_response)
21
- )
29
+ FakeWeb.register_uri(:post, FEDEX_TRACK_URL, :body => load_fixture(:fedex_success_response))
22
30
  @tracking = @fedex.track_package(@package_id)
23
31
  end
24
32
  specify { @tracking.should be_a Trackerific::Details }
@@ -29,13 +37,10 @@ describe "Trackerific::FedEx" do
29
37
  @tracking.summary.should_not be_empty
30
38
  end
31
39
  end
40
+
32
41
  context "with an error response from the server" do
33
42
  before(:all) do
34
- FakeWeb.register_uri(
35
- :post,
36
- FEDEX_TRACK_URL,
37
- :body => load_fixture(:fedex_error_response)
38
- )
43
+ FakeWeb.register_uri(:post, FEDEX_TRACK_URL, :body => load_fixture(:fedex_error_response))
39
44
  end
40
45
  specify { lambda { @fedex.track_package("invalid package id") }.should raise_error(Trackerific::Error) }
41
46
  end
@@ -6,19 +6,28 @@ UPS_TRACK_URL = 'https://wwwcie.ups.com/ups.app/xml/Track'
6
6
  describe "Trackerific::UPS" do
7
7
  include Fixtures
8
8
 
9
- before(:all) do
10
- @package_id = '1Z12345E0291980793'
11
- @ups = Trackerific::UPS.new :key => 'testkey', :user_id => 'testuser', :password => 'secret'
9
+ describe :required_options do
10
+ subject { Trackerific::UPS.required_options }
11
+ it { should include(:key) }
12
+ it { should include(:user_id) }
13
+ it { should include(:password) }
12
14
  end
13
15
 
14
- describe "track_package" do
16
+ describe :package_id_matchers do
17
+ it "should be an Array of Regexp" do
18
+ Trackerific::UPS.package_id_matchers.should each { |m| m.should be_a Regexp }
19
+ end
20
+ end
21
+
22
+ describe :track_package do
23
+ before(:all) do
24
+ @package_id = '1Z12345E0291980793'
25
+ @ups = Trackerific::UPS.new :key => 'testkey', :user_id => 'testuser', :password => 'secret'
26
+ end
27
+
15
28
  context "with a successful response from the server" do
16
29
  before(:all) do
17
- FakeWeb.register_uri(
18
- :post,
19
- UPS_TRACK_URL,
20
- :body => load_fixture(:ups_success_response)
21
- )
30
+ FakeWeb.register_uri(:post, UPS_TRACK_URL, :body => load_fixture(:ups_success_response))
22
31
  @tracking = @ups.track_package(@package_id)
23
32
  end
24
33
  specify { @tracking.should be_a Trackerific::Details }
@@ -29,13 +38,10 @@ describe "Trackerific::UPS" do
29
38
  @tracking.summary.should_not be_empty
30
39
  end
31
40
  end
41
+
32
42
  context "with an error response from the server" do
33
43
  before(:all) do
34
- FakeWeb.register_uri(
35
- :post,
36
- UPS_TRACK_URL,
37
- :body => load_fixture(:ups_error_response)
38
- )
44
+ FakeWeb.register_uri(:post, UPS_TRACK_URL, :body => load_fixture(:ups_error_response))
39
45
  end
40
46
  specify { lambda { @ups.track_package("invalid package id") }.should raise_error(Trackerific::Error) }
41
47
  end