latinum 0.2.0 → 0.2.3

Sign up to get free protection for your applications and to get access to all the features.
data/README.md CHANGED
@@ -7,6 +7,83 @@ Latinum
7
7
 
8
8
  Latinum is a framework for resource and currency calculations. *It is currently a work in progress and not designed to be taken seriously at this time*.
9
9
 
10
+ Basic Usage
11
+ -----------
12
+
13
+ Latinum has several core concepts:
14
+
15
+ - A `Resource` represents an immutable value with a specific face name (e.g. `'USD'`).
16
+ - A `Resource` can only be combined with resources with the same face name.
17
+ - A `Bank` is responsible for managing currencies and formatting options.
18
+ - A `Bank` can exchange currencies explicitly with a given set of exchange rates.
19
+ - A `Collection` is responsible for adding currencies together and is completely deterministic.
20
+
21
+ ### Resources and Collections ###
22
+
23
+ To create a new resource, use a string for accuracy:
24
+
25
+ > ten = Latinum::Resource.new("10.00", "NZD")
26
+ => 10.0 NZD
27
+ > ten.amount == "10.00".to_d
28
+ => true
29
+
30
+ You can add resources of different values but with the same name:
31
+
32
+ > ten + ten
33
+ => 20.0 NZD
34
+
35
+ But, you can't add resources of different names together:
36
+
37
+ > twenty = Latinum::Resource.new("20.00", "AUD")
38
+ => 20.0 AUD
39
+ > ten + twenty
40
+ ArgumentError: Cannot operate on different currencies!
41
+
42
+ To add multiple currencies together, use a collection:
43
+
44
+ > currencies = Set.new
45
+ > collection = Latinum::Collection.new(currencies)
46
+ > collection << ten
47
+ > collection << twenty
48
+ > currencies.collect {|currency| collection[currency]}
49
+ => [10.0 NZD, 20.0 AUD]
50
+
51
+ ### Banks and Exchange Rates ###
52
+
53
+ The bank is responsible for formatting and exchange rates:
54
+
55
+ require 'latinum/bank'
56
+ require 'latinum/currencies/global'
57
+
58
+ > bank = Latinum::Bank.new(Latinum::Currencies::Global)
59
+ > bank << Latinum::ExchangeRate.new("NZD", "AUD", "0.5")
60
+
61
+ > nzd = Latinum::Resource.new("10", "NZD")
62
+ => 10.0 NZD
63
+ > aud = bank.exchange nzd, "AUD"
64
+ => 5.0 AUD
65
+
66
+ Formatting an amount is typically required for presentation to the end user:
67
+
68
+ > bank.format(nzd)
69
+ => "$10.00 NZD"
70
+
71
+ > bank.format(aud, :format => :compact)
72
+ => "$5.00"
73
+
74
+ The bank can also be used to parse currency, which will depend on the priority of currencies if a symbol that matches multiple currencies is supplied:
75
+
76
+ > bank.parse("$5")
77
+ => 5.0 USD
78
+
79
+ > bank.parse("€5")
80
+ => 5.0 EUR
81
+
82
+ Currency codes take priority over symbols if specified:
83
+
84
+ > bank.parse("€5 NZD")
85
+ => 5.0 NZD
86
+
10
87
  License
11
88
  -------
12
89
 
data/lib/latinum.rb CHANGED
@@ -18,5 +18,13 @@
18
18
  # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
19
19
  # THE SOFTWARE.
20
20
 
21
+ require 'latinum/bank'
21
22
  require 'latinum/resource'
22
- require 'latinum/collection'
23
+ require 'latinum/collection'
24
+
25
+ require 'bigdecimal'
26
+ require 'bigdecimal/util'
27
+
28
+ if RUBY_VERSION < "1.9"
29
+ require 'latinum/extensions/bigdecimal-1.8'
30
+ end
data/lib/latinum/bank.rb CHANGED
@@ -25,7 +25,7 @@ module Latinum
25
25
  def initialize(input, output, factor)
26
26
  @input = input
27
27
  @output = output
28
- @factor = BigDecimal(factor)
28
+ @factor = factor.to_d
29
29
  end
30
30
 
31
31
  attr :input
@@ -38,6 +38,8 @@ module Latinum
38
38
  @rates = []
39
39
  @exchange = {}
40
40
 
41
+ # This implementation may change:
42
+ @currencies = {}
41
43
  @formatters = {}
42
44
 
43
45
  # Symbols and their associated priorities
@@ -52,8 +54,10 @@ module Latinum
52
54
  resources.each do |name, config|
53
55
  name = (config[:name] || name).to_s
54
56
 
57
+ @currencies[name] = config
58
+
55
59
  # Create a formatter:
56
- self[name] = config[:formatter].new(config)
60
+ @formatters[name] = config[:formatter].new(config)
57
61
 
58
62
  if config[:symbol]
59
63
  symbols = (@symbols[config[:symbol]] ||= [])
@@ -63,30 +67,32 @@ module Latinum
63
67
  end
64
68
  end
65
69
 
70
+ def [] name
71
+ @currencies[name]
72
+ end
73
+
66
74
  attr :rates
67
75
  attr :symbols
68
- attr :formatters
76
+ attr :currencies
69
77
 
70
- def << object
78
+ def << rate
71
79
  @rates << rate
72
80
 
73
81
  @exchange[rate.input] ||= {}
74
82
  @exchange[rate.input][rate.output] = rate
75
83
  end
76
84
 
77
- def []= name, formatter
78
- @formatters[name] = formatter
79
- end
80
-
81
85
  def exchange(resource, for_name)
82
86
  rate = @exchange[resource.name][for_name]
83
87
  raise ArgumentError.new("Invalid rate specified #{rate}") if rate == nil
84
88
 
85
- Resource.new(resource.amount * rate.factor, for_name)
89
+ config = self[for_name]
90
+
91
+ resource.exchange(rate.factor, for_name, config[:precision])
86
92
  end
87
93
 
88
94
  def parse(string)
89
- parts = string.strip.split(/\s+, 2/)
95
+ parts = string.strip.split(/\s+/, 2)
90
96
 
91
97
  if parts.size == 2
92
98
  Resource.new(parts[0].gsub(/[^\.0-9]/, ''), parts[1])
@@ -25,7 +25,7 @@ module Latinum
25
25
  class Collection
26
26
  def initialize(names = Set.new)
27
27
  @names = names
28
- @resources = Hash.new {|hash, key| @names << key; BigDecimal.new(0)}
28
+ @resources = Hash.new {|hash, key| @names << key; BigDecimal.new("0")}
29
29
  end
30
30
 
31
31
  attr :names
@@ -33,6 +33,8 @@ module Latinum
33
33
 
34
34
  def << resource
35
35
  @resources[resource.name] += resource.amount
36
+
37
+ return self
36
38
  end
37
39
 
38
40
  def [] key
@@ -27,6 +27,7 @@ module Latinum
27
27
  Global = {}
28
28
 
29
29
  Global[:NZD] = {
30
+ :precision => 2,
30
31
  :symbol => '$',
31
32
  :name => 'NZD',
32
33
  :description => 'New Zealand Dollar',
@@ -34,6 +35,7 @@ module Latinum
34
35
  }
35
36
 
36
37
  Global[:GBP] = {
38
+ :precision => 2,
37
39
  :symbol => '£',
38
40
  :name => 'GBP',
39
41
  :description => 'Pound Sterling',
@@ -41,6 +43,7 @@ module Latinum
41
43
  }
42
44
 
43
45
  Global[:AUD] = {
46
+ :precision => 2,
44
47
  :symbol => '$',
45
48
  :name => 'AUD',
46
49
  :description => 'Australian Dollar',
@@ -48,6 +51,7 @@ module Latinum
48
51
  }
49
52
 
50
53
  Global[:USD] = {
54
+ :precision => 2,
51
55
  :symbol => '$',
52
56
  :name => 'USD',
53
57
  :description => 'United States Dollar',
@@ -55,6 +59,7 @@ module Latinum
55
59
  }
56
60
 
57
61
  Global[:EUR] = {
62
+ :precision => 2,
58
63
  :symbol => '€',
59
64
  :name => 'EUR',
60
65
  :description => 'Euro',
@@ -62,5 +67,13 @@ module Latinum
62
67
  #:delimeter => '.',
63
68
  #:separator => ','
64
69
  }
70
+
71
+ Global[:JPY] = {
72
+ :precision => 0,
73
+ :symbol => '¥',
74
+ :name => 'JPY',
75
+ :description => 'Japanese Yen',
76
+ :formatter => Formatters::DecimalCurrencyFormatter
77
+ }
65
78
  end
66
79
  end
@@ -0,0 +1,6 @@
1
+
2
+ class BigDecimal
3
+ def to_d
4
+ self
5
+ end
6
+ end
@@ -39,14 +39,14 @@ module Latinum
39
39
  @symbol = options[:symbol] || '$'
40
40
  @separator = options[:separator] || '.'
41
41
  @delimeter = options[:delimter] || ','
42
- @places = options[:places] || 2
42
+ @places = options[:precision] || 2
43
43
  @zero = options[:zero] || '0'
44
44
 
45
45
  @name = options[:name]
46
46
  end
47
47
 
48
48
  def format(amount, options = DEFAULT_OPTIONS)
49
- fix, frac = amount.to_s('F').split(/\./, 2)
49
+ fix, frac = amount.abs.to_s('F').split(/\./, 2)
50
50
 
51
51
  # The sign of the number
52
52
  sign = amount.sign < 0 ? '-' : ''
@@ -29,19 +29,19 @@ module Latinum
29
29
  attr :name
30
30
 
31
31
  def initialize(amount, name)
32
- @amount = BigDecimal(amount)
32
+ @amount = amount.to_d
33
33
  @name = name
34
34
  end
35
35
 
36
36
  # By default, we can only add and subtract if the name is the same
37
37
  def + other
38
- throw ArgumentError.new("Cannot operate on different currencies!") if @name != other.name
38
+ raise ArgumentError.new("Cannot operate on different currencies!") if @name != other.name
39
39
 
40
40
  self.class.new(@amount + other.amount, @name)
41
41
  end
42
42
 
43
43
  def - other
44
- throw ArgumentError.new("Cannot operate on different currencies!") if @name != other.name
44
+ raise ArgumentError.new("Cannot operate on different currencies!") if @name != other.name
45
45
 
46
46
  self.class.new(@amount - other.amount, @name)
47
47
  end
@@ -54,6 +54,14 @@ module Latinum
54
54
  self.class.new(@amount * factor, @name)
55
55
  end
56
56
 
57
+ def exchange(rate, name, precision = nil)
58
+ exchanged_amount = @amount * rate
59
+
60
+ exchanged_amount = exchanged_amount.round(precision) if precision
61
+
62
+ self.class.new(exchanged_amount, name)
63
+ end
64
+
57
65
  def to_s(options = {})
58
66
  @amount.to_s('F') + ' ' + @name.to_s
59
67
  end
@@ -22,7 +22,7 @@ module Latinum
22
22
  module VERSION
23
23
  MAJOR = 0
24
24
  MINOR = 2
25
- TINY = 0
25
+ TINY = 3
26
26
 
27
27
  STRING = [MAJOR, MINOR, TINY].join('.')
28
28
  end
data/test/test_bank.rb CHANGED
@@ -1,13 +1,15 @@
1
1
 
2
2
  require 'helper'
3
3
 
4
- require 'latinum/bank'
4
+ require 'latinum'
5
5
  require 'latinum/currencies/global'
6
6
 
7
7
  class BankTest < Test::Unit::TestCase
8
8
  def setup
9
9
  @bank = Latinum::Bank.new
10
10
  @bank.import(Latinum::Currencies::Global)
11
+
12
+ @bank << Latinum::ExchangeRate.new("NZD", "AUD", "0.5")
11
13
  end
12
14
 
13
15
  def test_formatting
@@ -17,5 +19,23 @@ class BankTest < Test::Unit::TestCase
17
19
 
18
20
  resource = Latinum::Resource.new("391", "AUD")
19
21
  assert_equal "$391.00 AUD", @bank.format(resource)
22
+
23
+ resource = Latinum::Resource.new("-100", "NZD")
24
+ assert_equal "-$100.00 NZD", @bank.format(resource)
25
+ end
26
+
27
+ def test_exchange
28
+ nzd = Latinum::Resource.new("10", "NZD")
29
+
30
+ aud = @bank.exchange nzd, "AUD"
31
+ assert_equal Latinum::Resource.new("5", "AUD"), aud
32
+ end
33
+
34
+ def test_parsing
35
+ assert_equal Latinum::Resource.new("5", "USD"), @bank.parse("$5")
36
+ assert_equal Latinum::Resource.new("5", "NZD"), @bank.parse("$5 NZD")
37
+ assert_equal Latinum::Resource.new("5", "EUR"), @bank.parse("€5")
38
+
39
+ assert_equal Latinum::Resource.new("5", "NZD"), @bank.parse("5 NZD")
20
40
  end
21
41
  end
@@ -0,0 +1,27 @@
1
+
2
+ require 'helper'
3
+
4
+ require 'latinum'
5
+ require 'latinum/currencies/global'
6
+
7
+ require 'set'
8
+
9
+ class CollectionTest < Test::Unit::TestCase
10
+ def setup
11
+ @bank = Latinum::Bank.new
12
+ @bank.import(Latinum::Currencies::Global)
13
+ end
14
+
15
+ def test_collections
16
+ resource = Latinum::Resource.new("10", "NZD")
17
+
18
+ currencies = Set.new
19
+ collection = Latinum::Collection.new(currencies)
20
+
21
+ collection << resource
22
+ assert_equal resource, collection["NZD"]
23
+
24
+ collection << resource
25
+ assert_equal resource * 2, collection["NZD"]
26
+ end
27
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: latinum
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.2.0
4
+ version: 0.2.3
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2012-07-23 00:00:00.000000000 Z
12
+ date: 2012-07-27 00:00:00.000000000 Z
13
13
  dependencies: []
14
14
  description:
15
15
  email: samuel.williams@oriontransfer.co.nz
@@ -20,12 +20,14 @@ files:
20
20
  - lib/latinum/bank.rb
21
21
  - lib/latinum/collection.rb
22
22
  - lib/latinum/currencies/global.rb
23
+ - lib/latinum/extensions/bigdecimal-1.8.rb
23
24
  - lib/latinum/formatters.rb
24
25
  - lib/latinum/resource.rb
25
26
  - lib/latinum/version.rb
26
27
  - lib/latinum.rb
27
28
  - test/helper.rb
28
29
  - test/test_bank.rb
30
+ - test/test_collection.rb
29
31
  - README.md
30
32
  homepage: http://www.oriontransfer.co.nz/gems/latinum
31
33
  licenses: []