insulin 0.0.13 → 0.0.14
Sign up to get free protection for your applications and to get access to all the features.
- 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
|