beeminder 0.2.9 → 0.2.13
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.
- checksums.yaml +5 -13
- data/beeminder.gemspec +2 -2
- data/bin/beemind +4 -4
- data/lib/beeminder/goals.rb +40 -2
- data/lib/beeminder/user.rb +37 -16
- data/lib/beeminder/version.rb +1 -1
- data/lib/beeminder.rb +1 -0
- metadata +28 -29
checksums.yaml
CHANGED
@@ -1,15 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
|
5
|
-
data.tar.gz: !binary |-
|
6
|
-
OTBkNmMyMzdmOGM5YTk3ZTJlYjI5ZjIxNmI0MTU2ZWEwYjIxYTFlNA==
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 93a795ea4da67f8f37467e4fba52f1ceaed16612f5ecccc8fb9bd11d0ea1a9ce
|
4
|
+
data.tar.gz: a9e21515c529f820ebf58a2278a3ca36e9b8a44eba59469366820c2f9e21763b
|
7
5
|
SHA512:
|
8
|
-
metadata.gz:
|
9
|
-
|
10
|
-
OTcyODhkOWRjZWZmMGJjNWJhOTg2NjllNjQyYzg2NDMxZWUzZGNhYmFkMjdj
|
11
|
-
ZmI1NjIxODg2ZjA3NzIwYjJhYTA4NmIxMGExMDk2YzY3ZTQ5Njg=
|
12
|
-
data.tar.gz: !binary |-
|
13
|
-
NDI1ZjdlZDhkZTEyMmFiZWU0MTk0NjA1NTY0MjNhMTZmNWE2NGFlOTBhNzVm
|
14
|
-
MWE1YzhjNDhlODFkZTcyNmE1NjA2MzdhODc3NWE2N2UyZmE5NTJhZDU0ZjE1
|
15
|
-
YTYyOTZkZWZhOWZkNDJhMzFhNDA1YmZjMjBlYTc1YmQ5NmM2OGU=
|
6
|
+
metadata.gz: 6269b4af7d7365c6d9e091f2734776af8402dcd5dfd852c19d63d8346417698d7785c526748b3283a40be1db68d7eb3739f588f1f520ec99f37c32382248d5fd
|
7
|
+
data.tar.gz: 9b313b7322ebc9dcc2876c141d6aec6bdf012ab016cdbc4e81361b98dcbba5a92efaa843dfe934f36ea58b3a6bc30378c11888f2dc4616203ec33a7691b84daa
|
data/beeminder.gemspec
CHANGED
@@ -16,10 +16,10 @@ Gem::Specification.new do |gem|
|
|
16
16
|
gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
|
17
17
|
gem.require_paths = ["lib"]
|
18
18
|
|
19
|
-
gem.add_dependency 'activesupport', ['>= 3.2', '<
|
19
|
+
gem.add_dependency 'activesupport', ['>= 3.2', '< 7']
|
20
20
|
gem.add_dependency 'chronic', '~> 0.7'
|
21
21
|
gem.add_dependency 'json'
|
22
22
|
gem.add_dependency 'highline', '~> 1.6'
|
23
|
-
gem.add_dependency '
|
23
|
+
gem.add_dependency 'optimist', '~> 3'
|
24
24
|
gem.add_dependency 'tzinfo'
|
25
25
|
end
|
data/bin/beemind
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
|
4
4
|
require 'chronic'
|
5
5
|
require 'highline/import'
|
6
|
-
require '
|
6
|
+
require 'optimist'
|
7
7
|
require 'yaml'
|
8
8
|
|
9
9
|
# load library
|
@@ -18,7 +18,7 @@ else
|
|
18
18
|
end
|
19
19
|
|
20
20
|
usage = "usage: beemind goal value [comment]"
|
21
|
-
opts =
|
21
|
+
opts = Optimist::options do
|
22
22
|
banner usage
|
23
23
|
|
24
24
|
opt :config, "Path to config.", :type => :string, :default => "~/.beeminderrc"
|
@@ -27,7 +27,7 @@ opts = Trollop::options do
|
|
27
27
|
opt :date, "Set a manual date. Uses Chronic syntax.", :type => :string, :default => "now"
|
28
28
|
end
|
29
29
|
|
30
|
-
|
30
|
+
Optimist::die usage if not (2..3).include?(ARGV.size) and not opts[:list]
|
31
31
|
goal, value, comment = ARGV unless opts[:list]
|
32
32
|
|
33
33
|
opts[:config] = File.expand_path opts[:config]
|
@@ -66,7 +66,7 @@ if opts[:list]
|
|
66
66
|
end
|
67
67
|
else
|
68
68
|
date = Chronic.parse(opts[:date], :context => :past)
|
69
|
-
|
69
|
+
Optimist::die "invalid date" if date.nil?
|
70
70
|
|
71
71
|
g = bee.goal goal
|
72
72
|
dp = Beeminder::Datapoint.new :timestamp => date,
|
data/lib/beeminder/goals.rb
CHANGED
@@ -59,6 +59,18 @@ module Beeminder
|
|
59
59
|
|
60
60
|
# @return [Beeminder::User] User that owns this goal.
|
61
61
|
attr_reader :user
|
62
|
+
|
63
|
+
# @return [Array<Integer, Float, Float>] All road settings over time
|
64
|
+
attr_accessor :roadall
|
65
|
+
|
66
|
+
# @return [true|false] Whether the goal is currently frozen and therefore must be restarted before continuing to accept data.
|
67
|
+
attr_reader :frozen
|
68
|
+
|
69
|
+
# @return [Numeric] Where you are with respect to the yellow brick road (2 or more = above the road, 1 = top lane, -1 = bottom lane, -2 or less = below the road).
|
70
|
+
attr_reader :lane
|
71
|
+
|
72
|
+
# @return [Numeric] Good side of the road. I.e., the side of the road (+1/-1 = above/below) that makes you say “yay”.
|
73
|
+
attr_reader :yaw
|
62
74
|
|
63
75
|
def initialize user, name_or_info
|
64
76
|
@user = user
|
@@ -79,7 +91,7 @@ module Beeminder
|
|
79
91
|
# Reload data from Beeminder.
|
80
92
|
def reload
|
81
93
|
info = @user.get "users/me/goals/#{@slug}.json"
|
82
|
-
|
94
|
+
_parse_info info
|
83
95
|
end
|
84
96
|
|
85
97
|
# List of datapoints.
|
@@ -108,8 +120,9 @@ module Beeminder
|
|
108
120
|
"secret" => @secret || false,
|
109
121
|
"datapublic" => @datapublic || false,
|
110
122
|
}
|
123
|
+
data['roadall'] = @roadall if @roadall
|
111
124
|
|
112
|
-
@user.
|
125
|
+
@user.put_document "users/me/goals/#{@slug}.json", data
|
113
126
|
end
|
114
127
|
|
115
128
|
# Send new road setting to Beeminder.
|
@@ -126,6 +139,20 @@ module Beeminder
|
|
126
139
|
|
127
140
|
@user.post "users/me/goals/#{@slug}/dial_road.json", dials
|
128
141
|
end
|
142
|
+
|
143
|
+
# Schedule a break.
|
144
|
+
# Adds two new entries to `roadall` reflecting the break.
|
145
|
+
# Use #update to actually update the goal.
|
146
|
+
#
|
147
|
+
# @param start_time [Time] when to start the break -- must be after the akrasia horizon
|
148
|
+
# @param end_time [Time] when to end the break
|
149
|
+
# @param rate [Float] the slope of the road during the break
|
150
|
+
def schedule_break start_time, end_time, rate = 0.0
|
151
|
+
check_break start_time, end_time
|
152
|
+
|
153
|
+
roadall.insert(-2, [start_time.to_i, nil, roadall.last.last])
|
154
|
+
roadall.insert(-2, [end_time.to_i, nil, rate])
|
155
|
+
end
|
129
156
|
|
130
157
|
# Add one or more datapoints to the goal.
|
131
158
|
#
|
@@ -172,6 +199,14 @@ module Beeminder
|
|
172
199
|
|
173
200
|
private
|
174
201
|
|
202
|
+
def check_break start_time, end_time
|
203
|
+
akrasia_horizon = user.akrasia_horizon
|
204
|
+
fail ArgumentError, "break start can't be before the akrasia horizon (#{akrasia_horizon})" \
|
205
|
+
if start_time < akrasia_horizon
|
206
|
+
fail ArgumentError, 'break must start before it ends' \
|
207
|
+
unless end_time > start_time
|
208
|
+
end
|
209
|
+
|
175
210
|
def _parse_info info
|
176
211
|
# set variables
|
177
212
|
info.each do |k,v|
|
@@ -184,6 +219,9 @@ module Beeminder
|
|
184
219
|
@losedate = DateTime.strptime(@losedate.to_s, '%s').in_time_zone(@user.timezone) unless @losedate.nil?
|
185
220
|
@updated_at = DateTime.strptime(@updated_at.to_s, '%s').in_time_zone(@user.timezone)
|
186
221
|
@curdate = DateTime.strptime(@curdate.to_s, '%s').in_time_zone(@user.timezone) unless @curdate.nil?
|
222
|
+
|
223
|
+
# reported data is sometimes malformed like this
|
224
|
+
roadall.last[0] = nil if !roadall.nil? && roadall.last[0] == 0
|
187
225
|
end
|
188
226
|
end
|
189
227
|
|
data/lib/beeminder/user.rb
CHANGED
@@ -127,6 +127,14 @@ module Beeminder
|
|
127
127
|
_connection :put, cmd, data
|
128
128
|
end
|
129
129
|
|
130
|
+
# Send PUT request with a JSON document to API.
|
131
|
+
#
|
132
|
+
# @param cmd [String] the API command, like `users/#{user.name}.json`
|
133
|
+
# @param data [Hash] data to send
|
134
|
+
def put_document cmd, data = {}
|
135
|
+
_connection :put_json, cmd, data
|
136
|
+
end
|
137
|
+
|
130
138
|
# Converts time object to one with user's timezone.
|
131
139
|
#
|
132
140
|
# @param time [Date|DateTime|Time] Time to convert.
|
@@ -140,6 +148,15 @@ module Beeminder
|
|
140
148
|
}
|
141
149
|
end
|
142
150
|
|
151
|
+
# Returns the current akrasia horizon.
|
152
|
+
#
|
153
|
+
# @return [Time] The first instant changes can be made for.
|
154
|
+
def akrasia_horizon
|
155
|
+
Time.use_zone(@timezone) do
|
156
|
+
-8.days.ago.beginning_of_day
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
143
160
|
private
|
144
161
|
|
145
162
|
# Establish HTTPS connection to API.
|
@@ -151,7 +168,7 @@ module Beeminder
|
|
151
168
|
http = Net::HTTP.new(url.host, url.port)
|
152
169
|
http.read_timeout = 8640
|
153
170
|
http.use_ssl = true
|
154
|
-
http.verify_mode = OpenSSL::SSL::
|
171
|
+
http.verify_mode = OpenSSL::SSL::VERIFY_PEER # was VERIFY_NONE for some reason
|
155
172
|
|
156
173
|
# FIXME Sanity check for wrong timestamp. Source of bug unknown, but at least we can prevent screwing up someone's graph.
|
157
174
|
unless data["timestamp"].nil?
|
@@ -162,21 +179,25 @@ module Beeminder
|
|
162
179
|
|
163
180
|
json = ""
|
164
181
|
http.start do |http|
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
182
|
+
case type
|
183
|
+
when :post
|
184
|
+
req = Net::HTTP::Post.new(url.path)
|
185
|
+
req.set_form_data(data)
|
186
|
+
when :get
|
187
|
+
req = Net::HTTP::Get.new(url.path + "?" + data.to_query)
|
188
|
+
when :delete
|
189
|
+
req = Net::HTTP::Delete.new(url.path + "?" + data.to_query)
|
190
|
+
when :put
|
191
|
+
req = Net::HTTP::Put.new(url.path)
|
192
|
+
req.set_form_data(data)
|
193
|
+
when :put_json
|
194
|
+
req = Net::HTTP::Put.new(url.path)
|
195
|
+
req.body = data.to_json
|
196
|
+
req.content_type = 'application/json'
|
197
|
+
else
|
198
|
+
raise "invalid connection type"
|
199
|
+
end
|
200
|
+
|
180
201
|
res = http.request(req)
|
181
202
|
if not res.is_a? Net::HTTPSuccess
|
182
203
|
raise "request failed: #{res.code} / #{res.body}"
|
data/lib/beeminder/version.rb
CHANGED
data/lib/beeminder.rb
CHANGED
metadata
CHANGED
@@ -1,103 +1,103 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: beeminder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.13
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- muflax
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2022-04-19 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: activesupport
|
15
15
|
requirement: !ruby/object:Gem::Requirement
|
16
16
|
requirements:
|
17
|
-
- -
|
17
|
+
- - ">="
|
18
18
|
- !ruby/object:Gem::Version
|
19
19
|
version: '3.2'
|
20
|
-
- - <
|
20
|
+
- - "<"
|
21
21
|
- !ruby/object:Gem::Version
|
22
|
-
version: '
|
22
|
+
version: '7'
|
23
23
|
type: :runtime
|
24
24
|
prerelease: false
|
25
25
|
version_requirements: !ruby/object:Gem::Requirement
|
26
26
|
requirements:
|
27
|
-
- -
|
27
|
+
- - ">="
|
28
28
|
- !ruby/object:Gem::Version
|
29
29
|
version: '3.2'
|
30
|
-
- - <
|
30
|
+
- - "<"
|
31
31
|
- !ruby/object:Gem::Version
|
32
|
-
version: '
|
32
|
+
version: '7'
|
33
33
|
- !ruby/object:Gem::Dependency
|
34
34
|
name: chronic
|
35
35
|
requirement: !ruby/object:Gem::Requirement
|
36
36
|
requirements:
|
37
|
-
- - ~>
|
37
|
+
- - "~>"
|
38
38
|
- !ruby/object:Gem::Version
|
39
39
|
version: '0.7'
|
40
40
|
type: :runtime
|
41
41
|
prerelease: false
|
42
42
|
version_requirements: !ruby/object:Gem::Requirement
|
43
43
|
requirements:
|
44
|
-
- - ~>
|
44
|
+
- - "~>"
|
45
45
|
- !ruby/object:Gem::Version
|
46
46
|
version: '0.7'
|
47
47
|
- !ruby/object:Gem::Dependency
|
48
48
|
name: json
|
49
49
|
requirement: !ruby/object:Gem::Requirement
|
50
50
|
requirements:
|
51
|
-
- -
|
51
|
+
- - ">="
|
52
52
|
- !ruby/object:Gem::Version
|
53
53
|
version: '0'
|
54
54
|
type: :runtime
|
55
55
|
prerelease: false
|
56
56
|
version_requirements: !ruby/object:Gem::Requirement
|
57
57
|
requirements:
|
58
|
-
- -
|
58
|
+
- - ">="
|
59
59
|
- !ruby/object:Gem::Version
|
60
60
|
version: '0'
|
61
61
|
- !ruby/object:Gem::Dependency
|
62
62
|
name: highline
|
63
63
|
requirement: !ruby/object:Gem::Requirement
|
64
64
|
requirements:
|
65
|
-
- - ~>
|
65
|
+
- - "~>"
|
66
66
|
- !ruby/object:Gem::Version
|
67
67
|
version: '1.6'
|
68
68
|
type: :runtime
|
69
69
|
prerelease: false
|
70
70
|
version_requirements: !ruby/object:Gem::Requirement
|
71
71
|
requirements:
|
72
|
-
- - ~>
|
72
|
+
- - "~>"
|
73
73
|
- !ruby/object:Gem::Version
|
74
74
|
version: '1.6'
|
75
75
|
- !ruby/object:Gem::Dependency
|
76
|
-
name:
|
76
|
+
name: optimist
|
77
77
|
requirement: !ruby/object:Gem::Requirement
|
78
78
|
requirements:
|
79
|
-
- - ~>
|
79
|
+
- - "~>"
|
80
80
|
- !ruby/object:Gem::Version
|
81
|
-
version: '
|
81
|
+
version: '3'
|
82
82
|
type: :runtime
|
83
83
|
prerelease: false
|
84
84
|
version_requirements: !ruby/object:Gem::Requirement
|
85
85
|
requirements:
|
86
|
-
- - ~>
|
86
|
+
- - "~>"
|
87
87
|
- !ruby/object:Gem::Version
|
88
|
-
version: '
|
88
|
+
version: '3'
|
89
89
|
- !ruby/object:Gem::Dependency
|
90
90
|
name: tzinfo
|
91
91
|
requirement: !ruby/object:Gem::Requirement
|
92
92
|
requirements:
|
93
|
-
- -
|
93
|
+
- - ">="
|
94
94
|
- !ruby/object:Gem::Version
|
95
95
|
version: '0'
|
96
96
|
type: :runtime
|
97
97
|
prerelease: false
|
98
98
|
version_requirements: !ruby/object:Gem::Requirement
|
99
99
|
requirements:
|
100
|
-
- -
|
100
|
+
- - ">="
|
101
101
|
- !ruby/object:Gem::Version
|
102
102
|
version: '0'
|
103
103
|
description: Convenient access to Beeminder's API.
|
@@ -108,7 +108,7 @@ executables:
|
|
108
108
|
extensions: []
|
109
109
|
extra_rdoc_files: []
|
110
110
|
files:
|
111
|
-
- .gitignore
|
111
|
+
- ".gitignore"
|
112
112
|
- CHANGES.md
|
113
113
|
- Gemfile
|
114
114
|
- LICENSE.txt
|
@@ -124,24 +124,23 @@ files:
|
|
124
124
|
homepage: https://github.com/beeminder/beeminder-gem
|
125
125
|
licenses: []
|
126
126
|
metadata: {}
|
127
|
-
post_install_message:
|
127
|
+
post_install_message:
|
128
128
|
rdoc_options: []
|
129
129
|
require_paths:
|
130
130
|
- lib
|
131
131
|
required_ruby_version: !ruby/object:Gem::Requirement
|
132
132
|
requirements:
|
133
|
-
- -
|
133
|
+
- - ">="
|
134
134
|
- !ruby/object:Gem::Version
|
135
135
|
version: '0'
|
136
136
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
137
137
|
requirements:
|
138
|
-
- -
|
138
|
+
- - ">="
|
139
139
|
- !ruby/object:Gem::Version
|
140
140
|
version: '0'
|
141
141
|
requirements: []
|
142
|
-
|
143
|
-
|
144
|
-
signing_key:
|
142
|
+
rubygems_version: 3.2.32
|
143
|
+
signing_key:
|
145
144
|
specification_version: 4
|
146
145
|
summary: access Beeminder API
|
147
146
|
test_files: []
|