Class: PostRunner::ActivitiesDB

Inherits:
Object
  • Object
show all
Defined in:
lib/postrunner/ActivitiesDB.rb

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(db_dir, cfg) ⇒ ActivitiesDB

Returns a new instance of ActivitiesDB.



27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
# File 'lib/postrunner/ActivitiesDB.rb', line 27

def initialize(db_dir, cfg)
  @db_dir = db_dir
  @cfg = cfg
  @fit_dir = File.join(@db_dir, 'fit')
  @html_dir = File.join(@db_dir, 'html')
  @archive_file = File.join(@db_dir, 'archive.yml')

  create_directories
  begin
    if File.exists?(@archive_file)
      @activities = YAML.load_file(@archive_file)
    else
      @activities = []
    end
  rescue StandardError
    Log.fatal "Cannot load archive file '#{@archive_file}': #{$!}"
  end

  unless @activities.is_a?(Array)
    Log.fatal "The archive file '#{@archive_file}' is corrupted"
  end

  # Not all instance variables of Activity are stored in the file. The
  # normal constructor is not run during YAML::load_file. We have to
  # initialize those instance variables in a secondary step.
  @activities.each do |a|
    a.late_init(self)
  end

  @records = PersonalRecords.new(self)
end

Instance Attribute Details

#activitiesObject (readonly)

Returns the value of attribute activities.



25
26
27
# File 'lib/postrunner/ActivitiesDB.rb', line 25

def activities
  @activities
end

#cfgObject (readonly)

Returns the value of attribute cfg.



25
26
27
# File 'lib/postrunner/ActivitiesDB.rb', line 25

def cfg
  @cfg
end

#db_dirObject (readonly)

Returns the value of attribute db_dir.



25
26
27
# File 'lib/postrunner/ActivitiesDB.rb', line 25

def db_dir
  @db_dir
end

#fit_dirObject (readonly)

Returns the value of attribute fit_dir.



25
26
27
# File 'lib/postrunner/ActivitiesDB.rb', line 25

def fit_dir
  @fit_dir
end

#html_dirObject (readonly)

Returns the value of attribute html_dir.



25
26
27
# File 'lib/postrunner/ActivitiesDB.rb', line 25

def html_dir
  @html_dir
end

Instance Method Details

#activity_by_fit_file(fit_file) ⇒ Object



146
147
148
# File 'lib/postrunner/ActivitiesDB.rb', line 146

def activity_by_fit_file(fit_file)
  @activities.find { |a| a.fit_file == fit_file }
end

#add(fit_file) ⇒ TrueClass or FalseClass

Add a new FIT file to the database. otherwise.

Parameters:

  • fit_file (String)

    Name of the FIT file.

Returns:

  • (TrueClass or FalseClass)

    True if the file could be added. False



63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
# File 'lib/postrunner/ActivitiesDB.rb', line 63

def add(fit_file)
  base_fit_file = File.basename(fit_file)
  if @activities.find { |a| a.fit_file == base_fit_file }
    Log.debug "Activity #{fit_file} is already included in the archive"
    return false
  end

  if File.exists?(File.join(@fit_dir, base_fit_file))
    Log.debug "Activity #{fit_file} has been deleted before"
    return false
  end

  begin
    fit_activity = Fit4Ruby.read(fit_file)
  rescue Fit4Ruby::Error
    Log.error $!
    return false
  end

  begin
    FileUtils.cp(fit_file, @fit_dir)
  rescue StandardError
    Log.fatal "Cannot copy #{fit_file} into #{@fit_dir}: #{$!}"
  end

  @activities << (activity = Activity.new(self, base_fit_file,
                                          fit_activity))
  @activities.sort! do |a1, a2|
    a2.timestamp <=> a1.timestamp
  end

  activity.register_records(@records)

  # The HTML activity views contain links to their predecessors and
  # successors. After inserting a new activity, we need to re-generate
  # these views as well.
  if (pred = predecessor(activity))
    pred.generate_html_view
  end
  if (succ = successor(activity))
    succ.generate_html_view
  end

  sync
  Log.info "#{fit_file} successfully added to archive"

  true
end

#checkObject



132
133
134
# File 'lib/postrunner/ActivitiesDB.rb', line 132

def check
  @activities.each { |a| a.check }
end

#delete(activity) ⇒ Object



112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/postrunner/ActivitiesDB.rb', line 112

def delete(activity)
  pred = predecessor(activities)
  succ = successor(activities)

  @activities.delete(activity)

  # The HTML activity views contain links to their predecessors and
  # successors. After deleting an activity, we need to re-generate these
  # views as well.
  pred.generate_html_view if pred
  succ.generate_html_view if succ

  sync
end

#find(query) ⇒ Object



150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
# File 'lib/postrunner/ActivitiesDB.rb', line 150

def find(query)
  case query
  when /\A-?\d+$\z/
    index = query.to_i
    # The UI counts the activities from 1 to N. Ruby counts from 0 -
    # (N-1).
    index -= 1 if index > 0
    if (a = @activities[index])
      return [ a ]
    end
  when /\A-?\d+--?\d+\z/
    idxs = query.match(/(?<sidx>-?\d+)-(?<eidx>-?[0-9]+)/)
    sidx = idxs['sidx'].to_i
    eidx = idxs['eidx'].to_i
    # The UI counts the activities from 1 to N. Ruby counts from 0 -
    # (N-1).
    sidx -= 1 if sidx > 0
    eidx -= 1 if eidx > 0
    unless (as = @activities[sidx..eidx]).empty?
      return as
    end
  else
    Log.error "Invalid activity query: #{query}"
  end

  []
end

#generate_all_html_reportsObject

This method can be called to re-generate all HTML reports and all HTML index files.



253
254
255
256
257
258
259
260
261
# File 'lib/postrunner/ActivitiesDB.rb', line 253

def generate_all_html_reports
  Log.info "Re-generating all HTML report files..."
  # Generate HTML views for all activities in the DB.
  @activities.each { |a| a.generate_html_view }
  Log.info "All HTML report files have been re-generated."
  # (Re-)generate index files.
  ActivityListView.new(self).update_html_index
  Log.info "HTML index files have been updated."
end

#listObject



232
233
234
# File 'lib/postrunner/ActivitiesDB.rb', line 232

def list
  puts ActivityListView.new(self).to_s
end

#map_to_files(query) ⇒ Object



194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
# File 'lib/postrunner/ActivitiesDB.rb', line 194

def map_to_files(query)
  case query
  when /\A-?\d+$\z/
    index = query.to_i
    # The UI counts the activities from 1 to N. Ruby counts from 0 -
    # (N-1).
    index -= 1 if index > 0
    if (a = @activities[index])
      return [ File.join(@fit_dir, a.fit_file) ]
    end
  when /\A-?\d+--?\d+\z/
    idxs = query.match(/(?<sidx>-?\d+)-(?<eidx>-?[0-9]+)/)
    sidx = idxs['sidx'].to_i
    eidx = idxs['eidx'].to_i
    # The UI counts the activities from 1 to N. Ruby counts from 0 -
    # (N-1).
    sidx -= 1 if sidx > 0
    eidx -= 1 if eidx > 0
    unless (as = @activities[sidx..eidx]).empty?
      files = []
      as.each do |a|
        files << File.join(@fit_dir, a.fit_file)
      end
      return files
    end
  else
    Log.error "Invalid activity query: #{query}"
  end

  []
end

#predecessor(activity) ⇒ Object

Return the previous Activity before the provided activity. Note that this has a higher index. If none is found, return nil.



188
189
190
191
192
# File 'lib/postrunner/ActivitiesDB.rb', line 188

def predecessor(activity)
  idx = @activities.index(activity)
  return nil if idx.nil? || idx >= @activities.length - 2
  @activities[idx + 1]
end

#ref_by_fit_file(fit_file) ⇒ Object



136
137
138
139
140
141
142
143
144
# File 'lib/postrunner/ActivitiesDB.rb', line 136

def ref_by_fit_file(fit_file)
  i = 1
  @activities.each do |activity|
    return i if activity.fit_file == fit_file
    i += 1
  end

  nil
end

#rename(activity, name) ⇒ Object



127
128
129
130
# File 'lib/postrunner/ActivitiesDB.rb', line 127

def rename(activity, name)
  activity.rename(name)
  sync
end

#show_in_browser(html_file) ⇒ Object

Launch a web browser and show an HTML file.

Parameters:

  • html_file (String)

    file name of the HTML file to show



242
243
244
245
246
247
248
249
# File 'lib/postrunner/ActivitiesDB.rb', line 242

def show_in_browser(html_file)
  cmd = "#{ENV['BROWSER'] || 'firefox'} \"#{html_file}\" &"

  unless system(cmd)
    Log.fatal "Failed to execute the following shell command: #{$cmd}\n" +
              "#{$!}"
  end
end

#show_list_in_browserObject

Show the activity list in a web browser.



227
228
229
230
# File 'lib/postrunner/ActivitiesDB.rb', line 227

def show_list_in_browser
  ActivityListView.new(self).update_html_index
  show_in_browser(File.join(@html_dir, 'index.html'))
end

#show_recordsObject



236
237
238
# File 'lib/postrunner/ActivitiesDB.rb', line 236

def show_records
  puts @records.to_s
end

#successor(activity) ⇒ Object

Return the next Activity after the provided activity. Note that this has a lower index. If none is found, return nil.



180
181
182
183
184
# File 'lib/postrunner/ActivitiesDB.rb', line 180

def successor(activity)
  idx = @activities.index(activity)
  return nil if idx.nil? || idx == 0
  @activities[idx - 1]
end