shopify-money 0.10.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.document +5 -0
- data/.gitignore +51 -0
- data/.rspec +1 -0
- data/Gemfile +6 -0
- data/LICENSE.txt +20 -0
- data/README.md +156 -0
- data/Rakefile +42 -0
- data/bin/console +14 -0
- data/circle.yml +13 -0
- data/config/currency_historic.json +157 -0
- data/config/currency_iso.json +2642 -0
- data/config/currency_non_iso.json +82 -0
- data/dev.yml +9 -0
- data/lib/money.rb +10 -0
- data/lib/money/accounting_money_parser.rb +8 -0
- data/lib/money/core_extensions.rb +18 -0
- data/lib/money/currency.rb +59 -0
- data/lib/money/currency/loader.rb +26 -0
- data/lib/money/deprecations.rb +18 -0
- data/lib/money/helpers.rb +71 -0
- data/lib/money/money.rb +408 -0
- data/lib/money/money_parser.rb +152 -0
- data/lib/money/null_currency.rb +35 -0
- data/lib/money/version.rb +3 -0
- data/lib/money_accessor.rb +32 -0
- data/lib/money_column.rb +3 -0
- data/lib/money_column/active_record_hooks.rb +95 -0
- data/lib/money_column/active_record_type.rb +6 -0
- data/lib/money_column/railtie.rb +7 -0
- data/money.gemspec +27 -0
- data/spec/accounting_money_parser_spec.rb +204 -0
- data/spec/core_extensions_spec.rb +44 -0
- data/spec/currency/loader_spec.rb +21 -0
- data/spec/currency_spec.rb +113 -0
- data/spec/helpers_spec.rb +103 -0
- data/spec/money_accessor_spec.rb +86 -0
- data/spec/money_column_spec.rb +298 -0
- data/spec/money_parser_spec.rb +355 -0
- data/spec/money_spec.rb +853 -0
- data/spec/null_currency_spec.rb +46 -0
- data/spec/schema.rb +9 -0
- data/spec/spec_helper.rb +74 -0
- metadata +196 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: e9f1cbeeb932d4f9f9d1abb4ef49ae366e9f5467
|
4
|
+
data.tar.gz: a257d7dd55acb578b89690f153a8a613bc334089
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: ed81f64a2a63282fa961088381634c8d2d414ea30120f2e39049afb6cb6e5f85a36069d550f6ba956636481b9ccbde8eae8428347e5b105ecfd16b22146b2b5e
|
7
|
+
data.tar.gz: 7edd2b3d5dd0ec6d0f695a0959fd55f25e4c1bfefdd7c96171825b77085a353892d954d6edb00a49a7a224b57e019982f981554b3c8896b1ab02c443e4682115
|
data/.document
ADDED
data/.gitignore
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# rcov generated
|
2
|
+
coverage
|
3
|
+
|
4
|
+
# rdoc generated
|
5
|
+
rdoc
|
6
|
+
|
7
|
+
# yard generated
|
8
|
+
doc
|
9
|
+
.yardoc
|
10
|
+
|
11
|
+
# bundler
|
12
|
+
.bundle
|
13
|
+
|
14
|
+
# jeweler generated
|
15
|
+
pkg
|
16
|
+
|
17
|
+
# Have editor/IDE/OS specific files you need to ignore? Consider using a global gitignore:
|
18
|
+
#
|
19
|
+
# * Create a file at ~/.gitignore
|
20
|
+
# * Include files you want ignored
|
21
|
+
# * Run: git config --global core.excludesfile ~/.gitignore
|
22
|
+
#
|
23
|
+
# After doing this, these files will be ignored in all your git projects,
|
24
|
+
# saving you from having to 'pollute' every project you touch with them
|
25
|
+
#
|
26
|
+
# Not sure what to needs to be ignored for particular editors/OSes? Here's some ideas to get you started. (Remember, remove the leading # of the line)
|
27
|
+
#
|
28
|
+
# For MacOS:
|
29
|
+
#
|
30
|
+
#.DS_Store
|
31
|
+
|
32
|
+
# For TextMate
|
33
|
+
#*.tmproj
|
34
|
+
#tmtags
|
35
|
+
|
36
|
+
# For emacs:
|
37
|
+
#*~
|
38
|
+
#\#*
|
39
|
+
#.\#*
|
40
|
+
|
41
|
+
# For vim:
|
42
|
+
#*.swp
|
43
|
+
|
44
|
+
# For redcar:
|
45
|
+
#.redcar
|
46
|
+
|
47
|
+
# For rubinius:
|
48
|
+
#*.rbc
|
49
|
+
Gemfile.lock
|
50
|
+
|
51
|
+
.rspec_status
|
data/.rspec
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
--color
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2011 Shopify
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,156 @@
|
|
1
|
+
# money
|
2
|
+
|
3
|
+
[![Build Status](https://circleci.com/gh/Shopify/money.png?circle-token=88060f61185838446bb65723d96658bdd74ebb3c)](https://circleci.com/gh/Shopify/money) [![codecov](https://codecov.io/gh/Shopify/money/branch/master/graph/badge.svg)](https://codecov.io/gh/Shopify/money)
|
4
|
+
|
5
|
+
|
6
|
+
money_column expects a decimal 8,3 database field.
|
7
|
+
|
8
|
+
### Features
|
9
|
+
|
10
|
+
- Keeps value in decimal
|
11
|
+
- Provides a `Money` class which encapsulates all information about an certain
|
12
|
+
amount of money, such as its value and its currency.
|
13
|
+
- Provides a `Money::Currency` class which encapsulates all information about
|
14
|
+
a monetary unit.
|
15
|
+
- Does NOT provides APIs for exchanging money from one currency to another.
|
16
|
+
- wont lose pennies during division!
|
17
|
+
- Money::NullCurrency for no currency support
|
18
|
+
|
19
|
+
## Installation
|
20
|
+
|
21
|
+
gem 'shopify-money', require: 'money'
|
22
|
+
|
23
|
+
## Usage
|
24
|
+
|
25
|
+
``` ruby
|
26
|
+
require 'money'
|
27
|
+
|
28
|
+
# 10.00 USD
|
29
|
+
money = Money.new(10.00, "USD")
|
30
|
+
money.subunits #=> 1000
|
31
|
+
money.currency #=> Currency.new("USD")
|
32
|
+
|
33
|
+
# Comparisons
|
34
|
+
Money.new(1000, "USD") == Money.new(1000, "USD") #=> true
|
35
|
+
Money.new(1000, "USD") == Money.new(100, "USD") #=> false
|
36
|
+
Money.new(1000, "USD") == Money.new(1000, "EUR") #=> false
|
37
|
+
Money.new(1000, "USD") != Money.new(1000, "EUR") #=> true
|
38
|
+
|
39
|
+
# Arithmetic
|
40
|
+
Money.new(1000, "USD") + Money.new(500, "USD") == Money.new(1500, "USD")
|
41
|
+
Money.new(1000, "USD") - Money.new(200, "USD") == Money.new(800, "USD")
|
42
|
+
Money.new(1000, "USD") / 5 == Money.new(200, "USD")
|
43
|
+
Money.new(1000, "USD") * 5 == Money.new(5000, "USD")
|
44
|
+
|
45
|
+
# Unit to subunit conversions
|
46
|
+
Money.from_subunits(500, "USD") == Money.new(5, "USD") # 5 USD
|
47
|
+
Money.from_subunits(5, "JPY") == Money.new(5, "JPY") # 5 JPY
|
48
|
+
Money.from_subunits(5000, "TND") == Money.new(5, "TND") # 5 TND
|
49
|
+
```
|
50
|
+
|
51
|
+
## Currency
|
52
|
+
|
53
|
+
Currencies are consistently represented as instances of `Money::Currency`.
|
54
|
+
The most part of `Money` APIs allows you to supply either a `String` or a
|
55
|
+
`Money::Currency`.
|
56
|
+
|
57
|
+
``` ruby
|
58
|
+
Money.new(1000, "USD") == Money.new(1000, Money::Currency.new("USD"))
|
59
|
+
Money.new(1000, "EUR").currency == Money::Currency.new("EUR")
|
60
|
+
```
|
61
|
+
|
62
|
+
A `Money::Currency` instance holds all the information about the currency,
|
63
|
+
including the currency symbol, name and much more.
|
64
|
+
|
65
|
+
``` ruby
|
66
|
+
currency = Money.new(1000, "USD").currency
|
67
|
+
currency.iso_code #=> "USD"
|
68
|
+
currency.name #=> "United States Dollar"
|
69
|
+
currency.to_s #=> 'USD'
|
70
|
+
currency.symbol #=> '$'
|
71
|
+
currency.disambiguate_symbol #=> 'US$'
|
72
|
+
```
|
73
|
+
|
74
|
+
### Default Currency
|
75
|
+
|
76
|
+
By default `Money` defaults to Money::NullCurrency as its currency. This is a
|
77
|
+
global variable that can be changed using:
|
78
|
+
|
79
|
+
``` ruby
|
80
|
+
Money.default_currency = Money::Currency.new("USD")
|
81
|
+
```
|
82
|
+
|
83
|
+
In web apps you might want to set the default currency on a per request basis.
|
84
|
+
In Rails you can do this with an around action, for example:
|
85
|
+
|
86
|
+
```ruby
|
87
|
+
class ApplicationController < ActionController::Base
|
88
|
+
around_action :set_currency
|
89
|
+
|
90
|
+
private
|
91
|
+
|
92
|
+
def set_currency
|
93
|
+
Money.with_currency(current_shop.currency) { yield }
|
94
|
+
end
|
95
|
+
end
|
96
|
+
```
|
97
|
+
|
98
|
+
### Currency Minor Units
|
99
|
+
|
100
|
+
The exponent of a money value is the number of digits after the decimal
|
101
|
+
separator (which separates the major unit from the minor unit).
|
102
|
+
|
103
|
+
``` ruby
|
104
|
+
Money::Currency.new("USD").minor_units # => 2
|
105
|
+
Money::Currency.new("JPY").minor_units # => 0
|
106
|
+
Money::Currency.new("MGA").minor_units # => 1
|
107
|
+
```
|
108
|
+
|
109
|
+
## Money column
|
110
|
+
|
111
|
+
Since money internally uses BigDecimal it's logical to use a `decimal` column
|
112
|
+
(or `money` for PostgreSQL) for your database. The `money_column` method can
|
113
|
+
generate methods for use with ActiveRecord:
|
114
|
+
|
115
|
+
```ruby
|
116
|
+
create_table :orders do |t|
|
117
|
+
t.decimal :sub_total, precision: 20, scale: 3
|
118
|
+
t.decimal :tax, precision: 20, scale: 3
|
119
|
+
t.string :currency, limit: 3
|
120
|
+
end
|
121
|
+
|
122
|
+
class Order < ApplicationRecord
|
123
|
+
money_column :sub_total, :tax
|
124
|
+
end
|
125
|
+
```
|
126
|
+
|
127
|
+
### Options
|
128
|
+
|
129
|
+
| option | type | description |
|
130
|
+
| --- | --- | --- |
|
131
|
+
| currency_column | method | column from which to read/write the currency |
|
132
|
+
| currency | string | hardcoded currency value |
|
133
|
+
| currency_read_only | boolean | when true, `currency_column` won't write the currency back into the db. Must be set to true if `currency_column` is an attr_reader or delegate. Default: false |
|
134
|
+
| coerce_null | boolean | when true, a nil value will be returned as Money.zero. Default: false |
|
135
|
+
|
136
|
+
You can use multiple `money_column` calls to achieve the desired effects with
|
137
|
+
currency on the model or attribute level.
|
138
|
+
|
139
|
+
There are no validations generated. You can add these for the specified money
|
140
|
+
and currency attributes as you normally would for any other.
|
141
|
+
|
142
|
+
## Contributing to money
|
143
|
+
|
144
|
+
- Check out the latest master to make sure the feature hasn't been implemented or the bug hasn't been fixed yet
|
145
|
+
- Check out the issue tracker to make sure someone already hasn't requested it and/or contributed it
|
146
|
+
- Fork the project
|
147
|
+
- Start a feature/bugfix branch
|
148
|
+
- Commit and push until you are happy with your contribution
|
149
|
+
- Make sure to add tests for it. This is important so I don't break it in a future version unintentionally.
|
150
|
+
- Please try not to mess with the Rakefile, version, or history. If you want to have your own version, or is otherwise necessary, that is fine, but please isolate to its own commit so I can cherry-pick around it.
|
151
|
+
|
152
|
+
## Copyright
|
153
|
+
|
154
|
+
Copyright (c) 2011 Shopify. See LICENSE.txt for
|
155
|
+
further details.
|
156
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
|
3
|
+
begin
|
4
|
+
require 'bundler/gem_tasks'
|
5
|
+
rescue LoadError
|
6
|
+
nil
|
7
|
+
end
|
8
|
+
|
9
|
+
require 'rubygems'
|
10
|
+
require 'bundler'
|
11
|
+
require 'rdoc/task'
|
12
|
+
begin
|
13
|
+
Bundler.setup(:default, :development)
|
14
|
+
rescue Bundler::BundlerError => e
|
15
|
+
$stderr.puts e.message
|
16
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
17
|
+
exit e.status_code
|
18
|
+
end
|
19
|
+
require 'rake'
|
20
|
+
|
21
|
+
require 'rspec/core'
|
22
|
+
require 'rspec/core/rake_task'
|
23
|
+
RSpec::Core::RakeTask.new(:spec) do |spec|
|
24
|
+
spec.pattern = FileList['spec/**/*_spec.rb']
|
25
|
+
end
|
26
|
+
|
27
|
+
RSpec::Core::RakeTask.new(:rcov) do |spec|
|
28
|
+
spec.pattern = 'spec/**/*_spec.rb'
|
29
|
+
spec.rcov = true
|
30
|
+
end
|
31
|
+
|
32
|
+
task :default => :spec
|
33
|
+
|
34
|
+
require 'rake/task'
|
35
|
+
RDoc::Task.new do |rdoc|
|
36
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
37
|
+
|
38
|
+
rdoc.rdoc_dir = 'rdoc'
|
39
|
+
rdoc.title = "money #{version}"
|
40
|
+
rdoc.rdoc_files.include('README*')
|
41
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
42
|
+
end
|
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "money"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start(__FILE__)
|
data/circle.yml
ADDED
@@ -0,0 +1,157 @@
|
|
1
|
+
{
|
2
|
+
"cyp": {
|
3
|
+
"priority": 100,
|
4
|
+
"iso_code": "CYP",
|
5
|
+
"name": "Cypriot pound",
|
6
|
+
"symbol": "£",
|
7
|
+
"alternate_symbols": [],
|
8
|
+
"subunit": "Cent",
|
9
|
+
"subunit_to_unit": 100,
|
10
|
+
"symbol_first": true,
|
11
|
+
"html_entity": "£",
|
12
|
+
"decimal_mark": ".",
|
13
|
+
"thousands_separator": ",",
|
14
|
+
"iso_numeric": "196",
|
15
|
+
"smallest_denomination": 1
|
16
|
+
},
|
17
|
+
"eek": {
|
18
|
+
"priority": 100,
|
19
|
+
"iso_code": "EEK",
|
20
|
+
"name": "Estonian Kroon",
|
21
|
+
"symbol": "KR",
|
22
|
+
"alternate_symbols": [],
|
23
|
+
"subunit": "Sent",
|
24
|
+
"subunit_to_unit": 100,
|
25
|
+
"symbol_first": false,
|
26
|
+
"html_entity": "",
|
27
|
+
"decimal_mark": ".",
|
28
|
+
"thousands_separator": ",",
|
29
|
+
"iso_numeric": "233",
|
30
|
+
"smallest_denomination": 5
|
31
|
+
},
|
32
|
+
"ghc": {
|
33
|
+
"priority": 100,
|
34
|
+
"iso_code": "GHS",
|
35
|
+
"name": "Ghanaian Cedi",
|
36
|
+
"symbol": "₵",
|
37
|
+
"disambiguate_symbol": "GH₵",
|
38
|
+
"alternate_symbols": ["GH₵"],
|
39
|
+
"subunit": "Pesewa",
|
40
|
+
"subunit_to_unit": 100,
|
41
|
+
"symbol_first": true,
|
42
|
+
"html_entity": "₵",
|
43
|
+
"decimal_mark": ".",
|
44
|
+
"thousands_separator": ",",
|
45
|
+
"iso_numeric": "288",
|
46
|
+
"smallest_denomination": 1
|
47
|
+
},
|
48
|
+
"mtl": {
|
49
|
+
"priority": 100,
|
50
|
+
"iso_code": "MTL",
|
51
|
+
"name": "Maltese Lira",
|
52
|
+
"symbol": "₤",
|
53
|
+
"alternate_symbols": ["Lm"],
|
54
|
+
"subunit": "Cent",
|
55
|
+
"subunit_to_unit": 100,
|
56
|
+
"symbol_first": true,
|
57
|
+
"html_entity": "£",
|
58
|
+
"decimal_mark": ".",
|
59
|
+
"thousands_separator": ",",
|
60
|
+
"iso_numeric": "470",
|
61
|
+
"smallest_denomination": 1
|
62
|
+
},
|
63
|
+
"tmm": {
|
64
|
+
"priority": 100,
|
65
|
+
"iso_code": "TMM",
|
66
|
+
"name": "Turkmenistani Manat",
|
67
|
+
"symbol": "m",
|
68
|
+
"alternate_symbols": [],
|
69
|
+
"subunit": "Tennesi",
|
70
|
+
"subunit_to_unit": 100,
|
71
|
+
"symbol_first": false,
|
72
|
+
"html_entity": "",
|
73
|
+
"decimal_mark": ".",
|
74
|
+
"thousands_separator": ",",
|
75
|
+
"iso_numeric": "795",
|
76
|
+
"smallest_denomination": 1
|
77
|
+
},
|
78
|
+
"VEB": {
|
79
|
+
"priority": 100,
|
80
|
+
"iso_code": "VEB",
|
81
|
+
"name": "Venezuelan Bolívar",
|
82
|
+
"symbol": "Bs.",
|
83
|
+
"alternate_symbols": [],
|
84
|
+
"subunit": "Céntimo",
|
85
|
+
"subunit_to_unit": 100,
|
86
|
+
"symbol_first": true,
|
87
|
+
"html_entity": "",
|
88
|
+
"decimal_mark": ",",
|
89
|
+
"thousands_separator": ".",
|
90
|
+
"iso_numeric": "862",
|
91
|
+
"smallest_denomination": 1
|
92
|
+
},
|
93
|
+
"zwd": {
|
94
|
+
"priority": 100,
|
95
|
+
"iso_code": "ZWD",
|
96
|
+
"name": "Zimbabwean Dollar",
|
97
|
+
"symbol": "$",
|
98
|
+
"disambiguate_symbol": "ZWD",
|
99
|
+
"alternate_symbols": ["Z$"],
|
100
|
+
"subunit": "Cent",
|
101
|
+
"subunit_to_unit": 100,
|
102
|
+
"symbol_first": true,
|
103
|
+
"html_entity": "$",
|
104
|
+
"decimal_mark": ".",
|
105
|
+
"thousands_separator": ",",
|
106
|
+
"iso_numeric": "716",
|
107
|
+
"smallest_denomination": 100
|
108
|
+
},
|
109
|
+
"zwl": {
|
110
|
+
"priority": 100,
|
111
|
+
"iso_code": "ZWL",
|
112
|
+
"name": "Zimbabwean Dollar",
|
113
|
+
"symbol": "$",
|
114
|
+
"disambiguate_symbol": "ZWL",
|
115
|
+
"alternate_symbols": ["Z$"],
|
116
|
+
"subunit": "Cent",
|
117
|
+
"subunit_to_unit": 100,
|
118
|
+
"symbol_first": true,
|
119
|
+
"html_entity": "$",
|
120
|
+
"decimal_mark": ".",
|
121
|
+
"thousands_separator": ",",
|
122
|
+
"iso_numeric": "932",
|
123
|
+
"smallest_denomination": 100
|
124
|
+
},
|
125
|
+
"zwn": {
|
126
|
+
"priority": 100,
|
127
|
+
"iso_code": "ZWN",
|
128
|
+
"name": "Zimbabwean Dollar",
|
129
|
+
"symbol": "$",
|
130
|
+
"disambiguate_symbol": "ZWN",
|
131
|
+
"alternate_symbols": ["Z$"],
|
132
|
+
"subunit": "Cent",
|
133
|
+
"subunit_to_unit": 100,
|
134
|
+
"symbol_first": true,
|
135
|
+
"html_entity": "$",
|
136
|
+
"decimal_mark": ".",
|
137
|
+
"thousands_separator": ",",
|
138
|
+
"iso_numeric": "942",
|
139
|
+
"smallest_denomination": 100
|
140
|
+
},
|
141
|
+
"zwr": {
|
142
|
+
"priority": 100,
|
143
|
+
"iso_code": "ZWR",
|
144
|
+
"name": "Zimbabwean Dollar",
|
145
|
+
"symbol": "$",
|
146
|
+
"disambiguate_symbol": "ZWR",
|
147
|
+
"alternate_symbols": ["Z$"],
|
148
|
+
"subunit": "Cent",
|
149
|
+
"subunit_to_unit": 100,
|
150
|
+
"symbol_first": true,
|
151
|
+
"html_entity": "$",
|
152
|
+
"decimal_mark": ".",
|
153
|
+
"thousands_separator": ",",
|
154
|
+
"iso_numeric": "935",
|
155
|
+
"smallest_denomination": 100
|
156
|
+
}
|
157
|
+
}
|