fit4ruby 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,45 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # = Log.rb -- Fit4Ruby - FIT file processing library for Ruby
5
+ #
6
+ # Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org>
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of version 2 of the GNU General Public License as
10
+ # published by the Free Software Foundation.
11
+ #
12
+
13
+ require 'logger'
14
+
15
+ module Fit4Ruby
16
+
17
+ # This is the Exception type that will be thrown for all unrecoverable
18
+ # errors.
19
+ class Error < StandardError ; end
20
+
21
+ class ILogger < Logger
22
+
23
+ def fatal(msg)
24
+ super
25
+ exit 1
26
+ end
27
+
28
+ def critical(msg, exception = nil)
29
+ if exception
30
+ raise Error, "#{msg}: #{exception.message}", exception.backtrace
31
+ else
32
+ raise Error, msg
33
+ end
34
+ end
35
+
36
+ end
37
+
38
+ Log = ILogger.new(STDOUT)
39
+ Log.level = Logger::WARN
40
+ Log.formatter = proc do |severity, time, progname, msg|
41
+ msg + "\n"
42
+ end
43
+
44
+ end
45
+
@@ -0,0 +1,56 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # = Record.rb -- Fit4Ruby - FIT file processing library for Ruby
5
+ #
6
+ # Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org>
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of version 2 of the GNU General Public License as
10
+ # published by the Free Software Foundation.
11
+ #
12
+
13
+ module Fit4Ruby
14
+
15
+ class Record
16
+
17
+ attr_reader :timestamp, :latitude, :longitude, :altitude, :distance,
18
+ :speed, :vertical_oscillation, :cadence, :stance_time
19
+
20
+ def initialize
21
+ end
22
+
23
+ def set(field, value)
24
+ case field
25
+ when 'timestamp'
26
+ @timestamp = value
27
+ when 'position_lat'
28
+ @latitude = value
29
+ when 'position_long'
30
+ @longitude = value
31
+ when 'altitude'
32
+ @altitude = value
33
+ when 'distance'
34
+ @distance = value
35
+ when 'speed'
36
+ @speed = value
37
+ when 'vertical_oscillation'
38
+ @vertical_oscillation = value
39
+ when 'cadence'
40
+ @cadence = 2 * value
41
+ when 'fractional_cadence'
42
+ @cadence += 2 * value if @cadence
43
+ when 'stance_time'
44
+ @stance_time = value
45
+ else
46
+ end
47
+ end
48
+
49
+ def pace
50
+ 1000.0 / (@speed * 60.0)
51
+ end
52
+
53
+ end
54
+
55
+ end
56
+
@@ -0,0 +1,110 @@
1
+ #!/usr/bin/env ruby -w
2
+ # encoding: UTF-8
3
+ #
4
+ # = Session.rb -- Fit4Ruby - FIT file processing library for Ruby
5
+ #
6
+ # Copyright (c) 2014 by Chris Schlaeger <cs@taskjuggler.org>
7
+ #
8
+ # This program is free software; you can redistribute it and/or modify
9
+ # it under the terms of version 2 of the GNU General Public License as
10
+ # published by the Free Software Foundation.
11
+ #
12
+
13
+ require 'fit4ruby/Converters'
14
+
15
+ module Fit4Ruby
16
+
17
+ class Session
18
+
19
+ include Converters
20
+
21
+ attr_reader :start_time, :duration, :distance, :strides, :ascend,
22
+ :descent, :calories, :avg_speed, :avg_heart_rate,
23
+ :max_heart_rate, :avg_vertical_oscillation, :avg_stance_time,
24
+ :avg_running_cadence, :avg_running_cadence, :training_effect,
25
+ :first_lap_index, :num_laps
26
+
27
+ def initialize
28
+ @laps = []
29
+ end
30
+
31
+ def check(activity)
32
+ @first_lap_index.upto(@first_lap_index - @num_laps) do |i|
33
+ if (lap = activity.lap[i])
34
+ @laps << lap
35
+ else
36
+ Log.error "Session references lap #{i} which is not contained in "
37
+ "the FIT file."
38
+ end
39
+ end
40
+ end
41
+
42
+ def set(field, value)
43
+ return unless value
44
+
45
+ case field
46
+ when 'start_time'
47
+ @start_time = value
48
+ when 'total_timer_time'
49
+ @duration = value
50
+ when 'total_distance'
51
+ @distance = value
52
+ when 'total_strides'
53
+ @strides = value
54
+ when 'total_ascent'
55
+ @ascend = value
56
+ when 'total_descent'
57
+ @descent = value
58
+ when 'total_calories'
59
+ @calories = value
60
+ when 'avg_speed'
61
+ @avg_speed = value
62
+ when 'avg_heart_rate'
63
+ @avg_heart_rate = value
64
+ when 'max_heart_rate'
65
+ @max_heart_rate = value
66
+ when 'avg_vertical_oscillation'
67
+ @avg_vertical_oscillation = value
68
+ when 'avg_stance_time'
69
+ @avg_stance_time = value
70
+ when 'avg_running_cadence'
71
+ @avg_running_cadence = 2 * value
72
+ when 'avg_fraction_cadence'
73
+ @avg_running_cadence += 2 * value
74
+ when 'total_training_effect'
75
+ @training_effect = value
76
+ when 'first_lap_index'
77
+ @first_lap_index = value
78
+ when 'num_laps'
79
+ @num_laps = value
80
+ else
81
+ end
82
+ end
83
+
84
+ def avg_stride_length
85
+ @distance / @strides
86
+ end
87
+
88
+ def to_s
89
+ <<"EOT"
90
+ Date: #{@start_time}
91
+ Distance: #{'%.2f' % (@distance / 1000.0)} km
92
+ Time: #{secsToHMS(@duration)}
93
+ Avg Pace: #{speedToPace(@avg_speed)} min/km
94
+ Total Ascend: #{@ascend} m
95
+ Total Descend: #{@descent} m
96
+ Calories: #{@calories} kCal
97
+ Avg HR: #{@avg_heart_rate} bpm
98
+ Max HR: #{@max_heart_rate} bpm
99
+ Training Effect: #{@training_effect}
100
+ Avg Run Cadence: #{@avg_running_cadence.round} spm
101
+ Avg Vertical Oscillation: #{'%.1f' % (@avg_vertical_oscillation / 10)} cm
102
+ Avg Ground Contact Time: #{@avg_stance_time.round} ms
103
+ Avg Stride Length: #{'%.2f' % (avg_stride_length / 2)} m
104
+ EOT
105
+ end
106
+
107
+ end
108
+
109
+ end
110
+
@@ -0,0 +1,3 @@
1
+ module Fit4Ruby
2
+ VERSION = '0.0.1'
3
+ end
@@ -0,0 +1,169 @@
1
+ require 'time'
2
+
3
+ desc 'Generate the CHANGELOG file'
4
+ task :changelog do
5
+
6
+ class Entry
7
+
8
+ attr_reader :type
9
+
10
+ def initialize(ref, author, time, message)
11
+ @ref = ref
12
+ @author = author
13
+ @time = time
14
+ @message = message
15
+ if (m = /New: (.*)/.match(@message))
16
+ @type = :feature
17
+ @message = m[1]
18
+ elsif (m = /Fix: (.*)/.match(@message))
19
+ @type = :bugfix
20
+ @message = m[1]
21
+ else
22
+ @type = :other
23
+ end
24
+ end
25
+
26
+ def to_s
27
+ " * #{@message}\n"
28
+ end
29
+
30
+ end
31
+
32
+ class Release
33
+
34
+ attr_reader :date, :version, :tag
35
+
36
+ def initialize(tag, predecessor)
37
+ @tag = tag
38
+ # We only support release tags in the form X.X.X
39
+ @version = /\d+\.\d+\.\d+/.match(tag)
40
+
41
+ # Construct a Git range.
42
+ interval = predecessor ? "#{predecessor.tag}..#{@tag}" : @tag
43
+
44
+ # Get the date of the release
45
+ date = Time.parse(/Date: (.*)/.match(`git show #{tag}`)[1]).utc
46
+ @date = date.strftime("%Y-%m-%d")
47
+
48
+ @entries = []
49
+ # Use -z option for git-log to get 0 bytes as separators.
50
+ `git log -z #{interval}`.split("\0").each do |commit|
51
+ # We ignore merges.
52
+ next if commit =~ /^Merge: \d*/
53
+
54
+ ref, author, time, _, message = commit.split("\n", 5)
55
+ ref = ref[/commit ([0-9a-f]+)/, 1]
56
+ author = author[/Author: (.*)/, 1].strip
57
+ time = Time.parse(time[/Date: (.*)/, 1]).utc
58
+ # Eleminate git-svn-id: lines
59
+ message.gsub!(/git-svn-id: .*\n/, '')
60
+ # Eliminate Signed-off-by: lines
61
+ message.gsub!(/Signed-off-by: .*\n/, '')
62
+ message.strip!
63
+ @entries << Entry.new(ref, author, time, message)
64
+ end
65
+ end
66
+
67
+ def empty?
68
+ @entries.empty?
69
+ end
70
+
71
+ def to_s
72
+ s = ''
73
+ if hasFeatures? || hasFixes?
74
+ if hasFeatures?
75
+ s << "== New Features\n\n"
76
+ @entries.each do |entry|
77
+ s << entry.to_s if entry.type == :feature
78
+ end
79
+ s << "\n"
80
+ end
81
+ if hasFixes?
82
+ s << "== Bug Fixes\n\n"
83
+ @entries.each do |entry|
84
+ s << entry.to_s if entry.type == :bugfix
85
+ end
86
+ s << "\n"
87
+ end
88
+ else
89
+ @entries.each do |entry|
90
+ s << entry.to_s
91
+ end
92
+ end
93
+ s
94
+ end
95
+
96
+ private
97
+
98
+ def hasFeatures?
99
+ @entries.each do |entry|
100
+ return true if entry.type == :feature
101
+ end
102
+ false
103
+ end
104
+
105
+ def hasFixes?
106
+ @entries.each do |entry|
107
+ return true if entry.type == :bugfix
108
+ end
109
+ false
110
+ end
111
+
112
+ end
113
+
114
+ class ChangeLog
115
+
116
+ def initialize
117
+ @releases = []
118
+ predecessor = nil
119
+ getReleaseVersions.each do |version|
120
+ @releases << (predecessor = Release.new(version, predecessor))
121
+ end
122
+ end
123
+
124
+ def to_s
125
+ s = ''
126
+ @releases.reverse.each do |release|
127
+ next if release.empty?
128
+
129
+ # We use RDOC markup syntax to generate a title
130
+ if release.version
131
+ s << "= Release #{release.version} (#{release.date})\n\n"
132
+ else
133
+ s << "= Next Release (Some Day)\n\n"
134
+ end
135
+ s << release.to_s + "\n"
136
+ end
137
+ s
138
+ end
139
+
140
+ private
141
+
142
+ # 'git tag' is not sorted numerically. This function implements a
143
+ # numerical comparison for tag versions of the format 'release-X.X.X'. X
144
+ # can be a multi-digit number.
145
+ def compareTags(a, b)
146
+
147
+ def versionToComparable(v)
148
+ /\d+\.\d+\.\d+/.match(v)[0].split('.').map{ |l| sprintf("%03d", l.to_i)}.
149
+ join('.')
150
+ end
151
+
152
+ versionToComparable(a) <=> versionToComparable(b)
153
+ end
154
+
155
+ def getReleaseVersions
156
+ # Get list of release tags from Git repository
157
+ releaseVersions = `git tag`.split("\n").map { |r| r.chomp }.
158
+ delete_if { |r| ! (/release-\d+\.\d+\.\d+/ =~ r) }.
159
+ sort{ |a, b| compareTags(a, b) }
160
+ releaseVersions << 'HEAD'
161
+ end
162
+
163
+ end
164
+
165
+ File.open('CHANGELOG', 'w+') do |changelog|
166
+ changelog.puts ChangeLog.new.to_s
167
+ end
168
+
169
+ end
@@ -0,0 +1,52 @@
1
+ # GEM TASK
2
+ require 'find'
3
+ require 'rubygems'
4
+ require 'rubygems/package'
5
+
6
+ # Unfortunately Rake::GemPackageTest cannot deal with files that are generated
7
+ # by Rake targets. So we have to write our own packaging task.
8
+ desc 'Build the gem package'
9
+ task :gem => [:clobber] do
10
+ Rake::Task[:changelog].invoke
11
+ Rake::Task[:permissions].invoke
12
+
13
+ load 'fit4ruby.gemspec';
14
+
15
+ # Build the gem file according to the loaded spec.
16
+ if RUBY_VERSION >= "2.0.0"
17
+ Gem::Package.build(GEM_SPEC)
18
+ else
19
+ Gem::Builder.new(GEM_SPEC).build
20
+ end
21
+ pkgBase = "#{GEM_SPEC.name}-#{GEM_SPEC.version}"
22
+ # Create a pkg directory if it doesn't exist already.
23
+ FileUtils.mkdir_p('pkg')
24
+ # Move the gem file into the pkg directory.
25
+ verbose(true) { FileUtils.mv("#{pkgBase}.gem", "pkg/#{pkgBase}.gem")}
26
+ end
27
+
28
+ desc 'Make sure all files and directories are readable'
29
+ task :permissions do
30
+ # Find the bin and test directories relative to this file.
31
+ baseDir = File.expand_path('..', File.dirname(__FILE__))
32
+
33
+ execs = Dir.glob("#{baseDir}/bin/*") +
34
+ Dir.glob("#{baseDir}/test/**/genrefs")
35
+
36
+ Find.find(baseDir) do |f|
37
+ # Ignore the whoke pkg directory as it may contain links to the other
38
+ # directories.
39
+ next if Regexp.new("#{baseDir}/pkg/*").match(f)
40
+
41
+ FileUtils.chmod_R((FileTest.directory?(f) ||
42
+ execs.include?(f) ? 0755 : 0644), f)
43
+ end
44
+ end
45
+
46
+ desc 'Run all tests and build scripts and create the gem package'
47
+ task :release do
48
+ Rake::Task[:test].invoke
49
+ Rake::Task[:yard].invoke
50
+ Rake::Task[:gem].invoke
51
+ end
52
+
@@ -0,0 +1,14 @@
1
+ if RUBY_VERSION < '1.9.3'
2
+ require 'rake/rdoctask'
3
+ else
4
+ require 'rdoc/task'
5
+ end
6
+
7
+ # RDOC TASK
8
+ Rake::RDocTask.new(:rdoc) do |t|
9
+ t.rdoc_files = %w( README.rdoc COPYING CHANGELOG ) +
10
+ `git ls-files -- lib`.split("\n")
11
+ t.title = "TaskJuggler API documentation"
12
+ t.main = 'README.rdoc'
13
+ t.rdoc_dir = 'doc'
14
+ end