GpsTrail 0.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/lib/baseconverter.rb +12 -0
- data/lib/converters/forerunner301.rb +54 -0
- data/lib/fileutil.rb +10 -0
- data/lib/folder_template.kml +17 -0
- data/lib/gpstrail.rb +113 -0
- data/lib/journey.rb +70 -0
- data/lib/line_template.kml +28 -0
- data/lib/point.rb +51 -0
- data/lib/sample.rb +26 -0
- data/lib/template.rb +18 -0
- data/readme +43 -0
- data/test/tc_fileutil.rb +13 -0
- data/test/tc_journey.rb +37 -0
- data/test/tc_point.rb +40 -0
- data/test/tc_sample.rb +28 -0
- data/test/tc_template.kml +1 -0
- data/test/tc_template.rb +32 -0
- data/test/ts_gpstrail.rb +7 -0
- metadata +63 -0
@@ -0,0 +1,54 @@
|
|
1
|
+
require 'rexml/document'
|
2
|
+
require 'journey'
|
3
|
+
require 'point'
|
4
|
+
require 'sample'
|
5
|
+
require 'fileutil'
|
6
|
+
require 'template'
|
7
|
+
|
8
|
+
include REXML
|
9
|
+
|
10
|
+
class Forerunner301 < BaseConverter
|
11
|
+
|
12
|
+
@@device_name = "Forerunner301"
|
13
|
+
|
14
|
+
def convert(xml_doc)
|
15
|
+
convert_to_domain_model(xml_doc)
|
16
|
+
end
|
17
|
+
|
18
|
+
def convert_to_domain_model(doc)
|
19
|
+
journeys = Array.new
|
20
|
+
doc.elements.each("//Run/") do |journey_xml|
|
21
|
+
journeys.push(process_journey(journey_xml))
|
22
|
+
end
|
23
|
+
journeys.sort
|
24
|
+
end
|
25
|
+
|
26
|
+
def process_journey(journey_xml)
|
27
|
+
journey = Journey.new('Run')
|
28
|
+
|
29
|
+
journey_xml.each_element("Lap/Track/Trackpoint") do |trackpoint|
|
30
|
+
process_trackpoint(journey, trackpoint)
|
31
|
+
end
|
32
|
+
|
33
|
+
journey
|
34
|
+
end
|
35
|
+
|
36
|
+
def process_trackpoint(journey, trackpoint)
|
37
|
+
position = trackpoint.get_elements("Position")[0]
|
38
|
+
|
39
|
+
if(position)
|
40
|
+
time = trackpoint.get_elements("Time")[0].get_text
|
41
|
+
lat = position.get_elements("LatitudeDegrees")[0].get_text
|
42
|
+
long = position.get_elements("LongitudeDegrees")[0].get_text
|
43
|
+
alt = position.get_elements("AltitudeMeters")[0].get_text
|
44
|
+
point = Point.new(lat.to_s.to_f, long.to_s.to_f, alt.to_s.to_f)
|
45
|
+
sample = Sample.new(time, point)
|
46
|
+
journey.add_sample(sample)
|
47
|
+
end
|
48
|
+
end
|
49
|
+
|
50
|
+
def to_s
|
51
|
+
@@device_name
|
52
|
+
end
|
53
|
+
|
54
|
+
end
|
data/lib/fileutil.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
2
|
+
<kml xmlns="http://earth.google.com/kml/2.0">
|
3
|
+
<Document>
|
4
|
+
<name>Forerunner 301</name>
|
5
|
+
<visibility>0</visibility>
|
6
|
+
<open>1</open>
|
7
|
+
<Folder>
|
8
|
+
<name>Forerunner 301</name>
|
9
|
+
<open>1</open>
|
10
|
+
<Folder>
|
11
|
+
<name>${journey_type}</name>
|
12
|
+
<open>1</open>
|
13
|
+
${placemarks}
|
14
|
+
</Folder>
|
15
|
+
</Folder>
|
16
|
+
</Document>
|
17
|
+
</kml>
|
data/lib/gpstrail.rb
ADDED
@@ -0,0 +1,113 @@
|
|
1
|
+
#
|
2
|
+
# == Synonpsis
|
3
|
+
#
|
4
|
+
# GpsTrail lets you view your GPS trips in Google Earth.
|
5
|
+
#
|
6
|
+
# == Usage
|
7
|
+
#
|
8
|
+
# ruby gpstrail.rb [ -ld] | [ -h | -- help] [ -d gpsdevice] [ -f file ]
|
9
|
+
#
|
10
|
+
# -ld
|
11
|
+
# List the supported GPS devices
|
12
|
+
# -d
|
13
|
+
# Specify a listed device
|
14
|
+
# -f
|
15
|
+
# Specify the file containing the output from the specified device
|
16
|
+
#
|
17
|
+
# == Example
|
18
|
+
#
|
19
|
+
# ruby gpstrail.rb -d Forerunner301 -f "C:\Sport\history.hst"
|
20
|
+
|
21
|
+
require 'find'
|
22
|
+
require 'rexml/document'
|
23
|
+
require 'journey'
|
24
|
+
require 'point'
|
25
|
+
require 'sample'
|
26
|
+
require 'fileutil'
|
27
|
+
require 'template'
|
28
|
+
require 'baseconverter'
|
29
|
+
require 'rdoc/usage'
|
30
|
+
require 'optparse'
|
31
|
+
require 'ostruct'
|
32
|
+
|
33
|
+
include REXML
|
34
|
+
|
35
|
+
class GpsTrail
|
36
|
+
|
37
|
+
def process(file_to_process, converter)
|
38
|
+
start_time = Time.now
|
39
|
+
puts "Processing #{file_to_process}\nPlease wait..."
|
40
|
+
STDOUT.flush
|
41
|
+
xml_doc = Document.new(File.open(file_to_process))
|
42
|
+
journeys = converter.convert(xml_doc)
|
43
|
+
|
44
|
+
placemarks_kml = ""
|
45
|
+
journeys.each do |journey|
|
46
|
+
placemarks_kml += create_placemark_kml(journey)
|
47
|
+
end
|
48
|
+
|
49
|
+
map = {"placemarks" => placemarks_kml, "journey_type" => "Run"}
|
50
|
+
kml = Template.load_and_substitute('folder_template.kml', map)
|
51
|
+
|
52
|
+
kml_file_name = File.join(ENV['HOMEPATH'], "gpstrail.kml")
|
53
|
+
kml_file = File.new(kml_file_name, "w")
|
54
|
+
kml_file.puts(kml)
|
55
|
+
kml_file.close
|
56
|
+
|
57
|
+
total_time = Time.now - start_time
|
58
|
+
puts "Output written to #{kml_file_name}"
|
59
|
+
puts "Processed #{journeys.size} journeys in #{total_time}s"
|
60
|
+
end
|
61
|
+
|
62
|
+
def create_placemark_kml(journey)
|
63
|
+
look_at_lat, look_at_long = journey.find_center
|
64
|
+
coords = create_coords_list(journey)
|
65
|
+
|
66
|
+
map = { "look_at_long" => look_at_long.to_s, "look_at_lat" => look_at_lat.to_s,
|
67
|
+
"range" => journey.find_distance_of_longest_vector.to_s,
|
68
|
+
"tilt" => 45.to_s, "heading" => 0.to_s, "coordinates" => coords,
|
69
|
+
"name" => journey.start_time.to_s}
|
70
|
+
|
71
|
+
Template.load_and_substitute('line_template.kml', map)
|
72
|
+
end
|
73
|
+
|
74
|
+
def create_coords_list(journey)
|
75
|
+
coords = ""
|
76
|
+
journey.samples.each do |sample|
|
77
|
+
point = sample.point
|
78
|
+
coords += point.long.to_s + "," + point.lat.to_s + ",0\n"
|
79
|
+
end
|
80
|
+
coords
|
81
|
+
end
|
82
|
+
|
83
|
+
def load_converters
|
84
|
+
Find.find("./converters") do |filename|
|
85
|
+
load filename if filename =~ /rb$/
|
86
|
+
end
|
87
|
+
|
88
|
+
BaseConverter.converters
|
89
|
+
end
|
90
|
+
|
91
|
+
end
|
92
|
+
|
93
|
+
$: << 'converters'
|
94
|
+
options = OpenStruct.new
|
95
|
+
|
96
|
+
opts = OptionParser.new
|
97
|
+
opts.on("-h", "--help") {RDoc::usage}
|
98
|
+
opts.on("-ld") do
|
99
|
+
puts "Device List:\n"
|
100
|
+
GpsTrail.new.load_converters.each {|converter| puts "\t#{converter}" }
|
101
|
+
options.devices_listed = true
|
102
|
+
end
|
103
|
+
opts.on("-d" "=dev_name") {|dn| options.device_name = dn}
|
104
|
+
opts.on("-f", "=file_name") {|fn| options.file_name = fn}
|
105
|
+
opts.parse(ARGV) rescue RDoc::usage
|
106
|
+
|
107
|
+
if(options == OpenStruct.new)
|
108
|
+
RDoc::usage
|
109
|
+
elsif(options.device_name && options.file_name)
|
110
|
+
require options.device_name
|
111
|
+
dev = Object.const_get(options.device_name).new
|
112
|
+
GpsTrail.new.process(options.file_name, dev)
|
113
|
+
end
|
data/lib/journey.rb
ADDED
@@ -0,0 +1,70 @@
|
|
1
|
+
class Journey
|
2
|
+
include Enumerable
|
3
|
+
|
4
|
+
attr_reader :samples, :type
|
5
|
+
|
6
|
+
def initialize(type)
|
7
|
+
@samples = Array.new
|
8
|
+
@type = type
|
9
|
+
@max_long_index, @min_long_index = 0, 0
|
10
|
+
@max_lat_index, @min_lat_index = 0, 0
|
11
|
+
end
|
12
|
+
|
13
|
+
def add_sample(sample)
|
14
|
+
@samples.push(sample)
|
15
|
+
new_long = sample.long
|
16
|
+
new_lat = sample.lat
|
17
|
+
|
18
|
+
@max_long_index = @samples.length-1 if new_long > @samples[@max_long_index].long
|
19
|
+
@min_long_index = @samples.length-1 if new_long < @samples[@min_long_index].long
|
20
|
+
@max_lat_index = @samples.length-1 if new_lat > @samples[@max_lat_index].lat
|
21
|
+
@min_lat_index = @samples.length-1 if new_lat < @samples[@min_lat_index].lat
|
22
|
+
end
|
23
|
+
|
24
|
+
def [](index)
|
25
|
+
@samples[index]
|
26
|
+
end
|
27
|
+
|
28
|
+
def find_center
|
29
|
+
lat = (@samples[@max_lat_index].lat + @samples[@min_lat_index].lat) / 2
|
30
|
+
long = (@samples[@max_long_index].long + @samples[@min_long_index].long) / 2
|
31
|
+
[lat, long]
|
32
|
+
end
|
33
|
+
|
34
|
+
def find_distance_of_longest_vector
|
35
|
+
max_long_point = @samples[@max_long_index].point
|
36
|
+
min_long_point = @samples[@min_long_index].point
|
37
|
+
long_distance = max_long_point.distance_from(min_long_point)
|
38
|
+
|
39
|
+
max_lat_point = @samples[@max_lat_index].point
|
40
|
+
min_lat_point = @samples[@min_lat_index].point
|
41
|
+
lat_distance = max_lat_point.distance_from(min_lat_point)
|
42
|
+
[lat_distance, long_distance].max
|
43
|
+
end
|
44
|
+
|
45
|
+
def size
|
46
|
+
@samples.size
|
47
|
+
end
|
48
|
+
|
49
|
+
def each
|
50
|
+
samples.each {|sample| yield sample}
|
51
|
+
end
|
52
|
+
|
53
|
+
def <=>(other)
|
54
|
+
self.start_time <=> other.start_time
|
55
|
+
end
|
56
|
+
|
57
|
+
def start_time
|
58
|
+
samples[0].time
|
59
|
+
end
|
60
|
+
|
61
|
+
def to_s
|
62
|
+
time = @samples[0].time
|
63
|
+
journey = "#{journey_type} at #{time}:\n"
|
64
|
+
@samples.each do |sample|
|
65
|
+
journey += sample.to_s + "\n"
|
66
|
+
end
|
67
|
+
journey
|
68
|
+
end
|
69
|
+
|
70
|
+
end
|
@@ -0,0 +1,28 @@
|
|
1
|
+
<Placemark>
|
2
|
+
<name>${name}</name>
|
3
|
+
<LookAt>
|
4
|
+
<longitude>${look_at_long}</longitude>
|
5
|
+
<latitude>${look_at_lat}</latitude>
|
6
|
+
<range>${range}</range>
|
7
|
+
<tilt>${tilt}</tilt>
|
8
|
+
<heading>${heading}</heading>
|
9
|
+
</LookAt>
|
10
|
+
<visibility>0</visibility>
|
11
|
+
<open>0</open>
|
12
|
+
<Style>
|
13
|
+
<LineStyle>
|
14
|
+
<color>ff00ffff</color>
|
15
|
+
</LineStyle>
|
16
|
+
<PolyStyle>
|
17
|
+
<color>7f00ff00</color>
|
18
|
+
</PolyStyle>
|
19
|
+
</Style>
|
20
|
+
<LineString>
|
21
|
+
<extrude>0</extrude>
|
22
|
+
<tessellate>1</tessellate>
|
23
|
+
<altitudeMode>absolute</altitudeMode>
|
24
|
+
<coordinates>
|
25
|
+
${coordinates}
|
26
|
+
</coordinates>
|
27
|
+
</LineString>
|
28
|
+
</Placemark>
|
data/lib/point.rb
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# A Point specifies a latitude, longitude and elevation
|
2
|
+
# Note that the elevation is not considered in distance calculations
|
3
|
+
class Point
|
4
|
+
|
5
|
+
AVG_CIRCUMFERANCE_OF_EARTH = 6372795
|
6
|
+
attr_reader :lat, :long, :elevation
|
7
|
+
|
8
|
+
def initialize(lat, long, elevation=0.0)
|
9
|
+
if(lat.nil? or long.nil?)
|
10
|
+
raise ArgumentError
|
11
|
+
end
|
12
|
+
|
13
|
+
@lat = lat
|
14
|
+
@long = long
|
15
|
+
@elevation = elevation
|
16
|
+
end
|
17
|
+
|
18
|
+
def to_s
|
19
|
+
"Lat: #@lat Long: #@long Elevation: #@elevation"
|
20
|
+
end
|
21
|
+
|
22
|
+
# Return the distance between one point and another in metres.
|
23
|
+
# Note that distance_from does not take elevation into account.
|
24
|
+
# The formula used is based on great circle distance formula from spherical
|
25
|
+
# goemetry, but as the Earth is not a sphere a small error may result (up to 0.5%).
|
26
|
+
# The formula used is that listed on http://en.wikipedia.org/wiki/Great-circle_distance
|
27
|
+
def distance_from(other)
|
28
|
+
lat1, lat2 = Point.degrees_to_radians(@lat), Point.degrees_to_radians(other.lat)
|
29
|
+
long1, long2 = Point.degrees_to_radians(@long), Point.degrees_to_radians(other.long)
|
30
|
+
long_diff = (long1 - long2).abs
|
31
|
+
|
32
|
+
dvd1 = (Math.cos(lat2) * Math.sin(long_diff))**2
|
33
|
+
dvd2 = ((Math.cos(lat1)*Math.sin(lat2)) - (Math.sin(lat1)*Math.cos(lat2)*Math.cos(long_diff)))**2
|
34
|
+
dividend = Math.sqrt(dvd1 + dvd2)
|
35
|
+
|
36
|
+
dvr1 = Math.sin(lat1)*Math.sin(lat2)
|
37
|
+
dvr2 = Math.cos(lat1)*Math.cos(lat2)*Math.cos(long_diff)
|
38
|
+
divisor = dvr1 + dvr2
|
39
|
+
|
40
|
+
arctan_arg = dividend / divisor
|
41
|
+
|
42
|
+
angular_diff = Math.atan(arctan_arg)
|
43
|
+
|
44
|
+
angular_diff * AVG_CIRCUMFERANCE_OF_EARTH
|
45
|
+
end
|
46
|
+
|
47
|
+
def Point.degrees_to_radians(degrees)
|
48
|
+
degrees * ((2*Math::PI)/360)
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
data/lib/sample.rb
ADDED
@@ -0,0 +1,26 @@
|
|
1
|
+
class Sample
|
2
|
+
|
3
|
+
attr_reader :time, :point
|
4
|
+
|
5
|
+
def initialize(time, point)
|
6
|
+
if(time.nil? or point.nil?)
|
7
|
+
raise ArgumentError
|
8
|
+
end
|
9
|
+
|
10
|
+
@time = time
|
11
|
+
@point = point
|
12
|
+
end
|
13
|
+
|
14
|
+
def to_s
|
15
|
+
@time.to_s + " " + @point.to_s
|
16
|
+
end
|
17
|
+
|
18
|
+
def lat
|
19
|
+
point.lat
|
20
|
+
end
|
21
|
+
|
22
|
+
def long
|
23
|
+
point.long
|
24
|
+
end
|
25
|
+
|
26
|
+
end
|
data/lib/template.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
class Template
|
2
|
+
|
3
|
+
def Template.substitute(template, key_value_map)
|
4
|
+
result = template
|
5
|
+
key_value_map.each do |key, value|
|
6
|
+
result = result.gsub("${#{key}}", value)
|
7
|
+
end
|
8
|
+
result
|
9
|
+
end
|
10
|
+
|
11
|
+
def Template.load_and_substitute(template_name, key_value_map)
|
12
|
+
f = File.new(template_name)
|
13
|
+
template = f.readlines.to_s
|
14
|
+
f.close
|
15
|
+
Template.substitute(template, key_value_map)
|
16
|
+
end
|
17
|
+
|
18
|
+
end
|
data/readme
ADDED
@@ -0,0 +1,43 @@
|
|
1
|
+
# == Overview
|
2
|
+
#
|
3
|
+
# GpsTrail lets you view your GPS trips in Google Earth.
|
4
|
+
#
|
5
|
+
# == How To Use
|
6
|
+
#
|
7
|
+
# 1. Open Garmin Training Center
|
8
|
+
# 2. Click File -> Export History... -> Save
|
9
|
+
# 3. Run converter.rb and specify the location of the file you just saved
|
10
|
+
# 4. In Windows Explorer, navigate to the output directory
|
11
|
+
# (e.g. C:\Documents and Settings\Paul) and double click on forerunner301.kml
|
12
|
+
#
|
13
|
+
# Note: You'll need a Ruby interpreter installed on your Windows system in order
|
14
|
+
# to run the converter. If you don't have one, download the installer from
|
15
|
+
# http://rubyinstaller.rubyforge.org/wiki/wiki.pl
|
16
|
+
#
|
17
|
+
# == Known Issues (in the order I intend to fix them)
|
18
|
+
#
|
19
|
+
# - Currently only exports Runs (not Bike rides, Multisport or Other)
|
20
|
+
# - The KML file could become prohibitively large
|
21
|
+
# - Try KMZ rather than KML
|
22
|
+
# - Offer an option to create a single Google Earth file per trip
|
23
|
+
# - The message specifying the output file could be improved
|
24
|
+
# - Sometimes trips aren't perfectly centered in the Google Earth frame
|
25
|
+
# - Some paths could be tidied (e.g. tc_template.rb)
|
26
|
+
#
|
27
|
+
# == Contact
|
28
|
+
#
|
29
|
+
# Comments and suggestions welcome at paul.p.carey@gmail.com
|
30
|
+
#
|
31
|
+
# == Copyright 2006 Paul Carey
|
32
|
+
#
|
33
|
+
# Licensed under the Apache License, Version 2.0 (the "License");
|
34
|
+
# you may not use this file except in compliance with the License.
|
35
|
+
# You may obtain a copy of the License at
|
36
|
+
#
|
37
|
+
# http://www.apache.org/licenses/LICENSE-2.0
|
38
|
+
#
|
39
|
+
# Unless required by applicable law or agreed to in writing, software
|
40
|
+
# distributed under the License is distributed on an "AS IS" BASIS,
|
41
|
+
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
42
|
+
# See the License for the specific language governing permissions and
|
43
|
+
# limitations under the License.
|
data/test/tc_fileutil.rb
ADDED
@@ -0,0 +1,13 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'fileutil'
|
3
|
+
|
4
|
+
class FileUtilTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_convert_to_win_filename
|
7
|
+
chars = %W(\\ / : * ? \" < > |)
|
8
|
+
chars.each do |char|
|
9
|
+
assert_equal("1-1", FileUtil.convert_to_win_filename!("1#{char}1"))
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
end
|
data/test/tc_journey.rb
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'journey'
|
3
|
+
require 'point'
|
4
|
+
require 'sample'
|
5
|
+
|
6
|
+
class JourneyTest < Test::Unit::TestCase
|
7
|
+
|
8
|
+
def setup
|
9
|
+
now = Time.now
|
10
|
+
later = now + 60
|
11
|
+
p1 = Point.new(54.0, 2.0, 70)
|
12
|
+
p2 = Point.new(55.0, -1.0, 80)
|
13
|
+
@s1 = Sample.new(now, p1)
|
14
|
+
@s2 = Sample.new(later, p2)
|
15
|
+
|
16
|
+
@j1 = Journey.new('run')
|
17
|
+
@j1.add_sample(@s1)
|
18
|
+
@j1.add_sample(@s2)
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_journey_type
|
22
|
+
assert_equal('run', @j1.type)
|
23
|
+
end
|
24
|
+
|
25
|
+
def test_run
|
26
|
+
assert_equal(2, @j1.size)
|
27
|
+
assert_equal(@s1, @j1[0])
|
28
|
+
assert_equal(@s2, @j1[1])
|
29
|
+
end
|
30
|
+
|
31
|
+
def test_find_center
|
32
|
+
lat, long = @j1.find_center
|
33
|
+
assert_equal(54.5, lat)
|
34
|
+
assert_equal(0.5, long)
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
data/test/tc_point.rb
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'point'
|
3
|
+
|
4
|
+
class PointTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_valid_point
|
7
|
+
p1 = Point.new(2.3, 4.5, 50)
|
8
|
+
assert_equal(2.3, p1.lat)
|
9
|
+
assert_equal(4.5, p1.long)
|
10
|
+
assert_equal(50, p1.elevation)
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_variable_length_constructor
|
14
|
+
p1 = Point.new(5, 10)
|
15
|
+
assert_equal(0, p1.elevation)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_nil_atts_passed_to_constructor
|
19
|
+
assert_raise(ArgumentError) {Point.new(nil, 1, 1)}
|
20
|
+
assert_raise(ArgumentError) {Point.new(1, nil, 1)}
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_degrees_to_radians
|
24
|
+
assert_in_delta(0.0174532925, Point.degrees_to_radians(1), 0.00001)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_distance1
|
28
|
+
bna = Point.new(36.12, -86.67)
|
29
|
+
lax = Point.new(33.94, -118.4)
|
30
|
+
distance = bna.distance_from(lax)
|
31
|
+
assert_in_delta(2887000, distance, 10000)
|
32
|
+
end
|
33
|
+
|
34
|
+
def test_distance2
|
35
|
+
dublin = Point.new(53.21, -6.15)
|
36
|
+
lusaka = Point.new(-15.28, 28.16)
|
37
|
+
assert_in_delta(8300000, dublin.distance_from(lusaka), 10000)
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
data/test/tc_sample.rb
ADDED
@@ -0,0 +1,28 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'point'
|
3
|
+
require 'sample'
|
4
|
+
|
5
|
+
class SampleTest < Test::Unit::TestCase
|
6
|
+
|
7
|
+
def setup
|
8
|
+
@now = Time.now
|
9
|
+
@p1 = Point.new(54, 6.8, 70)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_valid_sample
|
13
|
+
s1 = Sample.new(@now, @p1)
|
14
|
+
assert_equal(@now, s1.time)
|
15
|
+
assert_equal(@p1, s1.point)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_nil_time
|
19
|
+
assert_raise(ArgumentError) { Sample.new(nil, @p1) }
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_nil_point
|
23
|
+
assert_raise(ArgumentError) do
|
24
|
+
Sample.new(@now, nil)
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
end
|
@@ -0,0 +1 @@
|
|
1
|
+
How ${pronoun} doin'?
|
data/test/tc_template.rb
ADDED
@@ -0,0 +1,32 @@
|
|
1
|
+
require 'test/unit'
|
2
|
+
require 'template'
|
3
|
+
|
4
|
+
class TemplateTest < Test::Unit::TestCase
|
5
|
+
|
6
|
+
def test_no_substitution
|
7
|
+
s = "hello name"
|
8
|
+
result = Template.substitute(s, Hash.new)
|
9
|
+
assert_equal("hello name", result)
|
10
|
+
end
|
11
|
+
|
12
|
+
def test_single_substitution
|
13
|
+
s = "hello ${name}"
|
14
|
+
m = { 'name' => 'paul'}
|
15
|
+
result = Template.substitute(s, m)
|
16
|
+
assert_equal("hello paul", result)
|
17
|
+
end
|
18
|
+
|
19
|
+
def test_multiple_substitution
|
20
|
+
s = "Hello ${name}. This is <${de_ity}> speaking. It's good to meet you ${name}."
|
21
|
+
m = { 'name' => 'Paul', 'de_ity' => 'God'}
|
22
|
+
result = Template.substitute(s, m)
|
23
|
+
assert_equal("Hello Paul. This is <God> speaking. It's good to meet you Paul.", result)
|
24
|
+
end
|
25
|
+
|
26
|
+
def test_substitution_from_file
|
27
|
+
m = { 'pronoun' => 'you'}
|
28
|
+
result = Template.load_and_substitute('../test/tc_template.kml', m)
|
29
|
+
assert_equal("How you doin'?", result)
|
30
|
+
end
|
31
|
+
|
32
|
+
end
|
data/test/ts_gpstrail.rb
ADDED
metadata
ADDED
@@ -0,0 +1,63 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
rubygems_version: 0.8.11
|
3
|
+
specification_version: 1
|
4
|
+
name: GpsTrail
|
5
|
+
version: !ruby/object:Gem::Version
|
6
|
+
version: "0.3"
|
7
|
+
date: 2006-02-28 00:00:00 +00:00
|
8
|
+
summary: GpsTrail lets you view your Forerunner 301 trips in Google Earth
|
9
|
+
require_paths:
|
10
|
+
- lib
|
11
|
+
email: paul.p.carey@gmail.com
|
12
|
+
homepage:
|
13
|
+
rubyforge_project:
|
14
|
+
description:
|
15
|
+
autorequire: converter
|
16
|
+
default_executable:
|
17
|
+
bindir: bin
|
18
|
+
has_rdoc: true
|
19
|
+
required_ruby_version: !ruby/object:Gem::Version::Requirement
|
20
|
+
requirements:
|
21
|
+
- - ">"
|
22
|
+
- !ruby/object:Gem::Version
|
23
|
+
version: 0.0.0
|
24
|
+
version:
|
25
|
+
platform: ruby
|
26
|
+
signing_key:
|
27
|
+
cert_chain:
|
28
|
+
authors:
|
29
|
+
- Paul Carey
|
30
|
+
files:
|
31
|
+
- lib/baseconverter.rb
|
32
|
+
- lib/converters
|
33
|
+
- lib/fileutil.rb
|
34
|
+
- lib/folder_template.kml
|
35
|
+
- lib/gpstrail.rb
|
36
|
+
- lib/journey.rb
|
37
|
+
- lib/line_template.kml
|
38
|
+
- lib/point.rb
|
39
|
+
- lib/sample.rb
|
40
|
+
- lib/template.rb
|
41
|
+
- lib/converters/forerunner301.rb
|
42
|
+
- test/tc_fileutil.rb
|
43
|
+
- test/tc_journey.rb
|
44
|
+
- test/tc_point.rb
|
45
|
+
- test/tc_sample.rb
|
46
|
+
- test/tc_template.kml
|
47
|
+
- test/tc_template.rb
|
48
|
+
- test/ts_gpstrail.rb
|
49
|
+
- readme
|
50
|
+
test_files:
|
51
|
+
- test/ts_gpstrail.rb
|
52
|
+
rdoc_options: []
|
53
|
+
|
54
|
+
extra_rdoc_files:
|
55
|
+
- readme
|
56
|
+
executables: []
|
57
|
+
|
58
|
+
extensions: []
|
59
|
+
|
60
|
+
requirements: []
|
61
|
+
|
62
|
+
dependencies: []
|
63
|
+
|