Skip to content

HTTPS clone URL

Subversion checkout URL

You can clone with HTTPS or Subversion.

Download ZIP
Browse files

Initial commit

  • Loading branch information...
commit 90729ab87725852c7511014c0ab233b7d4826f18 0 parents
@scottjbarr authored
1  .gitignore
@@ -0,0 +1 @@
+pkg
15 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 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 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 config.yml
@@ -0,0 +1,4 @@
+---
+version:
+ major: 0
+ minor: 1
3  init.rb
@@ -0,0 +1,3 @@
+# require 'lib/yahoo_currency'
+# require 'lib/exchange_rate'
+require 'yahoo_currency'
2  lib/yahoo_currency.rb
@@ -0,0 +1,2 @@
+require 'yahoo_currency/yahoo_currency'
+require 'yahoo_currency/exchange_rate'
12 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 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
0  test/docs/.keep
No changes.
1  test/docs/FAKE-FAKE.csv
@@ -0,0 +1 @@
+"FAKEFAKE=X",0.00,"N/A","N/A"
1  test/docs/JPY-USD.csv
@@ -0,0 +1 @@
+"JPY to USD",0.0093,"6/18/2008","2:45am"
1  test/docs/USD-CAD.csv
@@ -0,0 +1 @@
+"USD to CAD",1.0191,"6/18/2008","2:45am"
0  test/integration/.keep
No changes.
28 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 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  test/test_helper.rb
@@ -0,0 +1,2 @@
+require 'test/unit'
+require 'yahoo_currency'
37 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
Please sign in to comment.
Something went wrong with that request. Please try again.