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 +7 -0
- data/lib/m26.rb +16 -0
- data/lib/m26_age.rb +109 -0
- data/lib/m26_constants.rb +27 -0
- data/lib/m26_distance.rb +82 -0
- data/lib/m26_elapsed_time.rb +92 -0
- data/lib/m26_ruby_extensions.rb +15 -0
- data/lib/m26_speed.rb +130 -0
- metadata +64 -0
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
|
data/lib/m26_distance.rb
ADDED
@@ -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
|
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: []
|