Browse files

WIP: Adding DMS conversion updates

  • Loading branch information...
1 parent af058d7 commit f4850169cde2b290d6e30a9158b21024bd013c5b @nateklaiber nateklaiber committed Nov 3, 2012
View
15 lib/geo_position/conversion/dms.rb
@@ -13,8 +13,8 @@ module Conversion
# => -12.061783333333333
#
class Dms
- ALLOWED_MINUTES = (0.0..60.0)
- ALLOWED_DEGREES = (0.0..360.0)
+ ALLOWED_SECONDS = (0.0..60.0)
+ ALLOWED_DEGREES = (0.0..180.0)
ALLOWED_DIRECTIONS = %w( N n E e S s W w )
MINUTES_CONVERSION = 60
SECONDS_CONVERSION = 3600
@@ -32,8 +32,9 @@ def initialize(degrees, minutes, seconds, direction)
raise GeoPosition::Error::InvalidFloatError.new("Arguments could not be coerced to a float") unless valid_floats?([degrees, minutes, seconds])
raise GeoPosition::Error::InvalidDegreesError.new("Degrees must be between 0 and 360. %s was provided" % [degrees]) unless valid_degrees?(degrees)
raise GeoPosition::Error::InvalidMinutesError.new("Minutes must be between 0 and 60. %s was provided" % [minutes]) unless valid_minutes?(minutes)
+ raise GeoPosition::Error::InvalidSecondsError.new("Seonds must be between 0 and 60. %s was provided" % [seconds]) unless valid_seconds?(seconds)
- @degrees = degrees # Can only be between 0 and 360
+ @degrees = degrees
@minutes = minutes
@seconds = seconds
@@ -96,12 +97,16 @@ def valid_degrees?(deg)
end
def valid_minutes?(min)
- ALLOWED_MINUTES.include?(min.to_f.abs)
+ ALLOWED_SECONDS.include?(min.to_f.abs)
+ end
+
+ def valid_seconds?(sec)
+ ALLOWED_SECONDS.include?(sec.to_f.abs)
end
def convert!
result = (self.degrees + ((self.minutes/MINUTES_CONVERSION) + (self.seconds/SECONDS_CONVERSION)))
- if negative? then -(result) else result end
+ if negative? then (result * -1) else result end
end
def negative?
View
5 lib/geo_position/error.rb
@@ -4,5 +4,10 @@ module Error
autoload :InvalidFloatError, File.join(File.dirname(__FILE__), 'error/invalid_float_error')
autoload :InvalidDegreesError, File.join(File.dirname(__FILE__), 'error/invalid_degrees_error')
autoload :InvalidMinutesError, File.join(File.dirname(__FILE__), 'error/invalid_minutes_error')
+ autoload :InvalidSecondsError, File.join(File.dirname(__FILE__), 'error/invalid_seconds_error')
+
+ autoload :InvalidDmsStringError, File.join(File.dirname(__FILE__), 'error/invalid_dms_string_error')
+ autoload :InvalidLatitudeError, File.join(File.dirname(__FILE__), 'error/invalid_latitude_error')
+ autoload :InvalidLongitudeError, File.join(File.dirname(__FILE__), 'error/invalid_longitude_error')
end
end
View
6 lib/geo_position/error/invalid_dms_string_error.rb
@@ -0,0 +1,6 @@
+module GeoPosition
+ module Error
+ class InvalidDmsStringError < StandardError
+ end
+ end
+end
View
6 lib/geo_position/error/invalid_seconds_error.rb
@@ -0,0 +1,6 @@
+module GeoPosition
+ module Error
+ class InvalidSecondsError < StandardError
+ end
+ end
+end
View
49 lib/geo_position/parser/dms.rb
@@ -0,0 +1,49 @@
+module GeoPosition
+ module Parser
+ class Dms
+ FORMAT_REGEX = Regexp.new(/^(?<degrees>[\d]+)\s{1}[^\d]*(?<minutes>[\d]+)\s{1}(?<seconds>[\d]+(\.?[\d]+))\s{1}(?<direction>[nNsSeEwW]{1})/)
+
+ def initialize(dms_string)
+ sanitize_string!(dms_string)
+
+ raise GeoPosition::Error::InvalidDmsStringError.new('String could not be parsed') unless valid_string?(dms_string)
+
+ @dms_string = dms_string.to_s
+ end
+
+ def degrees
+ parsed[:degrees].to_i
+ end
+
+ def minutes
+ parsed[:minutes].to_i
+ end
+
+ def seconds
+ parsed[:seconds].to_f
+ end
+
+ def direction
+ parsed[:direction].upcase
+ end
+
+ def to_hash
+ keys = [:degrees, :minutes, :seconds, :direction]
+ keys.inject({}) { |hsh, key| hsh[key] = self.send(key); hsh }
+ end
+
+ private
+ def valid_string?(str)
+ FORMAT_REGEX.match(str.to_s)
+ end
+
+ def sanitize_string!(str)
+ str.gsub!(/['"]/, '')
+ end
+
+ def parsed
+ @dms_string.match(FORMAT_REGEX)
+ end
+ end
+ end
+end
View
8 spec/conversion/dms_spec.rb
@@ -20,13 +20,17 @@
lambda { described_class.new([12], [3], [42.42], 'w') }.should raise_error(GeoPosition::Error::InvalidFloatError)
end
- it "raises an exception if degrees are greater than 360" do
- lambda{ described_class.new(361, 12, 123, 'n') }.should raise_error(GeoPosition::Error::InvalidDegreesError)
+ it "raises an exception if degrees are greater than 180" do
+ lambda{ described_class.new(181, 12, 123, 'n') }.should raise_error(GeoPosition::Error::InvalidDegreesError)
end
it "raises an exception if minutes are greater than 60" do
lambda { described_class.new(12, 61, 12, 'n') }.should raise_error(GeoPosition::Error::InvalidMinutesError)
end
+
+ it "raises an exception if seconds are greater than 60" do
+ lambda { described_class.new(12, 30, 61, 'n') }.should raise_error(GeoPosition::Error::InvalidSecondsError)
+ end
end
it "coerces the degrees to a float" do
View
91 spec/parser/dms_spec.rb
@@ -0,0 +1,91 @@
+require 'spec_helper'
+
+describe GeoPosition::Parser::Dms do
+ let(:dms_string) { "40 deg 20' 13.20\" N" }
+ subject { described_class.new(dms_string) }
+
+ context('Error Handling') do
+ it "raises an exception if the string is not in an accepted format" do
+ lambda { described_class.new('invalid format') }.should raise_error(GeoPosition::Error::InvalidDmsStringError)
+ end
+ end
+
+ context("Simple format") do
+ let(:simple_string) { "12 12 42.42 n" }
+ subject { described_class.new(simple_string) }
+
+ it "returns 12 degrees" do
+ subject.degrees.should eql(12)
+ end
+
+ it "returns 12 minutes" do
+ subject.minutes.should eql(12)
+ end
+
+ it "returns 42.42 seconds" do
+ subject.seconds.should eql(42.42)
+ end
+
+ it "returns 'W' for the direction" do
+ subject.direction.should == "N"
+ end
+
+ it "serializes to a hash" do
+ expected = {
+ :degrees => 12,
+ :minutes => 12,
+ :seconds => 42.42,
+ :direction => 'N'
+ }
+ subject.to_hash.should == expected
+ end
+ end
+
+ context("With 'deg' in the name") do
+ it "returns 40 degrees" do
+ subject.degrees.should eql(40)
+ end
+
+ it "returns 20 minutes" do
+ subject.minutes.should eql(20)
+ end
+
+ it "returns 13.20 seconds" do
+ subject.seconds.should eql(13.20)
+ end
+
+ it "returns 'N' for the direction" do
+ subject.direction.should == "N"
+ end
+
+ it "serializes to a hash" do
+ expected = {
+ :degrees => 40,
+ :minutes => 20,
+ :seconds => 13.20,
+ :direction => 'N'
+ }
+ subject.to_hash.should == expected
+ end
+ end
+
+ it "responds to #degrees" do
+ subject.should respond_to(:degrees)
+ end
+
+ it "responds to #minutes" do
+ subject.should respond_to(:minutes)
+ end
+
+ it "responds to #seconds" do
+ subject.should respond_to(:seconds)
+ end
+
+ it "responds to #direction" do
+ subject.should respond_to(:direction)
+ end
+
+ it "responds to #to_hash" do
+ subject.should respond_to(:to_hash)
+ end
+end

0 comments on commit f485016

Please sign in to comment.