gooby 1.1.0 → 1.2.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 (78) hide show
  1. data/README +200 -35
  2. data/bin/code_scan.rb +1 -3
  3. data/bin/gooby_been_there.rb +12 -14
  4. data/bin/gooby_config.rb +11 -3
  5. data/bin/gooby_csv_validation.rb +50 -0
  6. data/bin/gooby_first_trackpoints_as_poi.rb +31 -0
  7. data/bin/gooby_gen_gmap.rb +7 -3
  8. data/bin/gooby_parser.rb +7 -5
  9. data/bin/gooby_splitter.rb +7 -4
  10. data/bin/gooby_version.rb +7 -3
  11. data/bin/run_all.sh +12 -2
  12. data/bin/run_been_there.sh +4 -1
  13. data/bin/run_config.sh +12 -0
  14. data/bin/run_csv_validation.sh +15 -0
  15. data/bin/run_db_gen.sh +1 -1
  16. data/bin/run_db_load.sh +1 -1
  17. data/bin/run_first_trackpoints_as_poi.sh +16 -0
  18. data/bin/run_gen_gmaps.sh +7 -6
  19. data/bin/run_parse_full.sh +45 -0
  20. data/bin/run_parse_samples.sh +21 -0
  21. data/bin/run_split.sh +5 -4
  22. data/bin/run_version.sh +12 -0
  23. data/config/gooby_config.yaml +130 -131
  24. data/data/20050305_corporate_cup_hm.csv +251 -251
  25. data/data/20050430_nashville_marathon_km.csv +1208 -0
  26. data/data/20060115_phoenix_marathon.csv +1280 -1280
  27. data/data/20070101_davidson_11m.csv +251 -0
  28. data/data/{davidson_11m_20070101.xml → 20070101_davidson_11m.xml} +0 -0
  29. data/data/{davidson_5K_20070505.xml → 20070505_davidson_5k.xml} +0 -0
  30. data/data/20070505_davidson_5k_km.csv +286 -0
  31. data/data/hrm1.csv +5 -0
  32. data/lib/gooby.rb +27 -3144
  33. data/lib/gooby_code_scanner.rb +288 -0
  34. data/lib/gooby_command.rb +210 -0
  35. data/lib/gooby_configuration.rb +123 -0
  36. data/lib/gooby_counter_hash.rb +95 -0
  37. data/lib/gooby_course.rb +117 -0
  38. data/lib/gooby_csv_point.rb +71 -0
  39. data/lib/gooby_csv_reader.rb +71 -0
  40. data/lib/gooby_csv_run.rb +28 -0
  41. data/lib/gooby_delim_line.rb +42 -0
  42. data/lib/gooby_dttm.rb +87 -0
  43. data/lib/gooby_duration.rb +86 -0
  44. data/lib/gooby_forerunner_xml_parser.rb +191 -0
  45. data/lib/gooby_forerunner_xml_splitter.rb +115 -0
  46. data/lib/gooby_google_map_generator.rb +385 -0
  47. data/lib/gooby_history.rb +41 -0
  48. data/lib/gooby_kernel.rb +163 -0
  49. data/lib/gooby_lap.rb +30 -0
  50. data/lib/gooby_line.rb +80 -0
  51. data/lib/gooby_object.rb +22 -0
  52. data/lib/gooby_point.rb +172 -0
  53. data/lib/gooby_run.rb +213 -0
  54. data/lib/gooby_simple_xml_parser.rb +50 -0
  55. data/lib/gooby_test_helper.rb +23 -0
  56. data/lib/gooby_track.rb +47 -0
  57. data/lib/gooby_track_point.rb +229 -0
  58. data/lib/gooby_training_center_xml_parser.rb +224 -0
  59. data/lib/gooby_training_center_xml_splitter.rb +116 -0
  60. data/lib/split_code.sh +29 -0
  61. data/samples/20050305_corporate_cup_hm.html +269 -269
  62. data/samples/20050430_nashville_marathon.html +1410 -1266
  63. data/samples/20060115_phoenix_marathon.html +1311 -1311
  64. data/samples/{davidson_11m_20070101.html → 20070101_davidson_11m.html} +267 -267
  65. data/samples/20070505_davidson_5k.html +413 -0
  66. data/samples/been_there.txt +52 -704
  67. data/samples/hrm1.html +87 -0
  68. data/sql/gooby.ddl +20 -16
  69. data/sql/gooby_load.dml +36 -9
  70. metadata +48 -14
  71. data/bin/example_usage.txt +0 -55
  72. data/bin/run_parse.sh +0 -43
  73. data/bin/run_parse_named.sh +0 -19
  74. data/data/20050430_nashville_marathon.csv +0 -1208
  75. data/data/davidson_11m_20070101.csv +0 -251
  76. data/data/davidson_5K_20070505.csv +0 -286
  77. data/data/test1.txt +0 -4
  78. data/samples/davidson_5K_20070505.html +0 -395
@@ -0,0 +1,288 @@
1
+ =begin
2
+
3
+ Gooby = Google APIs + Ruby
4
+ Gooby - Copyright 2007 by Chris Joakim.
5
+ Gooby is available under GNU General Public License (GPL) license.
6
+
7
+ =end
8
+
9
+ module Gooby
10
+
11
+ class CodeScanner < GoobyObject
12
+
13
+ def initialize(argv)
14
+
15
+ function = 'outline'
16
+ if (argv.size > 1)
17
+ function = argv[1]
18
+ end
19
+
20
+ @code_file = argv[0]
21
+ @test_file = "ts_#{@code_file}"
22
+ @code_lines = read_lines("lib/#{@code_file}")
23
+ @test_lines = read_lines("tests/#{@test_file}")
24
+
25
+ puts "code lines = #{@code_lines.size}"
26
+ puts "test lines = #{@test_lines.size}"
27
+
28
+ @tokens_hash = CounterHash.new
29
+ @module_names_hash = CounterHash.new
30
+ @class_names_hash = CounterHash.new
31
+ @method_names_hash = CounterHash.new
32
+ @mc_line_num_array = Array.new
33
+ @type_names = Hash.new
34
+ @code_hash = Hash.new
35
+ @test_hash = Hash.new
36
+ @api_hash = Hash.new
37
+ @merged_hash = Hash.new
38
+ @exclude_classes = Array.new
39
+
40
+ regenerate_test_suite if (function == 'regenerate_test_suite')
41
+ regenerate_test_suite if (function == 'tests')
42
+
43
+ model_class_outline if (function == 'model_class_outline')
44
+ model_class_outline if (function == 'outline')
45
+
46
+ quick_reference_guide if (function == 'quick_reference_guide')
47
+ quick_reference_guide if (function == 'qrg')
48
+
49
+ mcm_references if (function == 'mcm_references')
50
+ mcm_references if (function == 'mcm')
51
+ end
52
+
53
+ private
54
+
55
+ def regenerate_test_suite
56
+ @exclude_classes = %w( TestHelper CodeScanner )
57
+ parse_code_lines
58
+ parse_test_lines
59
+ merge_keys
60
+ regenerate(@test_file)
61
+ end
62
+
63
+ def model_class_outline
64
+ parse_code_lines
65
+ @mc_line_num_array.each { |line|
66
+ tokens = tokenize(line)
67
+ type = tokens[0].ljust(6)
68
+ name = tokens[1]
69
+ count = tokens[2].rjust(6)
70
+ #puts " #{count} #{type} #{name}"
71
+ puts "cp gooby.rb gooby_#{name.downcase}.rb"
72
+ }
73
+ puts hello
74
+ end
75
+
76
+ def quick_reference_guide
77
+ parse_code_lines
78
+ determine_longest_names
79
+ quick_reference_guide_report('module')
80
+ quick_reference_guide_report('class')
81
+ end
82
+
83
+ def quick_reference_guide_report(obj_type)
84
+ @api_hash.keys.sort.each { |key|
85
+ val = @api_hash[key]
86
+ tokens = tokenize(key, '|')
87
+ if (tokens[0] == obj_type)
88
+ s1 = tokens[0].ljust(6)
89
+ s2 = tokens[1].ljust(@longest_classname + 1)
90
+ s3 = tokens[2]
91
+ # s = sprintf("%6s '%30s %s'", tokens[0], tokens[1], tokens[2])
92
+ puts "#{s1} #{s2} #{s3}"
93
+ end
94
+ }
95
+ end
96
+
97
+ def determine_longest_names
98
+ @longest_classname = 0
99
+ @api_hash.keys.sort.each { |key|
100
+ tokens = tokenize(@api_hash[key], '|')
101
+ @longest_classname = tokens[1].size if tokens[1].size > @longest_classname
102
+ }
103
+ end
104
+
105
+ def mcm_references
106
+ parse_code_lines
107
+ determine_longest_names
108
+ @module_names_hash.sorted_keys.each { |name|
109
+ count = @tokens_hash.value(name)
110
+ puts "module: #{name} (#{count})"
111
+ }
112
+ @class_names_hash.sorted_keys.each { |name|
113
+ count = @tokens_hash.value(name)
114
+ puts "class: #{name} (#{count})"
115
+ }
116
+ @method_names_hash.sorted_keys.each { |name|
117
+ count = @tokens_hash.value(name)
118
+ puts "method: #{name} (#{count})"
119
+ }
120
+ end
121
+
122
+ def parse_code_lines
123
+ type = ''
124
+ type_name = ''
125
+ meth_name = ''
126
+ line_number = 0
127
+ @code_lines.each { | line |
128
+ line_number = line_number + 1
129
+ line.strip!
130
+ if (line.match(/^module /))
131
+ type = 'module'
132
+ tokens = line.split
133
+ type_name = tokens[1]
134
+ @module_names_hash.increment(type_name)
135
+ @mc_line_num_array << "module #{type_name} #{line_number}"
136
+ elsif (line.match(/^class /))
137
+ type = 'class'
138
+ tokens = line.split
139
+ type_name = tokens[1]
140
+ @class_names_hash.increment(type_name)
141
+ @mc_line_num_array << "class #{type_name} #{line_number}"
142
+ elsif (line.match(/^def /))
143
+ signature = line[4...999]
144
+ short_method = parse_meth_name("#{signature}")
145
+ @code_hash["test_#{type}_#{type_name}"] = "#{type_name}"
146
+ @code_hash["test_#{type}_#{type_name}_#{short_method}"] = "#{type_name}|#{signature}"
147
+ @api_hash["#{type}|#{type_name}|#{signature}" ] = "#{type}|#{type_name}|#{signature}"
148
+ @method_names_hash.increment(short_method)
149
+ end
150
+ increment_tokens(line)
151
+ }
152
+ end
153
+
154
+ def increment_tokens(line)
155
+ # see http://www.asciitable.com/
156
+ s = ''
157
+ line.each_byte { |b|
158
+ keep = false
159
+ keep = true if ((b >= 65) && (b <= 90)) # A-Z
160
+ keep = true if ((b >= 97) && (b <= 122)) # a-z
161
+ keep = true if ((b >= 48) && (b <= 57)) # 0-9
162
+ keep = true if (b == 95) # _
163
+ keep = true if (b == 64) # @
164
+ keep = true if (b == 63) # ?
165
+ keep = true if (b == 33) # !
166
+ if keep
167
+ s << b.chr
168
+ else
169
+ s << ' '
170
+ end
171
+ }
172
+ @tokens_hash.increment_tokens(s)
173
+ end
174
+
175
+ def parse_meth_name(string)
176
+ string.gsub!('(', ' ')
177
+ string.gsub!(')', ' ')
178
+ tokens = string.split
179
+ tokens[0]
180
+ end
181
+
182
+ def parse_test_lines
183
+ in_zone = true
184
+ method_name = 'a_start'
185
+ method_lines = Array.new
186
+ line_num = 0
187
+
188
+ @test_lines.each { | line |
189
+ line_num = line_num + 1
190
+ line.chomp!
191
+ prefix = line[0...5] # ' def' or ' end'
192
+ prefix42 = line [0..42]
193
+
194
+ if ((prefix == ' def') || (prefix == "\tdef"))
195
+ in_zone = true
196
+ tokens = line.split
197
+ method_name = tokens[1]
198
+ method_lines = Array.new
199
+ end
200
+
201
+ if in_zone
202
+ method_lines << "#{line}"
203
+ end
204
+ if (prefix42 == ' # beginning of tests - keep this marker')
205
+ in_zone = false
206
+ @test_hash["aaa"] = method_lines
207
+ end
208
+ if ((prefix == ' end') || (prefix == "\tend"))
209
+ in_zone = false
210
+ @test_hash["#{method_name}"] = method_lines
211
+ end
212
+ }
213
+ end
214
+
215
+ def merge_keys
216
+ @merged_hash = Hash.new
217
+ @code_hash.keys.sort.each { |key| @merged_hash["#{key}"] = "code" }
218
+ @test_hash.keys.sort.each { |key| @merged_hash["#{key}"] = "test" }
219
+ end
220
+
221
+ def regenerate(test_file)
222
+ code = ''
223
+ @merged_hash.keys.sort.each { |key|
224
+ tokens = key.split('_')
225
+ type, name, meth = tokens[1], tokens[2], tokens[3]
226
+
227
+ processThisKey = true
228
+ @exclude_classes.each { |xc| (xc == name) ? processThisKey = false : x = 0 }
229
+
230
+ next if !processThisKey
231
+
232
+ if @test_hash.has_key?(key)
233
+ # We already have a test method written in the test class,
234
+ # so keep this currently existing test code!
235
+
236
+ if @code_hash.has_key?(key)
237
+ comment = nil
238
+ else
239
+ if key != 'aaa'
240
+ comment = "# Warning: possible obsolete test method - #{key}"
241
+ end
242
+ end
243
+
244
+ code << "\n" if key != 'aaa'
245
+ code << "\n#{comment}\n" if comment
246
+ array = @test_hash["#{key}"]
247
+ array.each { |line| code << "\n#{line}" }
248
+ else
249
+ # We don't have this test method in the current test class,
250
+ # so generate a test method stub.
251
+ code << "\n"
252
+ code << "\n def #{key}"
253
+ code << "\n"
254
+
255
+ if @gen_impl_stub
256
+ if type = 'class'
257
+ code << "\n #obj = #{type}.new"
258
+ code << "\n #result = obj.#{meth}"
259
+ code << "\n #expected = ''"
260
+ s = "\n"
261
+ s << ' #assert_equal(expected, actual, "'
262
+ s << "#{type}.#{meth} "
263
+ s << 'values are not as expected; #{result} vs #{expected}")'
264
+ code << s
265
+ else
266
+ code << "\n #result = #{type}.#{meth}"
267
+ code << "\n #expected = ''"
268
+ s = "\n"
269
+ s << ' #assert_equal(expected, actual, "'
270
+ s << "#{type}.#{meth} "
271
+ s << 'values are not as expected; #{result} vs #{expected}")'
272
+ code << s
273
+ end
274
+ end
275
+ code << "\n\n end"
276
+ end
277
+ }
278
+ code << "\n\nend # end of class\n"
279
+ fn = "tests/#{test_file}"
280
+ out = File.new fn, "w+"
281
+ out.write code
282
+ out.flush
283
+ out.close
284
+ puts "file written: #{fn}"
285
+ end
286
+ end
287
+
288
+ end # end of module
@@ -0,0 +1,210 @@
1
+ =begin
2
+
3
+ Gooby = Google APIs + Ruby
4
+ Gooby - Copyright 2007 by Chris Joakim.
5
+ Gooby is available under GNU General Public License (GPL) license.
6
+
7
+ =end
8
+
9
+ module Gooby
10
+
11
+ class GoobyCommand < GoobyObject
12
+
13
+ attr_reader :configuration, :csv_points, :csv_col_names
14
+
15
+ def initialize(gooby_yaml_filename=nil)
16
+ @configuration = Gooby::Configuration.init(gooby_yaml_filename)
17
+ end
18
+
19
+ def display_configuration
20
+ #puts @configuration.to_s
21
+ @configuration.print_all
22
+ end
23
+
24
+ def display_version
25
+ s = "# #{project_name} #{project_version_number} #{project_date}. #{project_copyright}."
26
+ puts s
27
+ end
28
+
29
+ def split_garmin_export_file(argv)
30
+ if (argv == nil)
31
+ puts "ERROR: no ARGV args passed."
32
+ elsif (argv.size < 3)
33
+ puts ""
34
+ puts "Invalid program args; three args required - format, input filename, output directory"
35
+ puts " the first arg, format, should be one of: garmin201, garmin205, garmin305, etc."
36
+ puts " the second arg is the input filename - which is a garmin export file"
37
+ puts " the third arg is the output directory where the split files are written to\n\n"
38
+ puts "Please correct the program arguments and try again. \n\n"
39
+ else
40
+ format = argv[0].downcase
41
+ filename = argv[1]
42
+ out_dir = argv[2]
43
+
44
+ if (format == 'garmin201')
45
+ split_garmin_forerunner_logbook_xml(filename, out_dir)
46
+ else
47
+ split_garmin_training_center_xml(filename, out_dir)
48
+ end
49
+ end
50
+ end
51
+
52
+ def split_garmin_forerunner_logbook_xml(xml_filename, out_dir)
53
+ splitter = Gooby::ForerunnerXmlSplitter.new(xml_filename, out_dir)
54
+ splitter.split
55
+ end
56
+
57
+ def split_garmin_training_center_xml(tcx_filename, out_dir)
58
+ splitter = Gooby::TrainingCenterXmlSplitter.new(tcx_filename, out_dir)
59
+ splitter.split
60
+ end
61
+
62
+ def parse_garmin_xml_file(argv)
63
+ if (argv == nil)
64
+ puts "ERROR: no ARGV args passed."
65
+ elsif (argv.size < 2)
66
+ puts ""
67
+ puts "Invalid program args; three args required - format, uom, input (xml) filename"
68
+ puts " the first arg, format, should be one of: garmin201, garmin205, garmin305, etc."
69
+ puts " the second arg, unit-of-measure, should be either 'english' or 'metric'."
70
+ puts " the third arg, input xml filename, was produced by the Gooby 'splitter.rb' program."
71
+ puts "Please correct the program arguments and try again. \n\n"
72
+ else
73
+ format = argv[0].downcase
74
+ uom = argv[1].downcase
75
+ filename = argv[2]
76
+ puts Trackpoint.csv_header
77
+ if (format == 'garmin201')
78
+ parse_garmin_forerunner_logbook_xml(filename, uom)
79
+ else
80
+ parse_garmin_training_center_xml(filename, uom)
81
+ end
82
+ end
83
+ end
84
+
85
+ def parse_garmin_forerunner_logbook_xml(xml_filename, uom)
86
+ handler = Gooby::ForerunnerXmlParser.new(uom)
87
+ Document.parse_stream((File.new xml_filename), handler)
88
+ handler.put_all_run_tkpt_csv()
89
+ end
90
+
91
+ def parse_garmin_training_center_xml(tcx_filename, uom)
92
+ handler = Gooby::TrainingCenterXmlParser.new(uom)
93
+ Document.parse_stream((File.new tcx_filename), handler)
94
+ handler.put_all_run_tkpt_csv()
95
+ end
96
+
97
+ def read_csv_files(array_of_filenames, record_index=0)
98
+ @csv_reader = Gooby::CsvReader.new(array_of_filenames)
99
+ @csv_points = @csv_reader.read
100
+ @csv_col_names = @csv_reader.col_names
101
+ puts @csv_reader.to_s
102
+ if (record_index > 0)
103
+ @csv_reader.display_formatted_record(record_index)
104
+ end
105
+ @csv_points
106
+ end
107
+
108
+ def been_there(course_id, proximity=0.0070, uom='deg')
109
+ unless @csv_points
110
+ puts "You must first invoke method 'read_csv_files' with a list of parsed CSV filenames."
111
+ return
112
+ end
113
+ course = configuration.get_course("#{course_id}")
114
+ unless course
115
+ puts "Unable to find course id '#{course_id}' in the gooby config yaml file."
116
+ return
117
+ end
118
+ puts ''
119
+ # collect the csv_points into run arrays
120
+ @curr_run_id = 'x'
121
+ @csv_runs = Array.new
122
+ @csv_points.each { |csv_point|
123
+ if (csv_point.run_id == @curr_run_id)
124
+ @curr_run.add_point(csv_point)
125
+ else
126
+ @curr_run_id = csv_point.run_id
127
+ @curr_run = Gooby::CsvRun.new(@curr_run_id)
128
+ @curr_run.add_point(csv_point)
129
+ @csv_runs << @curr_run
130
+ end
131
+ }
132
+
133
+ # iterate the runs - looking for a match vs the course
134
+ @csv_runs.each { |csv_run|
135
+ puts "Scanning run id '#{csv_run.id}', point count= #{csv_run.points.size}" if false
136
+ run_points = csv_run.points
137
+ course.reset
138
+ course.points.each { |course_point|
139
+ closest_diff = 999
140
+ closest_point = nil
141
+ run_points.each { |run_point|
142
+ diff = course_point.degrees_diff(run_point)
143
+ if ((diff < proximity) && (diff < closest_diff))
144
+ closest_diff = diff
145
+ closest_point = run_point
146
+ closest_point.degrees_diff = diff
147
+ course.matched(course_point.number, run_point)
148
+ end
149
+ }
150
+ }
151
+ if course.matched?
152
+ puts "Course '#{course.name}' matched vs run id '#{csv_run.id}'"
153
+ course.display_matches
154
+ else
155
+ puts "course not matched" if false
156
+ end
157
+ }
158
+ end
159
+
160
+ def first_trackpoints_as_poi(date_string)
161
+ # cat 2007_poi.csv | sort +4n > 2007_poi_sorted.csv
162
+ home_point = Point.new('35.495469007128285', '-80.83213448524475', '752.5755445824', 'Home at South Faulkner Way Stopsign') # TODO
163
+ # poi.123 35.484114 -80.820274 788.7661681152 2007-06-30 10:48:32 1.01214244648463
164
+ @csv_points.each { |csv_point|
165
+ proximity = home_point.proximity(csv_point, 'm')
166
+ if (csv_point.lap_number == 1)
167
+ if date_string
168
+ if csv_point.date == date_string
169
+ puts sprintf("%s %s %s %s %s %s %s", 'poi. ',
170
+ character_align('.', csv_point.latitude, 3, 7),
171
+ character_align('.', csv_point.longitude, 4, 7),
172
+ character_align('.', csv_point.altitude, 5, 11),
173
+ character_align('.', proximity.to_s, 3, 20),
174
+ csv_point.date,
175
+ csv_point.time,
176
+ csv_point.distance)
177
+ end
178
+ else
179
+ puts sprintf("%s %s %s %s %s %s %s", 'poi. ',
180
+ character_align('.', csv_point.latitude, 3, 7),
181
+ character_align('.', csv_point.longitude, 4, 7),
182
+ character_align('.', csv_point.altitude, 5, 11),
183
+ character_align('.', proximity.to_s, 3, 20),
184
+ csv_point.date,
185
+ csv_point.time,
186
+ csv_point.distance)
187
+ end
188
+ end
189
+ }
190
+ end
191
+
192
+ def generate_google_map(argv)
193
+ if (argv == nil)
194
+ puts "ERROR: no ARGV args passed."
195
+ elsif (argv.size < 1)
196
+ puts ""
197
+ puts "Invalid program args; one required - input csv filename"
198
+ puts " the first arg, csv filename, was produced by the Gooby 'parser.rb' program."
199
+ puts "Please correct the program arguments and try again. \n\n"
200
+ else
201
+ csv_filename = argv[0]
202
+ configuration = Gooby::Configuration.get_config
203
+ generator = Gooby::GoogleMapGenerator.new(csv_filename)
204
+ generator.generate_page(configuration)
205
+ end
206
+ end
207
+
208
+ end
209
+
210
+ end # end of module