Latinum SourceLatinumBank

class Bank

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

Definitions

def initialize(*imports)

Imports all given currencies.

Implementation

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

def import(resources)

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

Implementation

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

def [](name)

Look up a currency by name.

Implementation

def [](name)
	@currencies[name]
end

attr :symbols

A map of all recognised symbols ordered by priority.

Signature

attribute Hash(String, Tuple(Integer, Name))

attr :currencies

The supported currents and assocaited formatting details.

Signature

attribute Hash(String, Hash)

def <<(rate)

Add an exchange rate to the bank.

Signature

parameter rate ExchangeRate

The exchange rate to add.

Implementation

def <<(rate)
	@rates << rate
	
	@exchange[rate.input] ||= {}
	@exchange[rate.input][rate.output] = rate
end

def exchange(resource, for_name)

Exchange one resource for another using internally specified rates.

Implementation

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

def parse(string, default_name: nil)

Parse a string according to the loaded currencies.

Implementation

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

def round(resource)

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.

Signature

parameter resource Resource

The resource to round.

returns Resource

A copy of the resource with the amount rounded as per the formatter.

Implementation

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

def format(resource, *arguments, **options)

Format a resource as a string according to the loaded currencies.

Signature

parameter resource Resource

The resource to format.

Implementation

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

def to_integral(resource)

Convert the resource to an integral representation based on the currency's precision.

Signature

parameter resource Resource

The resource to convert.

returns Integer

The integer representation.

Implementation

def to_integral(resource)
	formatter = @formatters[resource.name]
	
	formatter.to_integral(resource.amount)
end

def from_integral(amount, name)

Convert the resource from an integral representation based on the currency's precision.

Signature

parameter amount Integer

The integral resource amount.

parameter name String

The resource name.

returns Resource

The converted resource.

Implementation

def from_integral(amount, name)
	formatter = @formatters[name]
	
	Resource.new(formatter.from_integral(amount), name)
end