-
Notifications
You must be signed in to change notification settings - Fork 0
/
currency_converter2.rb
143 lines (123 loc) · 3.59 KB
/
currency_converter2.rb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
#!/usr/bin/env ruby
# currency_converter2.rb
### RSS feeds for rates at
# http://www.currencysource.com/rss_currencyexchangerates.html
=begin rdoc
open-uri allows Kernel.open to read data using a URI, not just from
a local file.
=end
require 'open-uri'
=begin rdoc
YAML[http://www.yaml.org/] stands for "YAML Ain't Markup Language"
and is a simple human-readable data markup format.
=end
require 'yaml'
=begin rdoc
I also want to add a method to all <b>Hash</b>es.
=end
class Hash
=begin rdoc
Allow <b>Hash</b>es to be subtracted from each other.
=end
def -(hash_with_pairs_to_remove_from_self)
output = self.dup
hash_with_pairs_to_remove_from_self.each_key do |k|
output.delete(k)
end
output
end
end
class CurrencyConverter
BASE_URL = 'http://currencysource.com/RSS'
CURRENCY_CODES = {
'EUR' => 'Euro',
'CAD' => 'Canadian Dollar',
'CNY' => 'Chinese Yuan',
'INR' => 'Indian Rupee',
'MXN' => 'Mexican Peso',
'USD' => 'US Dollar',
}
RATES_DIRECTORY = 'extras/currency_exchange_rates'
def initialize(code='USD')
unless CURRENCY_CODES.has_key?(code)
fail "I know nothing about #{code}"
end
@base_currency = code
@name = CURRENCY_CODES[code]
end
def output_rates(mult=1, try_new_rates=true)
rates = get_rates(try_new_rates)
save_rates_in_local_file!(rates)
return get_value(mult, rates) + "\n"
end
private
def download_new_rates()
puts 'Downloading new exchange rates...'
begin
raw_rate_lines = get_xml_lines()
rescue
puts 'Download failed. Falling back to local file.'
return nil
end
rates = Hash.new('')
comparison_codes = CURRENCY_CODES - { @base_currency => @name }
comparison_codes.each_key do |abbr|
rates[abbr] = get_rate_for_abbr_from_raw_rate_lines(
abbr,
raw_rate_lines
)
end
return rates
end
def get_rates(try_new_rates)
return load_old_rates unless try_new_rates
return download_new_rates || load_old_rates
end
def get_rate_for_abbr_from_raw_rate_lines(abbr, raw_rate_lines)
regex = {
:open =>
/^\<title\>1 #{@base_currency} = #{abbr} \(/,
:close =>
/\)\<\/title\>\r\n$/
}
line = raw_rate_lines.detect { |line| line =~ /#{abbr}/ }
line.gsub(regex[:open], '').gsub(regex[:close], '').to_f
end
def get_value(mult, rates)
return "#{pluralize(mult, @name)} (#{@base_currency}) = \n" +
rates.keys.map do |abbr|
"\t#{pluralize(mult * rates[abbr], CURRENCY_CODES[abbr])} (#{abbr})"
end.join("\n")
end
=begin rdoc
get_xml_lines is able to read from a URI with the open-uri library.
This also could have been implemented with the RSS library written by
Kouhei Sutou <[email protected]> and detailed at
http://www.cozmixng.org/~rwiki/?cmd=view;name=RSS+Parser%3A%3ATutorial.en
=end
def get_xml_lines()
open("#{BASE_URL}/#{@base_currency}.xml").readlines.find_all do |line|
line =~ /1 #{@base_currency} =/
end
end
def load_old_rates()
puts "Reading stored exchange rates from local file #{rates_filename()}"
rates = YAML.load(File.open(rates_filename))
fail 'no old rates' unless rates
return rates
end
def pluralize(num, term)
(num == 1) ? "#{num} #{term}" : "#{num} #{term}s"
end
def rates_filename()
"#{RATES_DIRECTORY}/#{@base_currency}.yaml"
end
=begin rdoc
Store new rates in an external YAML file.
This is a side-effect akin to memoization, hence the bang.
=end
def save_rates_in_local_file!(rates)
return unless rates
File.open(rates_filename, 'w') { |rf| YAML.dump(rates, rf) }
end
end