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.
- data/Gemfile +1 -0
- data/Gemfile.lock +40 -38
- data/README.rdoc +4 -9
- data/VERSION +1 -1
- data/doc/Trackerific.html +34 -22
- data/doc/Trackerific/Base.html +237 -20
- data/doc/Trackerific/Details.html +6 -6
- data/doc/Trackerific/Error.html +2 -2
- data/doc/Trackerific/Event.html +7 -7
- data/doc/Trackerific/FedEx.html +190 -3
- data/doc/Trackerific/UPS.html +190 -3
- data/doc/Trackerific/USPS.html +190 -3
- data/doc/_index.html +1 -1
- data/doc/file.README.html +6 -24
- data/doc/index.html +6 -24
- data/doc/method_list.html +68 -4
- data/doc/top-level-namespace.html +1 -1
- data/lib/trackerific.rb +37 -74
- data/lib/trackerific/base.rb +70 -0
- data/lib/{trackerific_details.rb → trackerific/details.rb} +0 -0
- data/lib/trackerific/error.rb +4 -0
- data/lib/{trackerific_event.rb → trackerific/event.rb} +0 -0
- data/lib/{fedex.rb → trackerific/services/fedex.rb} +9 -2
- data/lib/{ups.rb → trackerific/services/ups.rb} +10 -4
- data/lib/{usps.rb → trackerific/services/usps.rb} +10 -3
- data/spec/lib/trackerific/base_spec.rb +34 -0
- data/spec/lib/{trackerific_details_spec.rb → trackerific/details_spec.rb} +0 -0
- data/spec/lib/trackerific/error_spec.rb +5 -0
- data/spec/lib/{trackerific_event_spec.rb → trackerific/event_spec.rb} +0 -0
- data/spec/lib/{fedex_spec.rb → trackerific/services/fedex_spec.rb} +19 -14
- data/spec/lib/{ups_spec.rb → trackerific/services/ups_spec.rb} +20 -14
- data/spec/lib/{usps_spec.rb → trackerific/services/usps_spec.rb} +18 -14
- data/spec/lib/trackerific_spec.rb +7 -30
- data/spec/spec_helper.rb +1 -0
- data/trackerific.gemspec +18 -22
- metadata +38 -27
data/lib/trackerific.rb
CHANGED
@@ -1,71 +1,15 @@
|
|
1
|
-
|
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
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
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
|
File without changes
|
File without changes
|
@@ -45,16 +45,23 @@ module Trackerific
|
|
45
45
|
)
|
46
46
|
end
|
47
47
|
|
48
|
-
|
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
|
-
|
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
|
-
|
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
|
File without changes
|
File without changes
|
@@ -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
|
-
|
10
|
-
|
11
|
-
|
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
|
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
|
-
|
10
|
-
|
11
|
-
|
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
|
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
|