GpsTrail 0.3
Sign up to get free protection for your applications and to get access to all the features.
- 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
|
+
|