insulin 0.0.13 → 0.0.14
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.
- data/Gemfile.lock +1 -1
- data/bin/insulin +10 -0
- data/lib/insulin/day.rb +13 -6
- data/lib/insulin/event.rb +1 -1
- data/lib/insulin/on_track/csv_file.rb +64 -0
- data/lib/insulin/on_track/csv_line.rb +42 -0
- data/lib/insulin/on_track/date.rb +27 -0
- data/lib/insulin/on_track/note.rb +49 -0
- data/lib/insulin/on_track/note_set.rb +48 -0
- data/lib/insulin/version.rb +1 -1
- data/lib/insulin.rb +6 -5
- data/spec/{insulin_config_spec.rb → config_spec.rb} +0 -0
- data/spec/{insulin_day_spec.rb → day_spec.rb} +1 -3
- data/spec/{insulin_event_spec.rb → event_spec.rb} +1 -1
- data/spec/{insulin_mongo_handle_spec.rb → mongo_handle_spec.rb} +0 -0
- data/spec/{insulin_on_track_csv_file_spec.rb → on_track/csv_file_spec.rb} +3 -3
- data/spec/{insulin_on_track_csv_line_spec.rb → on_track/csv_line_spec.rb} +3 -3
- data/spec/{insulin_on_track_date_spec.rb → on_track/date_spec.rb} +3 -3
- data/spec/{insulin_on_track_note_set_spec.rb → on_track/note_set_spec.rb} +4 -4
- data/spec/{insulin_on_track_note_spec.rb → on_track/note_spec.rb} +4 -4
- data/spec/spec_helper.rb +1 -1
- metadata +24 -24
- data/lib/insulin/on_track_csv_file.rb +0 -61
- data/lib/insulin/on_track_csv_line.rb +0 -39
- data/lib/insulin/on_track_date.rb +0 -25
- data/lib/insulin/on_track_note.rb +0 -46
- data/lib/insulin/on_track_note_set.rb +0 -45
data/Gemfile.lock
CHANGED
data/bin/insulin
CHANGED
@@ -29,6 +29,16 @@ module Insulin
|
|
29
29
|
end
|
30
30
|
end
|
31
31
|
|
32
|
+
desc "week DATE", "show stats for week commencing DATE (defaults to previous 7 days)"
|
33
|
+
def week date = nil
|
34
|
+
if not date
|
35
|
+
require 'time'
|
36
|
+
date = (Time.new - (6 * 86400)).strftime "%F"
|
37
|
+
end
|
38
|
+
w = Insulin::Week.new date, @@mongo
|
39
|
+
puts w.to_s
|
40
|
+
end
|
41
|
+
|
32
42
|
default_task :day
|
33
43
|
end
|
34
44
|
end
|
data/lib/insulin/day.rb
CHANGED
@@ -14,7 +14,7 @@ module Insulin
|
|
14
14
|
self["all"] = []
|
15
15
|
|
16
16
|
@mongo.db.collection(date).find().each do |e|
|
17
|
-
ev =
|
17
|
+
ev = Event.new(e)
|
18
18
|
keys.each do |k|
|
19
19
|
sub = ev[k]
|
20
20
|
if self[sub]
|
@@ -31,10 +31,14 @@ module Insulin
|
|
31
31
|
def average_glucose
|
32
32
|
t = 0
|
33
33
|
c = 0
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
34
|
+
begin
|
35
|
+
self["glucose"].each do |g|
|
36
|
+
@glucose_units = g["units"]
|
37
|
+
t += g["value"]
|
38
|
+
c += 1
|
39
|
+
end
|
40
|
+
rescue NoMethodError
|
41
|
+
return 0
|
38
42
|
end
|
39
43
|
|
40
44
|
return t / c
|
@@ -46,11 +50,13 @@ module Insulin
|
|
46
50
|
s << "\n"
|
47
51
|
|
48
52
|
self["all"].each do |e|
|
53
|
+
s << " "
|
49
54
|
s << e.simple
|
50
55
|
s << "\n"
|
51
56
|
end
|
52
57
|
|
53
|
-
s << "
|
58
|
+
s << " "
|
59
|
+
s << "Average glucose: %4.2f %s" % [
|
54
60
|
self.average_glucose,
|
55
61
|
@glucose_units
|
56
62
|
]
|
@@ -64,6 +70,7 @@ module Insulin
|
|
64
70
|
|
65
71
|
self["all"].each do |e|
|
66
72
|
if ["breakfast", "lunch", "dinner", "bedtime"].include? e["tag"]
|
73
|
+
s << " "
|
67
74
|
s << e.simple
|
68
75
|
s << "\n"
|
69
76
|
end
|
data/lib/insulin/event.rb
CHANGED
@@ -0,0 +1,64 @@
|
|
1
|
+
module Insulin
|
2
|
+
# Author:: Sam (mailto:sam@cruft.co)
|
3
|
+
# License:: MIT
|
4
|
+
|
5
|
+
module OnTrack
|
6
|
+
|
7
|
+
# This class represents a CSV file as exported by OnTrack
|
8
|
+
class CsvFile
|
9
|
+
attr_reader :file, :lines, :events
|
10
|
+
|
11
|
+
# Take the path to the CSV, open it, process it
|
12
|
+
def initialize csv_path
|
13
|
+
@csv_path = csv_path
|
14
|
+
@file = File.new @csv_path
|
15
|
+
self.read_lines
|
16
|
+
self.create_events
|
17
|
+
end
|
18
|
+
|
19
|
+
# Read the lines
|
20
|
+
def read_lines
|
21
|
+
@lines = []
|
22
|
+
|
23
|
+
# Where an event has more than one note, a 'line' will contain '\n's
|
24
|
+
l = ""
|
25
|
+
while line = @file.gets
|
26
|
+
# Stuff the line in to 'l'
|
27
|
+
l << line
|
28
|
+
|
29
|
+
# A '"' at the end of the line closes the event
|
30
|
+
if line[-2] == '"'
|
31
|
+
|
32
|
+
# Create a CsvLine, stripping the final '\n'
|
33
|
+
o = CsvLine.new l[0..-2]
|
34
|
+
@lines << o
|
35
|
+
|
36
|
+
# Reset the placeholder
|
37
|
+
l = ""
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
# Sort the list by the serial numbers (required for a future feature)
|
42
|
+
@lines.sort_by! {|o| o["serial"]}
|
43
|
+
end
|
44
|
+
|
45
|
+
# Turn the lines into Events
|
46
|
+
def create_events
|
47
|
+
@events = []
|
48
|
+
@lines.each do |l|
|
49
|
+
e = Event.new l
|
50
|
+
@events << e
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Save the events to Mongo
|
55
|
+
def save_events mongo
|
56
|
+
# print "saving %d events to mongo... " % @events.count
|
57
|
+
@events.each do |e|
|
58
|
+
e.save mongo
|
59
|
+
end
|
60
|
+
# puts "done"
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
module Insulin
|
2
|
+
# Author:: Sam (mailto:sam@cruft.co)
|
3
|
+
# License:: MIT
|
4
|
+
|
5
|
+
module OnTrack
|
6
|
+
|
7
|
+
# This class represents a single OnTrack CSV line
|
8
|
+
class CsvLine < Hash
|
9
|
+
|
10
|
+
# Parse the passed-in CSV line
|
11
|
+
def initialize line
|
12
|
+
|
13
|
+
# Split on commas
|
14
|
+
bits = line.split ","
|
15
|
+
self["serial"] = bits[0].to_i
|
16
|
+
|
17
|
+
# OnTrack embeds commas in the dates of its CSVs. Duh
|
18
|
+
self.update Date.new "%s%s" % [
|
19
|
+
bits[1],
|
20
|
+
bits[2]
|
21
|
+
]
|
22
|
+
self["type"] = bits[3].downcase
|
23
|
+
self["subtype"] = bits[4].downcase if not bits[4] == ""
|
24
|
+
self["tag"] = bits[5].downcase
|
25
|
+
self["value"] = bits[6].to_f
|
26
|
+
|
27
|
+
# Notes get complicated. Everything from field 7 to the end will be part
|
28
|
+
# of the notes
|
29
|
+
notes = bits[7..-1]
|
30
|
+
|
31
|
+
# We may have embedded commas
|
32
|
+
notes = notes.join ","
|
33
|
+
|
34
|
+
# Strip the trailing '\n'
|
35
|
+
notes = notes[1..-2]
|
36
|
+
|
37
|
+
# See Insulin::OnTrack::NoteSet
|
38
|
+
self["notes"] = NoteSet.new notes if not notes == ""
|
39
|
+
end
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require "time"
|
2
|
+
|
3
|
+
module Insulin
|
4
|
+
# Author:: Sam (mailto:sam@cruft.co)
|
5
|
+
# License:: MIT
|
6
|
+
module OnTrack
|
7
|
+
|
8
|
+
# OnTrack uses really shitty date formats, including embedding a comma in
|
9
|
+
# the CSV export file. Christ on a crutch
|
10
|
+
class Date < Hash
|
11
|
+
|
12
|
+
# Parse the string 'd', looking for datetime information
|
13
|
+
def initialize d
|
14
|
+
t = Time.parse d
|
15
|
+
|
16
|
+
# We extract loads of stuff. Might be useful one day
|
17
|
+
self["timestamp"] = t
|
18
|
+
self["tzoffset"] = t.strftime "%z"
|
19
|
+
self["timezone"] = t.zone
|
20
|
+
self["unixtime"] = t.to_i
|
21
|
+
self["day"] = t.strftime("%A").downcase
|
22
|
+
self["date"] = t.strftime "%F"
|
23
|
+
self["time"] = t.strftime "%T #{self['timezone']}"
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,49 @@
|
|
1
|
+
module Insulin
|
2
|
+
# Author:: Sam (mailto:sam@cruft.co)
|
3
|
+
# License:: MIT
|
4
|
+
|
5
|
+
module OnTrack
|
6
|
+
|
7
|
+
# Class representing a single OnTrack note
|
8
|
+
class Note
|
9
|
+
|
10
|
+
# Lookups. We will only deal with notes of these types
|
11
|
+
@@keys = {
|
12
|
+
"F" => 'food',
|
13
|
+
"B" => 'booze',
|
14
|
+
"N" => 'note'
|
15
|
+
}
|
16
|
+
|
17
|
+
attr_reader :type, :content
|
18
|
+
|
19
|
+
# Parse the raw note 'n'
|
20
|
+
def initialize n
|
21
|
+
|
22
|
+
# Key/value splits on ':'
|
23
|
+
bits = n.split ":"
|
24
|
+
|
25
|
+
# Remove leading/trailing cruft from key part
|
26
|
+
t = bits[0].strip
|
27
|
+
|
28
|
+
# We only deal with the keys we know about
|
29
|
+
if @@keys.keys.include? t
|
30
|
+
|
31
|
+
# Remove cruft from content, downcase
|
32
|
+
@content = bits[1].strip.downcase
|
33
|
+
|
34
|
+
# These keys mean we turn the content into a list
|
35
|
+
if ["F", "B"].include? t
|
36
|
+
a = []
|
37
|
+
@content.split(",").each do |v|
|
38
|
+
a << v.strip
|
39
|
+
end
|
40
|
+
@content = a
|
41
|
+
end
|
42
|
+
|
43
|
+
# Set key from lookup list
|
44
|
+
@type = @@keys[t]
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
@@ -0,0 +1,48 @@
|
|
1
|
+
module Insulin
|
2
|
+
# Author:: Sam (mailto:sam@cruft.co)
|
3
|
+
# License:: MIT
|
4
|
+
|
5
|
+
module OnTrack
|
6
|
+
|
7
|
+
# This class represents a set of notes
|
8
|
+
class NoteSet < Hash
|
9
|
+
|
10
|
+
# Parse the string 's'
|
11
|
+
def initialize s
|
12
|
+
|
13
|
+
# Notes separated by newlines
|
14
|
+
l = s.split"\n"
|
15
|
+
|
16
|
+
# For each line
|
17
|
+
l.each do |n|
|
18
|
+
|
19
|
+
# Make a note
|
20
|
+
x = Note.new n
|
21
|
+
|
22
|
+
# This field will only exists for notes of a valid type
|
23
|
+
if x.type
|
24
|
+
|
25
|
+
# If we don't yet have this key
|
26
|
+
if not self[x.type]
|
27
|
+
|
28
|
+
# If the content is a list
|
29
|
+
if x.content.class.name == "Array"
|
30
|
+
|
31
|
+
# This becomes our value
|
32
|
+
self[x.type] = x.content
|
33
|
+
else
|
34
|
+
|
35
|
+
# Otherwise make it onto a list
|
36
|
+
self[x.type] = [x.content]
|
37
|
+
end
|
38
|
+
else
|
39
|
+
|
40
|
+
# This key exists, so we append this value
|
41
|
+
self[x.type] << x.content
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
end
|
data/lib/insulin/version.rb
CHANGED
data/lib/insulin.rb
CHANGED
@@ -1,13 +1,14 @@
|
|
1
1
|
require "insulin/version"
|
2
2
|
require "insulin/config"
|
3
3
|
require "insulin/mongo_handle"
|
4
|
-
require "insulin/on_track_date"
|
5
|
-
require "insulin/on_track_note"
|
6
|
-
require "insulin/on_track_note_set"
|
7
|
-
require "insulin/on_track_csv_line"
|
8
|
-
require "insulin/on_track_csv_file"
|
9
4
|
require "insulin/event"
|
10
5
|
require "insulin/day"
|
6
|
+
require "insulin/week"
|
7
|
+
require "insulin/on_track/date"
|
8
|
+
require "insulin/on_track/note"
|
9
|
+
require "insulin/on_track/note_set"
|
10
|
+
require "insulin/on_track/csv_line"
|
11
|
+
require "insulin/on_track/csv_file"
|
11
12
|
|
12
13
|
# Author:: Sam (mailto:sam@cruft.co)
|
13
14
|
# License:: MIT
|
File without changes
|
@@ -29,14 +29,12 @@ describe Insulin::Day do
|
|
29
29
|
end
|
30
30
|
|
31
31
|
it "should display correctly" do
|
32
|
-
d.to_s.should include "19:07:42 BST dinner
|
32
|
+
d.to_s.should include "19:07:42 BST | dinner | medication | humalog | 6.0 x10^-5 L"
|
33
33
|
end
|
34
34
|
|
35
35
|
it "minimal display should be correct" do
|
36
36
|
d.minimal.should_not include "exercise"
|
37
37
|
end
|
38
38
|
|
39
|
-
puts d.minimal
|
40
|
-
|
41
39
|
drop_test_db
|
42
40
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'insulin'
|
2
2
|
|
3
3
|
describe Insulin::Event do
|
4
|
-
event = Insulin::Event.new Insulin::
|
4
|
+
event = Insulin::Event.new Insulin::OnTrack::CsvLine.new %q{266,"Jun 28, 2012 10:21:05 AM",Medication,Humalog,After Breakfast,4.0,"F:2 bacon, 2 toast
|
5
5
|
N:test note
|
6
6
|
X:fail note
|
7
7
|
N:other note"}
|
File without changes
|
@@ -1,14 +1,14 @@
|
|
1
1
|
require 'insulin'
|
2
2
|
|
3
|
-
describe Insulin::
|
4
|
-
csv_file = Insulin::
|
3
|
+
describe Insulin::OnTrack::CsvFile do
|
4
|
+
csv_file = Insulin::OnTrack::CsvFile.new 'files/on_track.csv'
|
5
5
|
|
6
6
|
it "should open the file" do
|
7
7
|
csv_file.file.path.should == 'files/on_track.csv'
|
8
8
|
end
|
9
9
|
|
10
10
|
it "should create csv lines" do
|
11
|
-
csv_file.lines[0].class.name.should == "Insulin::
|
11
|
+
csv_file.lines[0].class.name.should == "Insulin::OnTrack::CsvLine"
|
12
12
|
end
|
13
13
|
|
14
14
|
it "line with serial 342 should have proper noteset" do
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'insulin'
|
2
2
|
|
3
|
-
describe Insulin::
|
4
|
-
csv = Insulin::
|
3
|
+
describe Insulin::OnTrack::CsvLine do
|
4
|
+
csv = Insulin::OnTrack::CsvLine.new %q{199,"Jun 22, 2012 8:01:39 AM",Glucose,,Breakfast,5.7,""}
|
5
5
|
|
6
6
|
it "should have the correct serial" do
|
7
7
|
csv["serial"].should == 199
|
@@ -35,7 +35,7 @@ describe Insulin::OnTrackCsvLine do
|
|
35
35
|
csv["notes"].should == nil
|
36
36
|
end
|
37
37
|
|
38
|
-
csv_with_note = Insulin::
|
38
|
+
csv_with_note = Insulin::OnTrack::CsvLine.new %q{266,"Jun 28, 2012 10:21:05 AM",Medication,Humalog,After Breakfast,4.0,"F:2 bacon, 2 toast
|
39
39
|
N:test note
|
40
40
|
X:fail note
|
41
41
|
N:other note"}
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'insulin'
|
2
2
|
|
3
|
-
describe Insulin::
|
4
|
-
otd = Insulin::
|
3
|
+
describe Insulin::OnTrack::Date do
|
4
|
+
otd = Insulin::OnTrack::Date.new "Jun 22 2012 9:00:12 AM"
|
5
5
|
|
6
6
|
it "should have the correct timestamp" do
|
7
7
|
otd["timestamp"].to_s.should == "2012-06-22 09:00:12 +0100"
|
@@ -19,7 +19,7 @@ describe Insulin::OnTrackDate do
|
|
19
19
|
otd["day"].should == "friday"
|
20
20
|
end
|
21
21
|
|
22
|
-
otd_gmt = Insulin::
|
22
|
+
otd_gmt = Insulin::OnTrack::Date.new "Jan 22 2012 9:00:12 PM"
|
23
23
|
|
24
24
|
it "should have the correct timestamp" do
|
25
25
|
otd_gmt["timestamp"].to_s.should == "2012-01-22 21:00:12 +0000"
|
@@ -1,7 +1,7 @@
|
|
1
1
|
require 'insulin'
|
2
2
|
|
3
|
-
describe Insulin::
|
4
|
-
simple_note_set = Insulin::
|
3
|
+
describe Insulin::OnTrack::NoteSet do
|
4
|
+
simple_note_set = Insulin::OnTrack::NoteSet.new "F: turkey breast, salad"
|
5
5
|
|
6
6
|
it "should have the correct notes" do
|
7
7
|
simple_note_set.should == {
|
@@ -12,7 +12,7 @@ describe Insulin::OnTrackNoteSet do
|
|
12
12
|
}
|
13
13
|
end
|
14
14
|
|
15
|
-
multiple_note_set = Insulin::
|
15
|
+
multiple_note_set = Insulin::OnTrack::NoteSet.new "F: turkey breast, salad
|
16
16
|
N:After wine. No overnight hypo.
|
17
17
|
N:some other note
|
18
18
|
B: glass of wine"
|
@@ -33,7 +33,7 @@ describe Insulin::OnTrackNoteSet do
|
|
33
33
|
}
|
34
34
|
end
|
35
35
|
|
36
|
-
failing_note_set = Insulin::
|
36
|
+
failing_note_set = Insulin::OnTrack::NoteSet.new "F: turkey breast, salad
|
37
37
|
X:This should fail"
|
38
38
|
|
39
39
|
it "should have the correct notes" do
|
@@ -1,21 +1,21 @@
|
|
1
1
|
require 'insulin'
|
2
2
|
|
3
|
-
describe Insulin::
|
4
|
-
note = Insulin::
|
3
|
+
describe Insulin::OnTrack::Note do
|
4
|
+
note = Insulin::OnTrack::Note.new "N:After wine. No overnight hypo."
|
5
5
|
|
6
6
|
it "should have the correct note" do
|
7
7
|
note.type.should == "note"
|
8
8
|
note.content.should == "after wine. no overnight hypo."
|
9
9
|
end
|
10
10
|
|
11
|
-
list_note = Insulin::
|
11
|
+
list_note = Insulin::OnTrack::Note.new "F: turkey breast, salad"
|
12
12
|
|
13
13
|
it "should have the correct list-type note" do
|
14
14
|
list_note.type.should == "food"
|
15
15
|
list_note.content.should == ["turkey breast", "salad"]
|
16
16
|
end
|
17
17
|
|
18
|
-
fail_note = Insulin::
|
18
|
+
fail_note = Insulin::OnTrack::Note.new "X: this one should fail"
|
19
19
|
|
20
20
|
it "should handle the fail note correctly" do
|
21
21
|
fail_note.type.should == nil
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: insulin
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0.
|
4
|
+
version: 0.0.14
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -168,22 +168,22 @@ files:
|
|
168
168
|
- lib/insulin/day.rb
|
169
169
|
- lib/insulin/event.rb
|
170
170
|
- lib/insulin/mongo_handle.rb
|
171
|
-
- lib/insulin/
|
172
|
-
- lib/insulin/
|
173
|
-
- lib/insulin/
|
174
|
-
- lib/insulin/
|
175
|
-
- lib/insulin/
|
171
|
+
- lib/insulin/on_track/csv_file.rb
|
172
|
+
- lib/insulin/on_track/csv_line.rb
|
173
|
+
- lib/insulin/on_track/date.rb
|
174
|
+
- lib/insulin/on_track/note.rb
|
175
|
+
- lib/insulin/on_track/note_set.rb
|
176
176
|
- lib/insulin/version.rb
|
177
177
|
- scripts/build.sh
|
178
|
-
- spec/
|
179
|
-
- spec/
|
180
|
-
- spec/
|
181
|
-
- spec/
|
182
|
-
- spec/
|
183
|
-
- spec/
|
184
|
-
- spec/
|
185
|
-
- spec/
|
186
|
-
- spec/
|
178
|
+
- spec/config_spec.rb
|
179
|
+
- spec/day_spec.rb
|
180
|
+
- spec/event_spec.rb
|
181
|
+
- spec/mongo_handle_spec.rb
|
182
|
+
- spec/on_track/csv_file_spec.rb
|
183
|
+
- spec/on_track/csv_line_spec.rb
|
184
|
+
- spec/on_track/date_spec.rb
|
185
|
+
- spec/on_track/note_set_spec.rb
|
186
|
+
- spec/on_track/note_spec.rb
|
187
187
|
- spec/spec_helper.rb
|
188
188
|
homepage: http://pikesley.github.com/insulin/
|
189
189
|
licenses: []
|
@@ -210,13 +210,13 @@ signing_key:
|
|
210
210
|
specification_version: 3
|
211
211
|
summary: Doing stuff with my diabetes data
|
212
212
|
test_files:
|
213
|
-
- spec/
|
214
|
-
- spec/
|
215
|
-
- spec/
|
216
|
-
- spec/
|
217
|
-
- spec/
|
218
|
-
- spec/
|
219
|
-
- spec/
|
220
|
-
- spec/
|
221
|
-
- spec/
|
213
|
+
- spec/config_spec.rb
|
214
|
+
- spec/day_spec.rb
|
215
|
+
- spec/event_spec.rb
|
216
|
+
- spec/mongo_handle_spec.rb
|
217
|
+
- spec/on_track/csv_file_spec.rb
|
218
|
+
- spec/on_track/csv_line_spec.rb
|
219
|
+
- spec/on_track/date_spec.rb
|
220
|
+
- spec/on_track/note_set_spec.rb
|
221
|
+
- spec/on_track/note_spec.rb
|
222
222
|
- spec/spec_helper.rb
|
@@ -1,61 +0,0 @@
|
|
1
|
-
module Insulin
|
2
|
-
# Author:: Sam (mailto:sam@cruft.co)
|
3
|
-
# License:: MIT
|
4
|
-
|
5
|
-
# This class represents a CSV file as exported by OnTrack
|
6
|
-
class OnTrackCsvFile
|
7
|
-
attr_reader :file, :lines, :events
|
8
|
-
|
9
|
-
# Take the path to the CSV, open it, process it
|
10
|
-
def initialize csv_path
|
11
|
-
@csv_path = csv_path
|
12
|
-
@file = File.new @csv_path
|
13
|
-
self.read_lines
|
14
|
-
self.create_events
|
15
|
-
end
|
16
|
-
|
17
|
-
# Read the lines
|
18
|
-
def read_lines
|
19
|
-
@lines = []
|
20
|
-
|
21
|
-
# Where an event has more than one note, a 'line' will contain '\n's
|
22
|
-
l = ""
|
23
|
-
while line = @file.gets
|
24
|
-
# Stuff the line in to 'l'
|
25
|
-
l << line
|
26
|
-
|
27
|
-
# A '"' at the end of the line closes the event
|
28
|
-
if line[-2] == '"'
|
29
|
-
|
30
|
-
# Create a CsvLine, stripping the final '\n'
|
31
|
-
o = Insulin::OnTrackCsvLine.new l[0..-2]
|
32
|
-
@lines << o
|
33
|
-
|
34
|
-
# Reset the placeholder
|
35
|
-
l = ""
|
36
|
-
end
|
37
|
-
end
|
38
|
-
|
39
|
-
# Sort the list by the serial numbers (required for a future feature)
|
40
|
-
@lines.sort_by! {|o| o["serial"]}
|
41
|
-
end
|
42
|
-
|
43
|
-
# Turn the lines into Events
|
44
|
-
def create_events
|
45
|
-
@events = []
|
46
|
-
@lines.each do |l|
|
47
|
-
e = Insulin::Event.new l
|
48
|
-
@events << e
|
49
|
-
end
|
50
|
-
end
|
51
|
-
|
52
|
-
# Save the events to Mongo
|
53
|
-
def save_events mongo
|
54
|
-
# print "saving %d events to mongo... " % @events.count
|
55
|
-
@events.each do |e|
|
56
|
-
e.save mongo
|
57
|
-
end
|
58
|
-
# puts "done"
|
59
|
-
end
|
60
|
-
end
|
61
|
-
end
|
@@ -1,39 +0,0 @@
|
|
1
|
-
module Insulin
|
2
|
-
# Author:: Sam (mailto:sam@cruft.co)
|
3
|
-
# License:: MIT
|
4
|
-
|
5
|
-
# This class represents a single OnTrack CSV line
|
6
|
-
class OnTrackCsvLine < Hash
|
7
|
-
|
8
|
-
# Parse the passed-in CSV line
|
9
|
-
def initialize line
|
10
|
-
|
11
|
-
# Split on commas
|
12
|
-
bits = line.split ","
|
13
|
-
self["serial"] = bits[0].to_i
|
14
|
-
|
15
|
-
# OnTrack embeds commas in the dates of its CSVs. Duh
|
16
|
-
self.update OnTrackDate.new "%s%s" % [
|
17
|
-
bits[1],
|
18
|
-
bits[2]
|
19
|
-
]
|
20
|
-
self["type"] = bits[3].downcase
|
21
|
-
self["subtype"] = bits[4].downcase if not bits[4] == ""
|
22
|
-
self["tag"] = bits[5].downcase
|
23
|
-
self["value"] = bits[6].to_f
|
24
|
-
|
25
|
-
# Notes get complicated. Everything from field 7 to the end will be part
|
26
|
-
# of the notes
|
27
|
-
notes = bits[7..-1]
|
28
|
-
|
29
|
-
# We may have embedded commas
|
30
|
-
notes = notes.join ","
|
31
|
-
|
32
|
-
# Strip the trailing '\n'
|
33
|
-
notes = notes[1..-2]
|
34
|
-
|
35
|
-
# See Insulin::OnTrackNoteSet
|
36
|
-
self["notes"] = OnTrackNoteSet.new notes if not notes == ""
|
37
|
-
end
|
38
|
-
end
|
39
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
require "time"
|
2
|
-
|
3
|
-
module Insulin
|
4
|
-
# Author:: Sam (mailto:sam@cruft.co)
|
5
|
-
# License:: MIT
|
6
|
-
|
7
|
-
# OnTrack uses really shitty date formats, including embedding a comma in the
|
8
|
-
# CSV export file. Christ on a crutch
|
9
|
-
class OnTrackDate < Hash
|
10
|
-
|
11
|
-
# Parse the strind 'd', looking for datetime information
|
12
|
-
def initialize d
|
13
|
-
t = Time.parse d
|
14
|
-
|
15
|
-
# We extract loads of stuff. Might be useful one day
|
16
|
-
self["timestamp"] = t
|
17
|
-
self["tzoffset"] = t.strftime "%z"
|
18
|
-
self["timezone"] = t.zone
|
19
|
-
self["unixtime"] = t.to_i
|
20
|
-
self["day"] = t.strftime("%A").downcase
|
21
|
-
self["date"] = t.strftime "%F"
|
22
|
-
self["time"] = t.strftime "%T #{self['timezone']}"
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,46 +0,0 @@
|
|
1
|
-
module Insulin
|
2
|
-
# Author:: Sam (mailto:sam@cruft.co)
|
3
|
-
# License:: MIT
|
4
|
-
|
5
|
-
# Class representing a single OnTrack note
|
6
|
-
class OnTrackNote
|
7
|
-
|
8
|
-
# Lookups. We will only deal with notes of these types
|
9
|
-
@@keys = {
|
10
|
-
"F" => 'food',
|
11
|
-
"B" => 'booze',
|
12
|
-
"N" => 'note'
|
13
|
-
}
|
14
|
-
|
15
|
-
attr_reader :type, :content
|
16
|
-
|
17
|
-
# Parse the raw note 'n'
|
18
|
-
def initialize n
|
19
|
-
|
20
|
-
# Key/value splits on ':'
|
21
|
-
bits = n.split ":"
|
22
|
-
|
23
|
-
# Remove leading/trailing cruft from key part
|
24
|
-
t = bits[0].strip
|
25
|
-
|
26
|
-
# We only deal with the keys we know about
|
27
|
-
if @@keys.keys.include? t
|
28
|
-
|
29
|
-
# Remove cruft from content, downcase
|
30
|
-
@content = bits[1].strip.downcase
|
31
|
-
|
32
|
-
# These keys mean we turn the content into a list
|
33
|
-
if ["F", "B"].include? t
|
34
|
-
a = []
|
35
|
-
@content.split(",").each do |v|
|
36
|
-
a << v.strip
|
37
|
-
end
|
38
|
-
@content = a
|
39
|
-
end
|
40
|
-
|
41
|
-
# Set key from lookup list
|
42
|
-
@type = @@keys[t]
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|
46
|
-
end
|
@@ -1,45 +0,0 @@
|
|
1
|
-
module Insulin
|
2
|
-
# Author:: Sam (mailto:sam@cruft.co)
|
3
|
-
# License:: MIT
|
4
|
-
|
5
|
-
# This class represents a set of notes
|
6
|
-
class OnTrackNoteSet < Hash
|
7
|
-
|
8
|
-
# Parse the string 's'
|
9
|
-
def initialize s
|
10
|
-
|
11
|
-
# Notes separated by newlines
|
12
|
-
l = s.split"\n"
|
13
|
-
|
14
|
-
# For each line
|
15
|
-
l.each do |n|
|
16
|
-
|
17
|
-
# Make a note
|
18
|
-
x = OnTrackNote.new n
|
19
|
-
|
20
|
-
# This field will only exists for notes of a valid type
|
21
|
-
if x.type
|
22
|
-
|
23
|
-
# If we don't yet have this key
|
24
|
-
if not self[x.type]
|
25
|
-
|
26
|
-
# If the content is a list
|
27
|
-
if x.content.class.name == "Array"
|
28
|
-
|
29
|
-
# This becomes our value
|
30
|
-
self[x.type] = x.content
|
31
|
-
else
|
32
|
-
|
33
|
-
# Otherwise make it onto a list
|
34
|
-
self[x.type] = [x.content]
|
35
|
-
end
|
36
|
-
else
|
37
|
-
|
38
|
-
# This key exists, so we append this value
|
39
|
-
self[x.type] << x.content
|
40
|
-
end
|
41
|
-
end
|
42
|
-
end
|
43
|
-
end
|
44
|
-
end
|
45
|
-
end
|