trackerific 0.2.1 → 0.3.0
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/.yardoc/checksums +6 -0
- data/.yardoc/objects/root.dat +0 -0
- data/.yardoc/proxy_types +0 -0
- data/VERSION +1 -1
- data/doc/Trackerific.html +258 -0
- data/doc/Trackerific/Base.html +390 -0
- data/doc/Trackerific/Details.html +514 -0
- data/doc/Trackerific/Error.html +127 -0
- data/doc/Trackerific/Event.html +601 -0
- data/doc/Trackerific/FedEx.html +395 -0
- data/doc/Trackerific/UPS.html +360 -0
- data/doc/Trackerific/USPS.html +453 -0
- data/doc/_index.html +195 -0
- data/doc/class_list.html +47 -0
- data/doc/css/common.css +1 -0
- data/doc/css/full_list.css +53 -0
- data/doc/css/style.css +320 -0
- data/doc/file.README.html +213 -0
- data/doc/file_list.html +49 -0
- data/doc/frames.html +13 -0
- data/doc/index.html +213 -0
- data/doc/js/app.js +205 -0
- data/doc/js/full_list.js +150 -0
- data/doc/js/jquery.js +16 -0
- data/doc/method_list.html +206 -0
- data/doc/top-level-namespace.html +103 -0
- data/lib/fedex.rb +17 -7
- data/lib/trackerific.rb +16 -2
- data/lib/trackerific_details.rb +30 -0
- data/lib/trackerific_event.rb +38 -0
- data/lib/ups.rb +40 -14
- data/lib/usps.rb +28 -5
- data/spec/lib/fedex_spec.rb +8 -10
- data/spec/lib/trackerific_details_spec.rb +19 -0
- data/spec/lib/trackerific_event_spec.rb +20 -0
- data/spec/lib/ups_spec.rb +8 -6
- data/spec/lib/usps_spec.rb +8 -10
- data/trackerific.gemspec +32 -1
- metadata +35 -4
@@ -0,0 +1,103 @@
|
|
1
|
+
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
2
|
+
"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
3
|
+
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
|
4
|
+
<head>
|
5
|
+
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
6
|
+
<title>
|
7
|
+
Top Level Namespace
|
8
|
+
|
9
|
+
— Documentation by YARD 0.7.1
|
10
|
+
|
11
|
+
</title>
|
12
|
+
|
13
|
+
<link rel="stylesheet" href="css/style.css" type="text/css" media="screen" charset="utf-8" />
|
14
|
+
|
15
|
+
<link rel="stylesheet" href="css/common.css" type="text/css" media="screen" charset="utf-8" />
|
16
|
+
|
17
|
+
<script type="text/javascript" charset="utf-8">
|
18
|
+
relpath = '';
|
19
|
+
if (relpath != '') relpath += '/';
|
20
|
+
</script>
|
21
|
+
|
22
|
+
<script type="text/javascript" charset="utf-8" src="js/jquery.js"></script>
|
23
|
+
|
24
|
+
<script type="text/javascript" charset="utf-8" src="js/app.js"></script>
|
25
|
+
|
26
|
+
|
27
|
+
</head>
|
28
|
+
<body>
|
29
|
+
<script type="text/javascript" charset="utf-8">
|
30
|
+
if (window.top.frames.main) document.body.className = 'frames';
|
31
|
+
</script>
|
32
|
+
|
33
|
+
<div id="header">
|
34
|
+
<div id="menu">
|
35
|
+
|
36
|
+
<a href="_index.html">Index</a> »
|
37
|
+
|
38
|
+
|
39
|
+
<span class="title">Top Level Namespace</span>
|
40
|
+
|
41
|
+
|
42
|
+
<div class="noframes"><span class="title">(</span><a href="." target="_top">no frames</a><span class="title">)</span></div>
|
43
|
+
</div>
|
44
|
+
|
45
|
+
<div id="search">
|
46
|
+
|
47
|
+
<a id="class_list_link" href="#">Class List</a>
|
48
|
+
|
49
|
+
<a id="method_list_link" href="#">Method List</a>
|
50
|
+
|
51
|
+
<a id="file_list_link" href="#">File List</a>
|
52
|
+
|
53
|
+
</div>
|
54
|
+
<div class="clear"></div>
|
55
|
+
</div>
|
56
|
+
|
57
|
+
<iframe id="search_frame"></iframe>
|
58
|
+
|
59
|
+
<div id="content"><h1>Top Level Namespace
|
60
|
+
|
61
|
+
|
62
|
+
|
63
|
+
</h1>
|
64
|
+
|
65
|
+
<dl class="box">
|
66
|
+
|
67
|
+
|
68
|
+
|
69
|
+
|
70
|
+
|
71
|
+
|
72
|
+
|
73
|
+
|
74
|
+
</dl>
|
75
|
+
<div class="clear"></div>
|
76
|
+
|
77
|
+
<h2>Defined Under Namespace</h2>
|
78
|
+
<p class="children">
|
79
|
+
|
80
|
+
|
81
|
+
<strong class="modules">Modules:</strong> <span class='object_link'><a href="Trackerific.html" title="Trackerific (module)">Trackerific</a></span>
|
82
|
+
|
83
|
+
|
84
|
+
|
85
|
+
|
86
|
+
</p>
|
87
|
+
|
88
|
+
|
89
|
+
|
90
|
+
|
91
|
+
|
92
|
+
|
93
|
+
|
94
|
+
</div>
|
95
|
+
|
96
|
+
<div id="footer">
|
97
|
+
Generated on Mon Jun 13 13:53:34 2011 by
|
98
|
+
<a href="http://yardoc.org" title="Yay! A Ruby Documentation Tool" target="_parent">yard</a>
|
99
|
+
0.7.1 (ruby-1.9.2).
|
100
|
+
</div>
|
101
|
+
|
102
|
+
</body>
|
103
|
+
</html>
|
data/lib/fedex.rb
CHANGED
@@ -2,15 +2,23 @@ require 'httparty'
|
|
2
2
|
|
3
3
|
module Trackerific
|
4
4
|
|
5
|
+
# Provides package tracking support for FedEx
|
5
6
|
class FedEx < Base
|
6
7
|
include ::HTTParty
|
7
8
|
format :xml
|
8
9
|
base_uri "https://gateway.fedex.com"
|
9
10
|
|
11
|
+
# @return [Array] required options for tracking a FedEx package are :account
|
12
|
+
# and :meter.
|
10
13
|
def required_options
|
11
14
|
[:account, :meter]
|
12
15
|
end
|
13
16
|
|
17
|
+
# Tracks a FedEx package.
|
18
|
+
#
|
19
|
+
# A Trackerific::Error is raised when a package cannot be tracked.
|
20
|
+
#
|
21
|
+
# @return [Trackerific::Details] the tracking details
|
14
22
|
def track_package(package_id)
|
15
23
|
super
|
16
24
|
http_response = self.class.post "/GatewayDC", :body => build_xml_request
|
@@ -22,23 +30,25 @@ module Trackerific
|
|
22
30
|
details = track_reply["Package"]
|
23
31
|
events = []
|
24
32
|
details["Event"].each do |e|
|
25
|
-
date = Time.parse("#{e["Date"]} #{e["Time"]}")
|
33
|
+
date = Time.parse("#{e["Date"]} #{e["Time"]}")
|
26
34
|
desc = e["Description"]
|
27
35
|
addr = e["Address"]
|
28
36
|
# Adds event in this format:
|
29
37
|
# MM DD HH:MM am/pm Description City State Zip
|
30
|
-
events <<
|
38
|
+
events << Trackerific::Event.new(date, desc, "#{addr["StateOrProvinceCode"]} #{addr["PostalCode"]}")
|
31
39
|
end
|
32
40
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
41
|
+
Details.new(
|
42
|
+
details["TrackingNumber"],
|
43
|
+
details["StatusDescription"],
|
44
|
+
events
|
45
|
+
)
|
38
46
|
end
|
39
47
|
|
40
48
|
protected
|
41
49
|
|
50
|
+
# Builds the XML request to send to FedEx
|
51
|
+
# @return [String] a FDXTrack2Request XML
|
42
52
|
def build_xml_request
|
43
53
|
xml = ""
|
44
54
|
xmlns_api = "http://www.fedex.com/fsmapi"
|
data/lib/trackerific.rb
CHANGED
@@ -1,9 +1,13 @@
|
|
1
|
+
# Trackerific is a UPS, FedEx and USPS tracking provider.
|
1
2
|
module Trackerific
|
2
3
|
require 'rails'
|
4
|
+
require 'trackerific_details'
|
5
|
+
require 'trackerific_event'
|
3
6
|
|
4
|
-
|
5
|
-
end
|
7
|
+
# Raised if something other than tracking information is returned.
|
8
|
+
class Error < StandardError; end
|
6
9
|
|
10
|
+
# Base class for Trackerific package tracking services.
|
7
11
|
class Base
|
8
12
|
def initialize(options = {})
|
9
13
|
required = required_options
|
@@ -16,10 +20,14 @@ module Trackerific
|
|
16
20
|
@options = options
|
17
21
|
end
|
18
22
|
|
23
|
+
# Override this method if your subclass has required options.
|
24
|
+
# @return [Array] the required options
|
19
25
|
def required_options
|
20
26
|
[]
|
21
27
|
end
|
22
28
|
|
29
|
+
# Override this method in your subclass to implement tracking a package.
|
30
|
+
# @return [Hash] the tracking details
|
23
31
|
def track_package(package_id)
|
24
32
|
@package_id = package_id
|
25
33
|
end
|
@@ -29,6 +37,12 @@ module Trackerific
|
|
29
37
|
require 'fedex'
|
30
38
|
require 'ups'
|
31
39
|
|
40
|
+
# Checks a string for a valid package identifier, and returns a Trackerific
|
41
|
+
# class that should be able to track the package.
|
42
|
+
#
|
43
|
+
# @param [String] the package identifier.
|
44
|
+
# @return [Trackerific::Base] the Trackerific class that can track the given
|
45
|
+
# package id, or nil if none found.
|
32
46
|
def tracking_service(package_id)
|
33
47
|
case package_id
|
34
48
|
when /^.Z/, /^[HK].{10}$/ then Trackerific::UPS
|
@@ -0,0 +1,30 @@
|
|
1
|
+
module Trackerific
|
2
|
+
# Details returned when tracking a package. Stores the package identifier,
|
3
|
+
# a summary, and the events.
|
4
|
+
class Details
|
5
|
+
# Provides a new instance of Details
|
6
|
+
# @param [String] the package identifier
|
7
|
+
# @param [String] a summary of the tracking status
|
8
|
+
# @param [Array, Trackerific::Event] the tracking events
|
9
|
+
def initialize(package_id, summary, events)
|
10
|
+
@package_id = package_id
|
11
|
+
@summary = summary
|
12
|
+
@events = events
|
13
|
+
end
|
14
|
+
|
15
|
+
# @return [String] the package identifier
|
16
|
+
def package_id
|
17
|
+
@package_id
|
18
|
+
end
|
19
|
+
|
20
|
+
# @return [String] a summary of the tracking status
|
21
|
+
def summary
|
22
|
+
@summary
|
23
|
+
end
|
24
|
+
|
25
|
+
# @return [Array, Trackerific::Event] the tracking events
|
26
|
+
def events
|
27
|
+
@events
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,38 @@
|
|
1
|
+
module Trackerific
|
2
|
+
# Provides details for a tracking event
|
3
|
+
class Event
|
4
|
+
# Provides a new instance of Event
|
5
|
+
# @param [Time] the date / time of the event
|
6
|
+
# @param [String] the event's description
|
7
|
+
# @param [String] where the event took place
|
8
|
+
def initialize(date, description, location)
|
9
|
+
@date = date
|
10
|
+
@description = description
|
11
|
+
@location = location
|
12
|
+
end
|
13
|
+
|
14
|
+
# @return [Time] the date / time of the event
|
15
|
+
def date
|
16
|
+
@date
|
17
|
+
end
|
18
|
+
|
19
|
+
# @return [String] the event's description.
|
20
|
+
def description
|
21
|
+
@description
|
22
|
+
end
|
23
|
+
|
24
|
+
# @return [String] where the event took place (usually in City State Zip
|
25
|
+
# format)
|
26
|
+
def location
|
27
|
+
@location
|
28
|
+
end
|
29
|
+
|
30
|
+
# @return [String] converts the event into a string
|
31
|
+
def to_s
|
32
|
+
dte = self.date.strftime('%b %d %I:%M %P')
|
33
|
+
des = self.description
|
34
|
+
loc = self.location
|
35
|
+
"#{dte} #{des} #{loc}"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
data/lib/ups.rb
CHANGED
@@ -1,6 +1,9 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
1
3
|
module Trackerific
|
2
4
|
require 'httparty'
|
3
5
|
|
6
|
+
# Provides package tracking support for UPS.
|
4
7
|
class UPS < Base
|
5
8
|
include ::HTTParty
|
6
9
|
format :xml
|
@@ -9,14 +12,25 @@ module Trackerific
|
|
9
12
|
when 'production' then 'https://www.ups.com/ups.app/xml'
|
10
13
|
end : 'https://www.ups.com/ups.app/xml'
|
11
14
|
|
15
|
+
# The required options for tracking a UPS package are :key, :user_id, and
|
16
|
+
# :password.
|
17
|
+
#
|
18
|
+
# @return [Array] the required options for tracking a UPS package.
|
12
19
|
def required_options
|
13
20
|
[:key, :user_id, :password]
|
14
21
|
end
|
15
22
|
|
23
|
+
# Tracks a UPS package.
|
24
|
+
# A Trackerific::Error is raised when a package cannot be tracked.
|
25
|
+
# @return [Trackerific::Details] the tracking details
|
16
26
|
def track_package(package_id)
|
17
27
|
super
|
28
|
+
# connect to UPS via HTTParty
|
18
29
|
http_response = self.class.post('/Track', :body => build_xml_request)
|
30
|
+
# throw any HTTP errors
|
19
31
|
http_response.error! unless http_response.code == 200
|
32
|
+
# Check the response for errors, return a Trackerific::Error, or parse
|
33
|
+
# the response from UPS and return a Trackerific::Details
|
20
34
|
case http_response['TrackResponse']['Response']['ResponseStatusCode']
|
21
35
|
when "0" then raise Trackerific::Error, parse_error_response(http_response)
|
22
36
|
when "1" then return parse_success_response(http_response)
|
@@ -26,32 +40,44 @@ module Trackerific
|
|
26
40
|
|
27
41
|
protected
|
28
42
|
|
43
|
+
# Parses the response from UPS
|
44
|
+
# @return [Trackerific::Details]
|
29
45
|
def parse_success_response(http_response)
|
46
|
+
# get the activity from the UPS response
|
30
47
|
activity = http_response['TrackResponse']['Shipment']['Package']['Activity']
|
48
|
+
# if there's only one activity in the list, we need to put it in an array
|
31
49
|
activity = [activity] if activity.is_a? Hash
|
50
|
+
# UPS does not provide a summary, so we'll just use the last tracking status
|
51
|
+
summary = activity.first['Status']['StatusType']['Description'].titleize
|
32
52
|
details = []
|
33
53
|
activity.each do |a|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
54
|
+
# the time format from UPS is HHMMSS, which cannot be directly converted
|
55
|
+
# to a Ruby time.
|
56
|
+
hours = a['Time'][0..1]
|
57
|
+
minutes = a['Time'][2..3]
|
58
|
+
seconds = a['Time'][4..5]
|
59
|
+
date = Date.parse(a['Date'])
|
60
|
+
date = DateTime.parse("#{date} #{hours}:#{minutes}:#{seconds}")
|
61
|
+
desc = a['Status']['StatusType']['Description'].titleize
|
62
|
+
loc = a['ActivityLocation']['Address'].map {|k,v| v}.join(" ")
|
63
|
+
details << Trackerific::Event.new(date, desc, loc)
|
40
64
|
end
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
:details => details.reverse
|
48
|
-
}
|
65
|
+
|
66
|
+
Trackerific::Details.new(
|
67
|
+
@package_id,
|
68
|
+
summary,
|
69
|
+
details
|
70
|
+
)
|
49
71
|
end
|
50
72
|
|
73
|
+
# Parses a UPS tracking response, and returns any errors.
|
74
|
+
# @return [String] the UPS tracking error
|
51
75
|
def parse_error_response(http_response)
|
52
76
|
http_response['TrackResponse']['Response']['Error']['ErrorDescription']
|
53
77
|
end
|
54
78
|
|
79
|
+
# Builds the XML request to send to UPS for tracking a package.
|
80
|
+
# @return [String] the XML request
|
55
81
|
def build_xml_request
|
56
82
|
xml = ""
|
57
83
|
builder = ::Builder::XmlMarkup.new(:target => xml)
|
data/lib/usps.rb
CHANGED
@@ -1,7 +1,10 @@
|
|
1
|
+
require 'date'
|
2
|
+
|
1
3
|
module Trackerific
|
2
4
|
require 'builder'
|
3
5
|
require 'httparty'
|
4
6
|
|
7
|
+
# Provides package tracking support for USPS.
|
5
8
|
class USPS < Base
|
6
9
|
include HTTParty
|
7
10
|
format :xml
|
@@ -15,10 +18,16 @@ module Trackerific
|
|
15
18
|
@options = options
|
16
19
|
end
|
17
20
|
|
21
|
+
# The required option for tracking a UPS package is :user_id
|
22
|
+
#
|
23
|
+
# @return [Array] the required options for tracking a UPS package.
|
18
24
|
def required_options
|
19
25
|
[:user_id]
|
20
26
|
end
|
21
27
|
|
28
|
+
# Tracks a USPS package.
|
29
|
+
# A Trackerific::Error is raised when a package cannot be tracked.
|
30
|
+
# @return [Trackerific::Details] the tracking details
|
22
31
|
def track_package(package_id)
|
23
32
|
super
|
24
33
|
response = self.class.get('/ShippingAPITest.dll', :query => {:API => 'TrackV2', :XML => build_xml_request}.to_query)
|
@@ -26,15 +35,29 @@ module Trackerific
|
|
26
35
|
raise Trackerific::Error, response['Error']['Description'] unless response['Error'].nil?
|
27
36
|
raise Trackerific::Error, "Tracking information not found in response from server." if response['TrackResponse'].nil?
|
28
37
|
tracking_info = response['TrackResponse']['TrackInfo']
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
:
|
33
|
-
|
38
|
+
details = []
|
39
|
+
tracking_info['TrackDetail'].each do |d|
|
40
|
+
# each tracking detail is a string in this format:
|
41
|
+
# MM DD HH:MM am/pm DESCRIPTION CITY STATE ZIP.
|
42
|
+
# unfortunately, it will not be possible to tell the difference between
|
43
|
+
# the location, and the summary. So, for USPS, the location will be in
|
44
|
+
# the summary
|
45
|
+
d = d.split(" ")
|
46
|
+
date = DateTime.parse(d[0..3].join(" "))
|
47
|
+
desc = d[4..d.length].join(" ")
|
48
|
+
details << Trackerific::Event.new(date, desc, "")
|
49
|
+
end
|
50
|
+
Trackerific::Details.new(
|
51
|
+
tracking_info['ID'],
|
52
|
+
tracking_info['TrackSummary'],
|
53
|
+
details
|
54
|
+
)
|
34
55
|
end
|
35
56
|
|
36
57
|
protected
|
37
58
|
|
59
|
+
# Parses the response from UPS
|
60
|
+
# @return [Trackerific::Details]
|
38
61
|
def build_xml_request
|
39
62
|
tracking_request = ""
|
40
63
|
builder = ::Builder::XmlMarkup.new(:target => tracking_request)
|
data/spec/lib/fedex_spec.rb
CHANGED
@@ -19,17 +19,15 @@ describe "Trackerific::FedEx" do
|
|
19
19
|
FEDEX_TRACK_URL,
|
20
20
|
:body => load_fixture(:fedex_success_response)
|
21
21
|
)
|
22
|
-
@
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
-
|
30
|
-
}
|
22
|
+
@tracking = @fedex.track_package(@package_id)
|
23
|
+
end
|
24
|
+
specify { @tracking.should be_a Trackerific::Details }
|
25
|
+
it "should have at least one event" do
|
26
|
+
@tracking.events.length.should >= 1
|
27
|
+
end
|
28
|
+
it "should have a summary" do
|
29
|
+
@tracking.summary.should_not be_empty
|
31
30
|
end
|
32
|
-
specify { @fedex.track_package(@package_id).should eq @valid_response }
|
33
31
|
end
|
34
32
|
context "with an error response from the server" do
|
35
33
|
before(:all) do
|