兑换宝石让你可以直接在你的Numbers上轻松访问货币功能。它的测试对象是:Ruby 2.0、1.9、Re 和 rubinius(1.9 和 2.0 模式)。Exchange将在未来的版本中利用2.1的功能,如细化功能,请务必查看此页面的更新!
你可以在Rails 2和3、Sinatra或任何你喜欢的框架中使用它,只是普通的ruby项目。
与MRI 2.1.0-p0一起使用时的注意事项 ↑ ↑
MRI 2.1.0-p0在BigDecimal中存在一个确认的错误,导致它在BigDecimal除法中当r值小于1时返回错误结果。
安装¶ ↑
捆绑器/Rails¶ ↑
把它添加到你的Gemfile中
gem "exchange", "~> 1.2.0"
手动¶ ↑
把它安装成一个 gem
gem install exchange
然后要求它
要求 "交换"。
生产就绪¶ ↑
Exchange已经可以生产了。它在 rightclearing.com 上使用,这是一个值得注意的音乐许可服务。如果你在生产中使用这个宝石,请留言,以便你的应用可以被列在这里。
特点¶ ↑
轻松转换¶ ↑
货币的转换不会再容易了
1.in(:eur).to(:USD)
或更好的历史日期
1.in(:eur).to(:usd, :at => Time.now - 84600)
转换API的回撤 ↑
不用担心某个API很快就不可用了--如果所选的API目前不可用,或者不提供试图转换的汇率,Exchange提供了回退到其他转换API的可能性。因此,有可能将不同的API与不完整的货币集结合起来,以获得一个更完整的货币集。
如果一个API没有提供汇率,那么回退对性能的影响是最小的,而对http连接错误的性能影响则会对性能产生较大影响。
如果Xavier Media API不可用,使用的默认回退机制调用ECB API。你可以使用API配置来设置你自己的回退链。
精确计算¶ ↑
你可能知道这个交易。浮点错误会让你赔钱。
(0.29 * 50).round #=> 14,这是不正确的。
鉴于
(BigDecimal("0.29") * 50).round #=> 15, 这是正确的。
Exchange在其所有的货币和转换操作中都使用了BigDecimal,所以你不可能成为浮点数不准确的受害者。它甚至还隐含地转换了一些基本的操作,比如(* / - +)来安全地计算你的数值。
(50.in(:usd) * 0.29).round 0 #=> "USD 15.00"
(0.29 * 50.in(:usd)).round 0 #=> 15
BigDecimal?对我来说听起来很慢¶ ↑
如果性能与转换相结合是你关心的问题,不用担心。在ruby 1.9.3中,对于货币实例化,你会得到大约以下结果(例如1.in(:eur))
1000次操作
普通浮点运算需要0.000196s
大十进制操作需要0.001239s
货币宝石操作需要0.05348s
兑换宝石操作需要0.035287s
你是对的,大十进制比浮动操作慢,但话说回来,兑换宝石胜过货币宝石。
一个用于类型化的混合器¶ ↑
你可能需要将一个对象的某个属性类型化为金钱。Exchange有一个类型化混合器,你可以将它与Rails、Ohm、Datamapper或普通的Ruby类一起使用,将一个属性类型化为金钱。像这样使用它。
class Article
#让类的方法可用
#
扩展 Exchange::Typecasting
# 为价格安装类型转换
#
money :price, :currency => :currency
# 假设你将货币设置在一个独特的地方
#
def currency
manager.currency
结束
结束
现在你可以这样做了。
article = Article.new
article.price #=> 将给你定义在管理器上的货币的钱
article.price = 3.45.in(:usd) #如果Manager.currency不是:usd,将隐含地转换价格。
你可以用proc或代表该方法的符号来输入货币选项。关于类型转换的深入信息,请访问这里的文档
每天只有一个请求,让你保持最新的状态¶ ↑
你每天只在互联网上敲打,以获得新的汇率(如果你渴望得到绝对最新的汇率,可以每小时更新一次)。
ISO 4217货币格式化¶ ↑
货币的一个问题是。你永远不知道它们应该是什么格式。有了Exchange,你可以直接使用货币to_s方法,它为你处理正确的格式。你可以有一个前面有货币代码的字符串,或者只有正确格式的金额。
通过to_s的正常格式化包括ISO4217兼容的货币代码
1.in(:usd).to_s #=> "USD 1.00"
指定符号格式将打印出带有符号的货币。如果没有符号与货币相关联,则使用的后备方案是正常格式的字符串,包括ISO4217兼容的货币代码
1.2.in(:eur).to_s(:symbol) #=> "€1.40"
指定金额格式将只打印出格式化的金额
1440.4.in(:usd).to_s(:quantity) #=> "1,440.40"
指定普通格式将打印出只有一个点分隔符的格式化金额
1440.4.in(:usd).to_s(:plain) #=> "1440.40"
正如上面所看到的,Exchange为分隔符处理了正确的格式
155_000_000.in(:usd).to_s #=> "USD 155,000,000.00"
使用三个伟大的API或你自己的API¶ ↑
已经包括了三个开放的API。
Xaviermedia
欧洲中央银行
公开汇率(请在页面底部寻找免费计划)
但如果你有另一个你喜欢使用的API,那就变得很简单,只需编写一个类和两个方法来使用它。自定义API扩展的例子
使用伟大的缓存或你自己的伟大缓存¶ ↑ ↑
使用三种可用的缓存解决方案中的一种。
通过Dalli gem的Memcached
通过redis gem的Redis
Rails缓存(然而,这个宝石并不依赖rails)。
但是,在这里也一样,如果你不喜欢这些,或者想使用你自己的缓存方案,就像编写一个Class和两个方法来使用它一样简单。自定义缓存扩展的例子
基本操作¶ ↑
转换¶ ↑
将一种货币转换为另一种货币就像1,2,3一样简单。不要害怕,即使它返回的是货币对象,所有的Fixed和Float操作都可以作为方法缺失路线应用到该值上
1.in(:usd).to(:eur) #=> #<Exchange::Money @value=0.93 @currency=:eur>
2.3.in(:dkk).to(:sek) #=> #<Exchange::Money @value=3.33 @currency=:sek>.
45.54.in(:nok).to(:sek) #=> #<Exchange::Money @value=3.33 @currency=:sek>
轻松地将一种货币按历史汇率转换成另一种货币
1.52.in(:usd).to :eur, :at => '2011-01-01' #=> #<Exchange::Money @value=1.23 @currency=:eur>
3.45.in(:eur).to :sek, :at => Time.gm(2011,3,3) #=> #<Exchange::Money @value=19.23 @currency=:sek>
345.in(:sek).to :nok, :at => Time.gm(2011,3,3) #=> #<Exchange::Money @value=348 @currency=:nok>
甚至可以通过添加时间来定义一个货币的实例为历史性的。
1.52.in(:usd, :at => '2011-01-01').to(:eur) #=> #<Exchange::Money @value=1.23 @currency=:eur>
3.45.in(:usd, :at => Time.gm(2011,3,3)).to(:sek) #=> #<Exchange::Money @value=19.23 @currency=:sek>
345.in(:usd, :at => Time.gm(2011,3,3)).to(:nok) #=> #<Exchange::Money @value=348 @currency=:nok>
一次做多个转换步骤(如果有什么用的话)
3.in(:chf).to(:eur, :at => '2011-02-04').to(:usd) #=> #<Exchange::Money @value=5.3 @currency=:eur>。
比较¶ ↑
比较货币,它们将隐含地进行转换
2.in(:eur) > 2.in(:usd) #=> true (2.in(:usd)被转换为eur并进行比较)
2.in(:nok) < 2.in(:sek) #=> false (2.in(:sek)被转换为nok并进行比较)
5.in(:eur) == 4.34.in(:chf) #=> true
50.in(:eur) == 4.34.in(:chf) #=> false
50.in(:eur).to(:sek) ==50.in(:eur) #=> true
50.in(:eur, :at => '2011-1-1') == 50.in(:sek) #=> false
一次性对多种货币进行排序
[5.in(:eur), 4.in(:usd), 4.in(:chf, :at => '2010-01-01')].排序 #=> [#<Exchange::Money @value=4 @currency=:usd>, #<Exchange::Money @value=4 @currency=:chf>, #<Exchange::Money @value=5 @currency=:eur>]
这是真的,因为它使用相同的历史转换率
3.in(:eur, :at => '201-01-01').to(:usd) == 3.in(:eur).to(:usd, :at => '201-01-01')
但这显然是错误的,因为第二个实例使用的是目前的汇率,与历史上的汇率不同(如果两个汇率匹配,这将再次为真)
3.in(:eur, :at => '2001-01-01').to(:usd) == 3.in(:eur).to(:usd)