gooby 1.1.0 → 1.2.0

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