genesis_ruby 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/CHANGELOG.md +11 -0
- data/Gemfile +6 -0
- data/Gemfile.lock +158 -0
- data/LICENSE +21 -0
- data/README.md +343 -0
- data/Rakefile +12 -0
- data/VERSION +1 -0
- data/genesis_ruby.gemspec +43 -0
- data/lib/genesis_ruby/api/constants/currencies/iso4217.rb +1106 -0
- data/lib/genesis_ruby/api/constants/date_time_formats.rb +45 -0
- data/lib/genesis_ruby/api/constants/endpoints.rb +18 -0
- data/lib/genesis_ruby/api/constants/environments.rb +17 -0
- data/lib/genesis_ruby/api/constants/states/state.rb +43 -0
- data/lib/genesis_ruby/api/constants/states.rb +86 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/business/payment_types.rb +24 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/recurring/categories.rb +24 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/recurring/types.rb +28 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/sca_exemptions.rb +34 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/browser/color_depths.rb +46 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/card_holder_account/password_change_indicators.rb +37 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/card_holder_account/registration_indicators.rb +37 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/card_holder_account/shipping_address_usage_indicators.rb +34 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/card_holder_account/suspicious_activity_indicators.rb +28 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/card_holder_account/update_indicators.rb +34 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/control/challenge_indicators.rb +34 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/control/challenge_window_sizes.rb +37 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/control/device_types.rb +28 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/merchant_risk/delivery_timeframes.rb +34 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/merchant_risk/pre_order_purchase_indicators.rb +28 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/merchant_risk/reorder_item_indicators.rb +28 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/merchant_risk/shipping_indicators.rb +46 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/purchase/categories.rb +43 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/sdk/interfaces.rb +31 -0
- data/lib/genesis_ruby/api/constants/transactions/parameters/threeds/version2/sdk/ui_types.rb +37 -0
- data/lib/genesis_ruby/api/constants/transactions.rb +371 -0
- data/lib/genesis_ruby/api/mixins/constants/common.rb +27 -0
- data/lib/genesis_ruby/api/mixins/requests/address_info_attributes.rb +20 -0
- data/lib/genesis_ruby/api/mixins/requests/customer_address/billing_info_attributes.rb +33 -0
- data/lib/genesis_ruby/api/mixins/requests/customer_address/customer_info_attributes.rb +26 -0
- data/lib/genesis_ruby/api/mixins/requests/customer_address/shipping_info_attributes.rb +33 -0
- data/lib/genesis_ruby/api/mixins/requests/document_attributes.rb +14 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/async_attributes.rb +34 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/base_attributes.rb +16 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/business/airlines_air_carriers_attributes.rb +60 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/business/business_attributes.rb +56 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/business/car_plane_and_boat_rentals_attributes.rb +53 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/business/cruise_lines_attributes.rb +50 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/business/event_management_attributes.rb +54 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/business/furniture_attributes.rb +53 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/business/hotels_and_real_estate_rentals_attributes.rb +53 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/business/travel_agencies_attributes.rb +88 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/cards/credit_card_attributes.rb +31 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/cards/fx_rate_attributes.rb +18 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/cards/recurring/recurring_category_attributes.rb +31 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/cards/recurring/recurring_type_attributes.rb +31 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/cards/tokenization_attributes.rb +39 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/crypto_attributes.rb +25 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/dynamic_descriptor_attributes.rb +114 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/gaming_attributes.rb +25 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/moto_attributes.rb +25 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/notification_attributes.rb +25 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/payment_attributes.rb +32 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/pending_payment_attributes.rb +25 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/reference_attributes.rb +16 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/risk_attributes.rb +47 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/sca_attributes.rb +37 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/threeds/version2/browser.rb +92 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/threeds/version2/card_holder_account.rb +183 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/threeds/version2/common_attributes.rb +52 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/threeds/version2/control.rb +61 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/threeds/version2/merchant_risk.rb +114 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/threeds/version2/method.rb +44 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/threeds/version2/purchase.rb +42 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/threeds/version2/recurring.rb +49 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/threeds/version2/sdk.rb +107 -0
- data/lib/genesis_ruby/api/mixins/requests/financial/threeds/version2/wpf_attributes.rb +61 -0
- data/lib/genesis_ruby/api/mixins/requests/restricted_setter.rb +75 -0
- data/lib/genesis_ruby/api/request.rb +171 -0
- data/lib/genesis_ruby/api/requests/base/financial.rb +44 -0
- data/lib/genesis_ruby/api/requests/base/financials/credit_card.rb +27 -0
- data/lib/genesis_ruby/api/requests/financial/cards/authorize.rb +60 -0
- data/lib/genesis_ruby/api/requests/financial/cards/authorize3d.rb +76 -0
- data/lib/genesis_ruby/api/requests/financial/cards/sale.rb +59 -0
- data/lib/genesis_ruby/api/requests/financial/cards/sale3d.rb +75 -0
- data/lib/genesis_ruby/api/requests/wpf/create.rb +142 -0
- data/lib/genesis_ruby/api/response.rb +91 -0
- data/lib/genesis_ruby/builder.rb +42 -0
- data/lib/genesis_ruby/builders/base.rb +18 -0
- data/lib/genesis_ruby/builders/xml.rb +95 -0
- data/lib/genesis_ruby/configuration.rb +177 -0
- data/lib/genesis_ruby/connection.rb +20 -0
- data/lib/genesis_ruby/dependencies.rb +19 -0
- data/lib/genesis_ruby/errors/builder_error.rb +14 -0
- data/lib/genesis_ruby/errors/endpoint_not_set_error.rb +14 -0
- data/lib/genesis_ruby/errors/error.rb +18 -0
- data/lib/genesis_ruby/errors/invalid_argument_error.rb +14 -0
- data/lib/genesis_ruby/errors/network_error.rb +14 -0
- data/lib/genesis_ruby/errors/object_formatter_error.rb +14 -0
- data/lib/genesis_ruby/errors/parameter_error.rb +12 -0
- data/lib/genesis_ruby/errors/parser_error.rb +14 -0
- data/lib/genesis_ruby/errors/response_error.rb +14 -0
- data/lib/genesis_ruby/network/adapter/base_adapter.rb +31 -0
- data/lib/genesis_ruby/network/adapter/net_http_adapter.rb +92 -0
- data/lib/genesis_ruby/network/base_network.rb +83 -0
- data/lib/genesis_ruby/network/net_http.rb +28 -0
- data/lib/genesis_ruby/parser.rb +44 -0
- data/lib/genesis_ruby/parsers/base.rb +25 -0
- data/lib/genesis_ruby/parsers/xml.rb +120 -0
- data/lib/genesis_ruby/utils/common.rb +108 -0
- data/lib/genesis_ruby/utils/formatters/base.rb +40 -0
- data/lib/genesis_ruby/utils/formatters/response/definitions.rb +21 -0
- data/lib/genesis_ruby/utils/formatters/response/formats/amount.rb +34 -0
- data/lib/genesis_ruby/utils/formatters/response/formats/timestamp.rb +29 -0
- data/lib/genesis_ruby/utils/formatters/response/loader.rb +42 -0
- data/lib/genesis_ruby/utils/money/base/strategy.rb +38 -0
- data/lib/genesis_ruby/utils/money/conversions/amount_to_exponent.rb +22 -0
- data/lib/genesis_ruby/utils/money/conversions/exponent_to_amount.rb +22 -0
- data/lib/genesis_ruby/utils/money/format.rb +34 -0
- data/lib/genesis_ruby/utils/money_format.rb +39 -0
- data/lib/genesis_ruby/utils/object_formatter.rb +67 -0
- data/lib/genesis_ruby/utils/options/api_config.rb +36 -0
- data/lib/genesis_ruby/utils/options/base.rb +35 -0
- data/lib/genesis_ruby/utils/options/network_adapter_config.rb +41 -0
- data/lib/genesis_ruby/utils/transactions/financial_types.rb +50 -0
- data/lib/genesis_ruby/utils/transactions/references/capturable_types.rb +52 -0
- data/lib/genesis_ruby/utils/transactions/references/refundable_types.rb +70 -0
- data/lib/genesis_ruby/utils/transactions/references/voidable_types.rb +49 -0
- data/lib/genesis_ruby/utils/transactions/wpf_types.rb +43 -0
- data/lib/genesis_ruby/version.rb +5 -0
- data/lib/genesis_ruby.rb +57 -0
- metadata +372 -0
@@ -0,0 +1,31 @@
|
|
1
|
+
module GenesisRuby
|
2
|
+
module Network
|
3
|
+
module Adapter
|
4
|
+
# Base Network Adapter Class
|
5
|
+
class BaseAdapter
|
6
|
+
|
7
|
+
# Response body is plain string received from the server
|
8
|
+
# Response header is hash with the received headers from the server
|
9
|
+
attr_accessor :response_body, :response_headers
|
10
|
+
|
11
|
+
# Retrieve HTTP Response Status Code
|
12
|
+
def status
|
13
|
+
raise NotImplementedError, 'Status method must be implemented'
|
14
|
+
end
|
15
|
+
|
16
|
+
# Prepare the Request
|
17
|
+
# Return the adapter library request object
|
18
|
+
def prepare_request(data)
|
19
|
+
raise NotImplementedError, 'Prepare Request Body method must be implemented'
|
20
|
+
end
|
21
|
+
|
22
|
+
# Execute the request
|
23
|
+
# Return the adapter library response object
|
24
|
+
def execute
|
25
|
+
raise NotImplementedError, 'Execute method must be implemented'
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,92 @@
|
|
1
|
+
require 'genesis_ruby/network/adapter/base_adapter'
|
2
|
+
require 'genesis_ruby/errors/network_error'
|
3
|
+
require 'net/http'
|
4
|
+
|
5
|
+
module GenesisRuby
|
6
|
+
module Network
|
7
|
+
module Adapter
|
8
|
+
# Net-HTTP Adapter implementation
|
9
|
+
class NetHttpAdapter < BaseAdapter
|
10
|
+
|
11
|
+
# HTTP Response Status Code
|
12
|
+
def status
|
13
|
+
@response&.code
|
14
|
+
end
|
15
|
+
|
16
|
+
# Prepare the request from the given data
|
17
|
+
def prepare_request(data)
|
18
|
+
@request_data = data
|
19
|
+
@uri = parse_uri
|
20
|
+
# Force connection re-creation
|
21
|
+
@request = Net::HTTP.start(@uri.hostname ||= '', ssl_options)
|
22
|
+
end
|
23
|
+
|
24
|
+
# Send the request
|
25
|
+
def execute
|
26
|
+
raise NetworkError, 'Request is not initialized' unless @request
|
27
|
+
|
28
|
+
begin
|
29
|
+
# TODO: Use GenesisRuby::Api::Request::METHOD_XXX constants for sending GET and PUT request_data.type
|
30
|
+
@response = @request.post(path, request_data.body, headers)
|
31
|
+
rescue StandardError => e
|
32
|
+
raise NetworkError, "Network error raised by #{e.class.name}: #{e.message}"
|
33
|
+
ensure
|
34
|
+
# Close the request
|
35
|
+
@request.finish
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
# Response body
|
40
|
+
def response_body
|
41
|
+
@response_body ||= @response ? @response.body : ''
|
42
|
+
end
|
43
|
+
|
44
|
+
# Response headers
|
45
|
+
def response_headers
|
46
|
+
@response_headers ||= @response ? @response.each_header.to_h : {}
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
attr_reader :uri, :request, :response, :request_data
|
52
|
+
|
53
|
+
# Path accessor that secure always string return value
|
54
|
+
def path
|
55
|
+
path = @uri&.path
|
56
|
+
|
57
|
+
path.empty? ? '/' : path
|
58
|
+
end
|
59
|
+
|
60
|
+
# Override URI parsing errors
|
61
|
+
def parse_uri
|
62
|
+
URI.parse(request_data.url)
|
63
|
+
rescue URI::Error => e
|
64
|
+
raise NetworkError, "Error during URL parsing: #{e.message}"
|
65
|
+
end
|
66
|
+
|
67
|
+
# Define SSL requirements
|
68
|
+
def ssl_options
|
69
|
+
{
|
70
|
+
use_ssl: true,
|
71
|
+
verify_mode: OpenSSL::SSL::VERIFY_PEER,
|
72
|
+
verify_depth: 10,
|
73
|
+
verify_hostname: true,
|
74
|
+
read_timeout: request_data.timeout,
|
75
|
+
min_version: OpenSSL::SSL::TLS1_VERSION
|
76
|
+
}
|
77
|
+
end
|
78
|
+
|
79
|
+
# Define Headers
|
80
|
+
def headers
|
81
|
+
{
|
82
|
+
'Content-Type' => request_data.format,
|
83
|
+
'Content-Length' => request_data.body&.length.to_s,
|
84
|
+
'Authorization' => "Basic #{request_data.user_login}",
|
85
|
+
'User-Agent' => request_data.user_agent
|
86
|
+
}
|
87
|
+
end
|
88
|
+
|
89
|
+
end
|
90
|
+
end
|
91
|
+
end
|
92
|
+
end
|
@@ -0,0 +1,83 @@
|
|
1
|
+
require 'genesis_ruby/errors/invalid_argument_error'
|
2
|
+
require 'genesis_ruby/utils/options/network_adapter_config'
|
3
|
+
require 'base64'
|
4
|
+
|
5
|
+
module GenesisRuby
|
6
|
+
module Network
|
7
|
+
# Base Network factory class
|
8
|
+
class BaseNetwork
|
9
|
+
|
10
|
+
XML_HEADER = 'application/xml'.freeze
|
11
|
+
JSON_HEADER = 'application/json'.freeze
|
12
|
+
|
13
|
+
# Base constructor
|
14
|
+
def initialize(configuration)
|
15
|
+
@context = factory
|
16
|
+
@configuration = configuration
|
17
|
+
@network_adapter_config = GenesisRuby::Utils::Options::NetworkAdapterConfig.new
|
18
|
+
end
|
19
|
+
|
20
|
+
# Return the Response Body
|
21
|
+
def response_body
|
22
|
+
@context.response_body
|
23
|
+
end
|
24
|
+
|
25
|
+
# Return the Response Headers
|
26
|
+
def response_headers
|
27
|
+
@context.response_headers
|
28
|
+
end
|
29
|
+
|
30
|
+
# Send the request
|
31
|
+
def send_request
|
32
|
+
@context.execute
|
33
|
+
end
|
34
|
+
|
35
|
+
# Initialize the Adapter
|
36
|
+
def init_api_data(request)
|
37
|
+
@context.prepare_request(adapter_data_mapper(request))
|
38
|
+
end
|
39
|
+
|
40
|
+
# Every child defines is XML Response Type
|
41
|
+
def xml?
|
42
|
+
raise NotImplementedError, 'Is XML method must be implemented'
|
43
|
+
end
|
44
|
+
|
45
|
+
# Every child defines is JSON Response Type
|
46
|
+
def json?
|
47
|
+
raise NotImplementedError, 'Is JSON method must be implemented'
|
48
|
+
end
|
49
|
+
|
50
|
+
protected
|
51
|
+
|
52
|
+
# GenesisRuby::Configuration, Adapter Context, Network Adapter Config mapper
|
53
|
+
attr_reader :configuration, :context, :network_adapter_config
|
54
|
+
|
55
|
+
# Every child override and initialize its instance
|
56
|
+
def factory
|
57
|
+
raise NotImplementedError, 'Factory method must be implemented'
|
58
|
+
end
|
59
|
+
|
60
|
+
# Map the Request to the Network Adapter object
|
61
|
+
def adapter_data_mapper(request)
|
62
|
+
network_adapter_config.map_from_request(request).merge(
|
63
|
+
{
|
64
|
+
user_login: build_user_login,
|
65
|
+
user_agent: network_user_agent,
|
66
|
+
timeout: configuration.timeout
|
67
|
+
}
|
68
|
+
)
|
69
|
+
end
|
70
|
+
|
71
|
+
# Build the User login string used for the Authorization Header
|
72
|
+
def build_user_login
|
73
|
+
Base64.urlsafe_encode64("#{configuration.username}:#{configuration.password}")
|
74
|
+
end
|
75
|
+
|
76
|
+
# The default user agent for every Network
|
77
|
+
def network_user_agent
|
78
|
+
"Genesis Ruby Client #{GenesisRuby::VERSION}. Network: #{self.class.name}"
|
79
|
+
end
|
80
|
+
|
81
|
+
end
|
82
|
+
end
|
83
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'genesis_ruby/network/base_network'
|
2
|
+
require 'genesis_ruby/network/adapter/net_http_adapter'
|
3
|
+
|
4
|
+
module GenesisRuby
|
5
|
+
module Network
|
6
|
+
# Net HTTP Network module
|
7
|
+
class NetHttp < BaseNetwork
|
8
|
+
|
9
|
+
# JSON Response Type
|
10
|
+
def xml?
|
11
|
+
response_headers['content-type'].downcase.include?(BaseNetwork::XML_HEADER)
|
12
|
+
end
|
13
|
+
|
14
|
+
# JSON Response Type
|
15
|
+
def json?
|
16
|
+
response_headers['content-type'].downcase.include?(BaseNetwork::JSON_HEADER)
|
17
|
+
end
|
18
|
+
|
19
|
+
protected
|
20
|
+
|
21
|
+
# Adapter Initialization
|
22
|
+
def factory
|
23
|
+
GenesisRuby::Network::Adapter::NetHttpAdapter.new
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
require 'genesis_ruby/parsers/xml'
|
2
|
+
require 'genesis_ruby/errors/parser_error'
|
3
|
+
|
4
|
+
module GenesisRuby
|
5
|
+
# Parser handler
|
6
|
+
class Parser
|
7
|
+
|
8
|
+
# XML Parser
|
9
|
+
XML = 'xml'.freeze
|
10
|
+
|
11
|
+
# JSON Parser
|
12
|
+
JSON = 'json'.freeze
|
13
|
+
|
14
|
+
# Initialize the Parser Interface based on the Response requirements
|
15
|
+
def initialize(response_interface)
|
16
|
+
case response_interface
|
17
|
+
when XML
|
18
|
+
@parser_context = GenesisRuby::Parsers::Xml.new
|
19
|
+
else
|
20
|
+
raise GenesisRuby::ParserError, 'Invalid Parser interface!'
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
# Parsed document
|
25
|
+
def structure
|
26
|
+
parser_context.structure
|
27
|
+
end
|
28
|
+
|
29
|
+
# Parse tree-structure into Builder document
|
30
|
+
def parse_document(document)
|
31
|
+
parser_context.parse_document(document)
|
32
|
+
end
|
33
|
+
|
34
|
+
# Indicates that the Root element will not be included in the generated Object
|
35
|
+
def skip_root_node
|
36
|
+
parser_context.skip_root_node
|
37
|
+
end
|
38
|
+
|
39
|
+
private
|
40
|
+
|
41
|
+
attr_accessor :parser_context
|
42
|
+
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module GenesisRuby
|
2
|
+
module Parsers
|
3
|
+
# Contract for every parser abstraction
|
4
|
+
class Base
|
5
|
+
|
6
|
+
attr_reader :structure, :root_node_skipped
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@structure = {}
|
10
|
+
@root_node_skipped = false
|
11
|
+
end
|
12
|
+
|
13
|
+
# Parse given document to Hash Structuce
|
14
|
+
def parse_document(document)
|
15
|
+
raise NotImplementedError, 'Parse Document must be implemented'
|
16
|
+
end
|
17
|
+
|
18
|
+
# Indicates that the Root element will not be included in the generated Object
|
19
|
+
def skip_root_node
|
20
|
+
@root_node_skipped = true
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
@@ -0,0 +1,120 @@
|
|
1
|
+
require 'genesis_ruby/parsers/base'
|
2
|
+
require 'nokogiri'
|
3
|
+
|
4
|
+
module GenesisRuby
|
5
|
+
module Parsers
|
6
|
+
# XML Document Parser
|
7
|
+
class Xml < Base
|
8
|
+
|
9
|
+
def parse_document(document)
|
10
|
+
load_document(document)
|
11
|
+
|
12
|
+
@structure = if root_node_skipped
|
13
|
+
collect_nodes(@document.root)
|
14
|
+
else
|
15
|
+
{ @document.root.name.to_sym => collect_attributes(@document.root).merge(
|
16
|
+
collect_nodes(@document.root)
|
17
|
+
) }
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
attr_reader :document
|
24
|
+
|
25
|
+
# Nokogiri::XML.parse
|
26
|
+
def load_document(document)
|
27
|
+
@document = Nokogiri::XML.parse document, &:strict
|
28
|
+
rescue Nokogiri::SyntaxError
|
29
|
+
raise ParserError, 'Given Document is invalid'
|
30
|
+
end
|
31
|
+
|
32
|
+
# Loop the given Nokogiri::XML::Document
|
33
|
+
def collect_nodes(nodes, tree = {})
|
34
|
+
nodes.children.each do |child|
|
35
|
+
next if skip_element?(child)
|
36
|
+
|
37
|
+
tree[child.name.to_sym] = [tree[child.name.to_sym]] if duplicated_keys?(tree, child.name.to_sym)
|
38
|
+
|
39
|
+
process_node(child, tree)
|
40
|
+
end
|
41
|
+
|
42
|
+
tree
|
43
|
+
end
|
44
|
+
|
45
|
+
# Process every node by checking the type of the given tree and take decision for further processing
|
46
|
+
def process_node(node, tree)
|
47
|
+
key = node.name.to_sym
|
48
|
+
|
49
|
+
# The node has children of type Nokogiri::XML::Node.element?
|
50
|
+
return tree[key] = collect_children(node, tree) if children_elements?(node)
|
51
|
+
|
52
|
+
# The node is Element type and the tree has duplicated keys
|
53
|
+
return tree[key].push format_element(node) if tree[key].is_a? Array
|
54
|
+
|
55
|
+
# Simple Element formatting
|
56
|
+
tree[key] = format_element(node)
|
57
|
+
end
|
58
|
+
|
59
|
+
# Handle Nokogiri::XML::Element and take decision for further processing
|
60
|
+
def collect_children(child, tree)
|
61
|
+
key = child.name.to_sym
|
62
|
+
tree[key] = collect_attributes(child) unless tree[key]
|
63
|
+
|
64
|
+
case tree[key]
|
65
|
+
when Array
|
66
|
+
tree[key].push collect_attributes(child).merge collect_nodes(child, {})
|
67
|
+
when Hash
|
68
|
+
collect_nodes(child, tree[key])
|
69
|
+
end
|
70
|
+
end
|
71
|
+
|
72
|
+
# Format Nokogiri::XML::Element element
|
73
|
+
def format_element(element)
|
74
|
+
attributes = collect_attributes(element)
|
75
|
+
|
76
|
+
return element.content.to_s if attributes.empty? && !children_elements?(element)
|
77
|
+
|
78
|
+
attributes.merge(
|
79
|
+
element.content.to_s.empty? ? {} : { element.name.to_sym => element.content.to_s }
|
80
|
+
)
|
81
|
+
end
|
82
|
+
|
83
|
+
# Collect attributes of the given Nokogiri::XML::Node
|
84
|
+
def collect_attributes(element)
|
85
|
+
attributes = {}
|
86
|
+
|
87
|
+
element.attributes.each_value { |attribute| attributes.merge! format_attributes attribute }
|
88
|
+
|
89
|
+
attributes
|
90
|
+
end
|
91
|
+
|
92
|
+
# Format Nokogiri::XML:Element.attributes
|
93
|
+
def format_attributes(element)
|
94
|
+
{ element.name.to_sym => element.value.to_s }
|
95
|
+
end
|
96
|
+
|
97
|
+
# Check if the given tree already has definition of the given key
|
98
|
+
def duplicated_keys?(tree, key)
|
99
|
+
tree.is_a?(Hash) && tree.key?(key) && !tree[key].is_a?(Array)
|
100
|
+
end
|
101
|
+
|
102
|
+
# Check if the given element should be skipped
|
103
|
+
def skip_element?(element)
|
104
|
+
blank_element?(element) || element.comment? || element.cdata? || element.xml? || element.html?
|
105
|
+
end
|
106
|
+
|
107
|
+
# Check if the given Nokogiri::XML::Node has blank element (ex. "\n ")
|
108
|
+
# Doesn't remove <element/> as Genesis has such output (ex Chargeback cnn)
|
109
|
+
def blank_element?(element)
|
110
|
+
element.text? && element.content.strip.empty?
|
111
|
+
end
|
112
|
+
|
113
|
+
# Check if the given element has at least one child with Nokogiri::XML::Node.children of Element type
|
114
|
+
def children_elements?(element)
|
115
|
+
!element.children.find(&:element?).nil?
|
116
|
+
end
|
117
|
+
|
118
|
+
end
|
119
|
+
end
|
120
|
+
end
|
@@ -0,0 +1,108 @@
|
|
1
|
+
require 'uri'
|
2
|
+
require 'date'
|
3
|
+
|
4
|
+
module GenesisRuby
|
5
|
+
module Utils
|
6
|
+
# Common Utils used all across the project
|
7
|
+
class Common
|
8
|
+
|
9
|
+
class << self
|
10
|
+
|
11
|
+
# Deep compact over the given nested structure
|
12
|
+
def deep_compact!(structure)
|
13
|
+
structure.each do |element_key, element_value|
|
14
|
+
deep_compact!(element_key) if element_key.is_a? Hash
|
15
|
+
deep_compact!(element_value) if element_value.is_a?(Hash) || element_value.is_a?(Array)
|
16
|
+
end
|
17
|
+
|
18
|
+
compact_array! structure
|
19
|
+
compact_hash! structure
|
20
|
+
end
|
21
|
+
|
22
|
+
# Compact over given Array
|
23
|
+
def compact_array!(structure)
|
24
|
+
return unless structure.is_a? Array
|
25
|
+
|
26
|
+
structure.reject! do |element|
|
27
|
+
element.is_a?(Array) || element.is_a?(Hash) ? element.empty? : element.nil?
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
# Compact over given Hash
|
32
|
+
def compact_hash!(structure)
|
33
|
+
return unless structure.is_a? Hash
|
34
|
+
|
35
|
+
structure.reject! do |_key, value|
|
36
|
+
value.is_a?(Array) || value.is_a?(Hash) ? value.empty? : value.nil?
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# Deep compact empty over the given nested hash
|
41
|
+
def deep_compact_empty!(structure)
|
42
|
+
structure.each do |element_key, element_value|
|
43
|
+
deep_compact_empty!(element_key) if element_key.is_a? Hash
|
44
|
+
deep_compact_empty!(element_value) if element_value.is_a?(Hash) || element_value.is_a?(Array)
|
45
|
+
end
|
46
|
+
|
47
|
+
empty_compact_array!(structure)
|
48
|
+
empty_compact_hash!(structure)
|
49
|
+
end
|
50
|
+
|
51
|
+
# Remove empty elements from an Array
|
52
|
+
def empty_compact_array!(structure)
|
53
|
+
return unless structure.is_a? Array
|
54
|
+
|
55
|
+
structure.reject! do |element|
|
56
|
+
element.is_a?(Array) || element.is_a?(Hash) || element.is_a?(String) ? element.empty? : element.nil?
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
# Remove empty elements from an Hash
|
61
|
+
def empty_compact_hash!(structure)
|
62
|
+
return unless structure.is_a? Hash
|
63
|
+
|
64
|
+
structure.reject! do |_key, value|
|
65
|
+
value.is_a?(Array) || value.is_a?(Hash) || value.is_a?(String) ? value.empty? : value.nil?
|
66
|
+
end
|
67
|
+
end
|
68
|
+
|
69
|
+
# Retrieve all constant values defined in the given module or class
|
70
|
+
def constant_values(reference)
|
71
|
+
constant_values = []
|
72
|
+
|
73
|
+
reference.constants(false).each do |constant_value|
|
74
|
+
value = reference.const_get constant_value
|
75
|
+
|
76
|
+
constant_values.push value unless value.is_a?(Class) || value.is_a?(Module)
|
77
|
+
end
|
78
|
+
|
79
|
+
constant_values.sort
|
80
|
+
end
|
81
|
+
|
82
|
+
# Validates URL
|
83
|
+
def valid_url?(url)
|
84
|
+
uri = URI.parse(url)
|
85
|
+
|
86
|
+
%w(http https).include?(uri.scheme) && !uri.host.nil? && !uri.host.to_s.empty?
|
87
|
+
rescue StandardError
|
88
|
+
false
|
89
|
+
end
|
90
|
+
|
91
|
+
# Parses string to DateTime
|
92
|
+
def parse_date(date, formats)
|
93
|
+
parsed_date = nil
|
94
|
+
|
95
|
+
formats.each do |format|
|
96
|
+
return Date.strptime(date, format)
|
97
|
+
rescue StandardError
|
98
|
+
parsed_date = nil
|
99
|
+
end
|
100
|
+
|
101
|
+
parsed_date
|
102
|
+
end
|
103
|
+
|
104
|
+
end
|
105
|
+
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
module GenesisRuby
|
2
|
+
module Utils
|
3
|
+
module Formatters
|
4
|
+
# Object Formatter Contract
|
5
|
+
# ObjectFormatter iterate over each formatter with the given structure
|
6
|
+
class Base
|
7
|
+
|
8
|
+
# The Response keys that the formatter will be applied to
|
9
|
+
def formatting_keys
|
10
|
+
[]
|
11
|
+
end
|
12
|
+
|
13
|
+
# The keys required for formatting the specific response key
|
14
|
+
def required_keys
|
15
|
+
[]
|
16
|
+
end
|
17
|
+
|
18
|
+
# Format the given Response Key value
|
19
|
+
def format_key(*_args)
|
20
|
+
raise NotImplementedError, 'Format method is not implemented'
|
21
|
+
end
|
22
|
+
|
23
|
+
# Collect required key's values requires for the Response Object formatting
|
24
|
+
# Ex. Amount to Major requires Currency
|
25
|
+
def collect_required_key_values(response_object)
|
26
|
+
required_key_values = []
|
27
|
+
|
28
|
+
required_keys.each do |required_key|
|
29
|
+
next unless response_object.include?(required_key.to_sym)
|
30
|
+
|
31
|
+
required_key_values.push response_object[required_key.to_sym]
|
32
|
+
end
|
33
|
+
|
34
|
+
required_key_values
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
end
|
40
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
require 'genesis_ruby/utils/formatters/response/formats/amount'
|
2
|
+
require 'genesis_ruby/utils/formatters/response/formats/timestamp'
|
3
|
+
|
4
|
+
module GenesisRuby
|
5
|
+
module Utils
|
6
|
+
module Formatters
|
7
|
+
# Definition of all available Response Formatters
|
8
|
+
module Response
|
9
|
+
|
10
|
+
# Array of string of all available Response Formatters
|
11
|
+
def available_formatters
|
12
|
+
[
|
13
|
+
GenesisRuby::Utils::Formatters::Response::Formats::Amount,
|
14
|
+
GenesisRuby::Utils::Formatters::Response::Formats::Timestamp
|
15
|
+
]
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'genesis_ruby/utils/formatters/base'
|
2
|
+
require 'genesis_ruby/utils/money_format'
|
3
|
+
|
4
|
+
module GenesisRuby
|
5
|
+
module Utils
|
6
|
+
module Formatters
|
7
|
+
module Response
|
8
|
+
module Formats
|
9
|
+
# Response Amount Formatter. Converts Minor Currency to Major currency format
|
10
|
+
class Amount < Base
|
11
|
+
|
12
|
+
# The Response keys that the formatter will be applied to
|
13
|
+
def formatting_keys
|
14
|
+
%w(amount leftover_amount)
|
15
|
+
end
|
16
|
+
|
17
|
+
# The keys required for formatting the specific response key
|
18
|
+
def required_keys
|
19
|
+
%w(currency)
|
20
|
+
end
|
21
|
+
|
22
|
+
# Format the given amount response key and its currency to major currency format
|
23
|
+
def format_key(amount, currency)
|
24
|
+
GenesisRuby::Utils::MoneyFormat.exponent_to_amount(amount, currency)
|
25
|
+
rescue StandardError
|
26
|
+
amount
|
27
|
+
end
|
28
|
+
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|