Skip to content

Instantly share code, notes, and snippets.

@oz
Last active December 14, 2015 14:28
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save oz/5100368 to your computer and use it in GitHub Desktop.
Save oz/5100368 to your computer and use it in GitHub Desktop.
I often need to convert currencies. This can be done from various search engines, but it's faster (for me) to just type a command in a term, and get results immediately. HTH.
#!/usr/bin/env ruby
#
# change.rb -- currency conversions on the CLI
#
# Requirements:
#
# gem install nas-yahoo_stock moneta slop
#
# Getting started:
#
# 1. Run change.rb --help
# 2. Format currencies using ISO 4217.
# 3. Stock are cached in ~/.change.cache for 24 hours
require 'pathname'
require 'fileutils'
require 'yahoo_stock' # nas-yahoo_stock
require 'moneta'
require 'slop'
module Currency
module Utils
module_function
# key/value store to cache stock values.
def store
return @store if @store
store_path = Pathname.new(ENV['HOME']) + '.change.cache'
@store = Moneta.new(:PStore, file: store_path.to_s, expires: expire)
end
# Rounding
def precision
3
end
# Cache expiration
def expire
86400
end
end
# Get currency conversions from Yahoo Finance API
class Stock
def initialize(options = {})
@cache = options.fetch(:cache) { {} }
end
def get(name)
@cache.fetch(name) { fetch(name) }
@cache[name]
end
alias :[] :get
private
def fetch(name)
query = YahooStock::Quote.new(stock_symbols: [name])
query.results(:to_array).output.each_with_index do |quote, i|
@cache[ name ] = quote[1].to_f
end
end
end
# Convert amounts between currencies.
Converter = Struct.new(:amount, :from, :to) do
include Utils
# @return [Float]
def convert
change = Stock.new(cache: store).get(stock_symbol)
(amount.to_f * change.to_f).round(precision)
end
def stock_symbol
"#{ from }#{ to }=X".upcase
end
end
end
opts = Slop.parse do
banner "Usage: change.rb -f <currency> -t <currency> -a <amount>"
on :f, :from=, 'Origin currency', argument: :optional
on :t, :to=, 'Target currency', argument: :optional
on :a, :amount=, 'Amount', argument: :optional
on :h, :help, 'Show help'
end
if opts.help? || !opts.from? || !opts.to? || !opts.amount?
puts opts
exit(1)
end
value = Currency::Converter.new(opts[:amount], opts[:from], opts[:to]).convert
puts "#{ opts[:amount] } #{ opts[:from] } = #{ value } #{ opts[:to] }"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment