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.



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

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.



214
215
216
217
218
# File 'lib/amount/registry.rb', line 214

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:



142
143
144
145
146
147
148
149
# File 'lib/amount/registry.rb', line 142

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:



178
179
180
181
182
183
184
# File 'lib/amount/registry.rb', line 178

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)


192
193
194
# File 'lib/amount/registry.rb', line 192

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!


199
200
201
202
203
# File 'lib/amount/registry.rb', line 199

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

#locked?Boolean

Examples:

Amount.registry.locked?
# => true

Returns:

  • (Boolean)


209
210
211
# File 'lib/amount/registry.rb', line 209

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

#lookup(symbol) ⇒ Entry

Examples:

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

Parameters:

  • symbol (Symbol, String)

Returns:

Raises:



122
123
124
125
126
127
128
# File 'lib/amount/registry.rb', line 122

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, trim_zeros: false, 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` with an `of_` prefix, such as `Amount.of_usdc(“1.50”)`. The prefix avoids collisions with existing methods like `Object#try` (added by ActiveSupport).

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

  • trim_zeros (Boolean) (defaults to: false)

    strip trailing zeros from UI output

  • 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



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
102
103
104
105
# File 'lib/amount/registry.rb', line 77

def register(symbol, decimals:, display_symbol: symbol.to_s, display_position: :suffix,
             ui_decimals: decimals, display_units: nil, default_display: nil,
             trim_zeros: false, 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,
      trim_zeros:
    )

    @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:



158
159
160
161
162
163
164
165
166
167
168
169
# File 'lib/amount/registry.rb', line 158

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)


112
113
114
# File 'lib/amount/registry.rb', line 112

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

#remove_generated_methods!void

This method returns an undefined value.



221
222
223
224
225
# File 'lib/amount/registry.rb', line 221

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

#symbolsArray<Symbol>

Examples:

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

Returns:

  • (Array<Symbol>)


134
135
136
# File 'lib/amount/registry.rb', line 134

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