Unidad de Fomento (CLF/UF) and money gem - ruby

I've been struggling to understand how does the money gem formats the Unidad de Fomento. I've tested the version 6.5 and the 6.7 and both seems to present odd formats:
# Money 6.5
usd = Money.new(243, 'USD')
usd.to_f #=> 2.43
usd.format #=> "$2.43"
clf = Money.new(243, 'CLF')
clf.to_f #=> 243
clf.format #=> "CLF243"
# Money 6.7
usd = Money.new(243, 'USD')
usd.to_f #=> 2.43
usd.format #=> "$2.43"
clf = Money.new(243, 'CLF')
clf.to_f #=> 0.0243
clf.format #=> "CLF0.0243"
Is it meant to be this way or it is a bug?

It was an intentional change introduced with version 6.6.
See the changelog and the commit on GitHub. Unfortunately there is no hint as of why it was done.

OK, I think I've got it. I'm a fool who thinks we lived in a world of cents like USD or EUR (base 10 exponent 2, 10^2 cents equals 1 unit of the currency). There are many currencies that do not have any kind of minor currencies like the Japanse Yen (JPY) and there are also currencies with no base 10 at all. This article in the wikipedia explains it very well: https://en.wikipedia.org/wiki/ISO_4217
So, in my examples it seems that a long time ago the CLF was a currency with exponent 0, so it hasn't any type of minor currency. 2.34 was an invalid amount so money converted it into 234. The ISO changed, and then CLF was converted into a currency with exponent 4.
This comment on the money issue tracker solved my issue: https://github.com/RubyMoney/money/issues/614#issuecomment-194813943

Related

ValueError: Input is not valid. Should be a string, a list/tuple of strings or a list/tuple of integers

from os import listdir
from os.path import isfile, join
from datasets import load_dataset
from transformers import BertTokenizer
test_files = [join('./test/', f) for f in listdir('./test') if isfile(join('./test', f))]
dataset = load_dataset('json', data_files={"test": test_files}, cache_dir="./.cache_dir")
tokenizer = BertTokenizer.from_pretrained("bert-base-uncased")
def encode(batch):
return tokenizer.encode_plus(batch["abstract"], max_length=32, add_special_tokens=True, pad_to_max_length=True,
return_attention_mask=True, return_token_type_ids=False, return_tensors="pt")
dataset.set_transform(encode)
When I run this code, I have
ValueError: Input is not valid. Should be a string, a list/tuple of strings or a list/tuple of integers.
Instead of having a list of strings, I have a list of lists of strings. Here is the content of batch["article"]:
[['eleven politicians from 7 parties made comments in letter to a newspaper .', "said dpp alison saunders had ` damaged public confidence ' in justice .", 'ms saunders ruled lord janner unfit to stand trial over child abuse claims .', 'the cps has pursued at least 19 suspected paedophiles with dementia .'], ['an increasing number of surveys claim to reveal what makes us happiest .', 'but are these generic lists really of any use to us ?', 'janet street-porter makes her own list - of things making her unhappy !'], ["author of ` into the wild ' spoke to five rape victims in missoula , montana .", "` missoula : rape and the justice system in a college town ' was released april 21 .", "three of five victims profiled in the book sat down with abc 's nightline wednesday night .", 'kelsey belnap , allison huguet and hillary mclaughlin said they had been raped by university of montana football players .', "huguet and mclaughlin 's attacker , beau donaldson , pleaded guilty to rape in 2012 and was sentenced to 10 years .", 'belnap claimed four players gang-raped her in 2010 , but prosecutors never charged them citing lack of probable cause .', 'mr krakauer wrote book after realizing close friend was a rape victim .'], ['tesco announced a record annual loss of £ 6.38 billion yesterday .', 'drop in sales , one-off costs and pensions blamed for financial loss .', 'supermarket giant now under pressure to close 200 stores nationwide .', 'here , retail industry veterans , plus mail writers , identify what went wrong .'], ..., ['snp leader said alex salmond did not field questions over his family .', "said she was not ` moaning ' but also attacked criticism of women 's looks .", 'she made the remarks in latest programme profiling the main party leaders .', 'ms sturgeon also revealed her tv habits and recent image makeover .', 'she said she relaxed by eating steak and chips on a saturday night .']]
How could I fix this issue?

xarray too slow for performance critical code

I planned to use xarray extensively in some numerically intensive scientific code that I am writing. So far, it makes the code very elegant, but I think I will have to abandon it as the performance cost is far too high.
Here is an example, which creates two arrays and multiplies parts of them together using xarray (with several indexing schemes), and numpy. I used num_comp=2 and num_x=10000:
Line # Hits Time Per Hit % Time Line Contents
4 #profile
5 def xr_timing(num_comp, num_x):
6 1 4112 4112.0 10.1 da1 = xr.DataArray(np.random.random([num_comp, num_x]).astype(np.float32), dims=['component', 'x'], coords={'component': ['a', 'b'], 'x': np.linspace(0, 1, num_x)})
7 1 438 438.0 1.1 da2 = da1.copy()
8 1 1398 1398.0 3.4 da2[:] = np.random.random([num_comp, num_x]).astype(np.float32)
9 1 7148 7148.0 17.6 da3 = da1.isel(component=0).drop('component') * da2.isel(component=0).drop('component')
10 1 6298 6298.0 15.5 da4 = da1[dict(component=0)].drop('component') * da2[dict(component=0)].drop('component')
11 1 7541 7541.0 18.6 da5 = da1.sel(component='a').drop('component') * da2.sel(component='a').drop('component')
12 1 7184 7184.0 17.7 da6 = da1.loc[dict(component='a')].drop('component') * da2.loc[dict(component='a')].drop('component')
13 1 6479 6479.0 16.0 da7 = da1[0, :].drop('component') * da2[0, :].drop('component')
15 #profile
16 def np_timing(num_comp, num_x):
17 1 1027 1027.0 50.2 da1 = np.random.random([num_comp, num_x]).astype(np.float32)
18 1 977 977.0 47.8 da2 = np.random.random([num_comp, num_x]).astype(np.float32)
19 1 41 41.0 2.0 da3 = da1[0, :] * da2[0, :]
The fastest xarray multiplication takes about 150X the time of the numpy version. This is just one of the operations in my code, but I find most of them are many times slower than the numpy equivalent, which is unfortunate as xarray makes the code so much clearer. Am I doing something wrong?
Update: Even da1[0, :].values * da2[0, :].values (which loses many of the benefits of using xarray) takes 2464 time units.
I am using xarray 0.9.6, pandas 0.21.0, numpy 1.13.3, and Python 3.5.2.
Update 2:
As requested by #Maximilian, here is a re-run with num_x=1000000:
Line # Hits Time Per Hit % Time Line Contents
# xarray
9 5 408596 81719.2 11.3 da3 = da1.isel(component=0).drop('component') * da2.isel(component=0).drop('component')
10 5 407003 81400.6 11.3 da4 = da1[dict(component=0)].drop('component') * da2[dict(component=0)].drop('component')
11 5 411248 82249.6 11.4 da5 = da1.sel(component='a').drop('component') * da2.sel(component='a').drop('component')
12 5 411730 82346.0 11.4 da6 = da1.loc[dict(component='a')].drop('component') * da2.loc[dict(component='a')].drop('component')
13 5 406757 81351.4 11.3 da7 = da1[0, :].drop('component') * da2[0, :].drop('component')
14 5 48800 9760.0 1.4 da8 = da1[0, :].values * da2[0, :].values
# numpy
20 5 37476 7495.2 2.9 da3 = da1[0, :] * da2[0, :]
The performance difference has decreased substantially, as expected (only about 10X slower now), but I am still glad that the issue will be mentioned in the next release of the documentation as even this amount of difference may surprise some people.
Yes, this is a known limitation for xarray. Performance sensitive code that uses small arrays is much slower for xarray than NumPy. I wrote a new section about this in our docs for the next version:
http://xarray.pydata.org/en/stable/computation.html#wrapping-custom-computation
You basically have two options:
Write your performance sensitive code on unwrapped arrays, and then wrap them back in xarray data structures. Xarray v0.10 has a new helper function (apply_ufunc) that makes this a little easier. See the link above if you are interested in this.
Use something other than xarray/Python to do your computation. This could also make sense because Python itself adds significant overhead. Julia's AxisArrays.jl looks like interesting, though I haven't tried it myself.
I suppose option 3 would be to rewrite xarray itself in C++ (e.g., on top of xtensor), but that would be much more involved!

How to exchange correctly using the Money gem

I use the Money gem to work with different currencies. I'm seeing a strange behavior with the "JPY" currency.
I have the following rates:
config.add_rate('USD', 'EUR', 0.92)
config.add_rate('USD', 'JPY', 123.0)
Trying to exchange currencies, I get strange results:
10.to_money.exchange_to('EUR')
=> #<Money fractional:920 currency:EUR>
10.to_money.exchange_to('JPY')
=> #<Money fractional:1230 currency:JPY>
The "JPY" conversion should be #<Money fractional:123000 currency:JPY>. Any ideas on what's going on?
It really depends on definition of Currency. Below code shows that 10 USD is indeed equal to 1230 yen.
require "rails"
require "money-rails"
Money.add_rate('USD', 'EUR', 0.92)
Money.add_rate('USD', 'JPY', 123.0)
p 10.to_money.exchange_to('JPY') == Money.new(1230,"JPY")
#=> true
Your expectation that you should see 123000 may not be correct if you inspect the JPY currency
p Money.new(1230,"JPY").currency
#<Money::Currency id: jpy, priority: 6, symbol_first: true, thousands_separator: ,, html_entity: ¥, decimal_mark: ., name: Japanese Yen, symbol: ¥, subunit_to_unit: 1, exponent: 0.0, iso_code: JPY, iso_numeric: 392, subunit: , smallest_denomination: 1>
Important field to note in Currency definition is the value of subunit_to_unit: 1. As per documentation:
:subunit_to_unit the proportion between the unit and the subunit
This means that in case of Yen, the value displayed is in Yen, and it need not be multiplied by 100 as is the case with USD or EUR.
p 10.to_money.exchange_to('EUR')
#=> #<Money fractional:920 currency:EUR>
p 10.to_money.exchange_to('JPY')
#=> #<Money fractional:1230 currency:JPY>
Below is Currency definition for EUR
#<Money::Currency id: eur, priority: 2, symbol_first: true, thousands_separator: ., html_entity: €, decimal_mark: ,, name: Euro, symbol: €, subunit_to_unit: 100, exponent: 2.0, iso_code: EUR, iso_numeric: 978, subunit: Cent, smallest_denomination: 1>
In case of EUR, subunit_to_unit: 100 indicates that value is in cents (or equivalent)

measurement converter for selecting unit

I'm seeing quite a few measurement conversion relating gems, but I haven't been able to find one that will select the best/closest unit.
For example
If I give the gem the measurement of
9 inches + 6 inches
I'm trying to get the result
1 foot, 3 inches
The conversion tools I've seen, I'd have to tell the convertor to try to convert to feet, and then decide which is the most appropriate measurement.
Not sure how complicated you wanted to get but for your example I did this:
def plain_english_conversion(inches)
divmod_output = inches.divmod(12)
puts "#{divmod_output[0]} ft, #{divmod_output[1]} in"
end
puts "15 "
plain_english_conversion(15)
puts "37 "
plain_english_conversion(37)
With the output of:
15
1 ft, 3 in
37
3 ft, 1 in
Certainly I restricted it to feet/inches but you can abstract it out if necessary (inches & yards, feet & yards, etc.)

Business date/holiday handling

I've posted this question for C# but I may be working in Ruby instead. So I'm asking the same question about Ruby:
I'm looking for a Ruby class/library/module that works similarly to the Perl module Date::Manip as far as business/holiday dates. Using that module in Perl, I can pass it a date and find out whether it's a business day (ie, Mon-Fri) or a holiday. Holidays are very simple to define in a config file (see Date::Manip::Holidays). You can enter a 'fixed' date that applies to every year like:
12/25 = Christmas
or 'dynamic' dates for every year like:
last Monday in May = Memorial Day
or 'fixed' dates for a given year like:
5/22/2010 = Bob's Wedding
You can also pass in a date and get back the next/previous business day (which is any day that's not a weekend and not a holiday).
Does anyone know of anything like that in the Ruby world?
You may use the holidays-gem.
http://rubygems.org/gems/holidays
Some national (and regional) holidays are already predefined, you may define your own holiday definitions.
The business_time gem should do what you need.
The example at bottom of the README doc is a good starting example:
require 'rubygems'
require 'active_support'
require 'business_time'
# We can adjust the start and end time of our business hours
BusinessTime::Config.beginning_of_workday = "8:30 am"
BusinessTime::Config.end_of_workday = "5:30 pm"
# and we can add holidays that don't count as business days
# July 5 in 2010 is a monday that the U.S. takes off because
# our independence day falls on that Sunday.
three_day_weekend = Date.parse("July 5th, 2010")
BusinessTime::Config.holidays << three_day_weekend
friday_afternoon = Time.parse("July 2nd, 2010, 4:50 pm")
tuesday_morning = 1.business_hour.after(friday_afternoon)
You probably going to need the chronic gem to help you build the holiday dates from your config file. However YMMV because your example last monday in may doesn't work in chronic. Hackaround is do something like this:
# last monday in May (2010)
Chronic.parse('last monday', :now => Time.parse('2010-06-01'))
And look at the tickle gem which works on top of chronic for a way to add recurring events.
/I3az/
You could take a look at my Workpattern gem. It allows you to specify working and resting times. It was aimed at producing a "Calendar" like is used in planning tools such as Microsoft Project and Primavera P6, so you can specify right down to the minute.
Here is a simple example:
Create a new Workpattern mywp=Workpattern.new('My Workpattern',2011,10) This is for 10 years from 2011 but you can make it longer or shorter.
Tell it you want the Weekends to be resting and that you also want to rest during the week so you work between 9 and 12 in the morning and 1 and 6 in the afternoon.
mywp.resting(:days => :weekend)
mywp.resting(:days =>:weekday, :from_time=>Workpattern.clock(0,0),:to_time=>Workpattern.clock(8,59))
mywp.resting(:days =>:weekday, :from_time=>Workpattern.clock(12,0),:to_time=>Workpattern.clock(12,59))
mywp.resting(:days =>:weekday, :from_time=>Workpattern.clock(18,0),:to_time=>Workpattern.clock(23,59))
Now just calculate using minutes
mydate=DateTime.civil(2011,9,1,9,0)
result_date = mywp.calc(mydate,1920) # => 6/9/11#18:00
1920 is 4 days * 8 hours a day * 60 minutes and hour.
I wrote the gem to learn Ruby - only scratched the surface.
Check out the biz gem.
Here's an example configuration:
require 'biz'
Biz.configure do |config|
config.hours = {
mon: {'09:00' => '17:00'},
tue: {'00:00' => '24:00'},
wed: {'09:00' => '17:00'},
thu: {'09:00' => '12:00', '13:00' => '17:00'},
sat: {'10:00' => '14:00'}
}
config.holidays = [Date.new(2014, 1, 1), Date.new(2014, 12, 25)]
config.time_zone = 'America/Los_Angeles'
end
When you use the optional core extensions, it's as easy as the following to find out if a date is a business day:
require 'biz/core_ext'
Date.new(2014, 12, 25).business_day? # => false

Resources