m26 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 15f995dd18b557e11789a50ab805f0c55c9bf931
4
+ data.tar.gz: 5fed1890e8b2ac97842881bd2c097cf249c832aa
5
+ SHA512:
6
+ metadata.gz: ed11f1da2c64966757214c257fb598a94da563aa2cf4ebe6721da7e2622e043e663609028c1dcbca5f64fcf2cc867d43b4e988b6fc4d14f7333b43667ab6bd9a
7
+ data.tar.gz: fcb4b724ae2bb05b4958bf86361028c2b0ffef16b175a187bade30c79087451ec1dd5c783033110479f65080aaf18076695cd5c9e9ec1e895156e1da88cbea16
data/lib/m26.rb ADDED
@@ -0,0 +1,16 @@
1
+ =begin
2
+
3
+ Copyright (C) 2013 Chris Joakim, JoakimSoftware LLC
4
+
5
+ =end
6
+
7
+ puts "loading m26"
8
+
9
+ require 'rubygems'
10
+
11
+ require 'm26_ruby_extensions'
12
+ require 'm26_age'
13
+ require 'm26_constants'
14
+ require 'm26_distance'
15
+ require 'm26_elapsed_time'
16
+ require 'm26_speed'
data/lib/m26_age.rb ADDED
@@ -0,0 +1,109 @@
1
+ =begin
2
+
3
+ Copyright (C) 2013 Chris Joakim, JoakimSoftware LLC
4
+
5
+ =end
6
+
7
+ module M26
8
+
9
+ class Age
10
+ @@leap_years = []
11
+
12
+ attr_accessor :dob, :as_of_date, :yymm, :days, :whole_years, :float_years
13
+
14
+ def self.leap_years
15
+ @@leap_years
16
+ end
17
+
18
+ def leap_years
19
+ @@leap_years
20
+ end
21
+
22
+ def to_s
23
+ "Age - dob: #{dob} as_of: #{as_of_date } days: #{days} whole: #{whole_years} float: #{float_years} mp: #{max_pulse}"
24
+ end
25
+
26
+ def initialize(birth_yyyy_mm_dd, as_of_yyyy_mm_dd)
27
+ initialize_leap_years if @@leap_years.size == 0
28
+ @dob = Date.parse(birth_yyyy_mm_dd)
29
+ @as_of_date = Date.parse(as_of_yyyy_mm_dd)
30
+ @days = as_of_date - dob
31
+ @yymm = (dob.mon * 100) + (dob.day)
32
+
33
+ if relation_to_birthday < 0
34
+ @whole_years = as_of_date.year - dob.year - 1
35
+ else
36
+ @whole_years = as_of_date.year - dob.year
37
+ end
38
+
39
+ pbd, nbd = prev_birthday, next_birthday
40
+ ndays = (leap_year?(nbd.year) ? 366 : 365)
41
+ days_diff = as_of_date - pbd
42
+ if relation_to_birthday == 0
43
+ @float_years = @whole_years.to_f
44
+ else
45
+ @float_years = @whole_years.to_f + (days_diff.to_f / ndays.to_f)
46
+ end
47
+ end
48
+
49
+ def initialize_leap_years
50
+ (1900..2100).to_a.each { | y |
51
+ d = Date.parse("#{y}-01-01")
52
+ @@leap_years << y if d.leap?
53
+ }
54
+ end
55
+
56
+ def leap_year?(y)
57
+ @@leap_years.include?(y)
58
+ end
59
+
60
+ def next_birthday
61
+ bb = relation_to_birthday
62
+ if bb >= 0
63
+ Date.parse("#{as_of_date.year + 1}-#{dob_mm_dd}")
64
+ else
65
+ Date.parse("#{as_of_date.year}-#{dob_mm_dd}")
66
+ end
67
+ end
68
+
69
+ def prev_birthday
70
+ bb = relation_to_birthday
71
+ if bb > 0
72
+ Date.parse("#{as_of_date.year}-#{dob_mm_dd}")
73
+ else
74
+ Date.parse("#{as_of_date.year - 1}-#{dob_mm_dd}")
75
+ end
76
+ end
77
+
78
+ def dob_mm_dd
79
+ "#{dob.month}-#{dob.mday}"
80
+ end
81
+
82
+ def max_pulse
83
+ if float_years <= 20
84
+ 200.0
85
+ else
86
+ 220.0 - float_years
87
+ end
88
+ end
89
+
90
+ private
91
+
92
+ # return -1 (before), 0 (on), or 1 (after)
93
+ def relation_to_birthday
94
+ if as_of_date.mon < dob.mon
95
+ return -1
96
+ elsif as_of_date.mon == dob.mon
97
+ if as_of_date.mday < dob.mday
98
+ return -1
99
+ end
100
+ if as_of_date.mday == dob.mday
101
+ return 0
102
+ end
103
+ end
104
+ 1
105
+ end
106
+
107
+ end
108
+
109
+ end
@@ -0,0 +1,27 @@
1
+ =begin
2
+
3
+ Copyright (C) 2013 Chris Joakim, JoakimSoftware LLC
4
+
5
+ =end
6
+
7
+ module M26
8
+
9
+ module Constants
10
+
11
+ VERSION = '0.0.1'
12
+ DATE = '2013-08-29'
13
+ AUTHOR = 'Chris Joakim'
14
+ EMAIL = 'cjoakim@bellsouth.net'
15
+
16
+ UOM_MILES = 'm'
17
+ UOM_KILOMETERS = 'k'
18
+ UOM_YARDS = 'y'
19
+
20
+ KILOMETERS_PER_MILE = 1.61290322581
21
+ YARDS_PER_MILE = 1760.0
22
+ MILES_PER_KILOMETER = 0.62
23
+ YARDS_PER_KILOMETER = 1091.2
24
+ SECONDS_PER_HOUR = 3600
25
+ end
26
+
27
+ end
@@ -0,0 +1,82 @@
1
+ =begin
2
+
3
+ Copyright (C) 2013 Chris Joakim, JoakimSoftware LLC
4
+
5
+ =end
6
+
7
+ module M26
8
+
9
+ class Distance
10
+
11
+ include M26::Constants
12
+
13
+ attr_accessor :value, :uom
14
+
15
+ def initialize(v, um=UOM_MILES)
16
+ @value = v.to_f
17
+ @uom = um
18
+ end
19
+
20
+ public
21
+
22
+ def get_miles
23
+ case @uom
24
+ when UOM_MILES
25
+ return @value
26
+ when UOM_KILOMETERS
27
+ return @value / KILOMETERS_PER_MILE
28
+ when UOM_YARDS
29
+ return @value / YARDS_PER_MILE
30
+ end
31
+ end
32
+
33
+ def get_kilometers
34
+ case @uom
35
+ when UOM_MILES
36
+ return @value * KILOMETERS_PER_MILE
37
+ when UOM_KILOMETERS
38
+ return @value
39
+ when UOM_YARDS
40
+ return (@value / YARDS_PER_MILE) / MILES_PER_KILOMETER
41
+ end
42
+ end
43
+
44
+ def get_yards
45
+ case @uom
46
+ when UOM_MILES
47
+ return @value * YARDS_PER_MILE
48
+ when UOM_KILOMETERS
49
+ return (@value * MILES_PER_KILOMETER) * YARDS_PER_MILE
50
+ when UOM_YARDS
51
+ return @value
52
+ end
53
+ end
54
+
55
+ def subtract(another_instance)
56
+ if (another_instance != nil)
57
+ Distance.new(@value - another_instance.value, @uom)
58
+ else
59
+ nil
60
+ end
61
+ end
62
+
63
+ def valid?
64
+ return false if @value == nil
65
+ return false if @value < 0
66
+ return true if @uom == UOM_MILES
67
+ return true if @uom == UOM_KILOMETERS
68
+ return true if @uom == UOM_YARDS
69
+ false
70
+ end
71
+
72
+ def to_s
73
+ return "Distance: #{@value} #{@uom}"
74
+ end
75
+
76
+ def print_string
77
+ return to_s << " #{get_miles()} #{get_kilometers()} #{get_yards()}"
78
+ end
79
+
80
+ end
81
+
82
+ end
@@ -0,0 +1,92 @@
1
+ =begin
2
+
3
+ Copyright (C) 2013 Chris Joakim, JoakimSoftware LLC
4
+
5
+ =end
6
+
7
+ module M26
8
+
9
+ class ElapsedTime
10
+
11
+ include M26::Constants
12
+
13
+ attr_accessor :hh, :mm, :ss, :secs
14
+
15
+ public
16
+
17
+ def initialize(raw_val)
18
+ @hh, @mm, @ss = 0, 0, 0.0;
19
+ if (raw_val.kind_of? String)
20
+ initialize_string(raw_val)
21
+ else
22
+ initialize_number(raw_val)
23
+ end
24
+ end
25
+
26
+ def as_hours
27
+ @secs / SECONDS_PER_HOUR.to_f
28
+ end
29
+
30
+ def as_hhmmss
31
+ return "#{zero_pad(@hh)}:#{zero_pad(@mm)}:#{zero_pad(@ss)}"
32
+ end
33
+
34
+ def subtract(another_instance)
35
+ h1 = as_hours
36
+ h2 = another_instance.as_hours
37
+ h3 = h1 - h2
38
+ ElapsedTime.new(h3 * SECONDS_PER_HOUR)
39
+ end
40
+
41
+ def to_s
42
+ return "ElapsedTime: hh=#{@hh} mm=#{@mm} ss=#{@ss} secs=#{@secs} as_hours=#{as_hours()} as_hhmmss=#{as_hhmmss()}"
43
+ end
44
+
45
+ def print_string
46
+ return to_s << " #{@secs} #{as_hours}"
47
+ end
48
+
49
+ private
50
+
51
+ def initialize_string(raw_val)
52
+ array = raw_val.strip.split(':');
53
+ if (array.length == 3)
54
+ @hh = array[0].to_i
55
+ @mm = array[1].to_i
56
+ @ss = array[2].to_f
57
+ @ss = 59 if @ss > 59
58
+ end
59
+
60
+ if (array.length == 2)
61
+ @mm = array[0].to_i
62
+ @ss = array[1].to_f
63
+ @ss = 59 if @ss > 59
64
+ end
65
+
66
+ if (array.length == 1)
67
+ @ss = array[0].to_f.round
68
+ end
69
+
70
+ @secs = (@hh.to_i * SECONDS_PER_HOUR) + (@mm.to_i * 60) + (@ss.to_f);
71
+ end
72
+
73
+ def initialize_number(raw_val)
74
+ @secs = raw_val.to_i
75
+ @hh = (@secs / SECONDS_PER_HOUR).to_i
76
+ rem = @secs - (@hh * SECONDS_PER_HOUR)
77
+ @mm = (rem / 60).to_i
78
+ @ss = rem - (@mm * 60).to_i
79
+ @ss = 59 if @ss > 59
80
+ end
81
+
82
+ def zero_pad(val)
83
+ if (val.to_i < 10)
84
+ return '0' + val.to_s
85
+ else
86
+ return '' + val.to_s
87
+ end
88
+ end
89
+
90
+ end
91
+
92
+ end
@@ -0,0 +1,15 @@
1
+ =begin
2
+
3
+ Copyright (C) 2013 Chris Joakim, JoakimSoftware LLC
4
+
5
+ =end
6
+
7
+ class Float
8
+
9
+ def approximate?(val, tolerance=0.0001)
10
+ return false if (self) > (val + tolerance)
11
+ return false if (self) < (val - tolerance)
12
+ true
13
+ end
14
+
15
+ end
data/lib/m26_speed.rb ADDED
@@ -0,0 +1,130 @@
1
+ =begin
2
+
3
+ Copyright (C) 2013 Chris Joakim, JoakimSoftware LLC
4
+
5
+ =end
6
+
7
+ module M26
8
+
9
+ class Speed
10
+
11
+ include M26::Constants
12
+
13
+ attr_accessor :distance, :elapsed_time
14
+ attr_accessor :evt_age, :base_age, :ag_factor, :ag_secs, :ag_time, :ag_speed
15
+
16
+ def initialize(dist, et)
17
+ @distance = dist
18
+ @elapsed_time = et
19
+ @mph = 0
20
+ end
21
+
22
+ def self.from_pace_per_mile(ppm)
23
+ dist = M26::Distance.new(1.0)
24
+ tokens = ppm.split(':')
25
+ secs = ((tokens[0].to_i * 60) + tokens[1].to_i).to_f
26
+ et = M26::ElapsedTime.new(secs)
27
+ M26::Speed.new(dist, et)
28
+ end
29
+
30
+ def self.calculate_average_speed(s1, s2, t1, t2)
31
+ speed1, speed2, etime1, etime2 = s1, s2, t1, t2
32
+ total_time = (etime1.secs + etime2.secs).to_f
33
+ speed1_pct = ((etime1.secs).to_f) / total_time.to_f
34
+ speed2_pct = ((etime2.secs).to_f) / total_time.to_f
35
+ spm1 = ((speed1.seconds_per_mile).to_f) * speed1_pct
36
+ spm2 = ((speed2.seconds_per_mile).to_f) * speed2_pct
37
+ spm = spm1 + spm2
38
+ tpm = M26::ElapsedTime.new(spm)
39
+ M26::Speed.new(Distance.new(1.0), tpm)
40
+ end
41
+
42
+ public
43
+
44
+ def get_mph
45
+ num = @distance.get_miles.to_f
46
+ den = @elapsed_time.as_hours
47
+ num / den
48
+ end
49
+
50
+ def get_kph
51
+ @distance.get_kilometers / @elapsed_time.as_hours();
52
+ end
53
+
54
+ def get_yph
55
+ @distance.get_yards / @elapsed_time.as_hours();
56
+ end
57
+
58
+ def pace_per_mile
59
+ spm = seconds_per_mile()
60
+ mm = (spm / 60).floor;
61
+ ss = spm - (mm * 60);
62
+
63
+ if (ss < 10)
64
+ ss = '0' + ss.to_s;
65
+ else
66
+ ss = '' + ss.to_s;
67
+ end
68
+ ss = ss.slice(0..4)
69
+ return "#{mm}:#{ss}";
70
+ end
71
+
72
+ def seconds_per_mile
73
+ @elapsed_time.secs / @distance.get_miles
74
+ end
75
+
76
+ def projected_time(another_distance, algorithm='simple', pow=1.06, debug=false)
77
+ if (algorithm == 'riegel')
78
+ t1 = @elapsed_time.secs
79
+ d1 = @distance.get_miles
80
+ d2 = another_distance.get_miles
81
+ t2 = t1.to_f * ((d2.to_f / d1.to_f) ** pow)
82
+ et = ElapsedTime.new(t2);
83
+ return et.as_hhmmss
84
+ else
85
+ projSecs = seconds_per_mile() * another_distance.get_miles();
86
+ et = ElapsedTime.new(projSecs);
87
+ return et.as_hhmmss
88
+ end
89
+ end
90
+
91
+ def projected_times(space_delim_distances)
92
+ results = {}
93
+ array = space_delim_distances.split(' ');
94
+ array.each { |d|
95
+ another_distance = Distance.new(d.to_f, "m");
96
+ projSecs = seconds_per_mile() * another_distance.get_miles();
97
+ et = ElapsedTime.new(projSecs);
98
+ results["#{d}"] = et.as_hhmmss;
99
+ }
100
+ return results;
101
+ end
102
+
103
+ def to_s
104
+ return "Speed: miles=#{@distance.get_miles} seconds=#{@elapsed_time.secs} mph=#{get_mph()} kph=#{get_kph()} yph=#{get_yph()}"
105
+ end
106
+
107
+ def age_graded(dob, event_yyyy_mm_dd, base_yyyy_mm_dd)
108
+ @evt_age = M26::Age.new(dob, event_yyyy_mm_dd)
109
+ @base_age = M26::Age.new(dob, base_yyyy_mm_dd)
110
+ @ag_factor = (base_age.max_pulse / evt_age.max_pulse).to_f
111
+ @ag_secs = (elapsed_time.secs.to_f) * ag_factor
112
+ @ag_time = M26::ElapsedTime.new(ag_secs)
113
+ @ag_speed = M26::Speed.new(distance, ag_time)
114
+ # if false
115
+ # puts "evt age: #{evt_age.to_s} #{evt_age.date}"
116
+ # puts "base age: #{base_age.to_s} #{base_age.date}"
117
+ # puts "ag_factor: #{ag_factor}"
118
+ # puts "ag_secs: #{ag_secs}"
119
+ # puts "ag_speed: #{ag_speed.to_s}"
120
+ # puts "base pace: #{pace_per_mile}"
121
+ # puts "base time: #{elapsed_time.as_hhmmss}"
122
+ # puts "ag pace: #{ag_speed.pace_per_mile}"
123
+ # puts "ag time: #{ag_speed.elapsed_time.as_hhmmss}"
124
+ # end
125
+ @ag_speed
126
+ end
127
+
128
+ end
129
+
130
+ end
metadata ADDED
@@ -0,0 +1,64 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: m26
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.0.1
5
+ platform: ruby
6
+ authors:
7
+ - Chris Joakim
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2013-08-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: rspec
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - '>='
18
+ - !ruby/object:Gem::Version
19
+ version: 2.14.1
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - '>='
25
+ - !ruby/object:Gem::Version
26
+ version: 2.14.1
27
+ description: A ruby gem for running, cycling, and swimming calculations.
28
+ email: cjoakim@bellsouth.net
29
+ executables: []
30
+ extensions: []
31
+ extra_rdoc_files: []
32
+ files:
33
+ - lib/m26.rb
34
+ - lib/m26_age.rb
35
+ - lib/m26_constants.rb
36
+ - lib/m26_distance.rb
37
+ - lib/m26_elapsed_time.rb
38
+ - lib/m26_ruby_extensions.rb
39
+ - lib/m26_speed.rb
40
+ homepage: http://rubygems.org/gems/m26
41
+ licenses:
42
+ - GPL-3
43
+ metadata: {}
44
+ post_install_message:
45
+ rdoc_options: []
46
+ require_paths:
47
+ - lib
48
+ required_ruby_version: !ruby/object:Gem::Requirement
49
+ requirements:
50
+ - - '>='
51
+ - !ruby/object:Gem::Version
52
+ version: 2.0.0
53
+ required_rubygems_version: !ruby/object:Gem::Requirement
54
+ requirements:
55
+ - - '>='
56
+ - !ruby/object:Gem::Version
57
+ version: '0'
58
+ requirements: []
59
+ rubyforge_project:
60
+ rubygems_version: 2.0.6
61
+ signing_key:
62
+ specification_version: 4
63
+ summary: m26
64
+ test_files: []