Gooby 0.9.0

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.
Files changed (98) hide show
  1. data/README +218 -0
  2. data/bin/forerunner_xml_parser.rb +28 -0
  3. data/bin/forerunner_xml_parser.sh +16 -0
  4. data/bin/forerunner_xml_splitter.rb +60 -0
  5. data/bin/gen_gmap.rb +30 -0
  6. data/bin/gen_gmap.sh +19 -0
  7. data/bin/tests_gen.rb +13 -0
  8. data/data/20041113_richmond_marathon.csv +1036 -0
  9. data/data/20041113_richmond_marathon.xml +8663 -0
  10. data/data/20050305_corporate_cup_hm.csv +251 -0
  11. data/data/20050305_corporate_cup_hm.xml +2208 -0
  12. data/data/20050430_nashville_marathon.csv +1208 -0
  13. data/data/20050430_nashville_marathon.xml +10043 -0
  14. data/data/20051119_dowd_ymca_hm.csv +251 -0
  15. data/data/20051119_dowd_ymca_hm.xml +2210 -0
  16. data/data/20051124_hyatt_turkey_trot_8K.csv +321 -0
  17. data/data/20051124_hyatt_turkey_trot_8K.xml +2651 -0
  18. data/data/forerunner_2005.xml +259620 -0
  19. data/data/forerunner_2006.xml +190853 -0
  20. data/data/forerunner_2007.xml +259014 -0
  21. data/data/geo_data.txt +171 -0
  22. data/data/phx.csv +1280 -0
  23. data/data/phx.xml +10620 -0
  24. data/data/run_2007_01_01_16_38_27.xml +2020 -0
  25. data/data/run_2007_01_06_15_27_31.xml +2020 -0
  26. data/data/run_2007_01_10_12_25_47.xml +820 -0
  27. data/data/run_2007_01_10_22_44_54.csv +112 -0
  28. data/data/run_2007_01_10_22_44_54.xml +908 -0
  29. data/data/run_2007_01_11_10_48_45.xml +1292 -0
  30. data/data/run_2007_01_13_15_37_06.xml +1964 -0
  31. data/data/run_2007_01_14_15_46_02.xml +1368 -0
  32. data/data/run_2007_01_15_14_01_48.xml +1868 -0
  33. data/data/run_2007_01_20_16_22_05.xml +1702 -0
  34. data/data/run_2007_01_27_17_32_13.xml +3626 -0
  35. data/data/run_2007_01_28_19_14_52.xml +2538 -0
  36. data/data/run_2007_02_03_14_30_20.xml +2016 -0
  37. data/data/run_2007_02_04_18_02_30.xml +1476 -0
  38. data/data/run_2007_02_17_16_29_35.xml +1236 -0
  39. data/data/run_2007_02_19_14_44_33.xml +1816 -0
  40. data/data/run_2007_02_23_15_53_55.xml +36 -0
  41. data/data/run_2007_02_23_15_55_20.xml +1296 -0
  42. data/data/run_2007_02_24_15_01_35.csv +484 -0
  43. data/data/run_2007_02_24_15_01_35.xml +3884 -0
  44. data/data/test1.txt +4 -0
  45. data/lib/cls_counter_hash.rb +83 -0
  46. data/lib/cls_delim_line.rb +40 -0
  47. data/lib/cls_dttm.rb +84 -0
  48. data/lib/cls_duration.rb +87 -0
  49. data/lib/cls_forerunner_xml_parser.rb +183 -0
  50. data/lib/cls_forerunner_xml_splitter.rb +113 -0
  51. data/lib/cls_geo_data.rb +186 -0
  52. data/lib/cls_gooby_object.rb +23 -0
  53. data/lib/cls_google_map_generator.rb +368 -0
  54. data/lib/cls_history.rb +38 -0
  55. data/lib/cls_lap.rb +27 -0
  56. data/lib/cls_line.rb +78 -0
  57. data/lib/cls_options.rb +74 -0
  58. data/lib/cls_position.rb +49 -0
  59. data/lib/cls_run.rb +199 -0
  60. data/lib/cls_simple_xml_parser.rb +46 -0
  61. data/lib/cls_test_regen.rb +187 -0
  62. data/lib/cls_track.rb +52 -0
  63. data/lib/cls_trackpoint.rb +205 -0
  64. data/lib/mod_introspect.rb +33 -0
  65. data/lib/mod_io.rb +65 -0
  66. data/lib/mod_project_info.rb +81 -0
  67. data/lib/mod_string.rb +26 -0
  68. data/lib/mod_test_helper.rb +22 -0
  69. data/samples/20041113_richmond_marathon.html +532 -0
  70. data/samples/20050305_corporate_cup_hm.html +448 -0
  71. data/samples/20050430_nashville_marathon.html +530 -0
  72. data/samples/gps_point_capture.html +54 -0
  73. data/samples/phoenix_marathon.html +542 -0
  74. data/samples/run_2007_01_10_22_44_54.html +146 -0
  75. data/samples/run_2007_02_24_15_01_35.html +298 -0
  76. data/tests/tst_cls_counter_hash.rb +105 -0
  77. data/tests/tst_cls_delim_line.rb +72 -0
  78. data/tests/tst_cls_dttm.rb +129 -0
  79. data/tests/tst_cls_duration.rb +49 -0
  80. data/tests/tst_cls_forerunner_xml_parser.rb +68 -0
  81. data/tests/tst_cls_geo_data.rb +69 -0
  82. data/tests/tst_cls_gooby_object.rb +24 -0
  83. data/tests/tst_cls_google_map_generator.rb +107 -0
  84. data/tests/tst_cls_history.rb +44 -0
  85. data/tests/tst_cls_lap.rb +36 -0
  86. data/tests/tst_cls_line.rb +108 -0
  87. data/tests/tst_cls_options.rb +77 -0
  88. data/tests/tst_cls_position.rb +64 -0
  89. data/tests/tst_cls_run.rb +140 -0
  90. data/tests/tst_cls_simple_xml_parser.rb +48 -0
  91. data/tests/tst_cls_track.rb +68 -0
  92. data/tests/tst_cls_trackpoint.rb +143 -0
  93. data/tests/tst_gooby.rb +28 -0
  94. data/tests/tst_mod_introspect.rb +30 -0
  95. data/tests/tst_mod_io.rb +51 -0
  96. data/tests/tst_mod_project_info.rb +77 -0
  97. data/tests/tst_mod_string.rb +56 -0
  98. metadata +142 -0
@@ -0,0 +1,46 @@
1
+ =begin rdoc
2
+
3
+ Sample implementation of a REXML::StreamListener SAX parser.
4
+
5
+ Gooby - Copyright 2007 by Chris Joakim.
6
+ Gooby is available under GNU General Public License (GPL) license.
7
+
8
+ =end
9
+
10
+ module Gooby
11
+
12
+ class SimpleXmlParser
13
+
14
+ include REXML::StreamListener
15
+
16
+ attr_accessor :tag_count, :watched_tags
17
+
18
+ def initialize
19
+ @tag_count = 0
20
+ @counter_hash = CounterHash.new
21
+ end
22
+
23
+ public
24
+
25
+ # SAX API method. Increments the tagname in the counter hash.
26
+ def tag_start(tag_name, attrs)
27
+ @tag_count = @tag_count + 1
28
+ @counter_hash.increment(tag_name)
29
+ end
30
+
31
+ # SAX API method. No impl.
32
+ def tag_end(tagname)
33
+ end
34
+
35
+ # SAX API method. No impl.
36
+ def text(txt)
37
+ end
38
+
39
+ # Prints the state of this object (the counter hash).
40
+ def dump
41
+ puts @counter_hash.to_s
42
+ end
43
+
44
+ end
45
+
46
+ end
@@ -0,0 +1,187 @@
1
+ =begin rdoc
2
+
3
+ This class is used to generate, on an ongoing basis, the various Gooby test
4
+ classes. Regeneration retains the current test methods, and adds stubs for
5
+ new test methods. All methods, old and new, appear in the merged output in
6
+ propper sort sequence.
7
+
8
+ Gooby - Copyright 2007 by Chris Joakim.
9
+ Gooby is available under GNU General Public License (GPL) license.
10
+
11
+ =end
12
+
13
+ module Gooby
14
+
15
+ class TestGenerator < GoobyObject
16
+
17
+ def initialize
18
+ tested_files.each { | base_rb_file |
19
+ test_file = "tst_#{base_rb_file}"
20
+ if true
21
+ @codeLines = read_lines("lib/#{base_rb_file}")
22
+ @testLines = read_lines("tests/#{test_file}")
23
+ @codeHash = Hash.new
24
+ @testHash = Hash.new
25
+ @mergedHash = Hash.new
26
+ @excludeClasses = %w( TestHelper TestGenerator )
27
+ puts "current codeLines = #{@codeLines.size}"
28
+ puts "current testLines = #{@testLines.size}"
29
+ parse_code_lines
30
+ parse_test_lines
31
+ merge_keys
32
+ regenerate(test_file)
33
+ end
34
+ }
35
+ end
36
+
37
+ private
38
+
39
+ # Produce a Hash with keys and values like the following:
40
+ # test|class|Trackpoint|deg2rad Trackpoint|deg2rad(degrees)
41
+
42
+ def parse_code_lines
43
+ type = ''
44
+ type_name = ''
45
+ meth_name = ''
46
+ @codeLines.each { | line |
47
+ line.strip!
48
+ if (line.match(/^module /))
49
+ type = 'module'
50
+ tokens = line.split
51
+ type_name = tokens[1]
52
+ elsif (line.match(/^class /))
53
+ type = 'class'
54
+ tokens = line.split
55
+ type_name = tokens[1]
56
+ elsif (line.match(/^def /))
57
+ signature = line[4...999]
58
+ short_method = parse_meth_name("#{signature}")
59
+ @codeHash["test_#{type}_#{type_name}"] = "#{type_name}"
60
+ @codeHash["test_#{type}_#{type_name}_#{short_method}"] = "#{type_name}|#{signature}"
61
+ end
62
+ }
63
+ end
64
+
65
+ def parse_meth_name(string)
66
+ string.gsub!('(', ' ')
67
+ string.gsub!(')', ' ')
68
+ tokens = string.split
69
+ tokens[0]
70
+ end
71
+
72
+ def parse_test_lines
73
+ in_method = true
74
+ method_name = 'a_start'
75
+ method_lines = Array.new
76
+ line_num = 0
77
+
78
+ @testLines.each { | line |
79
+ line_num = line_num + 1
80
+ line.chomp!
81
+ prefix = line[0...5] # ' def'
82
+ prefix21 = line[0...21] # ' ### Start of tests.'
83
+
84
+ if ((prefix == ' def') || (prefix == "\tdef"))
85
+ in_method = true
86
+ tokens = line.split
87
+ method_name = tokens[1]
88
+ method_lines = Array.new
89
+ end
90
+ if in_method
91
+ method_lines << "#{line}"
92
+ end
93
+ if prefix21 == ' ### Start of tests.'
94
+ in_method = false
95
+ @testHash["#{method_name}"] = method_lines
96
+ end
97
+ if ((prefix == ' end') || (prefix == "\tend"))
98
+ in_method = false
99
+ @testHash["#{method_name}"] = method_lines
100
+ end
101
+ }
102
+ end
103
+
104
+ def merge_keys
105
+ @codeHash.keys.sort.each { |key| @mergedHash["#{key}"] = "code" }
106
+ @testHash.keys.sort.each { |key| @mergedHash["#{key}"] = "test" }
107
+ end
108
+
109
+ def regenerate(test_file)
110
+ code = ''
111
+ @mergedHash.keys.sort.each { |key|
112
+
113
+ tokens = key.split('_')
114
+ type, name, meth = tokens[1], tokens[2], tokens[3]
115
+
116
+ processThisKey = true
117
+ @excludeClasses.each { |xc|
118
+ if xc == name
119
+ processThisKey = false
120
+ end
121
+ }
122
+
123
+ next if !processThisKey
124
+
125
+ if @testHash.has_key?(key)
126
+ # We already have a test method written in the test class,
127
+ # so keep this currently existing test code!
128
+
129
+ if @codeHash.has_key?(key)
130
+ comment = nil
131
+ else
132
+ if key != 'a_start'
133
+ comment = "# Warning: possible obsolete test method - #{key}"
134
+ end
135
+ end
136
+
137
+ code << "\n"
138
+ if comment != nil
139
+ code << "\n#{comment}"
140
+ code << "\n"
141
+ end
142
+ array = @testHash["#{key}"]
143
+ array.each { |line| code << "\n#{line}" }
144
+ else
145
+ # We don't have this test method in the current test class,
146
+ # so generate a test method stub.
147
+
148
+ code << "\n"
149
+ code << "\n def #{key}"
150
+ code << "\n"
151
+
152
+ if @gen_impl_stub
153
+ if type = 'class'
154
+ code << "\n #obj = #{type}.new"
155
+ code << "\n #result = obj.#{meth}"
156
+ code << "\n #expected = ''"
157
+ s = "\n"
158
+ s << ' #assert_equal(expected, actual, "'
159
+ s << "#{type}.#{meth} "
160
+ s << 'values are not as expected; #{result} vs #{expected}")'
161
+ code << s
162
+ else
163
+ code << "\n #result = #{type}.#{meth}"
164
+ code << "\n #expected = ''"
165
+ s = "\n"
166
+ s << ' #assert_equal(expected, actual, "'
167
+ s << "#{type}.#{meth} "
168
+ s << 'values are not as expected; #{result} vs #{expected}")'
169
+ code << s
170
+ end
171
+ end
172
+ code << "\n end"
173
+ end
174
+ }
175
+ code << "\nend" # end of class
176
+ code << "\n"
177
+ fn = "tests/#{test_file}"
178
+ out = File.new fn, "w+"
179
+ out.write code
180
+ out.flush
181
+ out.close
182
+ puts "file written: #{fn}"
183
+ end
184
+
185
+ end
186
+
187
+ end
data/lib/cls_track.rb ADDED
@@ -0,0 +1,52 @@
1
+ =begin rdoc
2
+
3
+ Instances of this class represent a <Track> aggregate object from a Forerunner
4
+ XML file. Note that a <Run> may contain more than one <Track> aggregates.
5
+
6
+ Gooby - Copyright 2007 by Chris Joakim.
7
+ Gooby is available under GNU General Public License (GPL) license.
8
+
9
+ =end
10
+
11
+ module Gooby
12
+
13
+ class Track < GoobyObject
14
+
15
+ attr_reader :number, :descr, :trackpoints
16
+
17
+ def initialize(num=0, descr='')
18
+ @number = num
19
+ @descr = descr
20
+ @trackpoints = Array.new
21
+ end
22
+
23
+ public
24
+
25
+ def add_trackpoint(tkpt)
26
+ @trackpoints.push(tkpt)
27
+ end
28
+
29
+ def size
30
+ @trackpoints.size
31
+ end
32
+
33
+ def first_tkpt
34
+ @trackpoints.size > 0 ? @trackpoints[0] : nil
35
+ end
36
+
37
+ def last_tkpt
38
+ @trackpoints.size > 0 ? @trackpoints[-1] : nil
39
+ end
40
+
41
+ def to_s
42
+ return "Trk: #{@descr} tkpts: #{size}"
43
+ end
44
+
45
+ def dump
46
+ puts "Track: '#{@descr}' tkpts: #{size}"
47
+ @trackpoints.each { |tkpt| puts tkpt.to_csv } # to_geo_s
48
+ end
49
+
50
+ end
51
+
52
+ end
@@ -0,0 +1,205 @@
1
+ =begin rdoc
2
+
3
+ Instances of this class represent a <Trackpoint> aggregate from a Forerunner
4
+ XML file. Additionally, there is distance, pace, and Google Map generation
5
+ logic in this class.
6
+
7
+ <Trackpoint>
8
+ <Position>
9
+ <Latitude>35.49577</Latitude>
10
+ <Longitude>-80.83281</Longitude>
11
+ <Altitude>232.296</Altitude>
12
+ </Position>
13
+ <Time>2007-01-06T15:27:51Z</Time>
14
+ </Trackpoint>
15
+
16
+ Gooby - Copyright 2007 by Chris Joakim.
17
+ Gooby is available under GNU General Public License (GPL) license.
18
+
19
+ =end
20
+
21
+ module Gooby
22
+
23
+ class Trackpoint < Position
24
+
25
+ attr_reader :first, :last, :number, :runNumber, :dttm, :prevTkpt, :descr
26
+ attr_reader :cumulativeDistance, :cumulativePace, :incrementalDistance, :split, :prevSplit
27
+ attr_writer :first, :last, :runNumber
28
+
29
+ def initialize(num, lat, lng, alt, time_string, descr='')
30
+ @number = num
31
+ @runNumber = 0
32
+
33
+ # initialize superclass variables:
34
+ @latitude = lat.to_s
35
+ @longitude = lng.to_s
36
+ @altitude = alt.to_s
37
+ @note = note.to_s
38
+ @dttm = DtTm.new(time_string)
39
+ @first = false
40
+ @last = false
41
+ @prevTkpt = nil
42
+ @cumulativeDistance, @split = 0.0, 0.0
43
+ @cumulativePace = ""
44
+ @descr = descr
45
+ end
46
+
47
+ public
48
+
49
+ def position
50
+ Position.new(@latitude, @longitude, @altitude, @note)
51
+ end
52
+
53
+ def to_s
54
+ "Tkpt: #{@number} #{super.to_s} date: #{@dttm.to_s} cdist: #{@cumulativeDistance}"
55
+ end
56
+
57
+ def to_csv
58
+ ss = position.to_csv
59
+ "#{@runNumber} | #{@dttm.to_s} | #{@number} | #{ss} | #{@cumulativeDistance} "
60
+ end
61
+
62
+ def to_geo_s
63
+ ss = position.to_csv
64
+ "Tkpt: #{@number} | #{ss} | #{@descr}"
65
+ end
66
+
67
+ def compute_distance_and_pace(curr_index, start_dttm, prev_cumulative_dist, prev_trackpoint, units)
68
+ @prev_tkpt = prev_trackpoint
69
+ @cumulativeDistance = prev_cumulative_dist.to_f
70
+
71
+ if @prev_tkpt
72
+ arg1 = latitude().to_f
73
+ arg2 = @prev_tkpt.latitude().to_f
74
+ arg3 = latitude().to_f
75
+ arg4 = @prev_tkpt.latitude().to_f
76
+ theta = longitude().to_f - @prev_tkpt.longitude().to_f
77
+
78
+ res1 = Math.sin(deg2rad(arg1))
79
+ res2 = Math.sin(deg2rad(arg2))
80
+ res3 = Math.cos(deg2rad(arg3))
81
+ res4 = Math.cos(deg2rad(arg4))
82
+ res5 = Math.cos(deg2rad(theta.to_f))
83
+
84
+ incremental_distance = ((res1 * res2) + (res3 * res4 * res5)).to_f
85
+
86
+ if (!incremental_distance.nan?)
87
+ incremental_distance = Math.acos(incremental_distance.to_f)
88
+ if (!incremental_distance.nan?)
89
+ incremental_distance = rad2deg(incremental_distance)
90
+ if (!incremental_distance.nan?)
91
+ incremental_distance = incremental_distance * 60 * 1.1515;
92
+ if (!incremental_distance.nan?)
93
+ if units == "K"
94
+ incremental_distance = incremental_distance * 1.609344;
95
+ end
96
+ if units == "N"
97
+ incremental_distance = incremental_distance * 0.8684;
98
+ end
99
+ @cumulativeDistance = @cumulativeDistance + incremental_distance.to_f
100
+ end
101
+ end
102
+ end
103
+ end
104
+ compute_cumulative_pace(start_dttm)
105
+ @cumulativeDistance
106
+ else
107
+ 0
108
+ end
109
+ end
110
+
111
+ def compute_cumulative_pace(start_dttm)
112
+ if @cumulativeDistance > 0
113
+ secsDiff = @dttm.seconds_diff(start_dttm)
114
+ secsMile = ((secsDiff.to_f) / (@cumulativeDistance.to_f))
115
+ minsMile = (secsMile / 60)
116
+ wholeMins = minsMile.floor
117
+ secsBal = secsMile - (wholeMins * 60)
118
+ s1 = "#{secsDiff} #{secsMile} #{minsMile} #{wholeMins} #{secsBal} #{@cumulativeDistance} | "
119
+ s2 = sprintf("%d:%2.1f", minsMile, secsBal)
120
+ @cumulativePace = "#{s2}"
121
+ else
122
+ @cumulativePace = ""
123
+ end
124
+ end
125
+
126
+ def set_split(n, tkpt)
127
+ @split, @prevSplit = n, tkpt
128
+ end
129
+
130
+ def is_split()
131
+ (@split >= 1)
132
+ end
133
+
134
+ def is_first()
135
+ @first
136
+ end
137
+
138
+ def is_last()
139
+ @last
140
+ end
141
+
142
+ def split_info(dtTm)
143
+ if is_split
144
+ hhmmss = ''
145
+ if @prevSplit
146
+ return "#{@split} #{@dttm.hhmmss_diff(@prevSplit.dttm())}"
147
+ else
148
+ return "#{@split} #{@dttm.hhmmss_diff(dtTm)}"
149
+ end
150
+ else
151
+ ""
152
+ end
153
+ end
154
+
155
+ private
156
+
157
+ def deg2rad(degrees)
158
+ (((0 + degrees) * Math::PI) / 180)
159
+ end
160
+
161
+ def rad2deg(radians)
162
+ (((0 + radians) * 180) / Math::PI)
163
+ end
164
+
165
+ public
166
+
167
+ def as_glatlng(comments, tkpt_count, curr_idx, gpoint_count, start_dttm)
168
+ if comments
169
+ secs_diff = @dttm.seconds_diff(start_dttm)
170
+ fmt_time = @dttm.hhmmss_diff(start_dttm)
171
+ "\n points.push(new GLatLng(#{latitude_as_float},#{longitude_as_float})); " +
172
+ "// #{gpoint_count} (#{curr_idx + 1} of #{tkpt_count}) #{@dttm.to_s} #{secs_diff} #{fmt_time} #{@cumulativeDistance} #{split_info(start_dttm)} "
173
+ else
174
+ "\n points.push(new GLatLng(#{latitude_as_float},#{longitude_as_float})); "
175
+ end
176
+ end
177
+
178
+ def as_info_window_html(checkpoint, start_dttm)
179
+ s = "\"<table align='left'>"
180
+ if checkpoint
181
+ secs_diff = @dttm.seconds_diff(start_dttm)
182
+ fmt_time = @dttm.hhmmss_diff(start_dttm)
183
+
184
+ if checkpoint == 'Start'
185
+ s << "<tr><td colspan='2'><b>Start!</b></td></tr>"
186
+ elsif checkpoint == 'Finish'
187
+ s << "<tr><td colspan='2'><b>Finish!</b></td></tr>"
188
+ else
189
+ s << "<tr><td colspan='2'><b>Checkpoint #{checkpoint}</b></td></tr>"
190
+ end
191
+ s << "<tr><td>Distance: </td><td>#{@cumulativeDistance}</td></tr>"
192
+ s << "<tr><td>Time of Day: </td><td>#{@dttm.to_s} </td></tr>"
193
+ s << "<tr><td>Elapsed Time: </td><td>#{fmt_time} </td></tr>"
194
+ s << "<tr><td>Average Pace: </td><td>#{@cumulativePace} </td></tr>"
195
+ s << "<tr><td>Lat/Lng: </td><td>#{latitude_as_float} , #{longitude_as_float} </td></tr>"
196
+ s << "<tr><td>Altitude: </td><td>#{altitude_as_float}m </td></tr>"
197
+ s
198
+ end
199
+ s << "</table>\""
200
+ s
201
+ end
202
+
203
+ end
204
+
205
+ end