class Latinum::Bank

A bank defines exchange rates and formatting rules for resources. It is a centralised location for resource formatting and metadata.

Attributes

currencies[R]

The supported currents and assocaited formatting details. @attribute [Hash(String, Hash)]

rates[R]
symbols[R]

A map of all recognised symbols ordered by priority. @attribute [Hash(String, Tuple(Integer, Name))]

Public Class Methods

new(*imports) click to toggle source

Imports all given currencies.

# File lib/latinum/bank.rb, line 37
def initialize(*imports)
        @rates = []
        @exchange = {}
        
        # This implementation may change:
        @currencies = {}
        @formatters = {}
        
        # Symbols and their associated priorities
        @symbols = {}
        
        imports&.each do |resources|
                import(resources)
        end
end

Public Instance Methods

<<(rate) click to toggle source

Add an exchange rate to the bank. @parameter rate [ExchangeRate] The exchange rate to add.

# File lib/latinum/bank.rb, line 88
def <<(rate)
        @rates << rate
        
        @exchange[rate.input] ||= {}
        @exchange[rate.input][rate.output] = rate
end
[](name) click to toggle source

Look up a currency by name.

# File lib/latinum/bank.rb, line 72
def [](name)
        @currencies[name]
end
dump(resource) click to toggle source
# File lib/latinum/bank.rb, line 135
def dump(resource)
        resource.to_s if resource
end
exchange(resource, for_name) click to toggle source

Exchange one resource for another using internally specified rates.

# File lib/latinum/bank.rb, line 96
def exchange(resource, for_name)
        unless rate = @exchange.dig(resource.name, for_name)
                raise ArgumentError.new("Rate #{rate} unavailable")
        end
        
        config = self[for_name]
        
        return resource.exchange(rate.factor, for_name, config[:precision])
end
format(resource, *arguments, **options) click to toggle source

Format a resource as a string according to the loaded currencies. @parameter resource [Resource] The resource to format.

# File lib/latinum/bank.rb, line 160
def format(resource, *arguments, **options)
        unless formatter = @formatters[resource.name]
                raise ArgumentError.new("No formatter found for #{resource.name}")
        end
        
        formatter.format(resource.amount, *arguments, **options)
end
from_integral(amount, name) click to toggle source

Convert the resource from an integral representation based on the currency’s precision. @parameter amount [Integer] The integral resource amount. @parameter name [String] The resource name. @returns [Resource] The converted resource.

# File lib/latinum/bank.rb, line 181
def from_integral(amount, name)
        formatter = @formatters[name]
        
        Resource.new(formatter.from_integral(amount), name)
end
import(resources) click to toggle source

Import a list of resource templates, e.g. currencies.

# File lib/latinum/bank.rb, line 54
def import(resources)
        resources.each do |name, config|
                name = (config[:name] || name).to_s
                
                @currencies[name] = config
                
                # Create a formatter:
                @formatters[name] = config[:formatter].new(**config)
                
                if config[:symbol]
                        symbols = (@symbols[config[:symbol]] ||= [])
                        symbols << [config.fetch(:priority, -1), name.to_s]
                        symbols.sort!.uniq!
                end
        end
end
load(input) click to toggle source
# File lib/latinum/bank.rb, line 128
def load(input)
        if input.is_a?(String)
                input = input.strip
                return parse(input) unless input.empty?
        end
end
parse(string, default_name: nil) click to toggle source

Parse a string according to the loaded currencies.

# File lib/latinum/bank.rb, line 107
def parse(string, default_name: nil)
        parts = string.strip.split(/\s+/, 2)
        
        if parts.size == 2
                return parse_named_resource(parts[1], parts[0])
        else
                # Lookup the named symbol, e.g. '$', and get the highest priority name:
                symbol = @symbols.fetch(string.gsub(/[\-\.,0-9]/, ''), []).last
                
                if symbol
                        name = symbol.last.to_s
                elsif default_name
                        name = default_name
                else
                        raise ArgumentError, "Could not parse #{string}, could not determine resource name!"
                end
                
                return parse_named_resource(name, string)
        end
end
round(resource) click to toggle source

Rounds the specified resource to the maximum precision as specified by the formatter. Whe computing things like tax, you often get fractional amounts which are unpayable because they are smaller than the minimum discrete unit of the currency. This method helps to round a currency to a payable amount. @parameter resource [Resource] The resource to round. @returns [Resource] A copy of the resource with the amount rounded as per the formatter.

# File lib/latinum/bank.rb, line 150
def round(resource)
        unless formatter = @formatters[resource.name]
                raise ArgumentError.new("No formatter found for #{resource.name}")
        end
        
        return Resource.new(formatter.round(resource.amount), resource.name)
end
to_integral(resource) click to toggle source

Convert the resource to an integral representation based on the currency’s precision. @parameter resource [Resource] The resource to convert. @returns [Integer] The integer representation.

# File lib/latinum/bank.rb, line 171
def to_integral(resource)
        formatter = @formatters[resource.name]
        
        formatter.to_integral(resource.amount)
end

Private Instance Methods

parse_named_resource(name, value) click to toggle source
# File lib/latinum/bank.rb, line 139
        def parse_named_resource(name, value)
        if formatter = @formatters[name]
                return Resource.new(formatter.parse(value), name)
        else
                raise ArgumentError, "No formatter found for #{name}!"
        end
end