tracking_number 0.2.0 → 0.3.0
Sign up to get free protection for your applications and to get access to all the features.
- data/VERSION +1 -1
- data/lib/base.rb +49 -0
- data/lib/dhl.rb +19 -0
- data/lib/fedex.rb +130 -0
- data/lib/tracking_number.rb +18 -164
- data/lib/ups.rb +92 -0
- data/lib/usps.rb +127 -0
- data/test/test_dhl_tracking_number.rb +17 -0
- data/test/test_fedex_tracking_number.rb +58 -0
- data/test/test_helper.rb +19 -3
- data/test/test_tracking_number.rb +8 -80
- data/test/test_ups_tracking_number.rb +17 -0
- data/test/test_usps_tracking_number.rb +46 -0
- data/tracking_number.gemspec +17 -5
- metadata +41 -22
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.3.0
|
data/lib/base.rb
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
class TrackingNumber
|
2
|
+
class Base
|
3
|
+
attr_accessor :tracking_number
|
4
|
+
def initialize(tracking_number)
|
5
|
+
@original_number = tracking_number
|
6
|
+
@tracking_number = tracking_number.gsub(" ", "").upcase
|
7
|
+
end
|
8
|
+
|
9
|
+
def self.search(body)
|
10
|
+
self.scan(body).uniq.collect { |possible| new(possible) }.select { |t| t.valid? }
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.scan(body)
|
14
|
+
possibles = body.scan(self.const_get("SEARCH_PATTERN")).uniq.flatten
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid?
|
18
|
+
return false unless valid_format?
|
19
|
+
return false unless valid_checksum?
|
20
|
+
return true
|
21
|
+
end
|
22
|
+
|
23
|
+
def valid_format?
|
24
|
+
!matches.nil? && !matches.empty?
|
25
|
+
end
|
26
|
+
|
27
|
+
def decode
|
28
|
+
{}
|
29
|
+
end
|
30
|
+
|
31
|
+
def matches
|
32
|
+
[]
|
33
|
+
end
|
34
|
+
|
35
|
+
def valid_checksum?
|
36
|
+
false
|
37
|
+
end
|
38
|
+
|
39
|
+
def to_s
|
40
|
+
self.tracking_number
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
class Unknown < Base
|
45
|
+
def carrier
|
46
|
+
:unknown
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
data/lib/dhl.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
class TrackingNumber
|
2
|
+
class DHL < Base
|
3
|
+
SEARCH_PATTERN = /(\b([0-9]\s*){11,11}\b)/
|
4
|
+
VERIFY_PATTERN = /^([0-9]{10,10})([0-9])$/
|
5
|
+
def carrier
|
6
|
+
:dhl
|
7
|
+
end
|
8
|
+
|
9
|
+
def matches
|
10
|
+
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
11
|
+
end
|
12
|
+
|
13
|
+
def valid_checksum?
|
14
|
+
# standard mod 7 check
|
15
|
+
sequence, check_digit = matches
|
16
|
+
return true if sequence.to_i % 7 == check_digit.to_i
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
data/lib/fedex.rb
ADDED
@@ -0,0 +1,130 @@
|
|
1
|
+
class TrackingNumber
|
2
|
+
class FedEx < Base
|
3
|
+
def carrier
|
4
|
+
:fedex
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class FedExExpress < FedEx
|
9
|
+
SEARCH_PATTERN = /(\b([0-9]\s*){12,12}\b)/
|
10
|
+
VERIFY_PATTERN = /^([0-9]{11,11})([0-9])$/
|
11
|
+
LENGTH = 12
|
12
|
+
|
13
|
+
def matches
|
14
|
+
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
15
|
+
end
|
16
|
+
|
17
|
+
def valid_checksum?
|
18
|
+
sequence = tracking_number.chars.to_a
|
19
|
+
check = sequence.pop
|
20
|
+
total = 0
|
21
|
+
sequence.zip([3,1,7,3,1,7,3,1,7,3,1]).collect { |pair| pair[0].to_i * pair[1].to_i }.each { |t| total += t.to_i }
|
22
|
+
return (total % 11) == check.to_i
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
#TODO Fix these FedEx ground numberss
|
27
|
+
|
28
|
+
class FedExGround96 < FedEx
|
29
|
+
SEARCH_PATTERN = /(\b9\s*6\s*([0-9]\s*){20,20}\b)/
|
30
|
+
VERIFY_PATTERN = /^96[0-9]{5,5}([0-9]{14,14})([0-9])$/
|
31
|
+
LENGTH = 22
|
32
|
+
|
33
|
+
def matches
|
34
|
+
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
35
|
+
end
|
36
|
+
|
37
|
+
def decode
|
38
|
+
{:application_id => self.tracking_number.to_s.slice(0...2),
|
39
|
+
:serial_container => self.tracking_number.to_s.slice(2...4),
|
40
|
+
:service_code => self.tracking_number.to_s.slice(4...7),
|
41
|
+
:shipper_id => self.tracking_number.to_s.slice(7...14),
|
42
|
+
:package_identifier => self.tracking_number.to_s.slice(14...21),
|
43
|
+
:check_digit => self.tracking_number.slice(21...22)
|
44
|
+
}
|
45
|
+
end
|
46
|
+
|
47
|
+
def valid_checksum?
|
48
|
+
# 22 numbers
|
49
|
+
# http://fedex.com/us/solutions/ppe/FedEx_Ground_Label_Layout_Specification.pdf
|
50
|
+
# 96 - UCC/EAN Application Identifier
|
51
|
+
|
52
|
+
# [0-9]{2,2} - SCNC
|
53
|
+
# [0-9]{3,3} - Class Of Service
|
54
|
+
# [0-9]{7,7} - RPS Shipper ID (used in calculation)
|
55
|
+
# [0-9]{7,7} - Package Number (used in calculation)
|
56
|
+
# [0-9] - Check Digit
|
57
|
+
sequence, check_digit = matches
|
58
|
+
|
59
|
+
total = 0
|
60
|
+
sequence.chars.to_a.map(&:to_i).reverse.each_with_index do |x, i|
|
61
|
+
x *= 3 if i.even?
|
62
|
+
total += x
|
63
|
+
end
|
64
|
+
|
65
|
+
check = total % 10
|
66
|
+
check = (10 - check) unless (check.zero?)
|
67
|
+
return true if check == check_digit.to_i
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
class FedExGround < FedEx
|
72
|
+
SEARCH_PATTERN = /(\b([0-9]\s*){15,15}\b)/
|
73
|
+
VERIFY_PATTERN = /^([0-9]{15,15})$/
|
74
|
+
LENGTH = 15
|
75
|
+
|
76
|
+
def matches
|
77
|
+
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
78
|
+
end
|
79
|
+
|
80
|
+
def valid_checksum?
|
81
|
+
sequence = tracking_number.chars.to_a.map(&:to_i)
|
82
|
+
check_digit = sequence.pop
|
83
|
+
total = 0
|
84
|
+
sequence.reverse.each_with_index do |x, i|
|
85
|
+
x *= 3 if i.even?
|
86
|
+
total += x
|
87
|
+
end
|
88
|
+
check = total % 10
|
89
|
+
check = (10 - check) unless (check.zero?)
|
90
|
+
return true if check == check_digit.to_i
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
class FedExGround18 < FedEx
|
95
|
+
SEARCH_PATTERN = /(\b([0-9]\s*){18,18}\b)/
|
96
|
+
VERIFY_PATTERN = /^[0-9]{2,2}([0-9]{15,15})([0-9])$/
|
97
|
+
LENGTH = 20
|
98
|
+
|
99
|
+
def matches
|
100
|
+
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
101
|
+
end
|
102
|
+
|
103
|
+
def decode
|
104
|
+
{:application_id => self.tracking_number.to_s.slice(0...2),
|
105
|
+
:serial_container => self.tracking_number.to_s.slice(1...2),
|
106
|
+
:service_code => self.tracking_number.to_s.slice(2...3),
|
107
|
+
:shipper_id => self.tracking_number.to_s.slice(3...10),
|
108
|
+
:package_identifier => self.tracking_number.to_s.slice(10...17),
|
109
|
+
:check_digit => self.tracking_number.slice(17...18)
|
110
|
+
}
|
111
|
+
end
|
112
|
+
|
113
|
+
def valid_checksum?
|
114
|
+
# [0-9]{2,2} - Not used
|
115
|
+
# [0-9]{15, 15} - used for calculation
|
116
|
+
|
117
|
+
sequence = tracking_number.chars.to_a.map(&:to_i)
|
118
|
+
check_digit = sequence.pop
|
119
|
+
total = 0
|
120
|
+
sequence.reverse.each_with_index do |x, i|
|
121
|
+
x *= 3 if i.even?
|
122
|
+
total += x
|
123
|
+
end
|
124
|
+
check = total % 10
|
125
|
+
check = (10 - check) unless (check.zero?)
|
126
|
+
return true if check == check_digit.to_i
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
data/lib/tracking_number.rb
CHANGED
@@ -3,177 +3,31 @@
|
|
3
3
|
# Information on validating tracking numbers found here:
|
4
4
|
# http://answers.google.com/answers/threadview/id/207899.html
|
5
5
|
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
:fedex_ground_sscc18 => /(\b([0-9]\s*){18,18}\b)/,
|
12
|
-
:dhl => /(\b([0-9]\s*){11,11}\b)/,
|
13
|
-
:usps => /(\b([0-9]\s*){22,22}\b)/
|
14
|
-
}
|
15
|
-
|
16
|
-
VERIFY_PATTERNS = {
|
17
|
-
:ups => /^1Z(\w{15,15})(\w)$/,
|
18
|
-
:fedex_express => /^([0-9]{11,11})([0-9])$/,
|
19
|
-
:fedex_ground_96 => /^96[0-9]{5,5}([0-9]{14,14})([0-9])$/,
|
20
|
-
:fedex_ground_sscc18 => /^[0-9]{2,2}([0-9]{15,15})([0-9])$/,
|
21
|
-
:dhl => /^([0-9]{10,10})([0-9])$/,
|
22
|
-
:usps => /^([0-9]{21,21})([0-9])/
|
23
|
-
}
|
6
|
+
require 'base'
|
7
|
+
require 'usps'
|
8
|
+
require 'fedex'
|
9
|
+
require 'ups'
|
10
|
+
require 'dhl'
|
24
11
|
|
25
|
-
|
26
|
-
|
27
|
-
body.scan(pattern)
|
28
|
-
}.uniq.flatten
|
29
|
-
end
|
12
|
+
class TrackingNumber
|
13
|
+
TYPES = [UPS, FedExExpress, FedExGround, FedExGround18, FedExGround96, USPS91, USPS20, USPS13, DHL]
|
30
14
|
|
31
15
|
def self.search(body)
|
32
|
-
|
33
|
-
end
|
34
|
-
|
35
|
-
def initialize(tracking_number)
|
36
|
-
@original_number = tracking_number
|
37
|
-
@tracking_number = tracking_number.to_s.upcase.gsub(/\s/,"")
|
38
|
-
end
|
39
|
-
|
40
|
-
def valid?
|
41
|
-
carrier != :unknown
|
16
|
+
TYPES.collect { |type| type.search(body) }.flatten
|
42
17
|
end
|
43
18
|
|
44
|
-
def
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
:fedex
|
49
|
-
elsif fedex_ground_96?(@tracking_number)
|
50
|
-
:fedex
|
51
|
-
elsif fedex_ground_sscc18?(@tracking_number)
|
52
|
-
:fedex
|
53
|
-
elsif usps?(@tracking_number)
|
54
|
-
:usps
|
55
|
-
elsif dhl?(@tracking_number)
|
56
|
-
:dhl
|
57
|
-
else
|
58
|
-
:unknown
|
19
|
+
def self.detect(tracking_number)
|
20
|
+
detected = TYPES.collect do |test|
|
21
|
+
t = test.new(tracking_number)
|
22
|
+
t if t.valid?
|
59
23
|
end
|
60
|
-
|
61
|
-
|
62
|
-
def original_number
|
63
|
-
@original_number
|
64
|
-
end
|
65
|
-
|
66
|
-
def tracking_number
|
67
|
-
@tracking_number
|
68
|
-
end
|
24
|
+
found = detected.compact.first
|
69
25
|
|
70
|
-
|
71
|
-
|
26
|
+
return found if found
|
27
|
+
return Unknown.new(tracking_number)
|
72
28
|
end
|
73
29
|
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
results = tracking_number.scan(VERIFY_PATTERNS[:ups])
|
78
|
-
return false if results.nil? || results.empty?
|
79
|
-
|
80
|
-
sequence, check_digit = results.flatten
|
81
|
-
total = 0
|
82
|
-
sequence.chars.each_with_index do |c, i|
|
83
|
-
x = if c[/[0-9]/] # numeric
|
84
|
-
c.to_i
|
85
|
-
else
|
86
|
-
(c[0].ord - 3) % 10
|
87
|
-
end
|
88
|
-
x *= 2 if i.odd?
|
89
|
-
total += x
|
90
|
-
end
|
91
|
-
|
92
|
-
check = (total % 10)
|
93
|
-
check = (10 - check) unless (check.zero?)
|
94
|
-
|
95
|
-
return true if (check.to_i == check_digit.to_i)
|
96
|
-
end
|
97
|
-
|
98
|
-
|
99
|
-
def fedex_express?(tracking_number)
|
100
|
-
results = tracking_number.scan(VERIFY_PATTERNS[:fedex_express]).flatten
|
101
|
-
return false if results.nil? || results.empty?
|
102
|
-
sequence, check = results
|
103
|
-
|
104
|
-
sequence = sequence.chars.to_a.map(&:to_i)
|
105
|
-
total = 0
|
106
|
-
sequence.zip([3,1,7,3,1,7,3,1,7,3,1]).collect { |pair| pair[0] * pair[1] }.each { |t| total += t.to_i }
|
107
|
-
return true if (total % 11) == check.to_i
|
108
|
-
end
|
109
|
-
|
110
|
-
def fedex_ground_96?(tracking_number)
|
111
|
-
# 22 numbers
|
112
|
-
# http://fedex.com/us/solutions/ppe/FedEx_Ground_Label_Layout_Specification.pdf
|
113
|
-
# 96 - UCC/EAN Application Identifier
|
114
|
-
# [0-9]{2,2} - SCNC
|
115
|
-
# [0-9]{3,3} - Class Of Service
|
116
|
-
|
117
|
-
# [0-9]{7,7} - RPS Shipper ID (used in calculation)
|
118
|
-
# [0-9]{7,7} - Package Number (used in calculation)
|
119
|
-
|
120
|
-
# [0-9] - Check Digit
|
121
|
-
results = tracking_number.scan(VERIFY_PATTERNS[:fedex_ground_96]).flatten
|
122
|
-
return false if results.nil? || results.empty?
|
123
|
-
|
124
|
-
sequence, check_digit = results.flatten
|
125
|
-
total = 0
|
126
|
-
sequence.chars.to_a.reverse.map(&:to_i).each_with_index do |x, i|
|
127
|
-
x *= 3 if i.even?
|
128
|
-
total += x
|
129
|
-
end
|
130
|
-
check = total % 10
|
131
|
-
check = (10 - check) unless (check.zero?)
|
132
|
-
return true if check == check_digit.to_i
|
133
|
-
end
|
134
|
-
|
135
|
-
def fedex_ground_sscc18?(tracking_number)
|
136
|
-
# [0-9]{2,2} - Not used
|
137
|
-
# [0-9]{15, 15} - used for calculation
|
138
|
-
results = tracking_number.scan(VERIFY_PATTERNS[:fedex_ground_sscc18]).flatten
|
139
|
-
return false if results.nil? || results.empty?
|
140
|
-
sequence, check_digit = results
|
141
|
-
total = 0
|
142
|
-
sequence.chars.to_a.map(&:to_i).reverse.each_with_index do |x, i|
|
143
|
-
x *= 3 if i.even?
|
144
|
-
total += x
|
145
|
-
end
|
146
|
-
|
147
|
-
check = total % 10
|
148
|
-
check = (10 - check) unless (check.zero?)
|
149
|
-
return true if check == check_digit.to_i
|
150
|
-
end
|
151
|
-
|
152
|
-
def dhl?(tracking_number)
|
153
|
-
# standard mod 7 check
|
154
|
-
results = tracking_number.scan(VERIFY_PATTERNS[:dhl]).flatten
|
155
|
-
return false if results.nil? || results.empty?
|
156
|
-
|
157
|
-
sequence, check_digit = results
|
158
|
-
return true if sequence.to_i % 7 == check_digit.to_i
|
159
|
-
end
|
160
|
-
|
161
|
-
def usps?(tracking_number)
|
162
|
-
# standard mod 10 check
|
163
|
-
results = tracking_number.scan(VERIFY_PATTERNS[:usps]).flatten
|
164
|
-
return false if results.nil? || results.empty?
|
165
|
-
|
166
|
-
sequence, check_digit = results
|
167
|
-
total = 0
|
168
|
-
sequence.chars.to_a.reverse.each_with_index do |c, i|
|
169
|
-
x = c.to_i
|
170
|
-
x *= 3 if i.even?
|
171
|
-
|
172
|
-
total += x
|
173
|
-
end
|
174
|
-
|
175
|
-
check = total % 10
|
176
|
-
check = 10 - check unless (check.zero?)
|
177
|
-
return true if check == check_digit.to_i
|
178
|
-
end
|
30
|
+
def self.new(tracking_number)
|
31
|
+
self.detect(tracking_number)
|
32
|
+
end
|
179
33
|
end
|
data/lib/ups.rb
ADDED
@@ -0,0 +1,92 @@
|
|
1
|
+
class TrackingNumber
|
2
|
+
class UPS < Base
|
3
|
+
SEARCH_PATTERN = /(\b1\s*Z\s*(\w\s*){16,16}\b)/
|
4
|
+
VERIFY_PATTERN = /^1Z(\w{15,15})(\w)$/
|
5
|
+
|
6
|
+
def carrier
|
7
|
+
:ups
|
8
|
+
end
|
9
|
+
|
10
|
+
def matches
|
11
|
+
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
12
|
+
end
|
13
|
+
|
14
|
+
def valid_checksum?
|
15
|
+
sequence = tracking_number.slice(2...17)
|
16
|
+
check_digit = tracking_number.slice(17, 18)
|
17
|
+
|
18
|
+
total = 0
|
19
|
+
sequence.chars.each_with_index do |c, i|
|
20
|
+
x = if c[/[0-9]/] # numeric
|
21
|
+
c.to_i
|
22
|
+
else
|
23
|
+
(c[0].ord - 3) % 10
|
24
|
+
end
|
25
|
+
x *= 2 if i.odd?
|
26
|
+
total += x
|
27
|
+
end
|
28
|
+
|
29
|
+
check = (total % 10)
|
30
|
+
check = (10 - check) unless (check.zero?)
|
31
|
+
|
32
|
+
return (check.to_i == check_digit.to_i)
|
33
|
+
end
|
34
|
+
|
35
|
+
def decode
|
36
|
+
{:shipper_account => self.tracking_number.to_s.slice(2...8),
|
37
|
+
:service_type => self.tracking_number.to_s.slice(8...10),
|
38
|
+
:package_identifier => self.tracking_number.to_s.slice(10...17),
|
39
|
+
:check_digit => self.tracking_number.to_s.slice(17, 18)
|
40
|
+
}
|
41
|
+
end
|
42
|
+
|
43
|
+
def service_type
|
44
|
+
case decode[:service_type]
|
45
|
+
when "01":
|
46
|
+
"UPS United States Next Day Air (Red)"
|
47
|
+
when "02":
|
48
|
+
"UPS United States Second Day Air (Blue)"
|
49
|
+
when "03":
|
50
|
+
"UPS United States Ground"
|
51
|
+
when "12":
|
52
|
+
"UPS United States Third Day Select"
|
53
|
+
when "13":
|
54
|
+
"UPS United States Next Day Air Saver (Red Saver)"
|
55
|
+
when "15":
|
56
|
+
"UPS United States Next Day Air Early A.M."
|
57
|
+
when "22":
|
58
|
+
"UPS United States Ground - Returns Plus - Three Pickup Attempts"
|
59
|
+
when "32":
|
60
|
+
"UPS United States Next Day Air Early A.M. - COD"
|
61
|
+
when "33":
|
62
|
+
"UPS United States Next Day Air Early A.M. - Saturday Delivery, COD"
|
63
|
+
when "41":
|
64
|
+
"UPS United States Next Day Air Early A.M. - Saturday Delivery"
|
65
|
+
when "42":
|
66
|
+
"UPS United States Ground - Signature Required"
|
67
|
+
when "44":
|
68
|
+
"UPS United States Next Day Air - Saturday Delivery"
|
69
|
+
when "66":
|
70
|
+
"UPS United States Worldwide Express"
|
71
|
+
when "72":
|
72
|
+
"UPS United States Ground - Collect on Delivery"
|
73
|
+
when "78":
|
74
|
+
"UPS United States Ground - Returns Plus - One Pickup Attempt"
|
75
|
+
when "90":
|
76
|
+
"UPS United States Ground - Returns - UPS Prints and Mails Label"
|
77
|
+
when "A0":
|
78
|
+
"UPS United States Next Day Air Early A.M. - Adult Signature Required"
|
79
|
+
when "A1":
|
80
|
+
"UPS United States Next Day Air Early A.M. - Saturday Delivery, Adult Signature Required"
|
81
|
+
when "A2":
|
82
|
+
"UPS United States Next Day Air - Adult Signature Required"
|
83
|
+
when "A8":
|
84
|
+
"UPS United States Ground - Adult Signature Required"
|
85
|
+
when "A9":
|
86
|
+
"UPS United States Next Day Air Early A.M. - Adult Signature Required, COD"
|
87
|
+
when "AA":
|
88
|
+
"UPS United States Next Day Air Early A.M. - Saturday Delivery, Adult Signature Required, COD"
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
data/lib/usps.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
class TrackingNumber
|
2
|
+
class USPS < Base
|
3
|
+
def carrier
|
4
|
+
:usps
|
5
|
+
end
|
6
|
+
end
|
7
|
+
|
8
|
+
class USPS91 < USPS
|
9
|
+
SEARCH_PATTERN = /(\b9\s*1\s*(([0-9]\s*){20,20}\b))/
|
10
|
+
VERIFY_PATTERN = /^(91[0-9]{19,19})([0-9])$/
|
11
|
+
|
12
|
+
def matches
|
13
|
+
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
14
|
+
end
|
15
|
+
|
16
|
+
def decode
|
17
|
+
# Application ID: 91
|
18
|
+
# Service Code: 2 Digits
|
19
|
+
# Mailer Id: 8 Digits
|
20
|
+
# Package Id: 9 Digits
|
21
|
+
# Checksum: 1 Digit
|
22
|
+
|
23
|
+
{:application_id => self.tracking_number.to_s.slice(0...2),
|
24
|
+
:service_code => self.tracking_number.to_s.slice(2...4),
|
25
|
+
:mailer_id => self.tracking_number.to_s.slice(4...12),
|
26
|
+
:package_identifier => self.tracking_number.to_s.slice(12...21),
|
27
|
+
:check_digit => self.tracking_number.slice(21...22)
|
28
|
+
}
|
29
|
+
end
|
30
|
+
|
31
|
+
def valid_checksum?
|
32
|
+
chars = tracking_number.chars.to_a
|
33
|
+
check_digit = chars.pop
|
34
|
+
|
35
|
+
total = 0
|
36
|
+
chars.reverse.each_with_index do |c, i|
|
37
|
+
x = c.to_i
|
38
|
+
x *= 3 if i.even?
|
39
|
+
|
40
|
+
total += x
|
41
|
+
end
|
42
|
+
|
43
|
+
check = total % 10
|
44
|
+
check = 10 - check unless (check.zero?)
|
45
|
+
return true if check == check_digit.to_i
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
class USPS20 < USPS
|
50
|
+
SEARCH_PATTERN = /(\b([0-9]\s*){20,20}\b)/
|
51
|
+
VERIFY_PATTERN = /^([0-9]{2,2})([0-9]{9,9})([0-9]{8,8})([0-9])$/
|
52
|
+
|
53
|
+
def matches
|
54
|
+
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
55
|
+
end
|
56
|
+
|
57
|
+
def decode
|
58
|
+
{:service_code => self.tracking_number.to_s.slice(0...2),
|
59
|
+
:mailer_id => self.tracking_number.to_s.slice(2...11),
|
60
|
+
:package_identifier => self.tracking_number.to_s.slice(11...19),
|
61
|
+
:check_digit => self.tracking_number.slice(19...20)
|
62
|
+
}
|
63
|
+
end
|
64
|
+
|
65
|
+
def service_type
|
66
|
+
case decode[:service_code]
|
67
|
+
when "71"
|
68
|
+
"Certified Mail"
|
69
|
+
when "73"
|
70
|
+
"Insured Mail"
|
71
|
+
when "77"
|
72
|
+
"Registered Mail"
|
73
|
+
when "81"
|
74
|
+
"Return Receipt for Merchandise"
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def valid_checksum?
|
79
|
+
chars = tracking_number.chars.to_a
|
80
|
+
check_digit = chars.pop
|
81
|
+
|
82
|
+
total = 0
|
83
|
+
chars.reverse.each_with_index do |c, i|
|
84
|
+
x = c.to_i
|
85
|
+
x *= 3 if i.even?
|
86
|
+
|
87
|
+
total += x
|
88
|
+
end
|
89
|
+
|
90
|
+
check = total % 10
|
91
|
+
check = 10 - check unless (check.zero?)
|
92
|
+
return true if check == check_digit.to_i
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
class USPS13 < USPS
|
97
|
+
SEARCH_PATTERN = /(\b([A-Z]\s*){2,2}([0-9]\s*){9,9}([A-Z]\s*){2,2}\b)/
|
98
|
+
VERIFY_PATTERN = /^([A-Z]{2,2})([0-9]{9,9})([A-Z]{2,2})$/
|
99
|
+
|
100
|
+
def matches
|
101
|
+
self.tracking_number.scan(VERIFY_PATTERN).flatten
|
102
|
+
end
|
103
|
+
|
104
|
+
def valid_checksum?
|
105
|
+
sequence = tracking_number.scan(/[0-9]+/).flatten.to_s
|
106
|
+
chars = sequence.chars.to_a
|
107
|
+
check_digit = chars.pop.to_i
|
108
|
+
|
109
|
+
sum = 0
|
110
|
+
chars.zip([8,6,4,2,3,5,9,7]).each do |pair|
|
111
|
+
sum += (pair[0].to_i * pair[1].to_i)
|
112
|
+
end
|
113
|
+
|
114
|
+
remainder = sum % 11
|
115
|
+
check = case remainder
|
116
|
+
when 1
|
117
|
+
0
|
118
|
+
when 0
|
119
|
+
5
|
120
|
+
else
|
121
|
+
11 - remainder
|
122
|
+
end
|
123
|
+
|
124
|
+
return check == check_digit
|
125
|
+
end
|
126
|
+
end
|
127
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class DHLTrackingNumberTest < Test::Unit::TestCase
|
4
|
+
context "a DHL tracking number" do
|
5
|
+
["73891051146"].each do |valid_number|
|
6
|
+
should "return dhl for #{valid_number}" do
|
7
|
+
t = TrackingNumber.new(valid_number)
|
8
|
+
assert_equal :dhl, t.carrier
|
9
|
+
assert t.valid?
|
10
|
+
end
|
11
|
+
|
12
|
+
should "detect #{valid_number} regardless of spacing" do
|
13
|
+
should_detect_number_variants(valid_number, TrackingNumber::DHL)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,58 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class FedExTrackingNumberTest < Test::Unit::TestCase
|
4
|
+
context "a FedEx tracking number" do
|
5
|
+
["986578788855", "477179081230", "799531274483", "790535312317"].each do |valid_number|
|
6
|
+
should "return fedex express for #{valid_number}" do
|
7
|
+
t = TrackingNumber.new(valid_number)
|
8
|
+
assert_equal TrackingNumber::FedExExpress, t.class
|
9
|
+
assert_equal :fedex, t.carrier
|
10
|
+
assert t.valid?
|
11
|
+
end
|
12
|
+
|
13
|
+
should "detect #{valid_number} regardless of spacing" do
|
14
|
+
should_detect_number_variants(valid_number, TrackingNumber::FedExExpress)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
["9611020987654312345672"].each do |valid_number|
|
19
|
+
should "return fedex 96 for #{valid_number}" do
|
20
|
+
t = TrackingNumber.new(valid_number)
|
21
|
+
assert_equal TrackingNumber::FedExGround96, t.class
|
22
|
+
assert_equal :fedex, t.carrier
|
23
|
+
assert t.valid?
|
24
|
+
end
|
25
|
+
|
26
|
+
should "detect #{valid_number} regardless of spacing" do
|
27
|
+
should_detect_number_variants(valid_number, TrackingNumber::FedExGround96)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
["0414 4176 0228 964", "5682 8361 0012 000", "5682 8361 0012 734"].each do |valid_number|
|
32
|
+
should "return fedex ground for #{valid_number}" do
|
33
|
+
t = TrackingNumber.new(valid_number)
|
34
|
+
assert_equal TrackingNumber::FedExGround, t.class
|
35
|
+
assert_equal :fedex, t.carrier
|
36
|
+
assert t.valid?
|
37
|
+
end
|
38
|
+
|
39
|
+
should "detect #{valid_number} regardless of spacing" do
|
40
|
+
should_detect_number_variants(valid_number, TrackingNumber::FedExGround)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
["00 0123 4500 0000 0027"].each do |valid_number|
|
45
|
+
should "return fedex sscc18 for #{valid_number}" do
|
46
|
+
t = TrackingNumber.new(valid_number)
|
47
|
+
assert_equal TrackingNumber::FedExGround18, t.class
|
48
|
+
assert_equal :fedex, t.carrier
|
49
|
+
assert t.valid?
|
50
|
+
end
|
51
|
+
|
52
|
+
should "detect #{valid_number} regardless of spacing" do
|
53
|
+
should_detect_number_variants(valid_number, TrackingNumber::FedExGround18)
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end
|
data/test/test_helper.rb
CHANGED
@@ -16,13 +16,29 @@ require 'tracking_number'
|
|
16
16
|
|
17
17
|
class Test::Unit::TestCase
|
18
18
|
def possible_numbers(tracking)
|
19
|
+
tracking = tracking.to_s
|
19
20
|
possible_numbers = []
|
20
21
|
possible_numbers << tracking
|
22
|
+
possible_numbers << tracking.to_s.gsub(" ", "")
|
21
23
|
possible_numbers << tracking.chars.to_a.join(" ")
|
22
24
|
possible_numbers << tracking.chars.to_a.join(" ")
|
23
25
|
possible_numbers << tracking.slice(0, (tracking.length / 2)) + " " + tracking.slice((tracking.length / 2), tracking.length)
|
24
|
-
|
25
|
-
possible_numbers
|
26
|
+
|
27
|
+
possible_numbers.flatten.uniq
|
28
|
+
end
|
29
|
+
|
30
|
+
def possible_strings(tracking)
|
31
|
+
possible_numbers(tracking).flatten.collect { |t| search_string(t) }
|
32
|
+
end
|
33
|
+
|
34
|
+
def search_string(number)
|
35
|
+
%Q{Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor #{number} ut labore et dolore magna aliqua.}
|
36
|
+
end
|
37
|
+
|
38
|
+
def should_detect_number_variants(valid_number, type)
|
39
|
+
possible_strings(valid_number).each do |string|
|
40
|
+
results = type.search(string)
|
41
|
+
assert_equal 1, results.size, "could not find #{type} #{valid_number} in #{string}"
|
42
|
+
end
|
26
43
|
end
|
27
|
-
|
28
44
|
end
|
@@ -1,96 +1,24 @@
|
|
1
1
|
require 'test_helper'
|
2
2
|
|
3
|
-
class TrackingNumberTest < Test::Unit::TestCase
|
4
|
-
context "a UPS tracking number" do
|
5
|
-
should "return ups as the carrier" do
|
6
|
-
assert_equal :ups, TrackingNumber.new("1Z5R89390357567127").carrier
|
7
|
-
assert_equal :ups, TrackingNumber.new("1Z879E930346834440").carrier
|
8
|
-
assert_equal :ups, TrackingNumber.new("1Z410E7W0392751591").carrier
|
9
|
-
assert_equal :ups, TrackingNumber.new("1Z8V92A70367203024").carrier
|
10
|
-
end
|
11
|
-
end
|
12
|
-
|
13
|
-
context "a FedEx tracking number" do
|
14
|
-
should "return fedex as the carrier if it's a valid fedex express number" do
|
15
|
-
t = TrackingNumber.new("986578788855")
|
16
|
-
assert_equal :fedex, t.carrier
|
17
|
-
assert t.valid?
|
18
|
-
|
19
|
-
t = TrackingNumber.new("477179081230")
|
20
|
-
assert_equal :fedex, t.carrier
|
21
|
-
assert t.valid?
|
22
|
-
end
|
23
|
-
|
24
|
-
should "return fedex as the carrier with valid fedex ground (96) number" do
|
25
|
-
t = TrackingNumber.new("9611020987654312345672")
|
26
|
-
assert_equal :fedex, t.carrier
|
27
|
-
assert t.valid?
|
28
|
-
end
|
29
|
-
|
30
|
-
should "return fedex as the carrier with valid fedex ground (SSCC18) number" do
|
31
|
-
t = TrackingNumber.new("000123450000000027")
|
32
|
-
assert_equal :fedex, t.carrier
|
33
|
-
assert t.valid?
|
34
|
-
end
|
35
|
-
end
|
36
|
-
|
37
|
-
context "a DHL tracking number" do
|
38
|
-
should "return dhl if it's a valid number" do
|
39
|
-
t = TrackingNumber.new("73891051146")
|
40
|
-
assert_equal :dhl, t.carrier
|
41
|
-
assert t.valid?
|
42
|
-
end
|
43
|
-
end
|
44
|
-
|
45
|
-
context "a USPS tracking number" do
|
46
|
-
should "return usps with if number" do
|
47
|
-
t = TrackingNumber.new("9101 1234 5678 9000 0000 13")
|
48
|
-
assert_equal :usps, t.carrier
|
49
|
-
assert t.valid?
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
3
|
+
class TrackingNumberTest < Test::Unit::TestCase
|
53
4
|
context "a tracking number" do
|
54
5
|
should "return unknown when given invalid number" do
|
55
6
|
t = TrackingNumber.new("101")
|
7
|
+
assert_equal TrackingNumber::Unknown, t.class
|
56
8
|
assert_equal :unknown, t.carrier
|
57
9
|
assert !t.valid?
|
58
10
|
end
|
59
|
-
|
11
|
+
|
60
12
|
should "upcase and remove spaces from tracking number" do
|
61
13
|
t = TrackingNumber.new("abc 123 def")
|
62
14
|
assert_equal "ABC123DEF", t.tracking_number
|
63
15
|
end
|
64
16
|
end
|
65
|
-
|
66
|
-
context "tracking number search" do
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
{"9101123456789000000013" => :usps}].each do |pair|
|
71
|
-
expected_service = pair.to_a.flatten[1]
|
72
|
-
tracking = pair.to_a.flatten[0]
|
73
|
-
|
74
|
-
should "detect #{expected_service} with number #{tracking} regardless of spacing" do
|
75
|
-
possible_numbers(tracking).each do |spaced_tracking|
|
76
|
-
results = TrackingNumber.search("blah blah #{spaced_tracking} blah blah")
|
77
|
-
assert_equal 1, results.size, "#{spaced_tracking} did not match #{expected_service}"
|
78
|
-
assert_equal expected_service, results.first.carrier
|
79
|
-
end
|
80
|
-
end
|
81
|
-
|
82
|
-
should "not detect #{expected_service} when word word boundaries are not in tact" do
|
83
|
-
possible_numbers(tracking).each do |spaced_tracking|
|
84
|
-
bad_number = "x1#{spaced_tracking}1x"
|
85
|
-
results = TrackingNumber.search("blah blah #{bad_number} blah blah")
|
86
|
-
assert_equal 0, results.size, "#{bad_number} should not match #{expected_service}"
|
87
|
-
end
|
88
|
-
end
|
89
|
-
|
90
|
-
should "return two tracking numbers when given string with two" do
|
91
|
-
s = TrackingNumber.search("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 1Z879E930346834440 nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute 9611020987654312345672 dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
|
92
|
-
assert_equal 2, s.size
|
93
|
-
end
|
17
|
+
|
18
|
+
context "tracking number search" do
|
19
|
+
should "return two tracking numbers when given string with two" do
|
20
|
+
s = TrackingNumber.search("Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, 1Z879E930346834440 nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute 9611020987654312345672 dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.")
|
21
|
+
assert_equal 2, s.size
|
94
22
|
end
|
95
23
|
end
|
96
24
|
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class UPSTrackingNumberTest < Test::Unit::TestCase
|
4
|
+
context "a UPS tracking number" do
|
5
|
+
["1Z5R89390357567127", "1Z879E930346834440", "1Z410E7W0392751591", "1Z8V92A70367203024"].each do |valid_number|
|
6
|
+
should "return ups with valid number #{valid_number}" do
|
7
|
+
t = TrackingNumber.new(valid_number)
|
8
|
+
assert_equal TrackingNumber::UPS, t.class
|
9
|
+
assert_equal :ups, t.carrier
|
10
|
+
end
|
11
|
+
|
12
|
+
should "detect #{valid_number} regardless of spacing" do
|
13
|
+
should_detect_number_variants(valid_number, TrackingNumber::UPS)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
require 'test_helper'
|
2
|
+
|
3
|
+
class USPSTrackingNumberTest < Test::Unit::TestCase
|
4
|
+
context "a USPS tracking number" do
|
5
|
+
["9101 1234 5678 9000 0000 13"].each do |valid_number|
|
6
|
+
should "return usps with valid 22 digit number: #{valid_number}" do
|
7
|
+
t = TrackingNumber.new("9101 1234 5678 9000 0000 13")
|
8
|
+
assert_equal TrackingNumber::USPS91, t.class
|
9
|
+
assert_equal :usps, t.carrier
|
10
|
+
assert t.valid?
|
11
|
+
end
|
12
|
+
|
13
|
+
should "detect #{valid_number} regardless of spacing" do
|
14
|
+
should_detect_number_variants(valid_number, TrackingNumber::USPS91)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
|
18
|
+
# Actual tracking number I got from the USPS that doesn't validate. UGghhh
|
19
|
+
#"7196 9010 7560 0307 7385",
|
20
|
+
["0307 1790 0005 2348 3741"].each do |valid_number|
|
21
|
+
should "detect #{valid_number} regardless of spacing" do
|
22
|
+
should_detect_number_variants(valid_number, TrackingNumber::USPS20)
|
23
|
+
end
|
24
|
+
|
25
|
+
should "return usps with valid 20 digit number: #{valid_number}" do
|
26
|
+
t = TrackingNumber.new(valid_number)
|
27
|
+
assert_equal TrackingNumber::USPS20, t.class
|
28
|
+
assert_equal :usps, t.carrier
|
29
|
+
assert t.valid?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
["RB123456785US"].each do |valid_number|
|
34
|
+
should "return usps with valid 13 character number #{valid_number}" do
|
35
|
+
t = TrackingNumber.new(valid_number)
|
36
|
+
assert_equal TrackingNumber::USPS13, t.class
|
37
|
+
assert_equal :usps, t.carrier
|
38
|
+
assert t.valid?
|
39
|
+
end
|
40
|
+
|
41
|
+
should "detect #{valid_number} regardless of spacing" do
|
42
|
+
should_detect_number_variants(valid_number, TrackingNumber::USPS13)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
data/tracking_number.gemspec
CHANGED
@@ -5,11 +5,11 @@
|
|
5
5
|
|
6
6
|
Gem::Specification.new do |s|
|
7
7
|
s.name = %q{tracking_number}
|
8
|
-
s.version = "0.
|
8
|
+
s.version = "0.3.0"
|
9
9
|
|
10
10
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
11
|
s.authors = ["Jeff Keen"]
|
12
|
-
s.date = %q{2011-
|
12
|
+
s.date = %q{2011-02-09}
|
13
13
|
s.description = %q{Match tracking numbers to a service, and search blocks of text and pull out valid tracking numbers.}
|
14
14
|
s.email = %q{jeff@keen.me}
|
15
15
|
s.extra_rdoc_files = [
|
@@ -24,23 +24,35 @@ Gem::Specification.new do |s|
|
|
24
24
|
"README.rdoc",
|
25
25
|
"Rakefile",
|
26
26
|
"VERSION",
|
27
|
+
"lib/base.rb",
|
28
|
+
"lib/dhl.rb",
|
29
|
+
"lib/fedex.rb",
|
27
30
|
"lib/tracking_number.rb",
|
31
|
+
"lib/ups.rb",
|
32
|
+
"lib/usps.rb",
|
33
|
+
"test/test_dhl_tracking_number.rb",
|
34
|
+
"test/test_fedex_tracking_number.rb",
|
28
35
|
"test/test_helper.rb",
|
29
36
|
"test/test_tracking_number.rb",
|
37
|
+
"test/test_ups_tracking_number.rb",
|
38
|
+
"test/test_usps_tracking_number.rb",
|
30
39
|
"tracking_number.gemspec"
|
31
40
|
]
|
32
41
|
s.homepage = %q{http://github.com/jkeen/tracking_number}
|
33
42
|
s.licenses = ["MIT"]
|
34
43
|
s.require_paths = ["lib"]
|
35
|
-
s.rubygems_version = %q{1.
|
44
|
+
s.rubygems_version = %q{1.4.1}
|
36
45
|
s.summary = %q{Identifies valid tracking numbers}
|
37
46
|
s.test_files = [
|
47
|
+
"test/test_dhl_tracking_number.rb",
|
48
|
+
"test/test_fedex_tracking_number.rb",
|
38
49
|
"test/test_helper.rb",
|
39
|
-
"test/test_tracking_number.rb"
|
50
|
+
"test/test_tracking_number.rb",
|
51
|
+
"test/test_ups_tracking_number.rb",
|
52
|
+
"test/test_usps_tracking_number.rb"
|
40
53
|
]
|
41
54
|
|
42
55
|
if s.respond_to? :specification_version then
|
43
|
-
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
44
56
|
s.specification_version = 3
|
45
57
|
|
46
58
|
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
metadata
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: tracking_number
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
|
4
|
+
hash: 19
|
5
|
+
prerelease:
|
5
6
|
segments:
|
6
7
|
- 0
|
7
|
-
-
|
8
|
+
- 3
|
8
9
|
- 0
|
9
|
-
version: 0.
|
10
|
+
version: 0.3.0
|
10
11
|
platform: ruby
|
11
12
|
authors:
|
12
13
|
- Jeff Keen
|
@@ -14,65 +15,69 @@ autorequire:
|
|
14
15
|
bindir: bin
|
15
16
|
cert_chain: []
|
16
17
|
|
17
|
-
date: 2011-
|
18
|
+
date: 2011-02-09 00:00:00 -06:00
|
18
19
|
default_executable:
|
19
20
|
dependencies:
|
20
21
|
- !ruby/object:Gem::Dependency
|
21
|
-
|
22
|
-
requirement: &id001 !ruby/object:Gem::Requirement
|
22
|
+
version_requirements: &id001 !ruby/object:Gem::Requirement
|
23
23
|
none: false
|
24
24
|
requirements:
|
25
25
|
- - ">="
|
26
26
|
- !ruby/object:Gem::Version
|
27
|
+
hash: 3
|
27
28
|
segments:
|
28
29
|
- 0
|
29
30
|
version: "0"
|
30
|
-
|
31
|
+
requirement: *id001
|
31
32
|
prerelease: false
|
32
|
-
|
33
|
+
name: shoulda
|
34
|
+
type: :development
|
33
35
|
- !ruby/object:Gem::Dependency
|
34
|
-
|
35
|
-
requirement: &id002 !ruby/object:Gem::Requirement
|
36
|
+
version_requirements: &id002 !ruby/object:Gem::Requirement
|
36
37
|
none: false
|
37
38
|
requirements:
|
38
39
|
- - ~>
|
39
40
|
- !ruby/object:Gem::Version
|
41
|
+
hash: 23
|
40
42
|
segments:
|
41
43
|
- 1
|
42
44
|
- 0
|
43
45
|
- 0
|
44
46
|
version: 1.0.0
|
45
|
-
|
47
|
+
requirement: *id002
|
46
48
|
prerelease: false
|
47
|
-
|
49
|
+
name: bundler
|
50
|
+
type: :development
|
48
51
|
- !ruby/object:Gem::Dependency
|
49
|
-
|
50
|
-
requirement: &id003 !ruby/object:Gem::Requirement
|
52
|
+
version_requirements: &id003 !ruby/object:Gem::Requirement
|
51
53
|
none: false
|
52
54
|
requirements:
|
53
55
|
- - ~>
|
54
56
|
- !ruby/object:Gem::Version
|
57
|
+
hash: 7
|
55
58
|
segments:
|
56
59
|
- 1
|
57
60
|
- 5
|
58
61
|
- 2
|
59
62
|
version: 1.5.2
|
60
|
-
|
63
|
+
requirement: *id003
|
61
64
|
prerelease: false
|
62
|
-
|
65
|
+
name: jeweler
|
66
|
+
type: :development
|
63
67
|
- !ruby/object:Gem::Dependency
|
64
|
-
|
65
|
-
requirement: &id004 !ruby/object:Gem::Requirement
|
68
|
+
version_requirements: &id004 !ruby/object:Gem::Requirement
|
66
69
|
none: false
|
67
70
|
requirements:
|
68
71
|
- - ">="
|
69
72
|
- !ruby/object:Gem::Version
|
73
|
+
hash: 3
|
70
74
|
segments:
|
71
75
|
- 0
|
72
76
|
version: "0"
|
73
|
-
|
77
|
+
requirement: *id004
|
74
78
|
prerelease: false
|
75
|
-
|
79
|
+
name: rcov
|
80
|
+
type: :development
|
76
81
|
description: Match tracking numbers to a service, and search blocks of text and pull out valid tracking numbers.
|
77
82
|
email: jeff@keen.me
|
78
83
|
executables: []
|
@@ -90,9 +95,18 @@ files:
|
|
90
95
|
- README.rdoc
|
91
96
|
- Rakefile
|
92
97
|
- VERSION
|
98
|
+
- lib/base.rb
|
99
|
+
- lib/dhl.rb
|
100
|
+
- lib/fedex.rb
|
93
101
|
- lib/tracking_number.rb
|
102
|
+
- lib/ups.rb
|
103
|
+
- lib/usps.rb
|
104
|
+
- test/test_dhl_tracking_number.rb
|
105
|
+
- test/test_fedex_tracking_number.rb
|
94
106
|
- test/test_helper.rb
|
95
107
|
- test/test_tracking_number.rb
|
108
|
+
- test/test_ups_tracking_number.rb
|
109
|
+
- test/test_usps_tracking_number.rb
|
96
110
|
- tracking_number.gemspec
|
97
111
|
has_rdoc: true
|
98
112
|
homepage: http://github.com/jkeen/tracking_number
|
@@ -108,7 +122,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
108
122
|
requirements:
|
109
123
|
- - ">="
|
110
124
|
- !ruby/object:Gem::Version
|
111
|
-
hash:
|
125
|
+
hash: 3
|
112
126
|
segments:
|
113
127
|
- 0
|
114
128
|
version: "0"
|
@@ -117,16 +131,21 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
117
131
|
requirements:
|
118
132
|
- - ">="
|
119
133
|
- !ruby/object:Gem::Version
|
134
|
+
hash: 3
|
120
135
|
segments:
|
121
136
|
- 0
|
122
137
|
version: "0"
|
123
138
|
requirements: []
|
124
139
|
|
125
140
|
rubyforge_project:
|
126
|
-
rubygems_version: 1.
|
141
|
+
rubygems_version: 1.4.1
|
127
142
|
signing_key:
|
128
143
|
specification_version: 3
|
129
144
|
summary: Identifies valid tracking numbers
|
130
145
|
test_files:
|
146
|
+
- test/test_dhl_tracking_number.rb
|
147
|
+
- test/test_fedex_tracking_number.rb
|
131
148
|
- test/test_helper.rb
|
132
149
|
- test/test_tracking_number.rb
|
150
|
+
- test/test_ups_tracking_number.rb
|
151
|
+
- test/test_usps_tracking_number.rb
|