genesis_ruby 0.1.0
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.
- 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
|