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 CHANGED
@@ -1,15 +1,7 @@
1
1
  ---
2
- !binary "U0hBMQ==":
3
- metadata.gz: !binary |-
4
- MGNjOWExYTVhMzY0ODc3NzRmYTg0ZmM3ZGRiYWI5MzRlZWY0ZTQwZA==
5
- data.tar.gz: !binary |-
6
- OTBkNmMyMzdmOGM5YTk3ZTJlYjI5ZjIxNmI0MTU2ZWEwYjIxYTFlNA==
2
+ SHA256:
3
+ metadata.gz: 93a795ea4da67f8f37467e4fba52f1ceaed16612f5ecccc8fb9bd11d0ea1a9ce
4
+ data.tar.gz: a9e21515c529f820ebf58a2278a3ca36e9b8a44eba59469366820c2f9e21763b
7
5
  SHA512:
8
- metadata.gz: !binary |-
9
- NTcxNTBhNzE5Nzg2ZTUyMWI5OWZkNDZkMjY2OTk0Yjg5MmMwN2Q3MGNmZjhj
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', '< 5']
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 'trollop', '~> 2'
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 'trollop'
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 = Trollop::options do
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
- Trollop::die usage if not (2..3).include?(ARGV.size) and not opts[:list]
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
- Trollop::die "invalid date" if date.nil?
69
+ Optimist::die "invalid date" if date.nil?
70
70
 
71
71
  g = bee.goal goal
72
72
  dp = Beeminder::Datapoint.new :timestamp => date,
@@ -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
- parse_info info
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.put "users/me/goals/#{@slug}.json", data
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
 
@@ -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::VERIFY_NONE # FIXME: actually verify
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
- req = case type
166
- when :post
167
- Net::HTTP::Post.new(url.path)
168
- req.set_form_data(data)
169
- when :get
170
- Net::HTTP::Get.new(url.path + "?" + data.to_query)
171
- when :delete
172
- Net::HTTP::Delete.new(url.path + "?" + data.to_query)
173
- when :put
174
- Net::HTTP::Put.new(url.path)
175
- req.set_form_data(data)
176
- else
177
- raise "invalid connection type"
178
- end
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}"
@@ -1,3 +1,3 @@
1
1
  module Beeminder
2
- VERSION = "0.2.9"
2
+ VERSION = "0.2.13"
3
3
  end
data/lib/beeminder.rb CHANGED
@@ -1,5 +1,6 @@
1
1
  # coding: utf-8
2
2
 
3
+ require 'active_support'
3
4
  require 'active_support/core_ext'
4
5
  require 'date'
5
6
  require 'json'
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.9
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: 2014-04-20 00:00:00.000000000 Z
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: '5'
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: '5'
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: trollop
76
+ name: optimist
77
77
  requirement: !ruby/object:Gem::Requirement
78
78
  requirements:
79
- - - ~>
79
+ - - "~>"
80
80
  - !ruby/object:Gem::Version
81
- version: '2'
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: '2'
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
- rubyforge_project:
143
- rubygems_version: 2.2.2
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: []