eml 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (116) hide show
  1. checksums.yaml +7 -0
  2. data/.editorconfig +10 -0
  3. data/.env.example +6 -0
  4. data/.gitignore +5 -0
  5. data/.rspec +5 -0
  6. data/.rubocop.yml +90 -0
  7. data/Gemfile +6 -0
  8. data/LICENSE +21 -0
  9. data/README.md +87 -0
  10. data/eml.gemspec +37 -0
  11. data/lib/eml.rb +22 -0
  12. data/lib/eml/config.rb +49 -0
  13. data/lib/eml/data/countries.rb +260 -0
  14. data/lib/eml/data/currencies.rb +176 -0
  15. data/lib/eml/data/states.rb +4055 -0
  16. data/lib/eml/environment.rb +54 -0
  17. data/lib/eml/error.rb +25 -0
  18. data/lib/eml/error/rest.rb +42 -0
  19. data/lib/eml/error/rest/authentication.rb +21 -0
  20. data/lib/eml/error/rest/bad_request.rb +20 -0
  21. data/lib/eml/error/rest/daily_funding_limit.rb +19 -0
  22. data/lib/eml/error/rest/forbidden.rb +20 -0
  23. data/lib/eml/error/rest/internal_server.rb +9 -0
  24. data/lib/eml/error/rest/not_found.rb +20 -0
  25. data/lib/eml/error/rest/unprocessable_entity.rb +20 -0
  26. data/lib/eml/lib/endpoint_class.rb +42 -0
  27. data/lib/eml/parameters.rb +153 -0
  28. data/lib/eml/payload.rb +137 -0
  29. data/lib/eml/response.rb +103 -0
  30. data/lib/eml/uk.rb +51 -0
  31. data/lib/eml/uk/api_resource.rb +94 -0
  32. data/lib/eml/uk/config.rb +52 -0
  33. data/lib/eml/uk/lib/endpoint_class.rb +19 -0
  34. data/lib/eml/uk/lib/parse_date.rb +35 -0
  35. data/lib/eml/uk/model/transaction.rb +56 -0
  36. data/lib/eml/uk/parameters.rb +99 -0
  37. data/lib/eml/uk/parameters/agreement/show.rb +22 -0
  38. data/lib/eml/uk/parameters/card/activation.rb +24 -0
  39. data/lib/eml/uk/parameters/card/lock.rb +26 -0
  40. data/lib/eml/uk/parameters/card/register.rb +24 -0
  41. data/lib/eml/uk/parameters/card/reload.rb +24 -0
  42. data/lib/eml/uk/parameters/card/show.rb +102 -0
  43. data/lib/eml/uk/parameters/card/transaction.rb +59 -0
  44. data/lib/eml/uk/parameters/card/unload.rb +26 -0
  45. data/lib/eml/uk/parameters/card/unlock.rb +26 -0
  46. data/lib/eml/uk/parameters/card/void.rb +26 -0
  47. data/lib/eml/uk/payload.rb +94 -0
  48. data/lib/eml/uk/payload/agreement/show.rb +46 -0
  49. data/lib/eml/uk/payload/card/activation.rb +73 -0
  50. data/lib/eml/uk/payload/card/lock.rb +34 -0
  51. data/lib/eml/uk/payload/card/register.rb +70 -0
  52. data/lib/eml/uk/payload/card/reload.rb +38 -0
  53. data/lib/eml/uk/payload/card/show.rb +12 -0
  54. data/lib/eml/uk/payload/card/transaction.rb +12 -0
  55. data/lib/eml/uk/payload/card/unload.rb +38 -0
  56. data/lib/eml/uk/payload/card/unlock.rb +23 -0
  57. data/lib/eml/uk/payload/card/void.rb +23 -0
  58. data/lib/eml/uk/payload/contactentity.rb +64 -0
  59. data/lib/eml/uk/payload/iso.rb +48 -0
  60. data/lib/eml/uk/payload/location.rb +30 -0
  61. data/lib/eml/uk/resources/agreement.rb +32 -0
  62. data/lib/eml/uk/resources/card.rb +181 -0
  63. data/lib/eml/uk/response.rb +29 -0
  64. data/lib/eml/uk/responses/agreement/show.rb +16 -0
  65. data/lib/eml/uk/responses/card/reload.rb +19 -0
  66. data/lib/eml/uk/responses/card/show.rb +53 -0
  67. data/lib/eml/uk/responses/card/transaction.rb +24 -0
  68. data/lib/eml/version.rb +6 -0
  69. data/sorbet/config +2 -0
  70. data/sorbet/rbi/gems/addressable.rbi +198 -0
  71. data/sorbet/rbi/gems/ast.rbi +47 -0
  72. data/sorbet/rbi/gems/concurrent-ruby.rbi +218 -0
  73. data/sorbet/rbi/gems/crack.rbi +47 -0
  74. data/sorbet/rbi/gems/docile.rbi +31 -0
  75. data/sorbet/rbi/gems/domain_name.rbi +51 -0
  76. data/sorbet/rbi/gems/dotenv.rbi +67 -0
  77. data/sorbet/rbi/gems/faker.rbi +1350 -0
  78. data/sorbet/rbi/gems/hashdiff.rbi +65 -0
  79. data/sorbet/rbi/gems/http-cookie.rbi +92 -0
  80. data/sorbet/rbi/gems/http-form_data.rbi +73 -0
  81. data/sorbet/rbi/gems/http.rbi +609 -0
  82. data/sorbet/rbi/gems/http_parser.rb.rbi +36 -0
  83. data/sorbet/rbi/gems/i18n.rbi +191 -0
  84. data/sorbet/rbi/gems/jaro_winkler.rbi +14 -0
  85. data/sorbet/rbi/gems/parallel.rbi +81 -0
  86. data/sorbet/rbi/gems/parser.rbi +835 -0
  87. data/sorbet/rbi/gems/public_suffix.rbi +103 -0
  88. data/sorbet/rbi/gems/rainbow.rbi +117 -0
  89. data/sorbet/rbi/gems/rspec-core.rbi +1655 -0
  90. data/sorbet/rbi/gems/rspec-support.rbi +126 -0
  91. data/sorbet/rbi/gems/rspec.rbi +14 -0
  92. data/sorbet/rbi/gems/rubocop-performance.rbi +276 -0
  93. data/sorbet/rbi/gems/rubocop-rspec.rbi +860 -0
  94. data/sorbet/rbi/gems/rubocop.rbi +6943 -0
  95. data/sorbet/rbi/gems/ruby-progressbar.rbi +304 -0
  96. data/sorbet/rbi/gems/simplecov-html.rbi +30 -0
  97. data/sorbet/rbi/gems/simplecov.rbi +225 -0
  98. data/sorbet/rbi/gems/unf.rbi +18 -0
  99. data/sorbet/rbi/gems/unicode-display_width.rbi +16 -0
  100. data/sorbet/rbi/gems/vcr.rbi +503 -0
  101. data/sorbet/rbi/gems/webmock.rbi +521 -0
  102. data/sorbet/rbi/hidden-definitions/errors.txt +4802 -0
  103. data/sorbet/rbi/hidden-definitions/hidden.rbi +10700 -0
  104. data/sorbet/rbi/sorbet-typed/lib/bundler/all/bundler.rbi +8682 -0
  105. data/sorbet/rbi/sorbet-typed/lib/ruby/all/gem.rbi +4222 -0
  106. data/sorbet/rbi/sorbet-typed/lib/ruby/all/open3.rbi +111 -0
  107. data/sorbet/rbi/sorbet-typed/lib/ruby/all/resolv.rbi +543 -0
  108. data/sorbet/rbi/todo.rbi +24 -0
  109. data/spec/config_spec.rb +26 -0
  110. data/spec/helpers/config_helper.rb +21 -0
  111. data/spec/helpers/vcr_helper.rb +19 -0
  112. data/spec/spec_helper.rb +120 -0
  113. data/spec/uk/api_resource_spec.rb +39 -0
  114. data/spec/uk/resources/agreement_spec.rb +23 -0
  115. data/spec/uk/resources/card_spec.rb +197 -0
  116. metadata +339 -0
@@ -0,0 +1,54 @@
1
+ # typed: ignore
2
+ # frozen_string_literal: true
3
+
4
+ # Usually this class wouldn't be called directly, the environment can be managed
5
+ # via the EML::Config class or one of it's sub-classes
6
+ module EML
7
+ class Environment
8
+ class << self
9
+ def production?
10
+ to_sym == :production
11
+ end
12
+
13
+ def test?
14
+ to_sym == :test
15
+ end
16
+
17
+ def to_sym
18
+ @to_sym ||= set(default)
19
+ end
20
+
21
+ ENVIRONMENTS = %i[production test].freeze
22
+
23
+ def set(value)
24
+ return @to_sym = value if ENVIRONMENTS.include?(value)
25
+
26
+ error_value = value.is_a?(Symbol) ? ":#{value}" : value.to_s
27
+ raise(
28
+ ArgumentError,
29
+ "#{error_value} is not an acceptable environment; " \
30
+ "please use either :production or :test"
31
+ )
32
+ end
33
+
34
+ private
35
+
36
+ def default
37
+ return :test if ENV["ENV"] == "test"
38
+ return rails if rails?
39
+
40
+ :production
41
+ end
42
+
43
+ def rails?
44
+ defined?(Rails)
45
+ end
46
+
47
+ def rails
48
+ return :production if Rails.env.prod?
49
+
50
+ :test
51
+ end
52
+ end
53
+ end
54
+ end
@@ -0,0 +1,25 @@
1
+ # typed: ignore
2
+ # frozen_string_literal: true
3
+
4
+ module EML
5
+ # Error is the base class for more specific EML errors
6
+ class Error < ::StandardError
7
+ extend T::Sig
8
+
9
+ attr_reader :message
10
+
11
+ sig { params(message: T.nilable(String)).void }
12
+ def initialize(message = nil)
13
+ @message = T.let(message, T.nilable(String))
14
+ end
15
+ end
16
+ end
17
+
18
+ require "eml/error/rest"
19
+ require "eml/error/rest/authentication"
20
+ require "eml/error/rest/bad_request"
21
+ require "eml/error/rest/daily_funding_limit"
22
+ require "eml/error/rest/forbidden"
23
+ require "eml/error/rest/internal_server"
24
+ require "eml/error/rest/not_found"
25
+ require "eml/error/rest/unprocessable_entity"
@@ -0,0 +1,42 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module EML
5
+ # RESTError is the parent class for errors related to connections to the EML
6
+ # REST Web Services APIs
7
+ class RESTError < Error
8
+ extend T::Sig
9
+
10
+ sig do
11
+ params(
12
+ message: T.nilable(String),
13
+ response: T.nilable(EML::Response)
14
+ ).void
15
+ end
16
+ def initialize(message = nil, response = nil)
17
+ super(message)
18
+
19
+ @response = T.let(response, EML::Response)
20
+ end
21
+
22
+ sig { returns(String) }
23
+ def http_body
24
+ @response.error || @response.body.to_s
25
+ end
26
+
27
+ sig { returns(T::Hash[Symbol, String]) }
28
+ def http_headers
29
+ @response.headers
30
+ end
31
+
32
+ sig { returns(Integer) }
33
+ def http_status
34
+ @response.status
35
+ end
36
+
37
+ sig { returns(String) }
38
+ def url
39
+ @response.url.to_s
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,21 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module EML
5
+ module REST
6
+ class AuthenticationError < ::EML::RESTError
7
+ sig do
8
+ params(
9
+ message: T.nilable(String),
10
+ response: T.nilable(EML::Response)
11
+ ).void
12
+ end
13
+ def initialize(message = nil, response = nil)
14
+ message ||= "Your credentials were rejected by the server. " \
15
+ "Please confirm you have set your username and password in the " \
16
+ "appropriate country configuration"
17
+ super(message, response)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,20 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module EML
5
+ module REST
6
+ class BadRequestError < ::EML::RESTError
7
+ sig do
8
+ params(
9
+ message: T.nilable(String),
10
+ response: T.nilable(EML::Response)
11
+ ).void
12
+ end
13
+ def initialize(message = nil, response = nil)
14
+ message ||= "The request could not be Fault information understood " \
15
+ "by the server due to malformed syntax"
16
+ super(message, response)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,19 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module EML
5
+ module REST
6
+ class DailyFundingLimitError < ::EML::RESTError
7
+ sig do
8
+ params(
9
+ message: T.nilable(String),
10
+ response: T.nilable(EML::Response)
11
+ ).void
12
+ end
13
+ def initialize(message = nil, response = nil)
14
+ message ||= "The daily maximum load amount has been reached"
15
+ super(message, response)
16
+ end
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,20 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module EML
5
+ module REST
6
+ class ForbiddenError < ::EML::RESTError
7
+ sig do
8
+ params(
9
+ message: T.nilable(String),
10
+ response: T.nilable(EML::Response)
11
+ ).void
12
+ end
13
+ def initialize(message = nil, response = nil)
14
+ message ||= response&.body&.fetch("message", nil)
15
+ message ||= "The user is not authorised to perform the action"
16
+ super(message, response)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,9 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module EML
5
+ module REST
6
+ class InternalServerError < ::EML::RESTError
7
+ end
8
+ end
9
+ end
@@ -0,0 +1,20 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module EML
5
+ module REST
6
+ class NotFoundError < ::EML::RESTError
7
+ sig do
8
+ params(
9
+ message: T.nilable(String),
10
+ response: T.nilable(EML::Response),
11
+ id: String
12
+ ).void
13
+ end
14
+ def initialize(message = nil, response = nil, id:)
15
+ message ||= %(A record could not be found with ID "#{id}")
16
+ super(message, response)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module EML
5
+ module REST
6
+ class UnprocessableEntityError < ::EML::RESTError
7
+ sig do
8
+ params(
9
+ message: T.nilable(String),
10
+ response: T.nilable(EML::Response)
11
+ ).void
12
+ end
13
+ def initialize(message = nil, response = nil)
14
+ message ||= "The server understood the request but it could not be " \
15
+ "processed (possibly semantically erroneous)"
16
+ super(message, response)
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,42 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ module EML
5
+ class EndpointClass
6
+ extend T::Sig
7
+
8
+ def self.call(class_type:, resource_class:, endpoint:)
9
+ new(
10
+ class_type: class_type,
11
+ resource_class: resource_class,
12
+ endpoint: endpoint
13
+ ).call
14
+ end
15
+
16
+ def initialize(class_type:, resource_class:, endpoint:)
17
+ @class_type = class_type
18
+ @resource_class = resource_class
19
+ @endpoint = endpoint
20
+ end
21
+
22
+ def call
23
+ Object.const_get(class_name) if Object.const_defined?(class_name)
24
+ end
25
+
26
+ private
27
+
28
+ def class_name
29
+ @class_name ||= begin
30
+ name_parts = @resource_class.name.split("::")
31
+ name = name_parts[0..-2] << @class_type
32
+ name << name_parts.last
33
+ name << action_class_name
34
+ name.join("::")
35
+ end
36
+ end
37
+
38
+ def action_class_name
39
+ @endpoint.capitalize.sub(/s$/, "")
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,153 @@
1
+ # typed: strict
2
+ # frozen_string_literal: true
3
+
4
+ # A payload is the data sent in the body of a request such as POST or PUT
5
+ module EML
6
+ class Parameters
7
+ extend T::Sig
8
+
9
+ sig { params(params: T::Hash[Symbol, T.untyped]).void }
10
+ def initialize(params)
11
+ assign_params(params)
12
+ validate_required_params_presence
13
+ end
14
+
15
+ ENDPOINT_CLASS_TYPE = "Parameters"
16
+
17
+ class << self
18
+ extend T::Sig
19
+
20
+ sig do
21
+ params(
22
+ resource_class: T.untyped,
23
+ endpoint: String,
24
+ params: T::Hash[Symbol, T.untyped]
25
+ ).returns(T.untyped)
26
+ end
27
+ def self.convert(resource_class, endpoint, params)
28
+ endpoint_class = EML::EndpointClass.(
29
+ class_type: ENDPOINT_CLASS_TYPE, resource_class: resource_class,
30
+ endpoint: endpoint
31
+ )
32
+
33
+ convert_with_endpoint_class(
34
+ endpoint: endpoint, endpoint_class: endpoint_class,
35
+ resource_class: resource_class, params: params
36
+ )
37
+ end
38
+
39
+ protected
40
+
41
+ sig do
42
+ params(
43
+ endpoint_class: T.nilable(T.class_of(EML::Parameters)),
44
+ resource_class: T.untyped,
45
+ endpoint: String,
46
+ params: T::Hash[Symbol, T.untyped]
47
+ ).returns(T.untyped)
48
+ end
49
+ def convert_with_endpoint_class(
50
+ endpoint_class:, resource_class:, endpoint:, params:
51
+ )
52
+ return endpoint_class.new(params) unless endpoint_class.nil?
53
+ return params if params.empty?
54
+
55
+ message = "No endpoint class can be found for resource, " \
56
+ "#{resource_class}, with endpoint #{endpoint}"
57
+ raise ArgumentError, message
58
+ end
59
+ end
60
+
61
+ sig { returns(T::Hash[Symbol, T.untyped]) }
62
+ def to_h
63
+ instance_variables.each_with_object({}) do |variable_name, params|
64
+ key = variable_name.to_s[1..-1].to_sym
65
+ params[key] = instance_variable_get(variable_name)
66
+ params[key] = params[key].to_h if params[key].respond_to?(:to_h)
67
+ end
68
+ end
69
+
70
+ protected
71
+
72
+ sig do
73
+ params(
74
+ param_name: String,
75
+ param_value: String,
76
+ allowed_values: T::Array[String]
77
+ ).void
78
+ end
79
+ def validate_array(param_name, param_value, allowed_values)
80
+ return if allowed_values.include?(param_value)
81
+
82
+ error_message = "#{param_name} can include any of " \
83
+ "#{array_as_string(allowed_values)} but included #{param_value}"
84
+ raise ArgumentError, error_message
85
+ end
86
+
87
+ sig do
88
+ params(param_name: Symbol, param_value: String, allowed_values: T::Array[String]).
89
+ void
90
+ end
91
+ def validate_enum(param_name, param_value, allowed_values)
92
+ return if allowed_values.include?(param_value)
93
+
94
+ value_message = array_as_string(allowed_values)
95
+ raise(ArgumentError, "#{param_name} must be one of #{value_message}")
96
+ end
97
+
98
+ sig do
99
+ params(param_name: Symbol, param_value: String, length: Integer).void
100
+ end
101
+ def validate_max_length(param_name, param_value, length)
102
+ return if param_value.to_s.length <= length
103
+
104
+ raise(
105
+ ArgumentError,
106
+ "#{param_name} is expected to be no more than #{length} characters"
107
+ )
108
+ end
109
+
110
+ private
111
+
112
+ def array_as_string(array)
113
+ array.dup.tap { |vals| vals[-1] = "or #{vals.last}" }.join(", ")
114
+ end
115
+
116
+ sig { params(params: T::Hash[Symbol, T.untyped]).void }
117
+ def assign_params(params)
118
+ params.each do |name, value|
119
+ __send__(:"#{name}=", value)
120
+ end
121
+ end
122
+
123
+ sig { void }
124
+ def validate_required_params_presence
125
+ return unless self.class.const_defined?(:REQUIRED_VALUES)
126
+
127
+ required_params = self.class.const_get(:REQUIRED_VALUES)
128
+ required_params.each do |param_name|
129
+ validate_required_parameter_presence(param_name)
130
+ end
131
+ end
132
+
133
+ # rubocop:disable Metrics/MethodLength
134
+ sig { params(param_name: Symbol, object: EML::Parameters).void }
135
+ def validate_required_parameter_presence(param_name, object: self)
136
+ names = param_name.to_s.split(".")
137
+ value = object.instance_variable_get(:"@#{names.shift}")
138
+
139
+ if value.nil?
140
+ raise(
141
+ ArgumentError,
142
+ "#{param_name} was not supplied but it is a required field"
143
+ )
144
+ end
145
+
146
+ if names.length.positive?
147
+ param_name = names.join(".").to_sym
148
+ validate_required_parameter_presence(param_name, object: value)
149
+ end
150
+ end
151
+ # rubocop:enable Metrics/MethodLength
152
+ end
153
+ end