active_utils 2.2.3 → 3.0.0.pre1

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 (42) hide show
  1. checksums.yaml +4 -4
  2. checksums.yaml.gz.sig +0 -0
  3. data/.travis.yml +13 -3
  4. data/Gemfile +1 -1
  5. data/Gemfile.activesupport32 +4 -0
  6. data/Gemfile.activesupport40 +4 -0
  7. data/Gemfile.activesupport41 +4 -0
  8. data/Gemfile.activesupport42 +4 -0
  9. data/active_utils.gemspec +2 -1
  10. data/lib/active_utils/common/connection.rb +3 -169
  11. data/lib/active_utils/common/country.rb +3 -329
  12. data/lib/active_utils/common/currency_code.rb +3 -49
  13. data/lib/active_utils/common/error.rb +3 -28
  14. data/lib/active_utils/common/network_connection_retries.rb +3 -72
  15. data/lib/active_utils/common/post_data.rb +3 -23
  16. data/lib/active_utils/common/posts_data.rb +3 -76
  17. data/lib/active_utils/common/requires_parameters.rb +3 -15
  18. data/lib/active_utils/common/utils.rb +3 -19
  19. data/lib/active_utils/common/validateable.rb +3 -80
  20. data/lib/active_utils/common/version.rb +4 -0
  21. data/lib/active_utils/connection.rb +170 -0
  22. data/lib/active_utils/country.rb +330 -0
  23. data/lib/active_utils/currency_code.rb +51 -0
  24. data/lib/active_utils/error.rb +29 -0
  25. data/lib/active_utils/network_connection_retries.rb +78 -0
  26. data/lib/active_utils/post_data.rb +24 -0
  27. data/lib/active_utils/posts_data.rb +78 -0
  28. data/lib/active_utils/requires_parameters.rb +16 -0
  29. data/lib/active_utils/utils.rb +20 -0
  30. data/lib/active_utils/validateable.rb +81 -0
  31. data/lib/active_utils/version.rb +1 -1
  32. data/lib/active_utils.rb +21 -16
  33. data/test/test_helper.rb +15 -4
  34. data/test/unit/connection_test.rb +15 -15
  35. data/test/unit/network_connection_retries_test.rb +62 -11
  36. data/test/unit/post_data_test.rb +6 -6
  37. data/test/unit/posts_data_test.rb +4 -4
  38. data/test/unit/utils_test.rb +1 -1
  39. data/test/unit/validateable_test.rb +1 -1
  40. data.tar.gz.sig +0 -0
  41. metadata +35 -6
  42. metadata.gz.sig +0 -0
@@ -1,50 +1,4 @@
1
- module ActiveMerchant
2
- class InvalidCurrencyCodeError < StandardError
3
- end
1
+ require "active_utils/active_merchant_shim"
4
2
 
5
- class CurrencyCode
6
- ISO_CURRENCIES = [
7
- "AED", "ALL", "AMD", "ANG", "AOA", "ARS", "AUD", "AWG", "AZN", "BAM", "BBD", "BDT", "BGN", "BHD",
8
- "BND", "BOB", "BRL", "BSD", "BTN", "BWP", "BYR", "BZD", "CAD", "CHF", "CLP", "CNY", "COP", "CRC",
9
- "CZK", "DKK", "DOP", "DZD", "EGP", "ETB", "EUR", "FJD", "GBP", "GEL", "GHS", "GMD", "GTQ", "GYD",
10
- "HKD", "HNL", "HRK", "HUF", "IDR", "ILS", "INR", "ISK", "JEP", "JMD", "JOD", "JPY", "KES", "KGS",
11
- "KHR", "KRW", "KWD", "KYD", "KZT", "LBP", "LKR", "LTL", "LVL", "MAD", "MDL", "MGA", "MKD", "MMK",
12
- "MNT", "MOP", "MUR", "MVR", "MXN", "MYR", "MZN", "NAD", "NGN", "NIO", "NOK", "NPR", "NZD", "OMR",
13
- "PEN", "PGK", "PHP", "PKR", "PLN", "PYG", "QAR", "RON", "RSD", "RUB", "RWF", "SAR", "SCR", "SEK",
14
- "SGD", "STD", "SYP", "THB", "TND", "TRY", "TTD", "TWD", "TZS", "UAH", "UGX", "USD", "UYU", "VEF",
15
- "VND", "VUV", "WST", "XAF", "XCD", "XOF", "XPF", "ZAR", "ZMW"
16
- ]
17
-
18
- NON_ISO_TO_ISO = {
19
- "ARN" => "ARS",
20
- "AZM" => "AZN",
21
- "CHP" => "CLP",
22
- "DHS" => "AED",
23
- "ECD" => "XCD",
24
- "GHC" => "GHS",
25
- "JAD" => "JMD",
26
- "JYE" => "JPY",
27
- "KUD" => "KWD",
28
- "MZM" => "MZN",
29
- "NTD" => "TWD",
30
- "NMP" => "MXN",
31
- "RDD" => "DOP",
32
- "RMB" => "CNY",
33
- "SFR" => "CHF",
34
- "SID" => "SGD",
35
- "UKL" => "GBP",
36
- "WON" => "KRW"
37
- }
38
-
39
- def self.standardize(code)
40
- code = code.upcase unless code.nil?
41
-
42
- return code if is_iso?(code)
43
- NON_ISO_TO_ISO[code] || raise(InvalidCurrencyCodeError, "#{code} is not an ISO currency, nor can it be converted to one.")
44
- end
45
-
46
- def self.is_iso?(code)
47
- ISO_CURRENCIES.include? code
48
- end
49
- end
50
- end
3
+ ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
4
+ require "active_utils/currency_code"
@@ -1,29 +1,4 @@
1
- module ActiveMerchant #:nodoc:
2
- class ActiveMerchantError < StandardError #:nodoc:
3
- end
1
+ require "active_utils/active_merchant_shim"
4
2
 
5
- class ConnectionError < ActiveMerchantError # :nodoc:
6
- end
7
-
8
- class RetriableConnectionError < ConnectionError # :nodoc:
9
- end
10
-
11
- class ResponseError < ActiveMerchantError # :nodoc:
12
- attr_reader :response
13
-
14
- def initialize(response, message = nil)
15
- @response = response
16
- @message = message
17
- end
18
-
19
- def to_s
20
- "Failed with #{response.code} #{response.message if response.respond_to?(:message)}"
21
- end
22
- end
23
-
24
- class ClientCertificateError < ActiveMerchantError # :nodoc
25
- end
26
-
27
- class InvalidResponseError < ActiveMerchantError # :nodoc
28
- end
29
- end
3
+ ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
4
+ require "active_utils/error"
@@ -1,73 +1,4 @@
1
- module ActiveMerchant
2
- module NetworkConnectionRetries
3
- DEFAULT_RETRIES = 3
4
- DEFAULT_CONNECTION_ERRORS = {
5
- EOFError => "The remote server dropped the connection",
6
- Errno::ECONNRESET => "The remote server reset the connection",
7
- Timeout::Error => "The connection to the remote server timed out",
8
- Errno::ETIMEDOUT => "The connection to the remote server timed out",
9
- SocketError => "The connection to the remote server could not be established",
10
- OpenSSL::SSL::SSLError => "The SSL connection to the remote server could not be established"
11
- }
1
+ require "active_utils/active_merchant_shim"
12
2
 
13
- def self.included(base)
14
- base.send(:attr_accessor, :retry_safe)
15
- end
16
-
17
- def retry_exceptions(options={})
18
- connection_errors = DEFAULT_CONNECTION_ERRORS.merge(options[:connection_exceptions] || {})
19
-
20
- retry_network_exceptions(options) do
21
- begin
22
- yield
23
- rescue Errno::ECONNREFUSED => e
24
- raise ActiveMerchant::RetriableConnectionError, "The remote server refused the connection"
25
- rescue OpenSSL::X509::CertificateError => e
26
- NetworkConnectionRetries.log(options[:logger], :error, e.message, options[:tag])
27
- raise ActiveMerchant::ClientCertificateError, "The remote server did not accept the provided SSL certificate"
28
- rescue Zlib::BufError => e
29
- raise ActiveMerchant::InvalidResponseError, "The remote server replied with an invalid response"
30
- rescue *connection_errors.keys => e
31
- raise ActiveMerchant::ConnectionError, connection_errors[e.class]
32
- end
33
- end
34
- end
35
-
36
- private
37
-
38
- def retry_network_exceptions(options = {})
39
- initial_retries = options[:max_retries] || DEFAULT_RETRIES
40
- retries = initial_retries
41
- request_start = nil
42
-
43
- begin
44
- request_start = Time.now.to_f
45
- result = yield
46
- log_with_retry_details(options[:logger], initial_retries-retries + 1, Time.now.to_f - request_start, "success", options[:tag])
47
- result
48
- rescue ActiveMerchant::RetriableConnectionError => e
49
- retries -= 1
50
-
51
- log_with_retry_details(options[:logger], initial_retries-retries, Time.now.to_f - request_start, e.message, options[:tag])
52
- retry unless retries.zero?
53
- raise ActiveMerchant::ConnectionError, e.message
54
- rescue ActiveMerchant::ConnectionError, ActiveMerchant::InvalidResponseError => e
55
- retries -= 1
56
- log_with_retry_details(options[:logger], initial_retries-retries, Time.now.to_f - request_start, e.message, options[:tag])
57
- retry if (options[:retry_safe] || retry_safe) && !retries.zero?
58
- raise
59
- end
60
- end
61
-
62
- def self.log(logger, level, message, tag=nil)
63
- tag ||= self.class.to_s
64
- message = "[#{tag}] #{message}"
65
- logger.send(level, message) if logger
66
- end
67
-
68
- private
69
- def log_with_retry_details(logger, attempts, time, message, tag)
70
- NetworkConnectionRetries.log(logger, :info, "connection_attempt=%d connection_request_time=%.4fs connection_msg=\"%s\"" % [attempts, time, message], tag)
71
- end
72
- end
73
- end
3
+ ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
4
+ require "active_utils/network_connection_retries"
@@ -1,24 +1,4 @@
1
- require 'cgi'
1
+ require "active_utils/active_merchant_shim"
2
2
 
3
- module ActiveMerchant
4
- class PostData < Hash
5
- class_attribute :required_fields, :instance_writer => false
6
- self.required_fields = []
7
-
8
- def []=(key, value)
9
- return if value.blank? && !required?(key)
10
- super
11
- end
12
-
13
- def to_post_data
14
- collect { |key, value| "#{key}=#{CGI.escape(value.to_s)}" }.join("&")
15
- end
16
-
17
- alias_method :to_s, :to_post_data
18
-
19
- private
20
- def required?(key)
21
- required_fields.include?(key)
22
- end
23
- end
24
- end
3
+ ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
4
+ require "active_utils/post_data"
@@ -1,77 +1,4 @@
1
- module ActiveMerchant #:nodoc:
2
- module PostsData #:nodoc:
1
+ require "active_utils/active_merchant_shim"
3
2
 
4
- def self.included(base)
5
- base.superclass_delegating_accessor :ssl_strict
6
- base.ssl_strict = true
7
-
8
- base.superclass_delegating_accessor :ssl_version
9
- base.ssl_version = nil
10
-
11
- base.class_attribute :retry_safe
12
- base.retry_safe = false
13
-
14
- base.superclass_delegating_accessor :open_timeout
15
- base.open_timeout = 60
16
-
17
- base.superclass_delegating_accessor :read_timeout
18
- base.read_timeout = 60
19
-
20
- base.superclass_delegating_accessor :max_retries
21
- base.max_retries = Connection::MAX_RETRIES
22
-
23
- base.superclass_delegating_accessor :logger
24
- base.superclass_delegating_accessor :wiredump_device
25
- end
26
-
27
- def ssl_get(endpoint, headers={})
28
- ssl_request(:get, endpoint, nil, headers)
29
- end
30
-
31
- def ssl_post(endpoint, data, headers = {})
32
- ssl_request(:post, endpoint, data, headers)
33
- end
34
-
35
- def ssl_request(method, endpoint, data, headers)
36
- handle_response(raw_ssl_request(method, endpoint, data, headers))
37
- end
38
-
39
- def raw_ssl_request(method, endpoint, data, headers = {})
40
- logger.warn "#{self.class} using ssl_strict=false, which is insecure" if logger unless ssl_strict
41
-
42
- connection = new_connection(endpoint)
43
- connection.open_timeout = open_timeout
44
- connection.read_timeout = read_timeout
45
- connection.retry_safe = retry_safe
46
- connection.verify_peer = ssl_strict
47
- connection.ssl_version = ssl_version
48
- connection.logger = logger
49
- connection.max_retries = max_retries
50
- connection.tag = self.class.name
51
- connection.wiredump_device = wiredump_device
52
-
53
- connection.pem = @options[:pem] if @options
54
- connection.pem_password = @options[:pem_password] if @options
55
-
56
- connection.ignore_http_status = @options[:ignore_http_status] if @options
57
-
58
- connection.request(method, data, headers)
59
- end
60
-
61
- private
62
-
63
- def new_connection(endpoint)
64
- Connection.new(endpoint)
65
- end
66
-
67
- def handle_response(response)
68
- case response.code.to_i
69
- when 200...300
70
- response.body
71
- else
72
- raise ResponseError.new(response)
73
- end
74
- end
75
-
76
- end
77
- end
3
+ ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
4
+ require "active_utils/posts_data"
@@ -1,16 +1,4 @@
1
- module ActiveMerchant #:nodoc:
2
- module RequiresParameters #:nodoc:
3
- def requires!(hash, *params)
4
- params.each do |param|
5
- if param.is_a?(Array)
6
- raise ArgumentError.new("Missing required parameter: #{param.first}") unless hash.has_key?(param.first)
1
+ require "active_utils/active_merchant_shim"
7
2
 
8
- valid_options = param[1..-1]
9
- raise ArgumentError.new("Parameter: #{param.first} must be one of #{valid_options.to_sentence(:words_connector => 'or')}") unless valid_options.include?(hash[param.first])
10
- else
11
- raise ArgumentError.new("Missing required parameter: #{param}") unless hash.has_key?(param)
12
- end
13
- end
14
- end
15
- end
16
- end
3
+ ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
4
+ require "active_utils/requires_parameters"
@@ -1,20 +1,4 @@
1
- require 'securerandom'
1
+ require "active_utils/active_merchant_shim"
2
2
 
3
- module ActiveMerchant #:nodoc:
4
- module Utils #:nodoc:
5
- def generate_unique_id
6
- SecureRandom.hex(16)
7
- end
8
-
9
- module_function :generate_unique_id
10
-
11
- def deprecated(message)
12
- warning = Kernel.caller[1] + message
13
- if respond_to?(:logger) && logger.present?
14
- logger.warn(warning)
15
- else
16
- warn(warning)
17
- end
18
- end
19
- end
20
- end
3
+ ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
4
+ require "active_utils/utils"
@@ -1,81 +1,4 @@
1
- module ActiveMerchant #:nodoc:
2
- module Validateable #:nodoc:
3
- def valid?
4
- errors.clear
1
+ require "active_utils/active_merchant_shim"
5
2
 
6
- before_validate if respond_to?(:before_validate, true)
7
- validate if respond_to?(:validate, true)
8
-
9
- errors.empty?
10
- end
11
-
12
- def initialize(attributes = {})
13
- self.attributes = attributes
14
- end
15
-
16
- def errors
17
- @errors ||= Errors.new(self)
18
- end
19
-
20
- private
21
-
22
- def attributes=(attributes)
23
- unless attributes.nil?
24
- for key, value in attributes
25
- send("#{key}=", value )
26
- end
27
- end
28
- end
29
-
30
- # This hash keeps the errors of the object
31
- class Errors < HashWithIndifferentAccess
32
-
33
- def initialize(base)
34
- super() { |h, k| h[k] = [] ; h[k] }
35
- @base = base
36
- end
37
-
38
- def count
39
- size
40
- end
41
-
42
- def empty?
43
- all? { |k, v| v && v.empty? }
44
- end
45
-
46
- # returns a specific fields error message.
47
- # if more than one error is available we will only return the first. If no error is available
48
- # we return an empty string
49
- def on(field)
50
- self[field].to_a.first
51
- end
52
-
53
- def add(field, error)
54
- self[field] << error
55
- end
56
-
57
- def add_to_base(error)
58
- add(:base, error)
59
- end
60
-
61
- def each_full
62
- full_messages.each { |msg| yield msg }
63
- end
64
-
65
- def full_messages
66
- result = []
67
-
68
- self.each do |key, messages|
69
- next if messages.blank?
70
- if key == 'base'
71
- result << "#{messages.first}"
72
- else
73
- result << "#{key.to_s.humanize} #{messages.first}"
74
- end
75
- end
76
-
77
- result
78
- end
79
- end
80
- end
81
- end
3
+ ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
4
+ require "active_utils/validateable"
@@ -0,0 +1,4 @@
1
+ require "active_utils/active_merchant_shim"
2
+
3
+ ActiveUtils::Utils.deprecated(ActiveUtils::MOVED_FILE_MESSAGE)
4
+ require "active_utils/version"
@@ -0,0 +1,170 @@
1
+ require 'uri'
2
+ require 'net/http'
3
+ require 'net/https'
4
+ require 'benchmark'
5
+
6
+ module ActiveUtils
7
+ class Connection
8
+ include NetworkConnectionRetries
9
+
10
+ MAX_RETRIES = 3
11
+ OPEN_TIMEOUT = 60
12
+ READ_TIMEOUT = 60
13
+ VERIFY_PEER = true
14
+ CA_FILE = (File.dirname(__FILE__) + '/../../certs/cacert.pem')
15
+ CA_PATH = nil
16
+ RETRY_SAFE = false
17
+ RUBY_184_POST_HEADERS = { "Content-Type" => "application/x-www-form-urlencoded" }
18
+
19
+ attr_accessor :endpoint
20
+ attr_accessor :open_timeout
21
+ attr_accessor :read_timeout
22
+ attr_accessor :verify_peer
23
+ attr_accessor :ssl_version
24
+ attr_accessor :ca_file
25
+ attr_accessor :ca_path
26
+ attr_accessor :retry_safe
27
+ attr_accessor :pem
28
+ attr_accessor :pem_password
29
+ attr_accessor :wiredump_device
30
+ attr_accessor :logger
31
+ attr_accessor :tag
32
+ attr_accessor :ignore_http_status
33
+ attr_accessor :max_retries
34
+ attr_accessor :proxy_address
35
+ attr_accessor :proxy_port
36
+
37
+ def initialize(endpoint)
38
+ @endpoint = endpoint.is_a?(URI) ? endpoint : URI.parse(endpoint)
39
+ @open_timeout = OPEN_TIMEOUT
40
+ @read_timeout = READ_TIMEOUT
41
+ @retry_safe = RETRY_SAFE
42
+ @verify_peer = VERIFY_PEER
43
+ @ca_file = CA_FILE
44
+ @ca_path = CA_PATH
45
+ @max_retries = MAX_RETRIES
46
+ @ignore_http_status = false
47
+ @ssl_version = nil
48
+ @proxy_address = nil
49
+ @proxy_port = nil
50
+ end
51
+
52
+ def request(method, body, headers = {})
53
+ request_start = Time.now.to_f
54
+
55
+ retry_exceptions(:max_retries => max_retries, :logger => logger, :tag => tag) do
56
+ begin
57
+ info "connection_http_method=#{method.to_s.upcase} connection_uri=#{endpoint}", tag
58
+
59
+ result = nil
60
+
61
+ realtime = Benchmark.realtime do
62
+ result = case method
63
+ when :get
64
+ raise ArgumentError, "GET requests do not support a request body" if body
65
+ http.get(endpoint.request_uri, headers)
66
+ when :post
67
+ debug body
68
+ http.post(endpoint.request_uri, body, RUBY_184_POST_HEADERS.merge(headers))
69
+ when :put
70
+ debug body
71
+ http.put(endpoint.request_uri, body, headers)
72
+ when :delete
73
+ # It's kind of ambiguous whether the RFC allows bodies
74
+ # for DELETE requests. But Net::HTTP's delete method
75
+ # very unambiguously does not.
76
+ raise ArgumentError, "DELETE requests do not support a request body" if body
77
+ http.delete(endpoint.request_uri, headers)
78
+ else
79
+ raise ArgumentError, "Unsupported request method #{method.to_s.upcase}"
80
+ end
81
+ end
82
+
83
+ info "--> %d %s (%d %.4fs)" % [result.code, result.message, result.body ? result.body.length : 0, realtime], tag
84
+ debug result.body
85
+ result
86
+ end
87
+ end
88
+
89
+ ensure
90
+ info "connection_request_total_time=%.4fs" % [Time.now.to_f - request_start], tag
91
+ end
92
+
93
+ private
94
+ def http
95
+ http = Net::HTTP.new(endpoint.host, endpoint.port, proxy_address, proxy_port)
96
+ configure_debugging(http)
97
+ configure_timeouts(http)
98
+ configure_ssl(http)
99
+ configure_cert(http)
100
+ http
101
+ end
102
+
103
+ def configure_debugging(http)
104
+ http.set_debug_output(wiredump_device)
105
+ end
106
+
107
+ def configure_timeouts(http)
108
+ http.open_timeout = open_timeout
109
+ http.read_timeout = read_timeout
110
+ end
111
+
112
+ def configure_ssl(http)
113
+ return unless endpoint.scheme == "https"
114
+
115
+ http.use_ssl = true
116
+ http.ssl_version = ssl_version if ssl_version
117
+
118
+ if verify_peer
119
+ http.verify_mode = OpenSSL::SSL::VERIFY_PEER
120
+ http.ca_file = ca_file
121
+ http.ca_path = ca_path
122
+ else
123
+ http.verify_mode = OpenSSL::SSL::VERIFY_NONE
124
+ end
125
+
126
+ end
127
+
128
+ def configure_cert(http)
129
+ return if pem.blank?
130
+
131
+ http.cert = OpenSSL::X509::Certificate.new(pem)
132
+
133
+ if pem_password
134
+ http.key = OpenSSL::PKey::RSA.new(pem, pem_password)
135
+ else
136
+ http.key = OpenSSL::PKey::RSA.new(pem)
137
+ end
138
+ end
139
+
140
+ def handle_response(response)
141
+ if @ignore_http_status then
142
+ return response.body
143
+ else
144
+ case response.code.to_i
145
+ when 200...300
146
+ response.body
147
+ else
148
+ raise ResponseError.new(response)
149
+ end
150
+ end
151
+ end
152
+
153
+ def debug(message, tag = nil)
154
+ log(:debug, message, tag)
155
+ end
156
+
157
+ def info(message, tag = nil)
158
+ log(:info, message, tag)
159
+ end
160
+
161
+ def error(message, tag = nil)
162
+ log(:error, message, tag)
163
+ end
164
+
165
+ def log(level, message, tag)
166
+ message = "[#{tag}] #{message}" if tag
167
+ logger.send(level, message) if logger
168
+ end
169
+ end
170
+ end