stalkr 0.9.0 → 0.9.1
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/VERSION +1 -1
- data/lib/stalkr.rb +7 -4
- data/lib/stalkr/error.rb +16 -0
- data/lib/stalkr/fedex.rb +38 -52
- data/lib/stalkr/ups.rb +42 -35
- data/lib/stalkr/usps.rb +50 -40
- data/test/stalkr/fedex_test.rb +20 -0
- data/test/stalkr/usps_test.rb +6 -0
- metadata +5 -4
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.9.
|
1
|
+
0.9.1
|
data/lib/stalkr.rb
CHANGED
@@ -11,6 +11,8 @@ require 'date'
|
|
11
11
|
|
12
12
|
require 'stalkr/base'
|
13
13
|
require 'stalkr/result'
|
14
|
+
require 'stalkr/error'
|
15
|
+
|
14
16
|
require 'stalkr/ups'
|
15
17
|
require 'stalkr/usps'
|
16
18
|
require 'stalkr/fedex'
|
@@ -23,16 +25,17 @@ if not DateTime.new.public_methods.include? "to_time" then
|
|
23
25
|
t = d.instance_eval do
|
24
26
|
Time.utc(year, mon, mday, hour, min, sec +
|
25
27
|
sec_fraction)
|
26
|
-
end
|
28
|
+
end
|
29
|
+
t.getlocal
|
27
30
|
end
|
28
31
|
end
|
29
32
|
end
|
30
33
|
|
31
34
|
module Stalkr
|
32
35
|
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
+
def self.shippers
|
37
|
+
return [ Stalkr::UPS, Stalkr::USPS, Stalkr::FEDEX ]
|
38
|
+
end
|
36
39
|
|
37
40
|
def self.track(id)
|
38
41
|
shipper = nil
|
data/lib/stalkr/error.rb
ADDED
data/lib/stalkr/fedex.rb
CHANGED
@@ -6,7 +6,7 @@ module Stalkr
|
|
6
6
|
|
7
7
|
class FEDEX < Base
|
8
8
|
|
9
|
-
self.regex = /\b((96\d\d\d\d\d ?\d\d\d\d|96\d\d) ?\d\d\d\d ?d\d\d\d( ?\d\d\d)?)
|
9
|
+
self.regex = /\b((96\d\d\d\d\d ?\d\d\d\d|96\d\d) ?\d\d\d\d ?d\d\d\d( ?\d\d\d)?)\b|\b(\d{12}|\d{15})\b/i
|
10
10
|
|
11
11
|
def track(id)
|
12
12
|
|
@@ -15,68 +15,54 @@ class FEDEX < Base
|
|
15
15
|
url.gsub!(/%CODE%/, id)
|
16
16
|
html = fetchurl(url)
|
17
17
|
|
18
|
-
|
19
|
-
ret = Result.new(:FEDEX)
|
20
|
-
ret.status = UNKNOWN
|
21
|
-
return ret
|
22
|
-
end
|
18
|
+
begin
|
23
19
|
|
24
|
-
|
20
|
+
if html =~ /invalid._header/ then
|
21
|
+
ret = Result.new(:FEDEX)
|
22
|
+
ret.status = UNKNOWN
|
23
|
+
return ret
|
24
|
+
end
|
25
25
|
|
26
|
-
|
26
|
+
info_scraper = Scraper.define do
|
27
27
|
|
28
|
-
|
29
|
-
process "div.detailshipdates > div.fielddata", :dates => :text
|
30
|
-
process "div.detaildestination > div.fielddata", :destination => :text
|
31
|
-
process_first "div.detailshipfacts div.dataentry", :service_type => :text
|
28
|
+
array :dates
|
32
29
|
|
33
|
-
|
30
|
+
process "div.detailshipmentstatus", :status => :text
|
31
|
+
process "div.detailshipdates > div.fielddata", :dates => :text
|
32
|
+
process "div.detaildestination > div.fielddata", :destination => :text
|
33
|
+
process_first "div.detailshipfacts div.dataentry", :service_type => :text
|
34
34
|
|
35
|
-
|
35
|
+
result :status, :dates, :destination, :service_type
|
36
36
|
|
37
|
-
|
37
|
+
end
|
38
38
|
|
39
|
-
|
39
|
+
ret = Result.new(:FEDEX)
|
40
40
|
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
41
|
+
info = info_scraper.scrape(html)
|
42
|
+
|
43
|
+
if info.status.strip.downcase == "delivered" then
|
44
|
+
ret.status = DELIVERED
|
45
|
+
end
|
46
|
+
ret.location = info.destination.strip
|
47
|
+
|
48
|
+
# obj.service_type = info.service_type.strip
|
49
|
+
|
50
|
+
# try to get dates
|
51
|
+
shipped_date = info.dates[0].strip
|
52
|
+
delivery_date = info.dates[1].strip if info.dates.length == 2
|
53
|
+
if shipped_date.empty? then
|
54
|
+
shipped_date = DateTime.strptime( $1, "%b %d, %Y" ).to_time if html =~ /var shipDate = "(.*?);$"/
|
55
|
+
delivery_date = DateTime.strptime( "#{$1} -5", "%b %d, %Y %I:%M %p %z" ).to_time if html =~ /var deliveryDateTime = "(.*?)";$/
|
56
|
+
end
|
57
|
+
ret.delivered_at = delivery_date
|
58
|
+
ret.updated_at = delivery_date
|
59
|
+
|
60
|
+
return ret
|
45
61
|
|
46
|
-
|
62
|
+
rescue Exception => ex
|
63
|
+
raise Stalkr::Error.new(ex, html)
|
47
64
|
|
48
|
-
# try to get dates
|
49
|
-
shipped_date = info.dates[0].strip
|
50
|
-
delivery_date = info.dates[1].strip if info.dates.length == 2
|
51
|
-
if shipped_date.empty? then
|
52
|
-
shipped_date = DateTime.strptime( $1, "%b %d, %Y" ).to_time if html =~ /var shipDate = "(.*?);$"/
|
53
|
-
delivery_date = DateTime.strptime( "#{$1} -5", "%b %d, %Y %I:%M %p %z" ).to_time if html =~ /var deliveryDateTime = "(.*?)";$/
|
54
65
|
end
|
55
|
-
ret.delivered_at = delivery_date
|
56
|
-
ret.updated_at = delivery_date
|
57
|
-
|
58
|
-
# pull progress from JSON
|
59
|
-
# if html =~ /^var detailInfoObject = (.*);$/ then
|
60
|
-
# json = $1
|
61
|
-
# progress = JSON.parse(json)
|
62
|
-
# scans = progress['scans']
|
63
|
-
#
|
64
|
-
# progress = []
|
65
|
-
#
|
66
|
-
# scans.each { |scan|
|
67
|
-
# o = OpenStruct.new
|
68
|
-
# o.location = scan['scanLocation']
|
69
|
-
# o.date = scan['scanDate']
|
70
|
-
# o.local_time = scan['scanTime']
|
71
|
-
# o.desc = scan['scanStatus']
|
72
|
-
# progress << o
|
73
|
-
# }
|
74
|
-
#
|
75
|
-
# obj.progress = progress
|
76
|
-
#
|
77
|
-
# end
|
78
|
-
|
79
|
-
return ret
|
80
66
|
|
81
67
|
end
|
82
68
|
|
data/lib/stalkr/ups.rb
CHANGED
@@ -25,53 +25,60 @@ class UPS < Base
|
|
25
25
|
url.gsub!(/%CODE%/, id)
|
26
26
|
html = fetchurl(url)
|
27
27
|
|
28
|
-
|
28
|
+
begin
|
29
29
|
|
30
|
-
|
31
|
-
array :vals
|
32
|
-
array :lists
|
30
|
+
detail_scraper = Scraper.define do
|
33
31
|
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
process "#fontControl dd", :vals => :text
|
38
|
-
process "#fontControl ul.clearfix li", :lists => :text
|
32
|
+
array :keys
|
33
|
+
array :vals
|
34
|
+
array :lists
|
39
35
|
|
40
|
-
|
36
|
+
process "#trkNum", :trackingNumber => :text
|
37
|
+
process "#tt_spStatus", :status => :text
|
38
|
+
process "#fontControl dt", :keys => :text
|
39
|
+
process "#fontControl dd", :vals => :text
|
40
|
+
process "#fontControl ul.clearfix li", :lists => :text
|
41
41
|
|
42
|
-
|
42
|
+
result :keys, :vals, :trackingNumber, :status, :lists
|
43
43
|
|
44
|
-
|
44
|
+
end
|
45
45
|
|
46
|
-
|
47
|
-
raise "UPS scraper failed"
|
48
|
-
end
|
46
|
+
details = detail_scraper.scrape(html)
|
49
47
|
|
50
|
-
|
48
|
+
if not details.trackingNumber then
|
49
|
+
raise "UPS scraper failed"
|
50
|
+
end
|
51
51
|
|
52
|
-
|
53
|
-
when "in transit"
|
54
|
-
IN_TRANSIT
|
55
|
-
when "delivered"
|
56
|
-
DELIVERED
|
57
|
-
else
|
58
|
-
UNKNOWN
|
59
|
-
end
|
52
|
+
ret = Result.new(:UPS)
|
60
53
|
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
54
|
+
ret.status = case details.status.strip.downcase
|
55
|
+
when "in transit"
|
56
|
+
IN_TRANSIT
|
57
|
+
when "delivered"
|
58
|
+
DELIVERED
|
59
|
+
else
|
60
|
+
UNKNOWN
|
61
|
+
end
|
65
62
|
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
63
|
+
hash = {}
|
64
|
+
details.keys.each_with_index do |k,i|
|
65
|
+
hash[k] = details.vals[i]
|
66
|
+
end
|
70
67
|
|
71
|
-
|
72
|
-
|
68
|
+
if ret.status == DELIVERED then
|
69
|
+
delivered_at = cleanup_html( hash["Delivered On:"] )
|
70
|
+
ret.delivered_at = DateTime.strptime( delivered_at, "%A, %m/%d/%Y at %I:%M %p" ).to_time
|
71
|
+
end
|
73
72
|
|
74
|
-
|
73
|
+
cleanup_html( details.lists[3] ) =~ /Updated: (.*?)$/
|
74
|
+
ret.updated_at = DateTime.strptime( $1, "%m/%d/%Y %I:%M %p" ).to_time
|
75
|
+
|
76
|
+
return ret
|
77
|
+
|
78
|
+
rescue Exception => ex
|
79
|
+
raise Stalkr::Error.new(ex, html)
|
80
|
+
|
81
|
+
end
|
75
82
|
|
76
83
|
end
|
77
84
|
|
data/lib/stalkr/usps.rb
CHANGED
@@ -3,8 +3,10 @@ module Stalkr
|
|
3
3
|
|
4
4
|
class USPS < Base
|
5
5
|
|
6
|
-
# 20 or 22 digits, beginning with 91 (and with or without spaces between groupings)
|
7
|
-
|
6
|
+
# 1) 20 or 22 digits, beginning with 91 (and with or without spaces between groupings)
|
7
|
+
# 2) 20 digits (no real pattern)
|
8
|
+
# TODO: 2nd pattern is too generic. Could also match other carriers.
|
9
|
+
self.regex = /\b(91\d{2} ?\d{4} ?\d{4} ?\d{4} ?\d{4} ?\d{2}|91\d{2} ?\d{4} ?\d{4} ?\d{4} ?\d{4})\b|\b(\d{20})\b/i
|
8
10
|
|
9
11
|
def track(id)
|
10
12
|
|
@@ -16,62 +18,70 @@ class USPS < Base
|
|
16
18
|
url.gsub!(/%CODE%/, id)
|
17
19
|
html = fetchurl(url)
|
18
20
|
|
19
|
-
|
21
|
+
begin
|
20
22
|
|
21
|
-
|
22
|
-
array :info
|
23
|
-
array :txt
|
23
|
+
info_scraper = Scraper.define do
|
24
24
|
|
25
|
-
|
26
|
-
|
27
|
-
|
25
|
+
array :details
|
26
|
+
array :info
|
27
|
+
array :txt
|
28
28
|
|
29
|
-
|
29
|
+
process "span.mainTextbold", :info => :text
|
30
|
+
process "td.mainTextbold", :details => :text
|
31
|
+
process "td.mainText", :txt => :text
|
30
32
|
|
31
|
-
|
33
|
+
result :details, :info, :txt
|
32
34
|
|
33
|
-
|
35
|
+
end
|
34
36
|
|
35
|
-
|
36
|
-
if scrape.info[0].gsub(/ /, '') != id then
|
37
|
-
raise "USPS scraper failed"
|
38
|
-
end
|
37
|
+
scrape = info_scraper.scrape(html)
|
39
38
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
elsif scrape.info.find{ |i| i.downcase == "delivered" } then
|
45
|
-
ret.status = DELIVERED
|
46
|
-
else
|
47
|
-
ret.status = UNKNOWN
|
48
|
-
end
|
39
|
+
# verify its the correct response page
|
40
|
+
if scrape.info[0].gsub(/ /, '') != id then
|
41
|
+
raise "USPS scraper failed"
|
42
|
+
end
|
49
43
|
|
50
|
-
|
51
|
-
|
52
|
-
|
44
|
+
# extract and return
|
45
|
+
ret = Result.new(:USPS)
|
46
|
+
if scrape.txt.find{ |t| t =~ /There is no record of this item/ } then
|
47
|
+
ret.status = UNKNOWN
|
48
|
+
elsif scrape.info.find{ |i| i.downcase == "delivered" } then
|
49
|
+
ret.status = DELIVERED
|
50
|
+
else
|
51
|
+
ret.status = UNKNOWN
|
52
|
+
end
|
53
|
+
|
54
|
+
if scrape.details and not scrape.details.empty? then
|
55
|
+
if scrape.details[0] =~ /^(.*?), (.*? \d+, \d+), (\d+:\d+ .m), (.*?)$/ then
|
56
|
+
ret.location = $4
|
57
|
+
# not sure if this time is always in EST or the time of the area in which it was delivered?
|
58
|
+
ret.updated_at = DateTime.strptime( "#{$2} #{$3} -0500", "%B %d, %Y %I:%M %p %z" ).to_time
|
59
|
+
if ret.status == DELIVERED then
|
60
|
+
ret.delivered_at = ret.updated_at
|
61
|
+
end
|
62
|
+
|
63
|
+
elsif scrape.details[0] =~ /Electronic Shipping Info Received/ then
|
64
|
+
ret.status = IN_TRANSIT
|
65
|
+
end
|
66
|
+
|
67
|
+
elsif s = scrape.txt.find{ |t| t =~ /files offline/ }
|
68
|
+
s =~ /at (\d+:\d+ .m) on (.*? \d+, \d+) in (.*?)\.$/
|
69
|
+
ret.location = $3
|
53
70
|
# not sure if this time is always in EST or the time of the area in which it was delivered?
|
54
|
-
ret.updated_at = DateTime.strptime( "#{$2} #{$
|
71
|
+
ret.updated_at = DateTime.strptime( "#{$2} #{$1} -0500", "%B %d, %Y %I:%M %p %z" ).to_time
|
55
72
|
if ret.status == DELIVERED then
|
56
73
|
ret.delivered_at = ret.updated_at
|
57
74
|
end
|
58
75
|
|
59
|
-
elsif scrape.details[0] =~ /Electronic Shipping Info Received/ then
|
60
|
-
ret.status = IN_TRANSIT
|
61
76
|
end
|
62
77
|
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
ret.updated_at = DateTime.strptime( "#{$2} #{$1} -0500", "%B %d, %Y %I:%M %p %z" ).to_time
|
68
|
-
if ret.status == DELIVERED then
|
69
|
-
ret.delivered_at = ret.updated_at
|
70
|
-
end
|
78
|
+
return ret
|
79
|
+
|
80
|
+
rescue Exception => ex
|
81
|
+
raise Stalkr::Error.new(ex, html)
|
71
82
|
|
72
83
|
end
|
73
84
|
|
74
|
-
return ret
|
75
85
|
end
|
76
86
|
|
77
87
|
end # class USPS
|
data/test/stalkr/fedex_test.rb
CHANGED
@@ -18,9 +18,29 @@ class FEDEX_Test < Test::Unit::TestCase
|
|
18
18
|
|
19
19
|
end
|
20
20
|
|
21
|
+
def test_track_bad_code_numeric
|
22
|
+
|
23
|
+
begin
|
24
|
+
id = "200793242831442"
|
25
|
+
info = Stalkr::FEDEX.new.track(id)
|
26
|
+
flunk("no exception raised")
|
27
|
+
|
28
|
+
rescue Exception => ex
|
29
|
+
assert(ex.kind_of? Stalkr::Error)
|
30
|
+
assert(!(ex.html.nil? || ex.html.empty?))
|
31
|
+
end
|
32
|
+
|
33
|
+
end
|
34
|
+
|
21
35
|
def test_extract_id
|
22
36
|
str = "asdf 106050761498748 asdfas"
|
23
37
|
assert(Stalkr::FEDEX.extract_id(str) == "106050761498748")
|
24
38
|
end
|
25
39
|
|
40
|
+
def test_should_not_extract
|
41
|
+
str = "Your tracking number is: 02185456301085740874. "
|
42
|
+
id = Stalkr::FEDEX.extract_id(str)
|
43
|
+
assert(id.nil?)
|
44
|
+
end
|
45
|
+
|
26
46
|
end
|
data/test/stalkr/usps_test.rb
CHANGED
@@ -30,4 +30,10 @@ class USPS_Test < Test::Unit::TestCase
|
|
30
30
|
assert(Stalkr::USPS.extract_id(str) == "9102901001299192824023")
|
31
31
|
end
|
32
32
|
|
33
|
+
def test_extract_id_2
|
34
|
+
str = "Your tracking number is: 02185456301085740874. "
|
35
|
+
id = Stalkr::USPS.extract_id(str)
|
36
|
+
assert(!id.nil? && id == "02185456301085740874")
|
37
|
+
end
|
38
|
+
|
33
39
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: stalkr
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
hash:
|
4
|
+
hash: 57
|
5
5
|
prerelease:
|
6
6
|
segments:
|
7
7
|
- 0
|
8
8
|
- 9
|
9
|
-
-
|
10
|
-
version: 0.9.
|
9
|
+
- 1
|
10
|
+
version: 0.9.1
|
11
11
|
platform: ruby
|
12
12
|
authors:
|
13
13
|
- Chetan Sarva
|
@@ -15,7 +15,7 @@ autorequire:
|
|
15
15
|
bindir: bin
|
16
16
|
cert_chain: []
|
17
17
|
|
18
|
-
date: 2011-02-
|
18
|
+
date: 2011-02-16 00:00:00 -05:00
|
19
19
|
default_executable:
|
20
20
|
dependencies:
|
21
21
|
- !ruby/object:Gem::Dependency
|
@@ -111,6 +111,7 @@ files:
|
|
111
111
|
- VERSION
|
112
112
|
- lib/stalkr.rb
|
113
113
|
- lib/stalkr/base.rb
|
114
|
+
- lib/stalkr/error.rb
|
114
115
|
- lib/stalkr/fedex.rb
|
115
116
|
- lib/stalkr/result.rb
|
116
117
|
- lib/stalkr/ups.rb
|