trackerific 0.3.5 → 0.4.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (42) hide show
  1. data/Gemfile +1 -1
  2. data/README.rdoc +37 -13
  3. data/VERSION +1 -1
  4. data/doc/OptionsHelper.html +287 -0
  5. data/doc/Trackerific.html +588 -35
  6. data/doc/Trackerific/Configuration.html +354 -0
  7. data/doc/Trackerific/Details.html +1 -1
  8. data/doc/Trackerific/Error.html +1 -1
  9. data/doc/Trackerific/Event.html +1 -1
  10. data/doc/Trackerific/FedEx.html +52 -35
  11. data/doc/Trackerific/{Base.html → Service.html} +54 -49
  12. data/doc/Trackerific/UPS.html +48 -31
  13. data/doc/Trackerific/USPS.html +51 -34
  14. data/doc/_index.html +35 -4
  15. data/doc/class_list.html +1 -1
  16. data/doc/file.README.html +42 -15
  17. data/doc/index.html +42 -15
  18. data/doc/method_list.html +83 -19
  19. data/doc/top-level-namespace.html +2 -2
  20. data/lib/helpers/options_helper.rb +20 -0
  21. data/lib/trackerific.rb +52 -18
  22. data/lib/trackerific/configuration.rb +49 -0
  23. data/lib/trackerific/service.rb +68 -0
  24. data/lib/trackerific/services/fedex.rb +18 -16
  25. data/lib/trackerific/services/ups.rb +16 -14
  26. data/lib/trackerific/services/usps.rb +17 -15
  27. data/spec/lib/trackerific/configuration_spec.rb +9 -0
  28. data/spec/lib/trackerific/details_spec.rb +12 -9
  29. data/spec/lib/trackerific/error_spec.rb +6 -2
  30. data/spec/lib/trackerific/event_spec.rb +21 -8
  31. data/spec/lib/trackerific/service_spec.rb +34 -0
  32. data/spec/lib/trackerific/services/fedex_spec.rb +23 -9
  33. data/spec/lib/trackerific/services/ups_spec.rb +23 -8
  34. data/spec/lib/trackerific/services/usps_spec.rb +22 -8
  35. data/spec/lib/trackerific_spec.rb +29 -7
  36. data/spec/spec_helper.rb +1 -0
  37. data/spec/support/fixtures.rb +16 -10
  38. data/spec/support/trackerific.rb +2 -2
  39. data/trackerific.gemspec +13 -8
  40. metadata +30 -25
  41. data/lib/trackerific/base.rb +0 -70
  42. data/spec/lib/trackerific/base_spec.rb +0 -34
@@ -0,0 +1,20 @@
1
+ # Helper for validating required options
2
+ module OptionsHelper
3
+ # Validates a list of options against a list of required options
4
+ # @param [Array] options list of options to validate
5
+ # @param [Array] required list of required options
6
+ # @return true
7
+ # @raise [ArgumentError] if the options do not pass validation
8
+ # @api private
9
+ def validate_options(options, required)
10
+ # make sure all the required options exist
11
+ required.each do |k|
12
+ raise ArgumentError.new("Missing required parameter: #{k}") unless options.has_key?(k)
13
+ end
14
+ # make sure no invalid options exist
15
+ options.each do |k, v|
16
+ raise ArgumentError.new("Invalid parameter: #{k}") unless required.include?(k)
17
+ end
18
+ true
19
+ end
20
+ end
data/lib/trackerific.rb CHANGED
@@ -1,5 +1,7 @@
1
1
  require 'rails'
2
- require 'trackerific/base'
2
+ require 'helpers/options_helper'
3
+ require 'trackerific/configuration'
4
+ require 'trackerific/service'
3
5
  require 'trackerific/error'
4
6
  require 'trackerific/details'
5
7
  require 'trackerific/event'
@@ -10,6 +12,30 @@ Dir[File.expand_path(services_path)].each { |file| require file }
10
12
 
11
13
  # Trackerific provides package tracking to Rails apps.
12
14
  module Trackerific
15
+
16
+ class << self
17
+ # Gets a list of all Trackerific services
18
+ # @return [Array, Symbol] the services
19
+ # @api private
20
+ def services
21
+ # a service is any Trackerific class that descends from Trackerific::Service
22
+ Trackerific.constants.reject { |const|
23
+ const unless Trackerific.const_get(const).superclass == Trackerific::Service
24
+ }
25
+ end
26
+
27
+ # Gets a Trackerific::Service class
28
+ # @param [Symbol] name the name of the service
29
+ # @return [Trackerific::Service] the service, or nil
30
+ # @api private
31
+ def service_get(name)
32
+ services.each do |service|
33
+ return Trackerific.const_get(service) if name == service.to_s.downcase.to_sym
34
+ end
35
+ return nil
36
+ end
37
+ end
38
+
13
39
  # Checks a string for a valid package tracking service
14
40
  # @param [String] package_id the package identifier
15
41
  # @return [Trackerific::Base] the Trackerific class that can track the given
@@ -19,33 +45,41 @@ module Trackerific
19
45
  # tracking_service "183689015000001" # => Trackerific::FedEx
20
46
  # @api public
21
47
  def tracking_service(package_id)
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
48
+ # loop through all the services
49
+ Trackerific.services.each do |service|
50
+ # get the class associated with this service
51
+ cls = Trackerific.const_get(service)
52
+ # loop through all the packge id regular expressions
53
+ cls.package_id_matchers.each do |matcher|
54
+ # return this class if the regular expression matches
55
+ return cls if package_id =~ matcher
33
56
  end
34
57
  end
35
58
  # if we've made it this far, nothing matched
36
59
  nil
37
60
  end
38
61
 
39
- # TODO: Tracks a package by determining its service from the package id
62
+ # Tracks a package by determining its service from the package id
40
63
  # @param [String] package_id the package identifier
41
64
  # @return [Trackerific::Details] the tracking results
42
65
  # @raise [Trackerific::Error] raised when the server returns an error (invalid credentials, tracking package, etc.)
43
66
  # @example Track a package
44
67
  # include Trackerific
45
- # details = track_package("183689015000001")
68
+ # # make sure to configure Trackerific before hand with the different services credentials
69
+ # Trackerific.config do |config|
70
+ # config.fedex :meter => '123456789', :account => '123456789'
71
+ # end
72
+ # details = track_package "183689015000001"
46
73
  # @api public
47
- # def track_package(package_id)
48
- # service = tracking_service(package_id)
49
- #
50
- # end
74
+ def track_package(package_id)
75
+ # find the service that will be able to track this package
76
+ service = tracking_service package_id
77
+ raise Trackerific::Error "Cannot find a service to track package id #{package_id}" if service.nil?
78
+ # get the name of the service
79
+ service_name = service.to_s.split('::')[1].downcase
80
+ # get the default configuration for the service
81
+ options = Trackerific.configuration.send service_name
82
+ # track the package
83
+ service.new(options).track_package package_id
84
+ end
51
85
  end
@@ -0,0 +1,49 @@
1
+ module Trackerific
2
+ # Provides a dynamic configuration
3
+ class Configuration
4
+ include OptionsHelper
5
+ # Creates a new instance of Trackerific::Configuration
6
+ # @api private
7
+ def initialize
8
+ @options = {}
9
+ end
10
+ # Overriding the method_missing method allows dynamic methods
11
+ # @return [Hash]
12
+ # @api private
13
+ def method_missing(sym, *args, &block)
14
+ # Get a list of all the services (convert symbols to lower case)
15
+ services = Trackerific.services.map { |service| service.to_s.downcase.to_sym }
16
+ # Do not accept any configuration values for anything except services
17
+ raise NoMethodError unless services.include? sym
18
+ # Only accept Hashes
19
+ unless args.empty?
20
+ raise ArgumentError unless args[0].class == Hash
21
+ # Validate configuration values against the required options for that service
22
+ validate_options args[0], Trackerific.service_get(sym).required_options
23
+ # Store the configuration options
24
+ @options[sym] = args[0]
25
+ end
26
+ # return the configuration options
27
+ @options[sym]
28
+ end
29
+ end
30
+ class << self
31
+ # Stores the configuration options for Trackerific
32
+ # @return [Trackerific::Configuration]
33
+ # @api private
34
+ def configuration
35
+ @configuration ||= Trackerific::Configuration.new
36
+ end
37
+ # Configures Trackerific
38
+ # @return [Trackerific::Configuration]
39
+ # @example Defining credentials
40
+ # Trackerific.configure do |config|
41
+ # config.fedex :meter => '123456789', :account => '123456789'
42
+ # end
43
+ # @api public
44
+ def configure
45
+ yield configuration
46
+ configuration
47
+ end
48
+ end
49
+ end
@@ -0,0 +1,68 @@
1
+ module Trackerific
2
+ # Base class for Trackerific services
3
+ class Service
4
+ include OptionsHelper
5
+
6
+ # Creates a new instance of Trackerific::Service with required options
7
+ # @api private
8
+ def initialize(options = {})
9
+ validate_options options, self.class.required_options
10
+ @options = options
11
+ end
12
+
13
+ # Gets the tracking information for the package from the server
14
+ # @param [String] package_id the package identifier
15
+ # @return [Trackerific::Details] the tracking details
16
+ # @example Override this method in your custom tracking service to implement tracking
17
+ # module Trackerific
18
+ # class MyTrackingService < Trackerific::Service
19
+ # def track_package
20
+ # # your tracking code here
21
+ # Trackerific::Details.new(
22
+ # "summary of tracking events",
23
+ # [Trackerific::Event.new(Time.now, "summary", "location")]
24
+ # )
25
+ # end
26
+ # end
27
+ # end
28
+ # @api semipublic
29
+ def track_package(package_id)
30
+ @package_id = package_id
31
+ end
32
+
33
+ class << self
34
+
35
+ # An Array of Regexp that matches valid package identifiers for your service
36
+ # @example Override this method in your custom tracking service
37
+ # module Trackerific
38
+ # class MyTrackingService < Service
39
+ # def self.package_id_matchers
40
+ # [ /^.Z/, /^[HK].{10}$/ ] # matchers for UPS package identifiers
41
+ # end
42
+ # end
43
+ # end
44
+ # @return [Array, Regexp] an array of regular expressions
45
+ # @api semipublic
46
+ def package_id_matchers
47
+ nil
48
+ end
49
+
50
+ # An array of options that are required to create a new instance of this class
51
+ # @return [Array] the required options
52
+ # @example Override this method in your custom tracking service to enforce some options
53
+ # module Trackerific
54
+ # class MyTrackingService < Service
55
+ # def self.required_options
56
+ # [:all, :these, :are, :required]
57
+ # end
58
+ # end
59
+ # end
60
+ # @api semipublic
61
+ def required_options
62
+ []
63
+ end
64
+
65
+ end
66
+
67
+ end
68
+ end
@@ -3,12 +3,29 @@ require 'httparty'
3
3
  module Trackerific
4
4
 
5
5
  # Provides package tracking support for FedEx
6
- class FedEx < Base
6
+ class FedEx < Trackerific::Service
7
7
  # setup HTTParty
8
8
  include ::HTTParty
9
9
  format :xml
10
10
  base_uri "https://gateway.fedex.com"
11
11
 
12
+ class << self
13
+ # An Array of Regexp that matches valid FedEx package IDs
14
+ # @return [Array, Regexp] the regular expression
15
+ # @api private
16
+ def package_id_matchers
17
+ [ /^[0-9]{15}$/ ]
18
+ end
19
+
20
+ # Returns an Array of required options used when creating a new instance
21
+ # @return [Array] required options for tracking a FedEx package are :account
22
+ # and :meter
23
+ # @api private
24
+ def required_options
25
+ [:account, :meter]
26
+ end
27
+ end
28
+
12
29
  # Tracks a FedEx package
13
30
  # @param [String] package_id the package identifier
14
31
  # @return [Trackerific::Details] the tracking details
@@ -45,21 +62,6 @@ module Trackerific
45
62
  )
46
63
  end
47
64
 
48
- # An Array of Regexp that matches valid FedEx package IDs
49
- # @return [Array, Regexp] the regular expression
50
- # @api private
51
- def self.package_id_matchers
52
- [ /^[0-9]{15}$/ ]
53
- end
54
-
55
- # Returns an Array of required options used when creating a new instance
56
- # @return [Array] required options for tracking a FedEx package are :account
57
- # and :meter
58
- # @api private
59
- def self.required_options
60
- [:account, :meter]
61
- end
62
-
63
65
  protected
64
66
 
65
67
  # Builds the XML request to send to FedEx
@@ -4,7 +4,7 @@ module Trackerific
4
4
  require 'httparty'
5
5
 
6
6
  # Provides package tracking support for UPS.
7
- class UPS < Base
7
+ class UPS < Trackerific::Service
8
8
  # setup HTTParty
9
9
  include ::HTTParty
10
10
  format :xml
@@ -14,6 +14,21 @@ module Trackerific
14
14
  when 'production' then 'https://www.ups.com/ups.app/xml'
15
15
  end : 'https://www.ups.com/ups.app/xml'
16
16
 
17
+ class << self
18
+ # An Array of Regexp that matches valid UPS package IDs
19
+ # @return [Array, Regexp] the regular expression
20
+ # @api private
21
+ def package_id_matchers
22
+ [ /^.Z/, /^[HK].{10}$/ ]
23
+ end
24
+ # The required options for tracking a UPS package
25
+ # @return [Array] the required options for tracking a UPS package
26
+ # @api private
27
+ def required_options
28
+ [:key, :user_id, :password]
29
+ end
30
+ end
31
+
17
32
  # Tracks a UPS package
18
33
  # @param [String] package_id the package identifier
19
34
  # @return [Trackerific::Details] the tracking details
@@ -37,19 +52,6 @@ module Trackerific
37
52
  end
38
53
  end
39
54
 
40
- # An Array of Regexp that matches valid UPS package IDs
41
- # @return [Array, Regexp] the regular expression
42
- # @api private
43
- def self.package_id_matchers
44
- [ /^.Z/, /^[HK].{10}$/ ]
45
- end
46
- # The required options for tracking a UPS package
47
- # @return [Array] the required options for tracking a UPS package
48
- # @api private
49
- def self.required_options
50
- [:key, :user_id, :password]
51
- end
52
-
53
55
  protected
54
56
 
55
57
  # Parses the response from UPS
@@ -5,7 +5,7 @@ module Trackerific
5
5
  require 'httparty'
6
6
 
7
7
  # Provides package tracking support for USPS.
8
- class USPS < Base
8
+ class USPS < Trackerific::Service
9
9
  # setup HTTParty
10
10
  include HTTParty
11
11
  format :xml
@@ -15,6 +15,22 @@ module Trackerific
15
15
  when 'production' then 'https://secure.shippingapis.com'
16
16
  end : 'https://secure.shippingapis.com'
17
17
 
18
+ class << self
19
+ # An Array of Regexp that matches valid USPS package IDs
20
+ # @return [Array, Regexp] the regular expression
21
+ # @api private
22
+ def package_id_matchers
23
+ [ /^E\D{1}\d{9}\D{2}$|^9\d{15,21}$/ ]
24
+ end
25
+
26
+ # The required options for tracking a UPS package
27
+ # @return [Array] the required options for tracking a UPS package
28
+ # @api private
29
+ def required_options
30
+ [:user_id]
31
+ end
32
+ end
33
+
18
34
  # Tracks a USPS package
19
35
  # @param [String] package_id the package identifier
20
36
  # @return [Trackerific::Details] the tracking details
@@ -56,20 +72,6 @@ module Trackerific
56
72
  )
57
73
  end
58
74
 
59
- # An Array of Regexp that matches valid USPS package IDs
60
- # @return [Array, 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
65
-
66
- # The required options for tracking a UPS package
67
- # @return [Array] the required options for tracking a UPS package
68
- # @api private
69
- def self.required_options
70
- [:user_id]
71
- end
72
-
73
75
  protected
74
76
 
75
77
  # Builds an XML request to send to USPS
@@ -0,0 +1,9 @@
1
+ require 'spec_helper'
2
+
3
+ describe "Trackerific.configuration" do
4
+ include Trackerific
5
+
6
+ subject { Trackerific.configuration }
7
+ it { should be_a Trackerific::Configuration }
8
+
9
+ end
@@ -1,19 +1,22 @@
1
1
  require 'spec_helper'
2
2
 
3
3
  describe Trackerific::Details do
4
- before(:all) do
5
- @details = Trackerific::Details.new(String.new, String.new, Array.new)
6
- end
4
+
5
+ before { @details = Trackerific::Details.new(String.new, String.new, Array.new) }
7
6
 
8
- describe "events" do
9
- specify { @details.events.should be_a Array }
7
+ describe :events do
8
+ subject { @details.events }
9
+ it { should be_a Array }
10
10
  end
11
11
 
12
- describe "package_id" do
13
- specify { @details.package_id.should be_a String }
12
+ describe :package_id do
13
+ subject { @details.package_id }
14
+ it { should be_a String }
14
15
  end
15
16
 
16
- describe "summary" do
17
- specify { @details.summary.should be_a String }
17
+ describe :summary do
18
+ subject { @details.summary }
19
+ it { should be_a String }
18
20
  end
21
+
19
22
  end
@@ -1,5 +1,9 @@
1
1
  require 'spec_helper'
2
2
 
3
- describe 'Trackerific::Error' do
4
- # nothing to do here, yet
3
+ describe Trackerific::Error do
4
+
5
+ before { @error = Trackerific::Error.new }
6
+ subject { @error }
7
+ specify { should be_a StandardError }
8
+
5
9
  end