trackerific 0.7.2 → 0.7.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 (35) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/README.rdoc +2 -1
  4. data/lib/dependencies.rb +9 -0
  5. data/lib/trackerific.rb +5 -19
  6. data/lib/trackerific/builders.rb +12 -0
  7. data/lib/trackerific/builders/base/soap.rb +14 -16
  8. data/lib/trackerific/builders/base/xml.rb +22 -28
  9. data/lib/trackerific/builders/fedex.rb +66 -44
  10. data/lib/trackerific/builders/ups.rb +28 -24
  11. data/lib/trackerific/builders/usps.rb +15 -13
  12. data/lib/trackerific/parsers.rb +8 -0
  13. data/lib/trackerific/parsers/base.rb +24 -28
  14. data/lib/trackerific/parsers/fedex.rb +43 -47
  15. data/lib/trackerific/parsers/ups.rb +49 -53
  16. data/lib/trackerific/parsers/usps.rb +44 -48
  17. data/lib/trackerific/services.rb +10 -0
  18. data/lib/trackerific/services/base.rb +82 -55
  19. data/lib/trackerific/services/concerns/soap.rb +10 -40
  20. data/lib/trackerific/services/concerns/xml.rb +15 -37
  21. data/lib/trackerific/services/fedex.rb +9 -19
  22. data/lib/trackerific/services/mock_service.rb +26 -37
  23. data/lib/trackerific/services/ups.rb +11 -24
  24. data/lib/trackerific/services/usps.rb +23 -35
  25. data/lib/trackerific/soap.rb +5 -0
  26. data/lib/trackerific/soap/wsdl.rb +8 -12
  27. data/lib/trackerific/version.rb +1 -1
  28. data/spec/lib/trackerific/services/base_spec.rb +21 -4
  29. data/spec/lib/trackerific/services/concerns/soap_spec.rb +6 -21
  30. data/spec/lib/trackerific/services/concerns/xml_spec.rb +5 -18
  31. data/spec/lib/trackerific/services/mock_service_spec.rb +12 -0
  32. data/spec/lib/trackerific/services/usps_spec.rb +4 -4
  33. data/spec/lib/trackerific/version_spec.rb +1 -1
  34. data/spec/support/test_concerns.rb +15 -0
  35. metadata +8 -2
@@ -1,59 +1,55 @@
1
- module Trackerific
2
- module Parsers
3
- class FedEx < Parsers::Base
4
- protected
5
-
6
- def response_error
7
- @response_error ||= if highest_severity == 'ERROR'
8
- Trackerific::Error.new(notifications[:message])
9
- else
10
- false
11
- end
12
- end
1
+ class Trackerific::Parsers::FedEx < Trackerific::Parsers::Base
2
+ protected
3
+
4
+ def response_error
5
+ @response_error ||= if highest_severity == 'ERROR'
6
+ Trackerific::Error.new(notifications[:message])
7
+ else
8
+ false
9
+ end
10
+ end
13
11
 
14
- def summary
15
- nil
16
- end
12
+ def summary
13
+ nil
14
+ end
17
15
 
18
- def events
19
- track_details.map do |detail|
20
- Trackerific::Event.new(parse_date(detail), nil, location(detail))
21
- end
22
- end
16
+ def events
17
+ track_details.map do |detail|
18
+ Trackerific::Event.new(parse_date(detail), nil, location(detail))
19
+ end
20
+ end
23
21
 
24
- private
22
+ private
25
23
 
26
- def location(detail)
27
- a = detail[:destination_address]
28
- "#{a[:city]}, #{a[:state_or_province_code]} #{a[:country_code]}"
29
- end
24
+ def location(detail)
25
+ a = detail[:destination_address]
26
+ "#{a[:city]}, #{a[:state_or_province_code]} #{a[:country_code]}"
27
+ end
30
28
 
31
- def parse_date(detail)
32
- detail[:ship_timestamp]
33
- end
29
+ def parse_date(detail)
30
+ detail[:ship_timestamp]
31
+ end
34
32
 
35
- def track_reply
36
- @response.hash[:envelope][:body][:track_reply]
37
- end
33
+ def track_reply
34
+ @response.hash[:envelope][:body][:track_reply]
35
+ end
38
36
 
39
- def track_details
40
- @track_details ||= begin
41
- details = track_reply[:completed_track_details][:track_details]
42
- details.select do |d|
43
- d[:ship_timestamp].present? && d[:destination_address].present? &&
44
- d[:destination_address][:city].present? &&
45
- d[:destination_address][:state_or_province_code].present?
46
- end
47
- end
37
+ def track_details
38
+ @track_details ||= begin
39
+ details = track_reply[:completed_track_details][:track_details]
40
+ details.select do |d|
41
+ d[:ship_timestamp].present? && d[:destination_address].present? &&
42
+ d[:destination_address][:city].present? &&
43
+ d[:destination_address][:state_or_province_code].present?
48
44
  end
45
+ end
46
+ end
49
47
 
50
- def highest_severity
51
- track_reply[:highest_severity]
52
- end
48
+ def highest_severity
49
+ track_reply[:highest_severity]
50
+ end
53
51
 
54
- def notifications
55
- track_reply[:notifications]
56
- end
57
- end
52
+ def notifications
53
+ track_reply[:notifications]
58
54
  end
59
55
  end
@@ -1,66 +1,62 @@
1
- module Trackerific
2
- module Parsers
3
- class UPS < Parsers::Base
4
- protected
5
-
6
- def response_error
7
- @response_error ||= if @response.code != 200
8
- Trackerific::Error.new("HTTP returned status #{@response.code}")
9
- elsif response_status_code == :error
10
- Trackerific::Error.new(error_response)
11
- elsif response_status_code == :success
12
- false
13
- else
14
- Trackerific::Error.new("Unknown status code from server.")
15
- end
16
- end
1
+ class Trackerific::Parsers::UPS < Trackerific::Parsers::Base
2
+ protected
3
+
4
+ def response_error
5
+ @response_error ||= if @response.code != 200
6
+ Trackerific::Error.new("HTTP returned status #{@response.code}")
7
+ elsif response_status_code == :error
8
+ Trackerific::Error.new(error_response)
9
+ elsif response_status_code == :success
10
+ false
11
+ else
12
+ Trackerific::Error.new("Unknown status code from server.")
13
+ end
14
+ end
17
15
 
18
- def summary
19
- description(activity.first)
20
- end
16
+ def summary
17
+ description(activity.first)
18
+ end
21
19
 
22
- def events
23
- activity.map do |a|
24
- date = parse_ups_date_time(a['Date'], a['Time'])
25
- Trackerific::Event.new(date, description(a), location(a))
26
- end
27
- end
20
+ def events
21
+ activity.map do |a|
22
+ date = parse_ups_date_time(a['Date'], a['Time'])
23
+ Trackerific::Event.new(date, description(a), location(a))
24
+ end
25
+ end
28
26
 
29
- private
27
+ private
30
28
 
31
- def track_response
32
- @response['TrackResponse']
33
- end
29
+ def track_response
30
+ @response['TrackResponse']
31
+ end
34
32
 
35
- def response_status_code
36
- { "0" => :error,
37
- "1" => :success
38
- }[track_response['Response']['ResponseStatusCode']]
39
- end
33
+ def response_status_code
34
+ { "0" => :error,
35
+ "1" => :success
36
+ }[track_response['Response']['ResponseStatusCode']]
37
+ end
40
38
 
41
- def error_response
42
- track_response['Response']['Error']['ErrorDescription']
43
- end
39
+ def error_response
40
+ track_response['Response']['Error']['ErrorDescription']
41
+ end
44
42
 
45
- def parse_ups_date_time(date, time)
46
- hours, minutes, seconds = time.scan(/.{2}/)
47
- DateTime.parse("#{Date.parse(date)} #{hours}:#{minutes}:#{seconds}")
48
- end
43
+ def parse_ups_date_time(date, time)
44
+ hours, minutes, seconds = time.scan(/.{2}/)
45
+ DateTime.parse("#{Date.parse(date)} #{hours}:#{minutes}:#{seconds}")
46
+ end
49
47
 
50
- def description(a)
51
- a['Status']['StatusType']['Description']
52
- end
48
+ def description(a)
49
+ a['Status']['StatusType']['Description']
50
+ end
53
51
 
54
- def location(a)
55
- a['ActivityLocation']['Address'].map {|k,v| v}.join(" ")
56
- end
52
+ def location(a)
53
+ a['ActivityLocation']['Address'].map {|k,v| v}.join(" ")
54
+ end
57
55
 
58
- def activity
59
- @activity ||= begin
60
- a = track_response['Shipment']['Package']['Activity']
61
- a.is_a?(Array) ? a : [a]
62
- end
63
- end
56
+ def activity
57
+ @activity ||= begin
58
+ a = track_response['Shipment']['Package']['Activity']
59
+ a.is_a?(Array) ? a : [a]
64
60
  end
65
61
  end
66
62
  end
@@ -1,51 +1,47 @@
1
- module Trackerific
2
- module Parsers
3
- class USPS < Parsers::Base
4
- protected
5
-
6
- def response_error
7
- @response_error ||= if @response.code != 200
8
- Trackerific::Error.new("HTTP returned status #{@response.code}")
9
- elsif @response['Error']
10
- Trackerific::Error.new(@response['Error']['Description'])
11
- elsif @response['TrackResponse'].nil? && @response['CityStateLookupResponse'].nil?
12
- Trackerific::Error.new("Invalid response from server.")
13
- else
14
- false
15
- end
16
- end
17
-
18
- def summary
19
- tracking_info['TrackSummary']
20
- end
21
-
22
- def events
23
- tracking_info.fetch('TrackDetail', []).map do |e|
24
- Trackerific::Event.new(date(e), description(e), location(e))
25
- end
26
- end
27
-
28
- private
29
-
30
- def tracking_info
31
- @response['TrackResponse']['TrackInfo']
32
- end
33
-
34
- def date(event)
35
- d = event.split(" ")
36
- DateTime.parse(d[0..3].join(" "))
37
- end
38
-
39
- def description(event)
40
- d = event.split(" ")
41
- d[4..d.length-4].join(" ")
42
- end
43
-
44
- def location(event)
45
- d = event.gsub(".", "").split(" ")
46
- city, state, zip = d.last(3)
47
- "#{city}, #{state} #{zip}"
48
- end
1
+ class Trackerific::Parsers::USPS < Trackerific::Parsers::Base
2
+ protected
3
+
4
+ def response_error
5
+ @response_error ||= if @response.code != 200
6
+ Trackerific::Error.new("HTTP returned status #{@response.code}")
7
+ elsif @response['Error']
8
+ Trackerific::Error.new(@response['Error']['Description'])
9
+ elsif @response['TrackResponse'].nil? && @response['CityStateLookupResponse'].nil?
10
+ Trackerific::Error.new("Invalid response from server.")
11
+ else
12
+ false
49
13
  end
50
14
  end
15
+
16
+ def summary
17
+ tracking_info['TrackSummary']
18
+ end
19
+
20
+ def events
21
+ tracking_info.fetch('TrackDetail', []).map do |e|
22
+ Trackerific::Event.new(date(e), description(e), location(e))
23
+ end
24
+ end
25
+
26
+ private
27
+
28
+ def tracking_info
29
+ @response['TrackResponse']['TrackInfo']
30
+ end
31
+
32
+ def date(event)
33
+ d = event.split(" ")
34
+ DateTime.parse(d[0..3].join(" "))
35
+ end
36
+
37
+ def description(event)
38
+ d = event.split(" ")
39
+ d[4..d.length-4].join(" ")
40
+ end
41
+
42
+ def location(event)
43
+ d = event.gsub(".", "").split(" ")
44
+ city, state, zip = d.last(3)
45
+ "#{city}, #{state} #{zip}"
46
+ end
51
47
  end
@@ -37,5 +37,15 @@ module Trackerific
37
37
  @services.map {|n,s| s if s.can_track?(id) }.compact
38
38
  end
39
39
  end
40
+
41
+ module Concerns
42
+ require 'trackerific/services/concerns/soap'
43
+ require 'trackerific/services/concerns/xml'
44
+ end
45
+
46
+ require 'trackerific/services/base'
47
+ require 'trackerific/services/fedex'
48
+ require 'trackerific/services/ups'
49
+ require 'trackerific/services/usps'
40
50
  end
41
51
  end
@@ -1,58 +1,85 @@
1
- module Trackerific
2
- module Services
3
- class Base
4
- @name = nil
5
-
6
- class << self
7
- attr_accessor :name
8
-
9
- # Registers the service with Trackerific
10
- # @api semipublic
11
- def register(name)
12
- self.name = name.to_sym
13
- Trackerific::Services[self.name] = self
14
- end
15
-
16
- # Creates a new instance and calls #track with the given id
17
- # @param id The package identifier
18
- # @return Either a Trackerific::Details or Trackerific::Error
19
- def track(id)
20
- new.track(id)
21
- end
22
-
23
- # Reads the credentials from Trackerific.config
24
- # @return [Hash] The service's credentials
25
- def credentials
26
- Trackerific.config[name]
27
- end
28
-
29
- # Checks if the given package ID can be tracked by this service
30
- # @param [String] id The package ID
31
- # @return [Boolean] true when this service can track the given ID
32
- # @note This will always be false if no credentials were found for the
33
- # service in Trackerific.config
34
- def can_track?(id)
35
- return false if credentials.nil?
36
- package_id_matchers.each {|m| return true if id =~ m }
37
- false
38
- end
39
-
40
- # An Array of Regexp that matches valid package ids for the service
41
- # @api semipublic
42
- def package_id_matchers
43
- raise NotImplementedError,
44
- "You must implement this method in your service", caller
45
- end
46
- end
47
-
48
- def initialize(credentials=self.class.credentials)
49
- @credentials = credentials
50
-
51
- if credentials.nil?
52
- raise Trackerific::Error,
53
- "Missing credentials for #{self.class.name}", caller
54
- end
55
- end
1
+ class Trackerific::Services::Base
2
+ class << self
3
+ attr_accessor :name
4
+ attr_accessor :config
5
+
6
+ # Configures the service
7
+ # @api semipublic
8
+ def configure(&block)
9
+ yield self.config = OpenStruct.new
10
+ end
11
+
12
+ # Includes the service concerns for the given service type
13
+ # @param [Symbol] service_type The module name for the service type
14
+ # @api semipublic
15
+ def concerns(service_type)
16
+ self.send :include,
17
+ "Trackerific::Services::Concerns::#{service_type}".constantize
18
+ end
19
+
20
+ # Registers the service with Trackerific
21
+ # @api semipublic
22
+ def register(name, options={})
23
+ concerns(options[:as]) if options[:as].present?
24
+ self.name = name.to_sym
25
+ Trackerific::Services[self.name] = self
26
+ end
27
+
28
+ # Creates a new instance and calls #track with the given id
29
+ # @param id The package identifier
30
+ # @return Either a Trackerific::Details or Trackerific::Error
31
+ def track(id)
32
+ new.track(id)
33
+ end
34
+
35
+ # Reads the credentials from Trackerific.config
36
+ # @return [Hash] The service's credentials
37
+ def credentials
38
+ Trackerific.config[name]
39
+ end
40
+
41
+ # Checks if the given package ID can be tracked by this service
42
+ # @param [String] id The package ID
43
+ # @return [Boolean] true when this service can track the given ID
44
+ # @note This will always be false if no credentials were found for the
45
+ # service in Trackerific.config
46
+ def can_track?(id)
47
+ return false if credentials.nil?
48
+ package_id_matchers.each {|m| return true if id =~ m }
49
+ false
50
+ end
51
+
52
+ # An Array of Regexp that matches valid package ids for the service
53
+ # @api semipublic
54
+ def package_id_matchers
55
+ config.package_id_matchers
56
+ end
57
+ end
58
+
59
+ def initialize(credentials=self.class.credentials)
60
+ @credentials = credentials
61
+
62
+ if credentials.nil?
63
+ raise Trackerific::Error,
64
+ "Missing credentials for #{self.class.name}", caller
56
65
  end
57
66
  end
67
+
68
+ def config
69
+ self.class.config
70
+ end
71
+
72
+ def track(id)
73
+ result = config.parser.new(id, request(id)).parse
74
+ result.is_a?(Trackerific::Error) ? raise(result) : result
75
+ end
76
+
77
+ protected
78
+
79
+ def builder(id)
80
+ members = config.builder.members - [:package_id]
81
+ credentials = @credentials.values_at(*members)
82
+ credentials << id
83
+ config.builder.new(*credentials)
84
+ end
58
85
  end