beeminder 0.2.3 → 0.2.4
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/TODO +2 -1
- data/beeminder.gemspec +2 -0
- data/lib/beeminder.rb +1 -0
- data/lib/beeminder/goals.rb +35 -8
- data/lib/beeminder/user.rb +37 -8
- data/lib/beeminder/version.rb +1 -1
- metadata +36 -4
data/TODO
CHANGED
data/beeminder.gemspec
CHANGED
@@ -16,8 +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
20
|
gem.add_dependency 'chronic', '~> 0.7'
|
20
21
|
gem.add_dependency 'json'
|
21
22
|
gem.add_dependency 'highline', '~> 1.6'
|
22
23
|
gem.add_dependency 'trollop', '~> 2'
|
24
|
+
gem.add_dependency 'tzinfo'
|
23
25
|
end
|
data/lib/beeminder.rb
CHANGED
data/lib/beeminder/goals.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
module Beeminder
|
4
4
|
class Goal
|
@@ -81,7 +81,13 @@ module Beeminder
|
|
81
81
|
# @return [Array<Beeminder::Datapoint>] returns list of datapoints
|
82
82
|
def datapoints
|
83
83
|
info = @user.get "users/me/goals/#{slug}/datapoints.json"
|
84
|
-
datapoints = info.map
|
84
|
+
datapoints = info.map do |d_info|
|
85
|
+
d_info = {
|
86
|
+
:goal => self,
|
87
|
+
}.merge(d_info)
|
88
|
+
|
89
|
+
Datapoint.new d_info
|
90
|
+
end
|
85
91
|
|
86
92
|
datapoints
|
87
93
|
end
|
@@ -106,8 +112,12 @@ module Beeminder
|
|
106
112
|
def dial_road dials={}
|
107
113
|
raise "Set exactly two dials." if dials.keys.size != 2
|
108
114
|
|
109
|
-
|
110
|
-
|
115
|
+
# convert to proper timestamp
|
116
|
+
unless dials["goaldate"].nil?
|
117
|
+
dials["goaldate"] = @user.convert_to_timezone dials["goaldate"] if @user.enforce_timezone?
|
118
|
+
dials["goaldate"] = dials["goaldate"].strftime('%s')
|
119
|
+
end
|
120
|
+
|
111
121
|
@user.post "users/me/goals/#{@slug}/dial_road.json", dials
|
112
122
|
end
|
113
123
|
|
@@ -117,12 +127,15 @@ module Beeminder
|
|
117
127
|
def add datapoints, opts={}
|
118
128
|
datapoints = [*datapoints]
|
119
129
|
|
120
|
-
# FIXME create_all doesn't work because Ruby's POST encoding of arrays is broken.
|
121
130
|
datapoints.each do |dp|
|
131
|
+
# we grab these datapoints for ourselves
|
132
|
+
dp.goal = self
|
133
|
+
|
122
134
|
data = {
|
123
135
|
"sendmail" => opts[:sendmail] || false
|
124
136
|
}.merge(dp.to_hash)
|
125
137
|
|
138
|
+
# TODO create_all doesn't work because Ruby's POST encoding of arrays is broken.
|
126
139
|
@user.post "users/me/goals/#{@slug}/datapoints.json", data
|
127
140
|
end
|
128
141
|
end
|
@@ -160,10 +173,10 @@ module Beeminder
|
|
160
173
|
end
|
161
174
|
|
162
175
|
# some conversions
|
163
|
-
@goaldate = DateTime.strptime(@goaldate.to_s, '%s') unless @goaldate.nil?
|
176
|
+
@goaldate = DateTime.strptime(@goaldate.to_s, '%s').in_time_zone(@user.timezone) unless @goaldate.nil?
|
164
177
|
@goal_type = @goal_type.to_sym unless @goal_type.nil?
|
165
|
-
@losedate = DateTime.strptime(@losedate.to_s, '%s') unless @losedate.nil?
|
166
|
-
@updated_at = DateTime.strptime(@updated_at.to_s, '%s')
|
178
|
+
@losedate = DateTime.strptime(@losedate.to_s, '%s').in_time_zone(@user.timezone) unless @losedate.nil?
|
179
|
+
@updated_at = DateTime.strptime(@updated_at.to_s, '%s').in_time_zone(@user.timezone)
|
167
180
|
end
|
168
181
|
end
|
169
182
|
|
@@ -183,6 +196,10 @@ module Beeminder
|
|
183
196
|
# @return [DateTime] The time that this datapoint was entered or last updated.
|
184
197
|
attr_reader :updated_at
|
185
198
|
|
199
|
+
# @return [Beeminder::Goal] Goal this datapoint belongs to.
|
200
|
+
# Optional for new datapoints. Use `Goal#add` to add new datapoints to a goal.
|
201
|
+
attr_accessor :goal
|
202
|
+
|
186
203
|
def initialize info={}
|
187
204
|
# set variables
|
188
205
|
info.each do |k,v|
|
@@ -196,11 +213,21 @@ module Beeminder
|
|
196
213
|
# some conversions
|
197
214
|
@timestamp = DateTime.strptime(@timestamp.to_s, '%s') unless @timestamp.is_a?(Date) || @timestamp.is_a?(Time)
|
198
215
|
@updated_at = DateTime.strptime(@updated_at.to_s, '%s') unless @updated_at.nil?
|
216
|
+
|
217
|
+
# set timezone if possible
|
218
|
+
unless @goal.nil?
|
219
|
+
@timestamp = @timestamp.in_time_zone @goal.user.timezone
|
220
|
+
@updated_at = @updated_at.in_time_zone @goal.user.timezone
|
221
|
+
end
|
199
222
|
end
|
200
223
|
|
201
224
|
# Convert datapoint to hash for POSTing.
|
202
225
|
# @return [Hash]
|
203
226
|
def to_hash
|
227
|
+
if not @goal.nil? and @goal.user.enforce_timezone?
|
228
|
+
@timestamp = @goal.user.convert_to_timezone @timestamp
|
229
|
+
end
|
230
|
+
|
204
231
|
{
|
205
232
|
"timestamp" => @timestamp.strftime('%s'),
|
206
233
|
"value" => @value || 0,
|
data/lib/beeminder/user.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
#
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
2
|
|
3
3
|
module Beeminder
|
4
4
|
class User
|
@@ -16,14 +16,19 @@ module Beeminder
|
|
16
16
|
|
17
17
|
# @return [Symbol] Type of user, can be `:personal` (default) or `:oauth`.
|
18
18
|
attr_reader :auth_type
|
19
|
+
|
20
|
+
# @return [true|false] Enforce user timezone for all passed times? Should be true unless you know what you're doing. (Default: `true`.)
|
21
|
+
attr_accessor :enforce_timezone
|
19
22
|
|
20
23
|
def initialize token, opts={}
|
21
24
|
opts = {
|
22
25
|
:auth_type => :personal,
|
26
|
+
:enforce_timezone => true,
|
23
27
|
}.merge(opts)
|
24
28
|
|
25
|
-
@token
|
26
|
-
@auth_type
|
29
|
+
@token = token
|
30
|
+
@auth_type = opts[:auth_type]
|
31
|
+
@enforce_timezone = opts[:enforce_timezone]
|
27
32
|
|
28
33
|
@token_type =
|
29
34
|
case @auth_type
|
@@ -38,14 +43,21 @@ module Beeminder
|
|
38
43
|
info = get "users/me.json"
|
39
44
|
|
40
45
|
@name = info["username"]
|
41
|
-
@timezone = info["timezone"]
|
42
|
-
@updated_at = DateTime.strptime(info["updated_at"].to_s, '%s')
|
46
|
+
@timezone = info["timezone"] || "UTC"
|
47
|
+
@updated_at = DateTime.strptime(info["updated_at"].to_s, '%s').in_time_zone(@timezone)
|
43
48
|
end
|
44
49
|
|
50
|
+
# Enforce timezone for all passed times?
|
51
|
+
#
|
52
|
+
# @return [true|false]
|
53
|
+
def enforce_timezone?
|
54
|
+
!!@enforce_timezone
|
55
|
+
end
|
56
|
+
|
45
57
|
# List of goals.
|
46
58
|
#
|
47
59
|
# @param filter [Symbol] filter goals, can be `:all` (default), `:frontburner` or `:backburner`
|
48
|
-
# @
|
60
|
+
# @return [Array<Beeminder::Goal>] returns list of goals
|
49
61
|
def goals filter=:all
|
50
62
|
raise "invalid goal filter: #{filter}" unless [:all, :frontburner, :backburner].include? filter
|
51
63
|
|
@@ -115,8 +127,25 @@ module Beeminder
|
|
115
127
|
_connection :put, cmd, data
|
116
128
|
end
|
117
129
|
|
118
|
-
|
130
|
+
# Converts time object to one with user's timezone.
|
131
|
+
#
|
132
|
+
# @param time [Date|DateTime|Time] Time to convert.
|
133
|
+
# @return [Time] Converted time.
|
134
|
+
def convert_to_timezone time
|
135
|
+
# TODO seems way too hack-ish
|
136
|
+
old_tz = Time.zone
|
137
|
+
Time.zone = @timezone
|
138
|
+
|
139
|
+
time = time.to_time
|
140
|
+
t = Time.new(time.year, time.month, time.day, time.hour, time.min, time.sec)
|
141
|
+
|
142
|
+
Time.zone = old_tz
|
143
|
+
|
144
|
+
t
|
145
|
+
end
|
119
146
|
|
147
|
+
private
|
148
|
+
|
120
149
|
# Establish HTTPS connection to API.
|
121
150
|
def _connection type, cmd, data
|
122
151
|
api = "https://www.beeminder.com/api/v1/#{cmd}"
|
@@ -128,7 +157,7 @@ module Beeminder
|
|
128
157
|
http.use_ssl = true
|
129
158
|
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # FIXME: actually verify
|
130
159
|
|
131
|
-
# FIXME Sanity check for wrong timestamp. Source of bug unknown,
|
160
|
+
# FIXME Sanity check for wrong timestamp. Source of bug unknown, but at least we can prevent screwing up someone's graph.
|
132
161
|
unless data["timestamp"].nil?
|
133
162
|
if not data["timestamp"].match(/^\d+$/) or data["timestamp"] < "1280000000"
|
134
163
|
raise ArgumentError, "invalid timestamp: #{data["timestamp"]}"
|
data/lib/beeminder/version.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
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.4
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,8 +9,24 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date: 2012-09-
|
12
|
+
date: 2012-09-19 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: activesupport
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
none: false
|
18
|
+
requirements:
|
19
|
+
- - ~>
|
20
|
+
- !ruby/object:Gem::Version
|
21
|
+
version: '3.2'
|
22
|
+
type: :runtime
|
23
|
+
prerelease: false
|
24
|
+
version_requirements: !ruby/object:Gem::Requirement
|
25
|
+
none: false
|
26
|
+
requirements:
|
27
|
+
- - ~>
|
28
|
+
- !ruby/object:Gem::Version
|
29
|
+
version: '3.2'
|
14
30
|
- !ruby/object:Gem::Dependency
|
15
31
|
name: chronic
|
16
32
|
requirement: !ruby/object:Gem::Requirement
|
@@ -75,6 +91,22 @@ dependencies:
|
|
75
91
|
- - ~>
|
76
92
|
- !ruby/object:Gem::Version
|
77
93
|
version: '2'
|
94
|
+
- !ruby/object:Gem::Dependency
|
95
|
+
name: tzinfo
|
96
|
+
requirement: !ruby/object:Gem::Requirement
|
97
|
+
none: false
|
98
|
+
requirements:
|
99
|
+
- - ! '>='
|
100
|
+
- !ruby/object:Gem::Version
|
101
|
+
version: '0'
|
102
|
+
type: :runtime
|
103
|
+
prerelease: false
|
104
|
+
version_requirements: !ruby/object:Gem::Requirement
|
105
|
+
none: false
|
106
|
+
requirements:
|
107
|
+
- - ! '>='
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
78
110
|
description: Convenient access to Beeminder's API.
|
79
111
|
email:
|
80
112
|
- mail@muflax.com
|
@@ -110,7 +142,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
110
142
|
version: '0'
|
111
143
|
segments:
|
112
144
|
- 0
|
113
|
-
hash:
|
145
|
+
hash: 4040090933613779056
|
114
146
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
115
147
|
none: false
|
116
148
|
requirements:
|
@@ -119,7 +151,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
119
151
|
version: '0'
|
120
152
|
segments:
|
121
153
|
- 0
|
122
|
-
hash:
|
154
|
+
hash: 4040090933613779056
|
123
155
|
requirements: []
|
124
156
|
rubyforge_project:
|
125
157
|
rubygems_version: 1.8.23
|