bpl 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +140 -0
- data/Rakefile +15 -0
- data/bin/bpl +110 -0
- data/bpl.gemspec +31 -0
- data/config/database.yml +3 -0
- data/lib/bpl/version.rb +3 -0
- data/lib/bpl.rb +112 -0
- data/lib/create_blood.rb +27 -0
- data/lib/lib_trollop.rb +782 -0
- data/lib/models/blood_pressure.rb +30 -0
- data/spec/bpl_spec.rb +57 -0
- data/spec/spec_helper.rb +14 -0
- metadata +208 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
Copyright (c) 2012 Florin T.PATRASCU
|
2
|
+
|
3
|
+
MIT License
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
6
|
+
a copy of this software and associated documentation files (the
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
11
|
+
the following conditions:
|
12
|
+
|
13
|
+
The above copyright notice and this permission notice shall be
|
14
|
+
included in all copies or substantial portions of the Software.
|
15
|
+
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
19
|
+
NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
@@ -0,0 +1,140 @@
|
|
1
|
+
### Blood Pressure Logger (BPL)
|
2
|
+
|
3
|
+
A very simple gem to help you track your [blood pressure](http://en.wikipedia.org/wiki/Blood_pressure) values over time. With BPL you can also:
|
4
|
+
|
5
|
+
- export your data to other applications; Numbers, Excel, etc.
|
6
|
+
- view history for a given period of time
|
7
|
+
- and more
|
8
|
+
|
9
|
+
Your privacy is very important, this is why the BPL application is open source and it is using only local resources such as the small database stored on your computer. A basic guarantee that your data is safe and completely under your own control.
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
Install the BP gem:
|
14
|
+
|
15
|
+
$ gem install bpl
|
16
|
+
|
17
|
+
Create a new folder `.bp` in your home directory:
|
18
|
+
|
19
|
+
$ mkdir ~/.bp
|
20
|
+
|
21
|
+
|
22
|
+
## Usage
|
23
|
+
|
24
|
+
You'll have to initialize the database first, this is a one-time command:
|
25
|
+
|
26
|
+
$ bpl init
|
27
|
+
|
28
|
+
After that you can start recording your BP measurements as needed. Examples:
|
29
|
+
|
30
|
+
$ bpl 145/81/67/L/87 -d 2012/12/10 -t 16:30 -m notes
|
31
|
+
$ bpl 136/60/66
|
32
|
+
$ bpl 136/60/66/r
|
33
|
+
$ bpl 125/71/67/L/87 -d 2012/12/11 -m "some notes"
|
34
|
+
$ bpl 136/60/66/l/85
|
35
|
+
$ bpl 120/64/67/L/87 -D "2012/12/10 16:30"
|
36
|
+
|
37
|
+
BPL expects you to enter the following values:
|
38
|
+
|
39
|
+
SYS/DIA/HR/ARM/WEIGHT
|
40
|
+
|
41
|
+
Where:
|
42
|
+
|
43
|
+
SYS: systolic pressure.
|
44
|
+
DIA: diastolic pressure.
|
45
|
+
HR: heart rate
|
46
|
+
ARM: 'l' or 'r'. Left or right. It is optional; LEFT arm, if not specified.
|
47
|
+
WEIGHT: weight (optional, see note below)
|
48
|
+
|
49
|
+
You can also specify the date, date and time, and an optional comment, as seen in the previous set of examples.
|
50
|
+
|
51
|
+
A special **note** to remember when you log your data. Your weight is important but you're not required to specify it every time you add a new measurement. Specify your weight at least once or very time it is changing. The last weight value will be reused when not specified explicitly in the measurement.
|
52
|
+
|
53
|
+
### Other useful commands
|
54
|
+
A handful of command lines and switches are provided for your convenience.
|
55
|
+
|
56
|
+
**View**
|
57
|
+
- display a page with the most recent records, or recorded at a specified date/time. Example:
|
58
|
+
|
59
|
+
$ bpl view
|
60
|
+
$ bpl view -d 2012/08/01
|
61
|
+
$ bpl view -d 08/14 -t 09:31:10
|
62
|
+
|
63
|
+
**Remove**
|
64
|
+
delete a record by record id. The record id can be observed with the **view** command. Example:
|
65
|
+
|
66
|
+
$ bpl view -d 08/14 -t 09:31:10
|
67
|
+
+--+-------------------+---+---+--+-----+------+-----+
|
68
|
+
|Id| Date |Sys|Dia|Hr| Arm |Weight|Notes|
|
69
|
+
+--+-------------------+---+---+--+-----+------+-----+
|
70
|
+
|2 |2012-09-25 09:31:11|120|80 |67|LEFT |90 | |
|
71
|
+
|1 |2012-09-25 09:30:30|1 |2 |3 |RIGHT|90 | |
|
72
|
+
+--+-------------------+---+---+--+-----+------+-----+
|
73
|
+
|
74
|
+
$ bpl remove 1
|
75
|
+
record: #1, was removed.
|
76
|
+
|
77
|
+
**Export to CSV**
|
78
|
+
export your data to a file that can be imported by other applications, including Numbers or Excel.
|
79
|
+
|
80
|
+
Here is an example exporting the data to the screen:
|
81
|
+
|
82
|
+
$ bpl export -d 9/14
|
83
|
+
ID,DATE,SYS,DIA,HR,ARM,WEIGHT,NOTES
|
84
|
+
2,'2012-09-25 09:31:11',120,80,67,'LEFT',90,''
|
85
|
+
|
86
|
+
And to a specified file:
|
87
|
+
|
88
|
+
$ bpl export -d 2012/08/01 -f > my_bp.csv
|
89
|
+
$
|
90
|
+
|
91
|
+
**Init**
|
92
|
+
use init with `-f` if you want to wipe out clean your local database. Warning, your data cannot be restored after this point in time. Example:
|
93
|
+
|
94
|
+
$ bpl init -f
|
95
|
+
|
96
|
+
**Help**
|
97
|
+
|
98
|
+
$ bpl -h
|
99
|
+
|
100
|
+
Simple blood pressure logger
|
101
|
+
|
102
|
+
Available commands: history, series, delete, view, init, plot
|
103
|
+
|
104
|
+
Examples:
|
105
|
+
|
106
|
+
$ bpl 145/81/67/L/87 -d 2012/12/10 -t 16:30 -m notes
|
107
|
+
$ bpl 136/60/66
|
108
|
+
$ bpl 136/60/66/r
|
109
|
+
$ bpl 125/71/67/L/87 -d 2012/12/11 -m "some notes"
|
110
|
+
$ bpl 136/60/66/l/85
|
111
|
+
$ bpl 120/64/67/L/87 -D "2012/12/10 16:30"
|
112
|
+
$ bpl export -d 2012/08/01 -f > my_bp.csv
|
113
|
+
|
114
|
+
The following options apply:
|
115
|
+
--date, -d <s>: Date (default: 2012/10/31)
|
116
|
+
--time, -t <s>: Time (default: 11:01:31)
|
117
|
+
--datetime, -D <s>: Specify the date and the time, surrounded with quotes ";
|
118
|
+
--message, -m <s>: Notes, comments
|
119
|
+
--force, -f: Force database initialization, all the data will be lost
|
120
|
+
--raw, -r: used to view the data without formatting
|
121
|
+
--page, -p <i>: total number of records to view (default: 15)
|
122
|
+
--all, -a: export the entire dataset, all the records
|
123
|
+
--quiet, -q: no echoing to console
|
124
|
+
--help, -h: Show this message
|
125
|
+
|
126
|
+
|
127
|
+
### TODO
|
128
|
+
|
129
|
+
- plot the data for simple visualizations
|
130
|
+
|
131
|
+
## Contributing
|
132
|
+
|
133
|
+
1. Fork it
|
134
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
135
|
+
3. Commit your changes (`git commit -am 'Add some feature'`)
|
136
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
137
|
+
5. Create new Pull Request
|
138
|
+
|
139
|
+
## License
|
140
|
+
MIT, please see the attached LICENSE.txt for more details.
|
data/Rakefile
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
|
3
|
+
require "bundler/gem_tasks"
|
4
|
+
require 'rspec/core/rake_task'
|
5
|
+
|
6
|
+
Bundler::GemHelper.install_tasks
|
7
|
+
|
8
|
+
desc 'Default: run tests.'
|
9
|
+
task :default => [:spec]
|
10
|
+
|
11
|
+
task :spec do
|
12
|
+
RSpec::Core::RakeTask.new(:spec) do |t|
|
13
|
+
t.pattern = './spec/**/*_spec.rb'
|
14
|
+
end
|
15
|
+
end
|
data/bin/bpl
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift File.join(File.dirname(__FILE__), *%w[.. lib])
|
4
|
+
|
5
|
+
require "date"
|
6
|
+
require "bundler/setup"
|
7
|
+
require 'yajl'
|
8
|
+
require 'active_record'
|
9
|
+
require "lib_trollop"
|
10
|
+
require "bpl"
|
11
|
+
require "bpl/version"
|
12
|
+
require "models/blood_pressure"
|
13
|
+
require "create_blood"
|
14
|
+
require 'tablizer'
|
15
|
+
require "chronic"
|
16
|
+
|
17
|
+
# Simple Blood Pressure logger
|
18
|
+
#
|
19
|
+
# Florin, 2012.10.15
|
20
|
+
|
21
|
+
|
22
|
+
SUB_COMMANDS = %w(history series delete view init plot)
|
23
|
+
|
24
|
+
# db_config = YAML::load(File.open(File.join(File.dirname(__FILE__),
|
25
|
+
# '../config','database.yml'))) [ENV['ENV'] ? ENV['ENV'] : 'development']
|
26
|
+
# ActiveRecord::Base.establish_connection(db_config)
|
27
|
+
|
28
|
+
ActiveRecord::Base.establish_connection :adapter => "sqlite3",
|
29
|
+
:database => File.expand_path("~/.bp/blood.sqlite3")
|
30
|
+
opts = Trollop::options do
|
31
|
+
banner <<-BANNER
|
32
|
+
Simple blood pressure logger
|
33
|
+
|
34
|
+
Available commands: #{SUB_COMMANDS.join(", ")}
|
35
|
+
|
36
|
+
Examples:
|
37
|
+
|
38
|
+
$ bpl 145/81/67/L/87 -d 2012/12/10 -t 16:30 -m notes
|
39
|
+
$ bpl 136/60/66
|
40
|
+
$ bpl 136/60/66/r
|
41
|
+
$ bpl view --all
|
42
|
+
$ bpl 125/71/67/L/87 -d 2012/12/11 -m "some notes"
|
43
|
+
$ bpl 136/60/66/l/85
|
44
|
+
$ bpl 120/64/67/L/87 -D "2012/12/10 16:30"
|
45
|
+
$ bpl export -r -a
|
46
|
+
$ bpl export -d 2012/08/01 -f > my_bp.csv
|
47
|
+
|
48
|
+
The following options apply:
|
49
|
+
BANNER
|
50
|
+
|
51
|
+
now = Time.now
|
52
|
+
|
53
|
+
opt :date, "Date", :short => "-d", :default => now.strftime("%Y/%m/%d"), :type => String
|
54
|
+
opt :time, "Time", :short => "-t", :default => now.strftime("%H:%M:%S"), :type => String
|
55
|
+
opt :datetime, "Specify the date and the time, surrounded with quotes \";", :short => "-D", :type => String
|
56
|
+
opt :message, "Notes, comments", :short => "-m", :type => String
|
57
|
+
opt :force, "Force database initialization, all the data will be lost", :short => "-f"
|
58
|
+
opt :raw, "used to view the data without formatting", :short => "-r", :default => false
|
59
|
+
opt :page, "total number of records to view", :short => "-p", :default => 15, :type => Integer
|
60
|
+
opt :all, "export the entire dataset, all the records", :short => "-a", :default => false
|
61
|
+
opt :quiet, "no echoing to console", :short => "-q", :default => false
|
62
|
+
|
63
|
+
end
|
64
|
+
|
65
|
+
include Bpl
|
66
|
+
Bpl.options opts
|
67
|
+
|
68
|
+
# Check the command line parameters
|
69
|
+
cmd = ARGV.shift # get the subcommand
|
70
|
+
|
71
|
+
# optimize the two regex and build a clever one to rule them all :)
|
72
|
+
# use http://rubular.com, to validate
|
73
|
+
# hints: http://strugglingwithruby.blogspot.ca/2009/05/regular-expressions-in-ruby.html
|
74
|
+
case cmd
|
75
|
+
when /^(\d+)\/(\d+)\/(\d+)(?:\/([lr]))(?:\/(\d+))$/i, /^(\d+)\/(\d+)\/(\d+)(?:\/([lr]))?$/i
|
76
|
+
begin
|
77
|
+
Bpl.add($1, $2, $3, $4, $5)
|
78
|
+
rescue => e
|
79
|
+
puts "Exception in BPL: #{e} at #{e.backtrace.join("\n")}"
|
80
|
+
end
|
81
|
+
|
82
|
+
when "history", "view"
|
83
|
+
Bpl.view
|
84
|
+
|
85
|
+
when "export"
|
86
|
+
puts Bpl.export
|
87
|
+
|
88
|
+
when "delete", "remove"
|
89
|
+
Bpl.remove ARGV[0]
|
90
|
+
|
91
|
+
when "init"
|
92
|
+
puts "Initializing the blood database ..."
|
93
|
+
begin
|
94
|
+
CreateBlood.up
|
95
|
+
rescue => e
|
96
|
+
if opts[:force]
|
97
|
+
# ActiveRecord::Base.connection.drop_database db_config["database"] rescue nil
|
98
|
+
CreateBlood.down
|
99
|
+
CreateBlood.up
|
100
|
+
puts " - done."
|
101
|
+
else
|
102
|
+
puts "error: #{e.message}"
|
103
|
+
puts "use -f, to force the process and overwrite the data. All your previous data will be lost!"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
else
|
108
|
+
Trollop::die "unknown command #{cmd.inspect}"
|
109
|
+
end
|
110
|
+
|
data/bpl.gemspec
ADDED
@@ -0,0 +1,31 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
require File.expand_path('../lib/bpl/version', __FILE__)
|
3
|
+
|
4
|
+
Gem::Specification.new do |gem|
|
5
|
+
gem.name = "bpl"
|
6
|
+
gem.version = Bpl::VERSION
|
7
|
+
gem.authors = ["Florin T.PATRASCU"]
|
8
|
+
gem.email = ["florin.patrascu@gmail.com"]
|
9
|
+
gem.description = %q{BPL is a gem to help you track your blood pressure and view your records over time}
|
10
|
+
gem.summary = %q{Blood pressure logger}
|
11
|
+
gem.homepage = ""
|
12
|
+
|
13
|
+
gem.files = `git ls-files`.split($/)
|
14
|
+
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
15
|
+
gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
|
16
|
+
gem.require_paths = ["lib"]
|
17
|
+
|
18
|
+
# Gem dependencies for run-time
|
19
|
+
gem.add_runtime_dependency "yajl-ruby"
|
20
|
+
gem.add_runtime_dependency 'sqlite3'
|
21
|
+
gem.add_runtime_dependency 'yajl-ruby'
|
22
|
+
gem.add_runtime_dependency 'chronic'
|
23
|
+
gem.add_runtime_dependency 'activerecord-sqlserver-adapter'
|
24
|
+
gem.add_runtime_dependency 'activerecord'
|
25
|
+
gem.add_runtime_dependency 'time_of_day'
|
26
|
+
gem.add_runtime_dependency 'tablizer'
|
27
|
+
|
28
|
+
# Gem dependencies for development
|
29
|
+
gem.add_development_dependency "rspec"
|
30
|
+
|
31
|
+
end
|
data/config/database.yml
ADDED
data/lib/bpl/version.rb
ADDED
data/lib/bpl.rb
ADDED
@@ -0,0 +1,112 @@
|
|
1
|
+
require "bpl/version"
|
2
|
+
require 'yajl'
|
3
|
+
require "models/blood_pressure"
|
4
|
+
require "csv"
|
5
|
+
|
6
|
+
module Bpl
|
7
|
+
def options(opts={})
|
8
|
+
@opts=opts
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.add(sys, dia, hr, arm='l', weight=nil)
|
12
|
+
@sys = sys.to_i
|
13
|
+
@dia = dia.to_i
|
14
|
+
@hr = hr.to_i
|
15
|
+
@arm = arm
|
16
|
+
@weight = weight
|
17
|
+
|
18
|
+
if weight.nil?
|
19
|
+
begin
|
20
|
+
@weight = BloodPressure.most_recent.weight
|
21
|
+
rescue => e
|
22
|
+
puts "Problems: #{e.message}"
|
23
|
+
puts "You should add your weight next time. It is: 0, now."
|
24
|
+
@weight = 0
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
if @opts[:datetime]
|
29
|
+
@created_at = Chronic.parse @opts[:datetime]
|
30
|
+
else
|
31
|
+
@created_at = Chronic.parse "#{@opts[:date]} #{@opts[:time]}"
|
32
|
+
end
|
33
|
+
|
34
|
+
bp = BloodPressure.new(:sys => @sys, :dia => @dia, :hr => @hr,
|
35
|
+
:arm => arm(@arm), :weight => @weight,
|
36
|
+
:created_at => @created_at,
|
37
|
+
:notes => @opts[:message])
|
38
|
+
bp.save
|
39
|
+
Bpl.echo unless @opts[:quiet]
|
40
|
+
bp
|
41
|
+
end
|
42
|
+
|
43
|
+
def self.remove(id)
|
44
|
+
begin
|
45
|
+
BloodPressure.find(id).delete unless id.nil?
|
46
|
+
puts "record: \##{id}, was removed."
|
47
|
+
rescue => e
|
48
|
+
puts e.message
|
49
|
+
end
|
50
|
+
|
51
|
+
end
|
52
|
+
|
53
|
+
def self.view(silent=false)
|
54
|
+
table = [['ID', 'DATE', 'SYS', 'DIA', 'HR', 'ARM', 'WEIGHT', 'NOTES']]
|
55
|
+
records = []
|
56
|
+
|
57
|
+
if @opts[:all]
|
58
|
+
records = BloodPressure.all_records
|
59
|
+
else
|
60
|
+
records = BloodPressure.records_since(Chronic.parse(@opts[:date]), @opts[:page])
|
61
|
+
end
|
62
|
+
|
63
|
+
if records.empty?
|
64
|
+
puts "the database has no records."
|
65
|
+
else
|
66
|
+
records.each do |r|
|
67
|
+
table << [r.id ,"#{r.date_collected} #{r.time_collected.time_of_day}", r.sys, r.dia, r.hr, r.arm, r.weight, r.notes.nil? ? '' : r.notes]
|
68
|
+
end
|
69
|
+
|
70
|
+
if @opts[:raw]
|
71
|
+
table.shift
|
72
|
+
puts table.inspect
|
73
|
+
else
|
74
|
+
puts Tablizer::Table.new(table, header: true) # can add align: 'ansi_rjust'
|
75
|
+
end unless silent
|
76
|
+
end
|
77
|
+
|
78
|
+
table
|
79
|
+
end
|
80
|
+
|
81
|
+
def self.echo
|
82
|
+
puts "[#{@created_at.inspect}] Sys: #{@sys}, DIA: #{@dia}, HR: #{@hr}, arm: #{arm(@arm)}, W: #{@weight}; Notes: #{@opts[:message]}"
|
83
|
+
end
|
84
|
+
|
85
|
+
def self.export
|
86
|
+
begin
|
87
|
+
table = Bpl.view true
|
88
|
+
csv_string = CSV.generate do |csv|
|
89
|
+
csv << table[0]
|
90
|
+
table.shift
|
91
|
+
table.each do |r|
|
92
|
+
csv << [r[0], "'#{r[1]}'", r[2], r[3], r[4], "'#{r[5]}'", r[6], "'#{r[7]}'"]
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
csv_string
|
97
|
+
rescue => e
|
98
|
+
# puts e.inspect
|
99
|
+
# puts e.backtrace
|
100
|
+
# or:
|
101
|
+
puts caller
|
102
|
+
puts "Error while exporting the data: #{e.message}"
|
103
|
+
''
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
protected
|
108
|
+
def arm(which_one)
|
109
|
+
which_one =~ /[rR]/ ? 'RIGHT' : 'LEFT'
|
110
|
+
end
|
111
|
+
|
112
|
+
end
|
data/lib/create_blood.rb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'active_record'
|
2
|
+
|
3
|
+
class CreateBlood < ActiveRecord::Migration
|
4
|
+
def self.up
|
5
|
+
create_table :blood_pressures do |t|
|
6
|
+
t.column :sys, :integer
|
7
|
+
t.column :dia, :integer
|
8
|
+
t.column :hr, :integer
|
9
|
+
t.column :arm, :string
|
10
|
+
t.column :weight, :integer
|
11
|
+
t.column :notes, :text
|
12
|
+
t.timestamps
|
13
|
+
end
|
14
|
+
add_index :blood_pressures, [:created_at]
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.down
|
18
|
+
drop_table :blood_pressures
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
# other methods:
|
23
|
+
# def init_db
|
24
|
+
# ActiveRecord::Schema.define do
|
25
|
+
# .....
|
26
|
+
# end
|
27
|
+
# end
|