Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
scottjbarr committed Feb 11, 2009
0 parents commit 90729ab
Show file tree
Hide file tree
Showing 18 changed files with 303 additions and 0 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -0,0 +1 @@
pkg
15 changes: 15 additions & 0 deletions Manifest
@@ -0,0 +1,15 @@
config.yml
init.rb
lib/yahoo_currency/exchange_rate.rb
lib/yahoo_currency/yahoo_currency.rb
lib/yahoo_currency.rb
Manifest
Rakefile
README.rdoc
test/docs/FAKE-FAKE.csv
test/docs/JPY-USD.csv
test/docs/USD-CAD.csv
test/integration/yahoo_currency_test.rb
test/mocks/yahoo_currency_mock.rb
test/test_helper.rb
test/unit/yahoo_currency_test.rb
61 changes: 61 additions & 0 deletions README.rdoc
@@ -0,0 +1,61 @@
=== YahooCurrency

Get the exchange rate for a set of currency codes.

==== The Yahoo! Finance Service

URL to fetch the AUD to USD exchange rate

http://download.finance.yahoo.com/d/quotes.csv?s=AUDUSD=X&f=nl1d1t1

Although the Yahoo! service supports multiple rates values from one request,
this class does not yet support this functionality yet.

$ curl "http://download.finance.yahoo.com/d/quotes.csv?s=USDCAD=X+JPYUSD=X+GBPUSD=X+USDJPY=X+EURUSD=X&f=nl1d1t1"
"USD to CAD",1.0191,"6/18/2008","2:45am"
"JPY to USD",0.0093,"6/18/2008","2:45am"
"GBP to USD",1.9514,"6/18/2008","2:44am"
"USD to JPY",108.085,"6/18/2008","2:45am"
"EUR to USD",1.5493,"6/18/2008","2:44am"

==== Features

* So easy to use, even a baby could find out what his currency is trading at.

==== Example

exchange_rate = YahooCurrency.get_rate!("JPY", "USD")
exchange_rate.from #=> "JPY"
exchange_rate.to #=> "USD"
exchange_rate.rate #=> 0.0111
exchange_rate.timestamp #=> Wed Feb 11 22:20:00 +0800 2009

==== References

* http://gummy-stuff.org/forex.htm
* http://www.thinkruby.org/tags/currency-converter
* http://finance.yahoo.com/currency
* http://gummy-stuff.org/Yahoo-data.htm - tag info (the f parameter)

==== License

Copyright (c) 2009 Global IT Creations Pte. Ltd. http://www.globalitcreations.com/

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:

The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.

65 changes: 65 additions & 0 deletions Rakefile
@@ -0,0 +1,65 @@
require 'rubygems'
require 'rake'
require 'rake/testtask'
require 'echoe'
require 'yaml'

APP_NAME = "yahoo_currency"
APP_URL = "http://github.com/scottbarr/yahoo_currency/tree/master"
APP_DESCRIPTION = "Fetch currency exchange rates from Yahoo! Finance"
AUTHOR_NAME = "Scott Barr"
AUTHOR_EMAIL = "scottb@globalitcreations.com"

#
# Create a version for this build from the config.yml and the BUILD_NUMBER
# environment variable.
#
def get_version
# read the config file
config = open("config.yml") {|f| YAML.load(f)}

# build the version number
version_major = config["version"]["major"]
version_minor = config["version"]["minor"]
version_build = ENV["BUILD_NUMBER"] ||= "0"
"#{version_major}.#{version_minor}.#{version_build}"
end

Rake::TestTask.new("test:units") { |t|
t.pattern = 'test/unit/*_test.rb'
t.verbose = true
t.warning = false
}

Rake::TestTask.new("test:integration") { |t|
t.pattern = 'test/integration/*_test.rb'
t.verbose = true
t.warning = false
}

# setup the gem
Echoe.new(APP_NAME, get_version) do |p|
p.description = APP_DESCRIPTION
p.url = APP_URL
p.author = AUTHOR_NAME
p.email = AUTHOR_EMAIL
p.ignore_pattern = ["tmp/*", "script/*"]
p.development_dependencies = []
end

# define a remove task method so the "test" task isn't breaking my stuff
Rake::TaskManager.class_eval do
def remove_task(task_name)
@tasks.delete(task_name.to_s)
end
end

# helper method to remove a task
def remove_task(task_name)
Rake.application.remove_task(task_name)
end

# remove the original test task
remove_task :test

task :test => ["test:units", "test:integration"]
4 changes: 4 additions & 0 deletions config.yml
@@ -0,0 +1,4 @@
---
version:
major: 0
minor: 1
3 changes: 3 additions & 0 deletions init.rb
@@ -0,0 +1,3 @@
# require 'lib/yahoo_currency'
# require 'lib/exchange_rate'
require 'yahoo_currency'
2 changes: 2 additions & 0 deletions lib/yahoo_currency.rb
@@ -0,0 +1,2 @@
require 'yahoo_currency/yahoo_currency'
require 'yahoo_currency/exchange_rate'
12 changes: 12 additions & 0 deletions lib/yahoo_currency/exchange_rate.rb
@@ -0,0 +1,12 @@
class ExchangeRate

attr_accessor :from, :to, :rate, :timestamp

def initialize(from, to, rate, timestamp)
@from = from
@to = to
@rate = rate
@timestamp = timestamp
end

end
50 changes: 50 additions & 0 deletions lib/yahoo_currency/yahoo_currency.rb
@@ -0,0 +1,50 @@
require 'net/http'
require 'time'

class YahooCurrency

# set the host and path we access the service from
HOST = 'download.finance.yahoo.com'
PATH = '/d/quotes.csv'

#
# Retrieve the exchange rate for the from and to currency codes.
#
def self.get_rate!(from, to)

# create the url
http = Net::HTTP.new(HOST, 80)
target = "#{PATH}?s=#{from}#{to}=X&f=nl1d1t1"

# hit the url
resp, data = http.get(target, nil)

# check the response code
if resp.code.to_i != 200
raise "#{resp.code} #{resp.message}"
end

ExchangeRate.new(from, to, parse_rate(data), parse_timestamp(data))
end

private

#
# The rate is the first field in the CSV
#
def self.parse_rate(data)
data.split(',')[1].to_f
end

#
# The timestamp is in the 2 and 3rd fields of the CSV
#
def self.parse_timestamp(data)
# the timestamp will be in M/D/YYYY HH:mm:ampm format
ts = (data.split(',')[2] + ' ' + data.split(',')[3]).gsub('"', '').chop
return nil if ts == "N/A N/A"

Time.parse(ts)
end

end
Empty file added test/docs/.keep
Empty file.
1 change: 1 addition & 0 deletions test/docs/FAKE-FAKE.csv
@@ -0,0 +1 @@
"FAKEFAKE=X",0.00,"N/A","N/A"
1 change: 1 addition & 0 deletions test/docs/JPY-USD.csv
@@ -0,0 +1 @@
"JPY to USD",0.0093,"6/18/2008","2:45am"
1 change: 1 addition & 0 deletions test/docs/USD-CAD.csv
@@ -0,0 +1 @@
"USD to CAD",1.0191,"6/18/2008","2:45am"
Empty file added test/integration/.keep
Empty file.
28 changes: 28 additions & 0 deletions test/integration/yahoo_currency_test.rb
@@ -0,0 +1,28 @@
require 'test/test_helper'

class YahooCurrencyTest < Test::Unit::TestCase

def setup
@timestamp = Time.parse("6/18/2008 2:45am")
end

def test_get_rate_usd_aud
exchange_rate = YahooCurrency.get_rate!("AUD", "USD")
assert_equal "AUD", exchange_rate.from
assert_equal "USD", exchange_rate.to
assert_not_nil exchange_rate.rate
assert_not_nil exchange_rate.timestamp
end

#
# Test one or more unknown currency codes
#
def test_get_rate_fake_fake
exchange_rate = YahooCurrency.get_rate!("FAKE", "FAKE")
assert_equal "FAKE", exchange_rate.from
assert_equal "FAKE", exchange_rate.to
assert_equal 0.00, exchange_rate.rate
assert_nil exchange_rate.timestamp
end

end
20 changes: 20 additions & 0 deletions test/mocks/yahoo_currency_mock.rb
@@ -0,0 +1,20 @@
#
# A mock of the YahooCurrency class
#
require 'lib/yahoo_currency'

# Reopen and override the class
class YahooCurrency

def self.get_rate!(from, to)

data = ""
# try and open a test csv files
File.open("test/docs/#{from}-#{to}.csv", "r") do |infile|
data = infile.gets
end

ExchangeRate.new(from, to, parse_rate(data), parse_timestamp(data))
end

end
2 changes: 2 additions & 0 deletions test/test_helper.rb
@@ -0,0 +1,2 @@
require 'test/unit'
require 'yahoo_currency'
37 changes: 37 additions & 0 deletions test/unit/yahoo_currency_test.rb
@@ -0,0 +1,37 @@
require 'test/test_helper'
require 'test/mocks/yahoo_currency_mock'

class YahooCurrencyTest < Test::Unit::TestCase

def setup
@timestamp = Time.parse("6/18/2008 2:45am")
end

def test_get_rate_jpy_usd
exchange_rate = YahooCurrency.get_rate!("JPY", "USD")
assert_equal "JPY", exchange_rate.from
assert_equal "USD", exchange_rate.to
assert_equal 0.0093, exchange_rate.rate
assert_equal @timestamp, exchange_rate.timestamp
end

def test_get_rate_usd_cad
exchange_rate = YahooCurrency.get_rate!("USD", "CAD")
assert_equal "USD", exchange_rate.from
assert_equal "CAD", exchange_rate.to
assert_equal 1.0191, exchange_rate.rate
assert_equal @timestamp, exchange_rate.timestamp
end

#
# Test one or more unknown currency codes
#
def test_get_rate_fake_fake
exchange_rate = YahooCurrency.get_rate!("FAKE", "FAKE")
assert_equal "FAKE", exchange_rate.from
assert_equal "FAKE", exchange_rate.to
assert_equal 0.00, exchange_rate.rate
assert_nil exchange_rate.timestamp
end

end

0 comments on commit 90729ab

Please sign in to comment.