Class: Amount::Registry

Inherits:
Object
  • Object
show all
Defined in:
lib/amount/registry.rb,
lib/amount/registry/generated_constructors.rb

Overview

Stores registered amount types and default directional conversion rates.

The registry is the configuration surface of the gem. Application code normally uses the shared global instance exposed by registry, configures it during boot, and optionally calls #lock! when setup is complete.

Examples:

Registering types at boot

Amount.register :USDC, decimals: 6

Amount.register :USD, decimals: 2

Amount.register_default_rate :USD, :USDC, "1"
Amount.registry.lock!

Defined Under Namespace

Classes: AlreadyRegistered, Entry, GeneratedConstructors, InvalidDisplayUnit, NoDefaultRate, RegistryLocked, UnknownType

Instance Method Summary collapse

Constructor Details

#initializeRegistry

Returns a new instance of Registry.



41
42
43
44
45
46
47
48
# File 'lib/amount/registry.rb', line 41

def initialize
  @entries       = {}
  @default_rates = {}
  @locked        = false

  @lock = Mutex.new
  @generated_constructors = GeneratedConstructors.new
end

Instance Method Details

#activate_generated_methods!void

This method returns an undefined value.



210
211
212
213
214
# File 'lib/amount/registry.rb', line 210

def activate_generated_methods!
  @lock.synchronize do
    @generated_constructors.activate(@entries)
  end
end

#clear!void

This method returns an undefined value.

Examples:

Amount.registry.clear!

Raises:



138
139
140
141
142
143
144
145
# File 'lib/amount/registry.rb', line 138

def clear!
  @lock.synchronize do
    ensure_unlocked!
    @generated_constructors.remove_all
    @entries.clear
    @default_rates.clear
  end
end

#default_rate(from, to) ⇒ BigDecimal

Examples:

Amount.registry.default_rate(:USD, :USDC)
# => 0.1e1

Parameters:

  • from (Symbol, String)
  • to (Symbol, String)

Returns:

  • (BigDecimal)

Raises:



174
175
176
177
178
179
180
# File 'lib/amount/registry.rb', line 174

def default_rate(from, to)
  @lock.synchronize do
    @default_rates.fetch([from.to_sym, to.to_sym]) do
      raise NoDefaultRate, "no default rate for #{from} -> #{to}; pass rate: explicitly"
    end
  end
end

#default_rate?(from, to) ⇒ Boolean

Examples:

Amount.registry.default_rate?(:USD, :USDC)
# => true

Parameters:

  • from (Symbol, String)
  • to (Symbol, String)

Returns:

  • (Boolean)


188
189
190
# File 'lib/amount/registry.rb', line 188

def default_rate?(from, to)
  @lock.synchronize { @default_rates.key?([from.to_sym, to.to_sym]) }
end

#lock!void

This method returns an undefined value.

Examples:

Locking the global registry after initialization

Amount.registry.lock!


195
196
197
198
199
# File 'lib/amount/registry.rb', line 195

def lock!
  @lock.synchronize do
    @locked = true
  end
end

#locked?Boolean

Examples:

Amount.registry.locked?
# => true

Returns:

  • (Boolean)


205
206
207
# File 'lib/amount/registry.rb', line 205

def locked?
  @lock.synchronize { @locked }
end

#lookup(symbol) ⇒ Entry

Examples:

Amount.registry.lookup(:USDC).decimals
# => 6

Parameters:

  • symbol (Symbol, String)

Returns:

Raises:



118
119
120
121
122
123
124
# File 'lib/amount/registry.rb', line 118

def lookup(symbol)
  @lock.synchronize do
    @entries.fetch(symbol.to_sym) do
      raise UnknownType, "#{symbol} is not registered"
    end
  end
end

#register(symbol, decimals:, display_symbol: symbol.to_s, display_position: :suffix, ui_decimals: decimals, display_units: nil, default_display: nil, class: nil) ⇒ void

This method returns an undefined value.

Registers a new fungible type.

When the symbol is a valid Ruby method name after downcasing, an ergonomic constructor is also generated on ‘Amount`, such as `Amount.usdc(“1.50”)`.

Examples:

Amount.register :USDC,
  decimals: 6,
  display_symbol: "$",
  display_position: :prefix,
  ui_decimals: 2

Parameters:

  • symbol (Symbol, String)

    registered type identifier

  • decimals (Integer)

    number of storage decimals

  • display_symbol (String) (defaults to: symbol.to_s)

    symbol used by UI helpers

  • display_position (Symbol) (defaults to: :suffix)

    either ‘:prefix` or `:suffix`

  • ui_decimals (Integer) (defaults to: decimals)

    decimals displayed by default UI formatting

  • display_units (Hash, nil) (defaults to: nil)

    optional display-only scaling definitions

  • default_display (Symbol, nil) (defaults to: nil)

    optional default display unit key

  • class (Class, nil) (defaults to: nil)

    optional custom ‘Amount` subclass

Raises:

  • (AlreadyRegistered)

    if the symbol is already registered or the generated constructor would collide with an existing method

  • (RegistryLocked)

    if the registry has been locked



74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
# File 'lib/amount/registry.rb', line 74

def register(symbol, decimals:, display_symbol: symbol.to_s, display_position: :suffix,
             ui_decimals: decimals, display_units: nil, default_display: nil,
             class: nil)
  raise ArgumentError, "symbol must not be blank" if symbol.nil? || symbol.to_s.empty?

  symbol = symbol.to_sym

  @lock.synchronize do
    ensure_unlocked!
    raise AlreadyRegistered, "#{symbol} already registered" if @entries.key?(symbol)

    validate_display_units!(display_units, default_display) if display_units

    entry = Entry.new(
      symbol:,
      decimals:,
      display_symbol:,
      display_position:,
      ui_decimals:,
      display_units:,
      default_display:,
      amount_class: binding.local_variable_get(:class) || Amount
    )

    @entries[symbol] = entry
    @generated_constructors.define_for(entry)
  end
end

#register_default_rate(from, to, rate) ⇒ void

This method returns an undefined value.

Examples:

Amount.register_default_rate :USD, :USDC, "1"

Parameters:

  • from (Symbol, String)
  • to (Symbol, String)
  • rate (String, Numeric, BigDecimal)

Raises:



154
155
156
157
158
159
160
161
162
163
164
165
# File 'lib/amount/registry.rb', line 154

def register_default_rate(from, to, rate)
  from = from.to_sym
  to = to.to_sym

  lookup(from)
  lookup(to)

  @lock.synchronize do
    ensure_unlocked!
    @default_rates[[from, to]] = Amount.coerce_decimal(rate)
  end
end

#registered?(symbol) ⇒ Boolean

Examples:

Amount.registry.registered?(:USDC)
# => true

Parameters:

  • symbol (Symbol, String)

Returns:

  • (Boolean)


108
109
110
# File 'lib/amount/registry.rb', line 108

def registered?(symbol)
  @lock.synchronize { @entries.key?(symbol.to_sym) }
end

#remove_generated_methods!void

This method returns an undefined value.



217
218
219
220
221
# File 'lib/amount/registry.rb', line 217

def remove_generated_methods!
  @lock.synchronize do
    @generated_constructors.remove_all
  end
end

#symbolsArray<Symbol>

Examples:

Amount.registry.symbols
# => [:USDC, :USD]

Returns:

  • (Array<Symbol>)


130
131
132
# File 'lib/amount/registry.rb', line 130

def symbols
  @lock.synchronize { @entries.keys }
end