Module: Nombaone::Internal::Util Private
- Defined in:
- lib/nombaone/internal/util.rb,
sig/nombaone/internal.rbs
Overview
This module is part of a private API. You should avoid using this module if possible, as it may be removed or be changed in the future.
Pure, dependency-free helpers shared across the transport and resources.
Constant Summary collapse
- PRESERVE_VALUE_KEYS =
This constant is part of a private API. You should avoid using this constant if possible, as it may be removed or be changed in the future.
Keys whose values are arbitrary user JSON and must never have their inner keys rewritten (a customer's
metadata, a sandbox webhookpayload). The key name itself is still normalized (both are already single words, so normalization is a no-op). %w[metadata payload].freeze
Class Method Summary collapse
-
.backoff_seconds(attempt) ⇒ Float
private
Full-jitter exponential backoff, in seconds: a random delay in
[0, min(8, 0.5 * 2**attempt)). -
.camelize(key) ⇒ String
private
Convert a snake_case key to the camelCase name the wire expects.
-
.deep_camelize_keys(value) ⇒ Object
private
Recursively rewrite Hash keys to camelCase, except that the value of a PRESERVE_VALUE_KEYS key is passed through untouched.
-
.encode_path_segment(value) ⇒ String
private
Percent-encode one URL path segment.
-
.generate_idempotency_key ⇒ String
private
A fresh idempotency key for one logical POST.
-
.merge_headers(*layers) ⇒ Hash{String => String}
private
Merge header layers left-to-right; later layers win.
-
.retry_after_seconds(raw) ⇒ Float?
private
Parse a
Retry-Afterheader into seconds. -
.serialize_body(hash) ⇒ Hash
private
Prepare a request body hash for the wire: drop omitted keys (keeping explicit
nils so nullable fields can be cleared), then camelize. -
.serialize_query(hash) ⇒ Hash{String => String}
private
Prepare query params: drop omitted and nil filters (an absent filter, not a null one), camelize keys, and stringify values.
Instance Method Summary collapse
- #self?.backoff_seconds ⇒ Float private
- #self?.camelize ⇒ String private
- #self?.deep_camelize_keys ⇒ Object private
- #self?.encode_path_segment ⇒ String private
- #self?.generate_idempotency_key ⇒ String private
- #self?.merge_headers ⇒ Hash[String, String] private
- #self?.retry_after_seconds ⇒ Float? private
- #self?.serialize_body ⇒ Hash[String, untyped] private
- #self?.serialize_query ⇒ Hash[String, String] private
Class Method Details
.backoff_seconds(attempt) ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Full-jitter exponential backoff, in seconds: a random delay in
[0, min(8, 0.5 * 2**attempt)). Jitter keeps a fleet of retrying
clients from stampeding the API in lockstep.
113 114 115 |
# File 'lib/nombaone/internal/util.rb', line 113 def backoff_seconds(attempt) rand * [8.0, 0.5 * (2**attempt)].min end |
.camelize(key) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Convert a snake_case key to the camelCase name the wire expects.
The wire field name is law; this is the single place the SDK's
idiomatic Ruby names become it (customer_id → customerId,
amount_in_kobo → amountInKobo, plan_ref → planRef).
40 41 42 43 44 45 46 |
# File 'lib/nombaone/internal/util.rb', line 40 def camelize(key) parts = key.to_s.split("_") return parts.first.to_s if parts.length <= 1 head, *tail = parts (head + tail.map { |word| word.empty? ? "" : word[0].upcase + word[1..] }.join) end |
.deep_camelize_keys(value) ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Recursively rewrite Hash keys to camelCase, except that the value of a PRESERVE_VALUE_KEYS key is passed through untouched.
53 54 55 56 57 58 59 60 61 62 63 64 65 |
# File 'lib/nombaone/internal/util.rb', line 53 def deep_camelize_keys(value) case value when Hash value.each_with_object({}) do |(key, val), out| out[camelize(key)] = PRESERVE_VALUE_KEYS.include?(key.to_s) ? val : deep_camelize_keys(val) end when Array value.map { |item| deep_camelize_keys(item) } else value end end |
.encode_path_segment(value) ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Percent-encode one URL path segment. Ids come from user input, so they
are never trusted raw; this matches JavaScript's encodeURIComponent
for the characters that appear in NombaOne ids.
95 96 97 |
# File 'lib/nombaone/internal/util.rb', line 95 def encode_path_segment(value) CGI.escape(value.to_s).gsub("+", "%20") end |
.generate_idempotency_key ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
A fresh idempotency key for one logical POST. Computed once, before the retry loop, so every automatic retry replays the same operation.
103 104 105 |
# File 'lib/nombaone/internal/util.rb', line 103 def generate_idempotency_key SecureRandom.uuid end |
.merge_headers(*layers) ⇒ Hash{String => String}
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Merge header layers left-to-right; later layers win. A nil value
deletes a header (lets a caller strip an SDK default for one request).
Header names are case-insensitive, so everything is lowercased once.
143 144 145 146 147 148 149 150 151 152 |
# File 'lib/nombaone/internal/util.rb', line 143 def merge_headers(*layers) layers.each_with_object({}) do |layer, out| next unless layer layer.each do |name, value| key = name.to_s.downcase value.nil? ? out.delete(key) : out[key] = value.to_s end end end |
.retry_after_seconds(raw) ⇒ Float?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Parse a Retry-After header into seconds. Accepts delta-seconds or an
HTTP-date; returns nil when absent or unparseable so the caller falls
back to its own backoff.
123 124 125 126 127 128 129 130 131 132 133 134 135 |
# File 'lib/nombaone/internal/util.rb', line 123 def retry_after_seconds(raw) return nil if raw.nil? seconds = Float(raw, exception: false) return [seconds, 0.0].max if seconds date = begin Time.httpdate(raw) rescue ArgumentError nil end date ? [date - Time.now, 0.0].max : nil end |
.serialize_body(hash) ⇒ Hash
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Prepare a request body hash for the wire: drop omitted keys (keeping
explicit nils so nullable fields can be cleared), then camelize.
72 73 74 |
# File 'lib/nombaone/internal/util.rb', line 72 def serialize_body(hash) deep_camelize_keys(hash.reject { |_, v| OMIT.equal?(v) }) end |
.serialize_query(hash) ⇒ Hash{String => String}
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
Prepare query params: drop omitted and nil filters (an absent filter, not a null one), camelize keys, and stringify values.
81 82 83 84 85 86 87 |
# File 'lib/nombaone/internal/util.rb', line 81 def serialize_query(hash) hash.each_with_object({}) do |(key, value), out| next if OMIT.equal?(value) || value.nil? out[camelize(key)] = value.to_s end end |
Instance Method Details
#self?.backoff_seconds ⇒ Float
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
14 |
# File 'sig/nombaone/internal.rbs', line 14
def self?.backoff_seconds: (Integer attempt) -> Float
|
#self?.camelize ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
8 |
# File 'sig/nombaone/internal.rbs', line 8
def self?.camelize: (String | Symbol key) -> String
|
#self?.deep_camelize_keys ⇒ Object
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
9 |
# File 'sig/nombaone/internal.rbs', line 9
def self?.deep_camelize_keys: (untyped value) -> untyped
|
#self?.encode_path_segment ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
12 |
# File 'sig/nombaone/internal.rbs', line 12
def self?.encode_path_segment: (untyped value) -> String
|
#self?.generate_idempotency_key ⇒ String
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
13 |
# File 'sig/nombaone/internal.rbs', line 13
def self?.generate_idempotency_key: () -> String
|
#self?.merge_headers ⇒ Hash[String, String]
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
16 |
# File 'sig/nombaone/internal.rbs', line 16
def self?.merge_headers: (*Hash[untyped, untyped]? layers) -> Hash[String, String]
|
#self?.retry_after_seconds ⇒ Float?
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
15 |
# File 'sig/nombaone/internal.rbs', line 15
def self?.retry_after_seconds: (String? raw) -> Float?
|
#self?.serialize_body ⇒ Hash[String, untyped]
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
10 |
# File 'sig/nombaone/internal.rbs', line 10
def self?.serialize_body: (Hash[untyped, untyped] hash) -> Hash[String, untyped]
|
#self?.serialize_query ⇒ Hash[String, String]
This method is part of a private API. You should avoid using this method if possible, as it may be removed or be changed in the future.
11 |
# File 'sig/nombaone/internal.rbs', line 11
def self?.serialize_query: (Hash[untyped, untyped] hash) -> Hash[String, String]
|