Implementations/Libraries/Ruby
From Geo Hashing
[edit] Ruby Geohasher v1.2
| This implementation IS FULLY 30W-compliant. |
ScottKuma did this as a first excursion into Ruby. Yes, it's long. Yes, it's kinda clunky. However, IT WORKS!
v1.2 adds the ability to use unix-style commandline options in any order.
Any changes, suggestions, etc. are happily accepted!
#!/usr/bin/ruby
# == Synopsis
# geohasher: prints geohash coordinates for a given date & graticule
#
# == Usage
#
# geohasher [OPTION] ...
# -d, --date YYYY-MM-DD:
# the date in YYYY-MM-DD or YYYY/MM/DD format),
#
# -t, --lat x:
# the latitude "base coordinate"
#
# -g, --long x:
# the longitude "base coordinate"
#
# -m, --dow x
require 'net/http'
require 'date'
require 'digest'
require 'getoptlong'
require 'rdoc/usage'
def hexFracToDecFrac(hexFracPart)
#I wish I had a neat little algorithm to do this in one line - but this works!
#NOTE: do not feed the preceding "0." to this function....only the fractional part (the part after the decimal point)
fracLen = hexFracPart.length
fracPortion = hexFracPart[0..(fracLen-1)]
fracLen = fracPortion.length
myLen = (fracLen - 1)
sum = 0
for i in (0 .. myLen)
numSixteenths = fracPortion[i..i].to_i(16)
conversionFactor = (16.**(i+1)).to_f
conversionFactor = 1./conversionFactor
sum = sum + ((numSixteenths) * conversionFactor)
end
return sum.to_s[2..8]
end
# Parse the command line options
opts = GetoptLong.new(
['--help','-h',GetoptLong::NO_ARGUMENT ],
['--lat','-t',GetoptLong::REQUIRED_ARGUMENT ],
['--long','-g',GetoptLong::REQUIRED_ARGUMENT ],
['--dow','-m',GetoptLong::REQUIRED_ARGUMENT ],
['--date','-d',GetoptLong::REQUIRED_ARGUMENT ]
)
# Set default items (still parsing...)
myLat = "39" # Change me to set the desired default graticule's latitude
myLong = "-84" # Change me to set the desired default graticule's longitude
t=Time.now
myDate = t.strftime("%Y-%m-%d")
dow = ""
begin
opts.each do |opt,arg|
case opt
when '--help'
RDoc::usage
when '--lat'
myLat = arg
when '--long'
myLong = arg
when '--dow'
dow = arg
when '--date'
myDate = arg
end
end
rescue
RDoc::usage
end
dateSplit = ''
if myDate.split('/').length == 3
dateSplit = myDate.split('/')
else
dateSplit = myDate.split('-')
end
myDate = Date.civil(dateSplit[0].to_i, dateSplit[1].to_i, dateSplit[2].to_i)
#fix for the "-30 rule"
fixDate = Date.civil(2008,05,25)
timeDelta = 0
if myLong.to_i > -30 and (myDate > fixDate)
puts "-30 rule in effect!"
timeDelta = 1
end
algorithmEncodedDate = myDate.to_s
urlEncodedDate = (myDate - timeDelta).strftime('%Y/%m/%d')
baseURL = 'carabiner.peeron.com'
basePath = '/xkcd/map/data/'
fullPath = basePath + urlEncodedDate
if dow==""
Net::HTTP.start(baseURL,80) do |http|
dow = http.get(fullPath).body
end
end
if !dow.include? "404 Not Found"
ghash = algorithmEncodedDate+'-'+dow
digest = Digest::MD5.hexdigest(ghash)
digest1 = digest[0..15]
digest2 = digest[16..31]
puts "(" + myLat + "." + hexFracToDecFrac(digest1) + ", " + myLong + "." + hexFracToDecFrac(digest2) + ")"
else
puts "Dow information not available for "+urlEncodedDate
end