active_utils 2.2.3 → 3.0.0.pre1

Sign up to get free protection for your applications and to get access to all the features.
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