Class: Arafa::Providers::Base

Inherits:
Object
  • Object
show all
Extended by:
Dry::Initializer
Defined in:
lib/arafa/providers/base.rb

Overview

Abstract superclass for provider adapters (AfricasTalking, Wasiliana, ...).

Subclasses implement #endpoint, #headers, #build_payload, #parse_response, and set a CONTRACT constant (a Dry::Validation::Contract) applied to to:/ text:/from: before any HTTP call is made.

Direct Known Subclasses

AfricasTalking, Wasiliana

Constant Summary collapse

TO_TYPE =

Wraps a scalar to: into an Array before per-element PhoneNumber coercion, so callers can pass either a single number or a list.

Types::Array.of(Types::PhoneNumber).constructor { |value| Array(value) }

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.connectionObject



53
54
55
# File 'lib/arafa/providers/base.rb', line 53

def connection
  @connection ||= build_connection
end

.new(*args, **kwargs) ⇒ Object

Accepts either provider keywords (text:, to:, from:) or a single positional object responding to #to_arafa (duck-typed message support).



34
35
36
37
38
39
40
41
# File 'lib/arafa/providers/base.rb', line 34

def new(*args, **kwargs)
  if args.size == 1 && args.first.respond_to?(:to_arafa)
    kwargs = args.first.to_arafa.merge(kwargs)
    args = []
  end

  super(*args, **kwargs)
end

.send(*args, **kwargs) ⇒ Object

Shortcut for new(**kwargs).send. Falls back to Kernel#send's dynamic-dispatch behavior for any other call shape (positional method-name args), since dry-initializer and friends rely on klass.send(:some_method, ...) internally.



47
48
49
50
51
# File 'lib/arafa/providers/base.rb', line 47

def send(*args, **kwargs)
  return super if args.any? || kwargs.empty?

  new(**kwargs).send
end

Instance Method Details

#build_payloadObject

Raises:

  • (NotImplementedError)


100
101
102
# File 'lib/arafa/providers/base.rb', line 100

def build_payload
  raise NotImplementedError, "#{self.class} must implement #build_payload"
end

#connectionObject



88
89
90
# File 'lib/arafa/providers/base.rb', line 88

def connection
  self.class.connection
end

#endpointObject

Raises:

  • (NotImplementedError)


92
93
94
# File 'lib/arafa/providers/base.rb', line 92

def endpoint
  raise NotImplementedError, "#{self.class} must implement #endpoint"
end

#headersObject

Raises:

  • (NotImplementedError)


96
97
98
# File 'lib/arafa/providers/base.rb', line 96

def headers
  raise NotImplementedError, "#{self.class} must implement #headers"
end

#parse_response(_response) ⇒ Object

Raises:

  • (NotImplementedError)


104
105
106
# File 'lib/arafa/providers/base.rb', line 104

def parse_response(_response)
  raise NotImplementedError, "#{self.class} must implement #parse_response"
end

#send(*args, **kwargs) ⇒ Object

Contract → HTTP call → response parsing. Returns a Dry::Monads::Result: Success(SendResult) or Failure(Arafa::Error subclass). Falls back to Kernel#send's dynamic-dispatch behavior if called with arguments.



76
77
78
79
80
81
82
83
84
85
86
# File 'lib/arafa/providers/base.rb', line 76

def send(*args, **kwargs)
  return super if args.any? || kwargs.any?

  validation = validate_contract
  return validation if validation.failure?

  response = connection.post(endpoint, build_payload, headers)
  parse_response(response)
rescue Faraday::ConnectionFailed, Faraday::TimeoutError => e
  Failure(Arafa::NetworkError.new(e.message))
end