m26 0.0.1

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.
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: []