Skip to content
This repository
Browse code

+ iso4271 standards and ECB API

  • Loading branch information...
commit 7a12ad020869f23c68a755ed31f5fda1266b0fcd 1 parent 7224178
Beat authored February 04, 2012
1  Gemfile
@@ -13,5 +13,6 @@ group :development do
13 13
   gem "yard", "~> 0.7.4"
14 14
   gem "bundler", "~> 1.0.0"
15 15
   gem "jeweler", "~> 1.8.3"
  16
+  gem "ruby-debug"
16 17
   gem "rspec"
17 18
 end
10  Gemfile.lock
... ...
@@ -1,6 +1,7 @@
1 1
 GEM
2 2
   remote: http://rubygems.org/
3 3
   specs:
  4
+    columnize (0.3.6)
4 5
     diff-lcs (1.1.3)
5 6
     git (1.2.5)
6 7
     jeweler (1.8.3)
@@ -9,9 +10,12 @@ GEM
9 10
       rake
10 11
       rdoc
11 12
     json (1.6.5)
  13
+    linecache (0.46)
  14
+      rbx-require-relative (> 0.0.4)
12 15
     memcached (1.3.6)
13 16
     nokogiri (1.5.0)
14 17
     rake (0.9.2.2)
  18
+    rbx-require-relative (0.0.5)
15 19
     rdoc (3.12)
16 20
       json (~> 1.4)
17 21
     redis (2.2.2)
@@ -23,6 +27,11 @@ GEM
23 27
     rspec-expectations (2.8.0)
24 28
       diff-lcs (~> 1.1.2)
25 29
     rspec-mocks (2.8.0)
  30
+    ruby-debug (0.10.4)
  31
+      columnize (>= 0.1)
  32
+      ruby-debug-base (~> 0.10.4.0)
  33
+    ruby-debug-base (0.10.4)
  34
+      linecache (>= 0.3)
26 35
     shoulda (2.11.3)
27 36
     yard (0.7.5)
28 37
 
@@ -37,5 +46,6 @@ DEPENDENCIES
37 46
   nokogiri (>= 1.4.0)
38 47
   redis (>= 2.2.0)
39 48
   rspec
  49
+  ruby-debug
40 50
   shoulda
41 51
   yard (~> 0.7.4)
631  iso4217.yml
... ...
@@ -0,0 +1,631 @@
  1
+--- 
  2
+NIO: 
  3
+  minor_unit: 2
  4
+  currency: Cordoba Oro
  5
+LAK: 
  6
+  minor_unit: 2
  7
+  currency: Kip
  8
+SAR: 
  9
+  format: "#,###.##"
  10
+  minor_unit: 2
  11
+  currency: Saudi Riyal
  12
+NOK: 
  13
+  format: "#.###,##"
  14
+  minor_unit: 2
  15
+  currency: Norwegian Krone
  16
+USD: 
  17
+  format: "#,###.##"
  18
+  minor_unit: 2
  19
+  currency: US Dollar
  20
+RUB: 
  21
+  format: "#.###,##"
  22
+  minor_unit: 2
  23
+  currency: Russian Ruble
  24
+XCD: 
  25
+  format: "#,###.##"
  26
+  minor_unit: 2
  27
+  currency: East Caribbean Dollar
  28
+XPT: 
  29
+  minor_unit: N.A.
  30
+  currency: Platinum
  31
+OMR: 
  32
+  format: "#,###.###"
  33
+  minor_unit: 3
  34
+  currency: Rial Omani
  35
+AMD: 
  36
+  format: "#,###.##"
  37
+  minor_unit: 2
  38
+  currency: Armenian Dram
  39
+CDF: 
  40
+  minor_unit: 2
  41
+  currency: Congolese Franc
  42
+KPW: 
  43
+  minor_unit: 2
  44
+  currency: North Korean Won
  45
+XSU: 
  46
+  minor_unit: N.A.
  47
+  currency: Sucre
  48
+CNY: 
  49
+  format: "#,###.##"
  50
+  minor_unit: 2
  51
+  currency: Yuan Renminbi
  52
+KES: 
  53
+  format: "#,###.##"
  54
+  minor_unit: 2
  55
+  currency: Kenyan Shilling
  56
+KHR: 
  57
+  minor_unit: 2
  58
+  currency: Riel
  59
+PLN: 
  60
+  format: "# ###,##"
  61
+  minor_unit: 2
  62
+  currency: Zloty
  63
+MVR: 
  64
+  minor_unit: 2
  65
+  currency: Rufiyaa
  66
+GTQ: 
  67
+  format: "#,###.##"
  68
+  minor_unit: 2
  69
+  currency: Quetzal
  70
+CLP: 
  71
+  format: "#.###"
  72
+  minor_unit: 0
  73
+  currency: Chilean Peso
  74
+INR: 
  75
+  format: "#,##,###.##"
  76
+  minor_unit: 2
  77
+  currency: Indian Rupee
  78
+BZD: 
  79
+  format: "#,###.##"
  80
+  minor_unit: 2
  81
+  currency: Belize Dollar
  82
+MYR: 
  83
+  format: "#,###.##"
  84
+  minor_unit: 2
  85
+  currency: Malaysian Ringgit
  86
+HKD: 
  87
+  format: "#,###.##"
  88
+  minor_unit: 2
  89
+  currency: Hong Kong Dollar
  90
+COP: 
  91
+  format: "#.###,##"
  92
+  minor_unit: 2
  93
+  currency: Colombian Peso
  94
+DKK: 
  95
+  format: "#.###,##"
  96
+  minor_unit: 2
  97
+  currency: Danish Krone
  98
+SEK: 
  99
+  format: "#.###,##"
  100
+  minor_unit: 2
  101
+  currency: Swedish Krona
  102
+BYR: 
  103
+  minor_unit: 0
  104
+  currency: Belarussian Ruble
  105
+LYD: 
  106
+  minor_unit: 3
  107
+  currency: Libyan Dinar
  108
+RON: 
  109
+  format: "#.###,##"
  110
+  minor_unit: 2
  111
+  currency: New Romanian Leu
  112
+DZD: 
  113
+  minor_unit: 2
  114
+  currency: Algerian Dinar
  115
+BIF: 
  116
+  minor_unit: 0
  117
+  currency: Burundi Franc
  118
+ARS: 
  119
+  format: "#.###,##"
  120
+  minor_unit: 2
  121
+  currency: Argentine Peso
  122
+GIP: 
  123
+  format: "#,###.##"
  124
+  minor_unit: 2
  125
+  currency: Gibraltar Pound
  126
+UYI: 
  127
+  minor_unit: 0
  128
+  currency: Uruguay Peso en Unidades Indexadas (URUIURUI)
  129
+XUA: 
  130
+  minor_unit: N.A.
  131
+  currency: ADB Unit of Account
  132
+BOB: 
  133
+  format: "#,###.##"
  134
+  minor_unit: 2
  135
+  currency: Boliviano
  136
+SSP: 
  137
+  minor_unit: 2
  138
+  currency: South Sudanese Pound
  139
+NGN: 
  140
+  minor_unit: 2
  141
+  currency: Naira
  142
+PGK: 
  143
+  minor_unit: 2
  144
+  currency: Kina
  145
+STD: 
  146
+  minor_unit: 2
  147
+  currency: Dobra
  148
+XOF: 
  149
+  minor_unit: 0
  150
+  currency: CFA Franc BCEAO
  151
+AED: 
  152
+  format: "#,###.##"
  153
+  minor_unit: 2
  154
+  currency: UAE Dirham
  155
+ERN: 
  156
+  minor_unit: 2
  157
+  currency: Nakfa
  158
+MWK: 
  159
+  minor_unit: 2
  160
+  currency: Kwacha
  161
+CUP: 
  162
+  format: "#,###.##"
  163
+  minor_unit: 2
  164
+  currency: Cuban Peso
  165
+USN: 
  166
+  minor_unit: 2
  167
+  currency: US Dollar (Next day)
  168
+GMD: 
  169
+  minor_unit: 2
  170
+  currency: Dalasi
  171
+CVE: 
  172
+  minor_unit: 2
  173
+  currency: Cape Verde Escudo
  174
+TZS: 
  175
+  format: "#,###.##"
  176
+  minor_unit: 2
  177
+  currency: Tanzanian Shilling
  178
+COU: 
  179
+  minor_unit: 2
  180
+  currency: Unidad de Valor Real
  181
+BTN: 
  182
+  minor_unit: 2
  183
+  currency: Ngultrum
  184
+ZWL: 
  185
+  minor_unit: 2
  186
+  currency: Zimbabwe Dollar
  187
+UGX: 
  188
+  minor_unit: 2
  189
+  currency: Uganda Shilling
  190
+SYP: 
  191
+  minor_unit: 2
  192
+  currency: Syrian Pound
  193
+MAD: 
  194
+  minor_unit: 2
  195
+  currency: Moroccan Dirham
  196
+MNT: 
  197
+  minor_unit: 2
  198
+  currency: Tugrik
  199
+LSL: 
  200
+  minor_unit: 2
  201
+  currency: Loti
  202
+XAF: 
  203
+  minor_unit: 0
  204
+  currency: CFA Franc BEAC
  205
+XTS: 
  206
+  minor_unit: N.A.
  207
+  currency: Codes specifically reserved for testing purposes
  208
+SHP: 
  209
+  minor_unit: 2
  210
+  currency: Saint Helena Pound
  211
+HTG: 
  212
+  minor_unit: 2
  213
+  currency: Gourde
  214
+RSD: 
  215
+  minor_unit: 2
  216
+  currency: Serbian Dinar
  217
+XAG: 
  218
+  minor_unit: N.A.
  219
+  currency: Silver
  220
+MGA: 
  221
+  minor_unit: 2
  222
+  currency: Malagasy Ariary
  223
+TOP: 
  224
+  format: "#,###.##"
  225
+  minor_unit: 2
  226
+  currency: !binary |
  227
+    UGHigJlhbmdh
  228
+
  229
+MZN: 
  230
+  minor_unit: 2
  231
+  currency: Mozambique Metical
  232
+LVL: 
  233
+  format: "#,###.##"
  234
+  minor_unit: 2
  235
+  currency: Latvian Lats
  236
+FKP: 
  237
+  minor_unit: 2
  238
+  currency: Falkland Islands Pound
  239
+USS: 
  240
+  minor_unit: 2
  241
+  currency: US Dollar (Same day)
  242
+BWP: 
  243
+  format: "#,###.##"
  244
+  minor_unit: 2
  245
+  currency: Pula
  246
+HNL: 
  247
+  format: "#,###.##"
  248
+  minor_unit: 2
  249
+  currency: Lempira
  250
+CHE: 
  251
+  minor_unit: 2
  252
+  currency: WIR Euro
  253
+EUR: 
  254
+  format: "#,###.##"
  255
+  minor_unit: 2
  256
+  currency: Euro
  257
+EGP: 
  258
+  format: "#,###.##"
  259
+  minor_unit: 2
  260
+  currency: Egyptian Pound
  261
+CHF: 
  262
+  format: "#'###.##"
  263
+  minor_unit: 2
  264
+  currency: Swiss Franc
  265
+ILS: 
  266
+  format: "#,###.##"
  267
+  minor_unit: 2
  268
+  currency: New Israeli Sheqel
  269
+PYG: 
  270
+  minor_unit: 0
  271
+  currency: Guarani
  272
+LBP: 
  273
+  format: "# ###"
  274
+  minor_unit: 2
  275
+  currency: Lebanese Pound
  276
+ANG: 
  277
+  format: "#.###,##"
  278
+  minor_unit: 2
  279
+  currency: Netherlands Antillean Guilder
  280
+KZT: 
  281
+  minor_unit: 2
  282
+  currency: Tenge
  283
+GYD: 
  284
+  minor_unit: 2
  285
+  currency: Guyana Dollar
  286
+WST: 
  287
+  minor_unit: 2
  288
+  currency: Tala
  289
+XFU: 
  290
+  minor_unit: N.A.
  291
+  currency: UIC-Franc
  292
+NPR: 
  293
+  format: "#,###.##"
  294
+  minor_unit: 2
  295
+  currency: Nepalese Rupee
  296
+KMF: 
  297
+  minor_unit: 0
  298
+  currency: Comoro Franc
  299
+THB: 
  300
+  format: "#,###.##"
  301
+  minor_unit: 2
  302
+  currency: Baht
  303
+IRR: 
  304
+  format: "#,###.##"
  305
+  minor_unit: 2
  306
+  currency: Iranian Rial
  307
+SRD: 
  308
+  minor_unit: 2
  309
+  currency: Surinam Dollar
  310
+JPY: 
  311
+  format: "#,###"
  312
+  minor_unit: 0
  313
+  currency: Yen
  314
+XBA: 
  315
+  minor_unit: N.A.
  316
+  currency: Bond Markets Unit European Composite Unit (EURCO)
  317
+BRL: 
  318
+  format: "#.###,##"
  319
+  minor_unit: 2
  320
+  currency: Brazilian Real
  321
+XPD: 
  322
+  minor_unit: N.A.
  323
+  currency: Palladium
  324
+UYU: 
  325
+  format: "#.###,##"
  326
+  minor_unit: 2
  327
+  currency: Peso Uruguayo
  328
+MOP: 
  329
+  minor_unit: 2
  330
+  currency: Pataca
  331
+BMD: 
  332
+  format: "#,###.##"
  333
+  minor_unit: 2
  334
+  currency: Bermudian Dollar
  335
+XBB: 
  336
+  minor_unit: N.A.
  337
+  currency: 0
  338
+SZL: 
  339
+  format: "#, ###.##"
  340
+  minor_unit: 2
  341
+  currency: Lilangeni
  342
+ETB: 
  343
+  minor_unit: 2
  344
+  currency: Ethiopian Birr
  345
+JOD: 
  346
+  format: "#,###.###"
  347
+  minor_unit: 3
  348
+  currency: Jordanian Dinar
  349
+XBC: 
  350
+  minor_unit: N.A.
  351
+  currency: 0
  352
+IDR: 
  353
+  format: "#.###,##"
  354
+  minor_unit: 2
  355
+  currency: Rupiah
  356
+MDL: 
  357
+  minor_unit: 2
  358
+  currency: Moldovan Leu
  359
+XPF: 
  360
+  minor_unit: 0
  361
+  currency: CFP Franc
  362
+MRO: 
  363
+  minor_unit: 2
  364
+  currency: Ouguiya
  365
+YER: 
  366
+  minor_unit: 2
  367
+  currency: Yemeni Rial
  368
+XBD: 
  369
+  minor_unit: N.A.
  370
+  currency: 0
  371
+BAM: 
  372
+  format: "#,###.##"
  373
+  minor_unit: 2
  374
+  currency: Convertible Mark
  375
+AWG: 
  376
+  format: "#,###.##"
  377
+  minor_unit: 2
  378
+  currency: Aruban Florin
  379
+NZD: 
  380
+  format: "#,###.##"
  381
+  minor_unit: 2
  382
+  currency: New Zealand Dollar
  383
+PEN: 
  384
+  format: "#,###.##"
  385
+  minor_unit: 2
  386
+  currency: Nuevo Sol
  387
+AOA: 
  388
+  minor_unit: 2
  389
+  currency: Kwanza
  390
+KYD: 
  391
+  format: "#,###.##"
  392
+  minor_unit: 2
  393
+  currency: Cayman Islands Dollar
  394
+SLL: 
  395
+  minor_unit: 2
  396
+  currency: Leone
  397
+TRY: 
  398
+  format: "#,###.##"
  399
+  minor_unit: 2
  400
+  currency: Turkish Lira
  401
+VEF: 
  402
+  format: "#.###,##"
  403
+  minor_unit: 2
  404
+  currency: Bolivar Fuerte
  405
+ISK: 
  406
+  format: "#.###"
  407
+  minor_unit: 0
  408
+  currency: Iceland Krona
  409
+GNF: 
  410
+  minor_unit: 0
  411
+  currency: Guinea Franc
  412
+BSD: 
  413
+  format: "#,###.##"
  414
+  minor_unit: 2
  415
+  currency: Bahamian Dollar
  416
+DJF: 
  417
+  minor_unit: 0
  418
+  currency: Djibouti Franc
  419
+HUF: 
  420
+  format: "#.###"
  421
+  minor_unit: 2
  422
+  currency: Forint
  423
+LTL: 
  424
+  format: "# ###,##"
  425
+  minor_unit: 2
  426
+  currency: Lithuanian Litas
  427
+MXN: 
  428
+  format: "#,###.##"
  429
+  minor_unit: 2
  430
+  currency: Mexican Peso
  431
+SCR: 
  432
+  minor_unit: 2
  433
+  currency: Seychelles Rupee
  434
+SGD: 
  435
+  format: "#,###.##"
  436
+  minor_unit: 2
  437
+  currency: Singapore Dollar
  438
+LKR: 
  439
+  minor_unit: 2
  440
+  currency: Sri Lanka Rupee
  441
+TJS: 
  442
+  minor_unit: 2
  443
+  currency: Somoni
  444
+TND: 
  445
+  minor_unit: 3
  446
+  currency: Tunisian Dinar
  447
+DOP: 
  448
+  format: "#,###.##"
  449
+  minor_unit: 2
  450
+  currency: Dominican Peso
  451
+FJD: 
  452
+  minor_unit: 2
  453
+  currency: Fiji Dollar
  454
+GEL: 
  455
+  minor_unit: 2
  456
+  currency: Lari
  457
+SDG: 
  458
+  minor_unit: 2
  459
+  currency: Sudanese Pound
  460
+VUV: 
  461
+  format: "#,###"
  462
+  minor_unit: 0
  463
+  currency: Vatu
  464
+XDR: 
  465
+  minor_unit: N.A.
  466
+  currency: SDR (Special Drawing Right)
  467
+BBD: 
  468
+  minor_unit: 2
  469
+  currency: Barbados Dollar
  470
+LRD: 
  471
+  minor_unit: 2
  472
+  currency: Liberian Dollar
  473
+KRW: 
  474
+  format: "#,###"
  475
+  minor_unit: 0
  476
+  currency: Won
  477
+MMK: 
  478
+  minor_unit: 2
  479
+  currency: Kyat
  480
+MUR: 
  481
+  format: "#,###"
  482
+  minor_unit: 2
  483
+  currency: Mauritius Rupee
  484
+PHP: 
  485
+  format: "#,###.##"
  486
+  minor_unit: 2
  487
+  currency: Philippine Peso
  488
+ZAR: 
  489
+  format: "# ###.##"
  490
+  minor_unit: 2
  491
+  currency: Rand
  492
+KGS: 
  493
+  minor_unit: 2
  494
+  currency: Som
  495
+GBP: 
  496
+  format: "#,###.##"
  497
+  minor_unit: 2
  498
+  currency: Pound Sterling
  499
+BGN: 
  500
+  minor_unit: 2
  501
+  currency: Bulgarian Lev
  502
+IQD: 
  503
+  minor_unit: 3
  504
+  currency: Iraqi Dinar
  505
+TMT: 
  506
+  minor_unit: 2
  507
+  currency: Turkmenistan New Manat
  508
+UAH: 
  509
+  format: "# ###,##"
  510
+  minor_unit: 2
  511
+  currency: Hryvnia
  512
+VND: 
  513
+  format: "#.###"
  514
+  minor_unit: 0
  515
+  currency: Dong
  516
+ZMK: 
  517
+  minor_unit: 2
  518
+  currency: Zambian Kwacha
  519
+XAU: 
  520
+  minor_unit: N.A.
  521
+  currency: Gold
  522
+BOV: 
  523
+  minor_unit: 2
  524
+  currency: Mvdol
  525
+HRK: 
  526
+  format: "#.###,##"
  527
+  minor_unit: 2
  528
+  currency: Croatian Kuna
  529
+TTD: 
  530
+  minor_unit: 2
  531
+  currency: Trinidad and Tobago Dollar
  532
+BHD: 
  533
+  format: "#,###.###"
  534
+  minor_unit: 3
  535
+  currency: Bahraini Dinar
  536
+CLF: 
  537
+  minor_unit: 0
  538
+  currency: Unidades de fomento
  539
+RWF: 
  540
+  minor_unit: 0
  541
+  currency: Rwanda Franc
  542
+MKD: 
  543
+  format: "#,###.##"
  544
+  minor_unit: 2
  545
+  currency: Denar
  546
+AUD: 
  547
+  format: "# ###.##"
  548
+  minor_unit: 2
  549
+  currency: Australian Dollar
  550
+CRC: 
  551
+  format: "#.###,##"
  552
+  minor_unit: 2
  553
+  currency: Costa Rican Colon
  554
+PKR: 
  555
+  format: "#,###.##"
  556
+  minor_unit: 2
  557
+  currency: Pakistan Rupee
  558
+TWD: 
  559
+  minor_unit: 2
  560
+  currency: New Taiwan Dollar
  561
+UZS: 
  562
+  minor_unit: 2
  563
+  currency: Uzbekistan Sum
  564
+CZK: 
  565
+  format: "#.###,##"
  566
+  minor_unit: 2
  567
+  currency: Czech Koruna
  568
+AZN: 
  569
+  minor_unit: 2
  570
+  currency: Azerbaijanian Manat
  571
+BDT: 
  572
+  format: "#,###.##"
  573
+  minor_unit: 2
  574
+  currency: Taka
  575
+NAD: 
  576
+  minor_unit: 2
  577
+  currency: Namibia Dollar
  578
+AFN: 
  579
+  minor_unit: 2
  580
+  currency: Afghani
  581
+MXV: 
  582
+  minor_unit: 2
  583
+  currency: Mexican Unidad de Inversion (UDI)
  584
+CUC: 
  585
+  format: "#,###.##"
  586
+  minor_unit: 2
  587
+  currency: Peso Convertible
  588
+PAB: 
  589
+  minor_unit: 2
  590
+  currency: Balboa
  591
+QAR: 
  592
+  minor_unit: 2
  593
+  currency: Qatari Rial
  594
+SOS: 
  595
+  minor_unit: 2
  596
+  currency: Somali Shilling
  597
+CHW: 
  598
+  minor_unit: 2
  599
+  currency: WIR Franc
  600
+XXX: 
  601
+  minor_unit: N.A.
  602
+  currency: The codes assigned for transactions where no currency is involved
  603
+CAD: 
  604
+  format: "#,###.##"
  605
+  minor_unit: 2
  606
+  currency: Canadian Dollar
  607
+JMD: 
  608
+  format: "#,###.##"
  609
+  minor_unit: 2
  610
+  currency: Jamaican Dollar
  611
+BND: 
  612
+  format: "#,###.##"
  613
+  minor_unit: 2
  614
+  currency: Brunei Dollar
  615
+ALL: 
  616
+  minor_unit: 2
  617
+  currency: Lek
  618
+SVC: 
  619
+  format: "#,###.##"
  620
+  minor_unit: 2
  621
+  currency: El Salvador Colon
  622
+SBD: 
  623
+  minor_unit: 2
  624
+  currency: Solomon Islands Dollar
  625
+GHS: 
  626
+  minor_unit: 2
  627
+  currency: Ghana Cedi
  628
+KWD: 
  629
+  format: "#,###.###"
  630
+  minor_unit: 3
  631
+  currency: Kuwaiti Dinar
5  lib/core_extensions/conversability.rb
@@ -28,5 +28,6 @@ def method_missing method, *args, &block
28 28
   end
29 29
 end
30 30
 
31  
-Fixnum.send :include, Exchange::Conversability
32  
-Float.send  :include, Exchange::Conversability
  31
+Fixnum.send     :include, Exchange::Conversability
  32
+Float.send      :include, Exchange::Conversability
  33
+BigDecimal.send :include, Exchange::Conversability
2  lib/exchange.rb
... ...
@@ -1,3 +1,4 @@
  1
+require 'bigdecimal'
1 2
 require 'open-uri'
2 3
 require 'bundler'
3 4
 require 'json'
@@ -5,6 +6,7 @@
5 6
 require 'redis'
6 7
 require 'memcached'
7 8
 require 'exchange/configuration'
  9
+require 'exchange/iso_4217'
8 10
 require 'exchange/currency'
9 11
 require 'exchange/external_api'
10 12
 require 'exchange/cache'
5  lib/exchange/configuration.rb
@@ -35,12 +35,11 @@ class << self
35 35
       # @example Set configuration values directly to the class
36 36
       #   Exchange::Configuration.cache = :redis
37 37
       #   Exchange::Configuration.api   = :xavier_media
  38
+      
38 39
       def define &blk
39 40
         self.instance_eval(&blk)
40 41
       end
41  
-      
42  
-      #TODO Precision ?
43  
-      
  42
+            
44 43
       [:api, :retries, :cache, :cache_host, :cache_port, :update, :allow_mixed_operations].each do |m|
45 44
         define_method m do
46 45
           @@config[m]
100  lib/exchange/currency.rb
@@ -43,7 +43,7 @@ class Currency
43 43
     #     #=> #<Exchange::Currency @number=37.0 @currency=:usd @time=#<Time> @from=#<Exchange::Currency @number=40.0 @currency=:usd>>
44 44
     
45 45
     def initialize value, currency, opts={}
46  
-      @value            = value.to_f
  46
+      @value            = Exchange::ISO4217.instantiate(value, currency)
47 47
       @currency         = currency
48 48
       @time             = assure_time(opts[:at], :default => :now)
49 49
       @from             = opts[:from] if opts[:from]
@@ -86,8 +86,8 @@ class << self
86 86
         # @macro [attach] install_operations
87 87
          
88 88
         def install_operation op
89  
-          define_method op do
90  
-            @value = self.value.send(op)
  89
+          define_method op do |*precision|
  90
+            @value = ISO4217.send(op, self.value, self.currency, precision.first)
91 91
             self
92 92
           end
93 93
         end
@@ -108,29 +108,50 @@ def #{op}(other)
108 108
       
109 109
     end
110 110
     
111  
-    # Round the currency (Equivalent to normal round)
  111
+    # Round the currency. Since this is a currency, it will round to the standard decimal value.
  112
+    # If you want to round it to another precision, you have to specifically ask for it.
112 113
     # @return [Exchange::Currency] The currency you started with with a rounded value
113  
-    # @example
114  
-    #   Exchange::Currency.new(40.5, :usd).round
115  
-    #     #=> #<Exchange::Currency @number=41 @currency=:usd>
  114
+    # @param [Integer] precision The precision you want the rounding to have. Defaults to the ISO 4217 standard value for the currency
  115
+    # @since 0.1
  116
+    # @version 0.3
  117
+    # @example Round your currency to the iso standard number of decimals
  118
+    #   Exchange::Currency.new(40.545, :usd).round
  119
+    #     #=> #<Exchange::Currency @value=40.55 @currency=:usd>
  120
+    # @example Round your currency to another number of decimals
  121
+    #   Exchange::Currency.new(40.545, :usd).round(0)
  122
+    #     #=> #<Exchange::Currency @value=41 @currency=:usd>
116 123
     
117 124
     install_operation :round
118 125
     
119 126
     
120  
-    # Ceil the currency (Equivalent to normal ceil)
  127
+    # Ceil the currency. Since this is a currency, it will ceil to the standard decimal value.
  128
+    # If you want to ceil it to another precision, you have to specifically ask for it.
121 129
     # @return [Exchange::Currency] The currency you started with with a ceiled value
122  
-    # @example
123  
-    #   Exchange::Currency.new(40.4, :usd).ceil
124  
-    #     #=> #<Exchange::Currency @number=41 @currency=:usd>
  130
+    # @param [Integer] precision The precision you want the ceiling to have. Defaults to the ISO 4217 standard value for the currency
  131
+    # @since 0.1
  132
+    # @version 0.3
  133
+    # @example Ceil your currency to the iso standard number of decimals
  134
+    #   Exchange::Currency.new(40.544, :usd).ceil
  135
+    #     #=> #<Exchange::Currency @value=40.55 @currency=:usd>
  136
+    # @example Ceil your currency to another number of decimals
  137
+    #   Exchange::Currency.new(40.445, :usd).ceil(0)
  138
+    #     #=> #<Exchange::Currency @value=41 @currency=:usd>
125 139
     
126 140
     install_operation :ceil
127 141
     
128 142
     
129  
-    # Floor the currency (Equivalent to normal floor)
  143
+    # Floor the currency. Since this is a currency, it will ceil to the standard decimal value.
  144
+    # If you want to ceil it to another precision, you have to specifically ask for it.
130 145
     # @return [Exchange::Currency] The currency you started with with a floored value
131  
-    # @example
132  
-    #   Exchange::Currency.new(40.7, :usd).floor
133  
-    #     #=> #<Exchange::Currency @number=40 @currency=:usd>
  146
+    # @param [Integer] precision The precision you want the flooring to have. Defaults to the ISO 4217 standard value for the currency
  147
+    # @since 0.1
  148
+    # @version 0.3
  149
+    # @example Floor your currency to the iso standard number of decimals
  150
+    #   Exchange::Currency.new(40.545, :usd).floor
  151
+    #     #=> #<Exchange::Currency @value=40.54 @currency=:usd>
  152
+    # @example Floor your currency to another number of decimals
  153
+    #   Exchange::Currency.new(40.545, :usd).floor(0)
  154
+    #     #=> #<Exchange::Currency @value=40 @currency=:usd>
134 155
     
135 156
     install_operation :floor
136 157
     
@@ -191,6 +212,17 @@ def #{op}(other)
191 212
     
192 213
     base_operation '/'
193 214
     
  215
+    # Compare a currency with another currency or another value. If the other is not an instance of Exchange::Currency, the value 
  216
+    # of the currency is compared
  217
+    # @param [Whatever you want to throw at it] other The counterpart to compare
  218
+    # @return [Boolean] true if the other is equal, false if not
  219
+    # @example Compare two currencies
  220
+    #   Exchange::Currency.new(40, :usd) == Exchange::Currency.new(34, :usd) #=> true
  221
+    # @example Compare two different currencies, the other will get converted for comparison
  222
+    #   Exchange::Currency.new(40, :usd) == Exchange::Currency.new(34, :eur) #=> true, will implicitly convert eur to usd at the actual rate
  223
+    # @example Compare a currency with a number, the value of the currency will get compared
  224
+    #   Exchange::Currency.new(35, :usd) == 35 #=> true
  225
+    
194 226
     def == other
195 227
       if other.is_a?(Exchange::Currency) && other.currency == self.currency
196 228
         other.value == self.value
@@ -201,8 +233,21 @@ def == other
201 233
       end
202 234
     end
203 235
     
  236
+    # Sortcompare a currency with another currency. If the other is not an instance of Exchange::Currency, the value 
  237
+    # of the currency is compared. Different currencies will be converted to the comparing instances currency
  238
+    # @param [Whatever you want to throw at it] other The counterpart to compare
  239
+    # @return [Fixed] a number which can be used for sorting
  240
+    # @since 0.3
  241
+    # @version 0.3
  242
+    # @example Compare two currencies in terms of value
  243
+    #   Exchange::Currency.new(40, :usd) <=> Exchange::Currency.new(28, :usd) #=> -1
  244
+    # @example Compare two different currencies, the other will get converted for comparison
  245
+    #   Exchange::Currency.new(40, :usd) <=> Exchange::Currency.new(28, :eur) #=> -1
  246
+    # @example Sort multiple currencies in an array
  247
+    #   [1.usd, 1.eur, 1.chf].sort.map(&:currency) #=> [:usd, :chf, :eur]
  248
+    
204 249
     def <=> other
205  
-      # TODO which historic converion should be used when two are present?
  250
+      # TODO which historic conversion should be used when two are present?
206 251
       if other.is_a?(Exchange::Currency) && ((other.currency == self.currency && self.value < other.value) || (other.currency != self.currency && self.value < other.convert_to(self.currency, :at => other.time).value))
207 252
         -1
208 253
       elsif other.is_a?(Exchange::Currency) && ((other.currency == self.currency && self.value > other.value) || (other.currency != self.currency && self.value > other.convert_to(self.currency, :at => other.time).value))
@@ -215,10 +260,25 @@ def <=> other
215 260
         
216 261
     end
217 262
     
218  
-    # TODO Make this easy or hard?
219  
-    # could have ISO Mapping, Symbol mapping, even translations
220  
-    # def to_s
221  
-    # end
  263
+    # Converts the currency to a string in ISO 4217 standardized format, either with or without the currency. This leaves you
  264
+    # with no worries how to display the currency.
  265
+    # @since 0.3
  266
+    # @version 0.3
  267
+    # @param [Symbol] format :currency (default) if you want a string with currency, :amount if you want just the amount.
  268
+    # @return [String] The formatted string
  269
+    # @example Convert a currency to a string
  270
+    #   Exchange::Currency.new(49.567, :usd).to_s #=> "USD 49.57"
  271
+    # @example Convert a currency without minor to a string
  272
+    #   Exchange::Currency.new(45, :jpy).to_s #=> "JPY 45"
  273
+    # @example Convert a currency with a three decimal minor to a string
  274
+    #   Exchange::Currency.new(34.34, :omr).to_s #=> "OMR 34.340"
  275
+    # @example Convert a currency to a string without the currency
  276
+    #   Exchange::ISO4217.stringif(34.34, :omr).to_s(:iso) #=> "34.340"
  277
+    
  278
+    def to_s format=:currency
  279
+      [format == :currency && Exchange::ISO4217.stringify(self.value, self.currency),
  280
+       format == :amount && Exchange::ISO4217.stringify(self.value, self.currency, :amount_only => true)].detect{|l| l.is_a?(String) }
  281
+    end
222 282
     
223 283
     protected
224 284
     
1  lib/exchange/external_api.rb
@@ -2,3 +2,4 @@
2 2
 require 'exchange/external_api/call'
3 3
 require 'exchange/external_api/currency_bot'
4 4
 require 'exchange/external_api/xavier_media'
  5
+require 'exchange/external_api/ecb'
9  lib/exchange/external_api/call.rb
@@ -12,6 +12,7 @@ class Call
12 12
       # @param [String] url The url of the API to call
13 13
       # @param [Hash] options The options of the API call
14 14
       # @option options [Time] :at The time of the historical exchange rate file to get
  15
+      # @option options [Class] :keyclass The class to generate the key for
15 16
       # @option options [Integer] :retries The number of retries if the API Call should fail with a HTTP Error
16 17
       # @option options [Array] :retry_with an Array of urls to retry the call with (if the API does not have a file for the specified date). These values will be shifted until a call succeeds or the number of maximum retries is reached.
17 18
       # @option options [Symbol] :format The format to return / yield the API call result in, defaults to :json
@@ -30,12 +31,12 @@ class Call
30 31
       #   # Do something with that result
31 32
       
32 33
       def initialize url, options={}, &block
33  
-        if Exchange::Configuration.cache
34  
-          result = Exchange::Configuration.cache_class.cached(Exchange::Configuration.api_class, :at => options[:at]) do
35  
-            load_url(url, options[:retries] || 5, options[:retry_with])
  34
+        if Exchange::Configuration.cache && options[:cache].nil?
  35
+          result = Exchange::Configuration.cache_class.cached(options[:keyclass] || Exchange::Configuration.api_class, :at => options[:at]) do
  36
+            load_url(url, options[:retries] || Exchange::Configuration.retries, options[:retry_with])
36 37
           end
37 38
         else
38  
-          result = load_url(url, options[:retries] || 5, options[:retry_with])
  39
+          result = load_url(url, options[:retries] || Exchange::Configuration.retries, options[:retry_with])
39 40
         end
40 41
         
41 42
         parsed = options[:format] == :xml ? Nokogiri.parse(result) : JSON.load(result)
2  lib/exchange/external_api/currency_bot.rb
@@ -24,7 +24,7 @@ def update(opts={})
24 24
         
25 25
         Call.new(api_url(time), :at => time) do |result|
26 26
           @base                 = result['base']
27  
-          @rates                = result['rates']
  27
+          @rates                = Hash[*result['rates'].keys.zip(result['rates'].values.map{|v| BigDecimal.new(v.to_s) }).flatten]
28 28
           @timestamp            = result['timestamp'].to_i
29 29
         end
30 30
       end
74  lib/exchange/external_api/ecb.rb
... ...
@@ -0,0 +1,74 @@
  1
+module Exchange
  2
+  module ExternalAPI
  3
+    
  4
+    # The ECB class, handling communication with the European Central Bank XML File API
  5
+    # You can find further information on the European Central Bank XML API API here: http://www.ecb.int/stats/exchange/eurofxref/html/index.en.html
  6
+    # @author Beat Richartz
  7
+    # @version 0.3
  8
+    # @since 0.3
  9
+    
  10
+    class ECB < Base
  11
+      # The base of the ECB API URL
  12
+      API_URL              = "http://www.ecb.europa.eu/stats/eurofxref"
  13
+      # The currencies the ECB API URL can handle
  14
+      CURRENCIES           = %W(usd jpy bgn czk dkk gbp huf ltl lvl pln ron sek chf nok hrk rub try aud brl cad cny hkd idr ils inr krw mxn myr nzd php sgd thb zar)
  15
+      
  16
+      attr_accessor :callresult
  17
+      
  18
+      # Updates the rates by getting the information from ECB API for today or a defined historical date
  19
+      # The call gets cached for a maximum of 24 hours. Getting history from ECB is a bit special, since they do not seem to have
  20
+      # any smaller portion history than an epic 4MB XML history file and a 90 day recent history file. We get each of that once and cache it in smaller portions.
  21
+      # @param [Hash] opts Options to define for the API Call
  22
+      # @option opts [Time, String] :at a historical date to get the exchange rates for
  23
+      # @example Update the currency bot API to use the file of March 2, 2010
  24
+      #   Exchange::ExternalAPI::XavierMedia.new.update(:at => Time.gm(3,2,2010))
  25
+      
  26
+      def update(opts={})
  27
+        time          = assure_time(opts[:at], :default => :now)
  28
+        api_url       = api_url(time)
  29
+        times         = Exchange::Configuration.retries.times.map{ |i| time - 86400 * (i+1) }
  30
+        api_call      = Proc.new { |inst|
  31
+          Call.new(api_url, :format => :xml, :at => time, :cache => false) do |result|
  32
+            t = time
  33
+            while (r = result.css("Cube[time=\"#{t.strftime("%Y-%m-%d")}\"]")).empty? && !times.empty?
  34
+              t = times.shift
  35
+            end
  36
+            inst.callresult = r.to_s
  37
+          end
  38
+        }
  39
+        
  40
+        if Exchange::Configuration.cache        
  41
+          Exchange::Configuration.cache_class.cached(self.class, :at => time) do
  42
+            api_call.call(self)
  43
+          end
  44
+        else
  45
+          Kernel.warn "WARNING: Using the ECB API without caching can be very, very slow."
  46
+          api_call.call(self)
  47
+        end
  48
+        
  49
+        parsed = Nokogiri.parse(callresult)
  50
+        
  51
+        @base                 = 'EUR' # We just have to assume, since it's the ECB
  52
+        @rates                = Hash[*(['EUR', BigDecimal.new("1")] + parsed.children.children.map {|c| c.attributes.values.map{|v| v.value.match(/\d/) ? BigDecimal.new(v.value) : v.value }.reverse unless c.attributes.values.empty? }.compact.flatten)]
  53
+        @timestamp            = time.to_i
  54
+      end
  55
+      
  56
+      private
  57
+      
  58
+        # A helper function which build a valid api url for the specified time
  59
+        # If the date is today, get the small daily file. If it is less than 90 days ago, get the 90 days file. 
  60
+        # If it is more than 90 days ago, get the big file
  61
+        # @param [Time] time The exchange rate date for which the URL should be built
  62
+        # @return [String] An Xaviermedia API URL for the specified time
  63
+      
  64
+        def api_url(time)
  65
+          border = Time.now - 90 * 86400
  66
+          [
  67
+            API_URL, 
  68
+            border <= time ? 'eurofxref-hist-90d.xml' : 'eurofxref-hist.xml'
  69
+          ].join('/')
  70
+        end
  71
+        
  72
+    end
  73
+  end
  74
+end
6  lib/exchange/external_api/xavier_media.rb
@@ -15,6 +15,7 @@ class XavierMedia < Base
15 15
       
16 16
       # Updates the rates by getting the information from Xaviermedia API for today or a defined historical date
17 17
       # The call gets cached for a maximum of 24 hours.
  18
+      # @version 0.3
18 19
       # @param [Hash] opts Options to define for the API Call
19 20
       # @option opts [Time, String] :at a historical date to get the exchange rates for
20 21
       # @example Update the currency bot API to use the file of March 2, 2010
@@ -23,12 +24,11 @@ class XavierMedia < Base
23 24
       def update(opts={})
24 25
         time       = assure_time(opts[:at], :default => :now)
25 26
         api_url    = api_url(time)
26  
-        #TODO make this array dependent on the number of retries (go back 1 day for each retry)
27  
-        retry_urls = [api_url(time - 86400), api_url(time - 172800), api_url(time - 259200)]
  27
+        retry_urls = Exchange::Configuration.retries.times.map{ |i| api_url(time - 86400 * (i+1)) }
28 28
         
29 29
         Call.new(api_url, :format => :xml, :at => time, :retry_with => retry_urls) do |result|
30 30
           @base                 = result.css('basecurrency').children[0].to_s
31  
-          @rates                = Hash[*result.css('fx currency_code').children.map(&:to_s).zip(result.css('fx rate').children.map{|c| c.to_s.to_f }).flatten]
  31
+          @rates                = Hash[*result.css('fx currency_code').children.map(&:to_s).zip(result.css('fx rate').children.map{|c| BigDecimal.new(c.to_s) }).flatten]
32 32
           @timestamp            = Time.gm(*result.css('fx_date').children[0].to_s.split('-')).to_i
33 33
         end
34 34
       end
95  lib/exchange/iso_4217.rb
... ...
@@ -0,0 +1,95 @@
  1
+module Exchange
  2
+  
  3
+  # This class handles everything that has to do with certified formatting of the different currencies. The standard is stored in 
  4
+  # the iso4217 YAML file.
  5
+  # @version 0.3
  6
+  # @since 0.3
  7
+  # @author Beat Richartz
  8
+  
  9
+  class ISO4217
  10
+    class << self
  11
+      
  12
+      # The ISO 4217 that have to be loaded. Nothing much to say here. Just use this method to get to the definitions
  13
+      # They are static, so they can be stored in a class variable without many worries
  14
+      # @return [Hash] The iso427 Definitions with the currency code as keys
  15
+      
  16
+      def definitions
  17
+        @@definitions ||= YAML.load_file('iso4217.yml')
  18
+      end
  19
+      
  20
+      # Use this to instantiate a currency amount. For one, it is important that we use BigDecimal here so nothing gets lost because
  21
+      # of floating point errors. For the other, This allows us to set the precision exactly according to the iso definition
  22
+      # @param [BigDecimal, Fixed, Float, String] amount The amount of money you want to instantiate
  23
+      # @param [String, Symbol] currency The currency you want to instantiate the money in
  24
+      # @return [BigDecimal] The instantiated currency
  25
+      # @example instantiate a currency from a string
  26
+      #   Exchange::ISO4217.instantiate("4523", "usd") #=> #<Bigdecimal 4523.00>
  27
+      
  28
+      def instantiate(amount, currency)
  29
+        BigDecimal.new(amount.to_s, definitions[currency.to_s.upcase]['minor_unit'])
  30
+      end
  31
+      
  32
+      # Converts the currency to a string in ISO 4217 standardized format, either with or without the currency. This leaves you
  33
+      # with no worries how to display the currency.
  34
+      # @param [BigDecimal, Fixed, Float] amount The amount of currency you want to stringify
  35
+      # @param [String, Symbol] currency The currency you want to stringify
  36
+      # @param [Hash] opts The options for formatting
  37
+      # @option opts [Boolean] :amount_only Whether you want to have the currency in the string or not
  38
+      # @return [String] The formatted string
  39
+      # @example Convert a currency to a string
  40
+      #   Exchange::ISO4217.stringify(49.567, :usd) #=> "USD 49.57"
  41
+      # @example Convert a currency without minor to a string
  42
+      #   Exchange::ISO4217.stringif(45, :jpy) #=> "JPY 45"
  43
+      # @example Convert a currency with a three decimal minor to a string
  44
+      #   Exchange::ISO4217.stringif(34.34, :omr) #=> "OMR 34.340"
  45
+      # @example Convert a currency to a string without the currency
  46
+      #   Exchange::ISO4217.stringif(34.34, :omr, :amount_only => true) #=> "34.340"
  47
+      
  48
+      def stringify(amount, currency, opts={})
  49
+        format      = "%.#{definitions[currency.to_s.upcase]['minor_unit']}f"
  50
+        "#{currency.to_s.upcase + ' ' unless opts[:amount_only]}#{format % amount}"
  51
+      end
  52
+      
  53
+      private
  54
+        # @private
  55
+        # @macro [attach] install_operations
  56
+      
  57
+        def install_operation op      
  58
+          self.class_eval <<-EOV
  59
+            def self.#{op}(amount, currency, precision=nil)
  60
+              minor = definitions[currency.to_s.upcase]['minor_unit']
  61
+              (amount.is_a?(BigDecimal) ? amount : BigDecimal.new(amount.to_s, minor)).#{op}(precision || minor)
  62
+            end
  63
+          EOV
  64
+        end
  65
+    end
  66
+    
  67
+    # Use this to round a currency amount. This allows us to round exactly to the number of minors the currency has in the 
  68
+    # iso definition
  69
+    # @param [BigDecimal, Fixed, Float, String] amount The amount of money you want to round
  70
+    # @param [String, Symbol] currency The currency you want to round the money in
  71
+    # @example Round a currency with 2 minors
  72
+    #   Exchange::ISO4217.round("4523.456", "usd") #=> #<Bigdecimal 4523.46>
  73
+    
  74
+    install_operation :round
  75
+    
  76
+    # Use this to ceil a currency amount. This allows us to ceil exactly to the number of minors the currency has in the 
  77
+    # iso definition
  78
+    # @param [BigDecimal, Fixed, Float, String] amount The amount of money you want to ceil
  79
+    # @param [String, Symbol] currency The currency you want to ceil the money in
  80
+    # @example Ceil a currency with 2 minors
  81
+    #   Exchange::ISO4217.ceil("4523.456", "usd") #=> #<Bigdecimal 4523.46>
  82
+    
  83
+    install_operation :ceil
  84
+    
  85
+    # Use this to floor a currency amount. This allows us to floor exactly to the number of minors the currency has in the 
  86
+    # iso definition
  87
+    # @param [BigDecimal, Fixed, Float, String] amount The amount of money you want to floor
  88
+    # @param [String, Symbol] currency The currency you want to floor the money in
  89
+    # @example Floor a currency with 2 minors
  90
+    #   Exchange::ISO4217.floor("4523.456", "usd") #=> #<Bigdecimal 4523.46>
  91
+    
  92
+    install_operation :floor
  93
+    
  94
+  end
  95
+end
27  spec/core_extensions/conversability_spec.rb
@@ -61,4 +61,31 @@
61 61
       3.25.chf(:at => '2010-01-01').time.year.should == 2010
62 62
     end
63 63
   end
  64
+  context "with a big decimal" do
  65
+    it "should allow to convert to a currency" do
  66
+      BigDecimal.new("3.25").eur.should be_kind_of Exchange::Currency
  67
+      BigDecimal.new("3.25").eur.value.should == 3.25
  68
+    end
  69
+    it "should allow to convert to a curreny with a negative number" do
  70
+      BigDecimal.new("-3.25").eur.should be_kind_of Exchange::Currency
  71
+      BigDecimal.new("-3.25").eur.value.should == -3.25
  72
+    end
  73
+    it "should allow to do full conversions" do
  74
+      mock_api("https://raw.github.com/currencybot/open-exchange-rates/master/latest.json", fixture('api_responses/example_json_api.json'), 3)
  75
+      BigDecimal.new("3.25").eur.to_chf.should be_kind_of Exchange::Currency
  76
+      BigDecimal.new("3.25").eur.to_chf.value.should == 3.92
  77
+      BigDecimal.new("3.25").eur.to_chf.currency.should == 'chf'
  78
+    end
  79
+    it "should allow to do full conversions with negative numbers" do
  80
+      mock_api("https://raw.github.com/currencybot/open-exchange-rates/master/latest.json", fixture('api_responses/example_json_api.json'), 3)
  81
+      BigDecimal.new("-3.25").eur.to_chf.should be_kind_of Exchange::Currency
  82
+      BigDecimal.new("-3.25").eur.to_chf.value.should == -3.92
  83
+      BigDecimal.new("-3.25").eur.to_chf.currency.should == 'chf'
  84
+    end
  85
+    it "should allow to define a historic time in which the currency should be interpreted" do
  86
+      BigDecimal.new("3.25").chf(:at => Time.gm(2010,1,1)).time.yday.should == 1
  87
+      BigDecimal.new("3.25").chf(:at => Time.gm(2010,1,1)).time.year.should == 2010
  88
+      BigDecimal.new("3.25").chf(:at => '2010-01-01').time.year.should == 2010
  89
+    end
  90
+  end
64 91
 end
88  spec/exchange/currency_spec.rb
@@ -167,29 +167,89 @@
167 167
     end
168 168
     describe "round" do
169 169
       subject { Exchange::Currency.new(40.123, :usd) }
170  
-      it "should apply it to its number" do
171  
-        subject.round.value.should == 40
172  
-        subject.round.currency.should == :usd
173  
-        subject.round.should be_kind_of Exchange::Currency
  170
+      context "without arguments" do
  171
+        it "should apply it to its number in the iso certified format" do
  172
+          subject.round.value.should == 40.12
  173
+          subject.round.currency.should == :usd
  174
+          subject.round.should be_kind_of Exchange::Currency
  175
+        end
  176
+      end
  177
+      context "with arguments" do
  178
+        it "should apply it to its number" do
  179
+          subject.round(0).value.should == 40
  180
+          subject.round(0).currency.should == :usd
  181
+          subject.round(0).should be_kind_of Exchange::Currency
  182
+        end
  183
+        it "should allow to round to whatever number of decimals" do
  184
+          subject.round(2).value.should == 40.12
  185
+          subject.round(2).currency.should == :usd
  186
+          subject.round(2).should be_kind_of Exchange::Currency
  187
+        end