eml 1.0.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.
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