slimtimercli 0.1.2 → 0.1.3
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/History.txt +4 -0
- data/bin/slimtimer +4 -6
- data/lib/slimtimercli.rb +214 -112
- data/lib/slimtimercli/version.rb +1 -1
- data/spec/slimtimercli_spec.rb +71 -19
- data/spec/spec_helper.rb +13 -3
- metadata +2 -2
data/History.txt
CHANGED
@@ -1,3 +1,7 @@
|
|
1
|
+
== 0.1.3 2008-04-07
|
2
|
+
* fixed bug that allows starting a nonexisting task
|
3
|
+
* refactored options to start slimtimer
|
4
|
+
|
1
5
|
== 0.1.2 2008-04-06
|
2
6
|
* time recording can only be stopped if a task was started
|
3
7
|
* time recording can only be started if no other task was started
|
data/bin/slimtimer
CHANGED
data/lib/slimtimercli.rb
CHANGED
@@ -6,7 +6,9 @@ require 'net/http'
|
|
6
6
|
require 'rubygems'
|
7
7
|
require 'active_record'
|
8
8
|
require 'active_support'
|
9
|
-
require 'yaml'
|
9
|
+
require 'yaml'
|
10
|
+
require 'optparse'
|
11
|
+
require 'ostruct'
|
10
12
|
|
11
13
|
require "slimtimercli/entities"
|
12
14
|
require "slimtimercli/slim_timer"
|
@@ -14,7 +16,7 @@ require "slimtimercli/version"
|
|
14
16
|
|
15
17
|
module Slimtimercli
|
16
18
|
module Helper
|
17
|
-
def
|
19
|
+
def login
|
18
20
|
config = Helper::load_config
|
19
21
|
st = SlimTimer.new(config["email"], config["password"],
|
20
22
|
config["api_key"])
|
@@ -23,23 +25,23 @@ module Slimtimercli
|
|
23
25
|
st
|
24
26
|
end
|
25
27
|
|
26
|
-
def
|
28
|
+
def root
|
27
29
|
File.join(ENV["HOME"], ".slimtimer")
|
28
30
|
end
|
29
31
|
|
30
|
-
def
|
32
|
+
def config_file
|
31
33
|
File.join(root, "config.yml")
|
32
34
|
end
|
33
35
|
|
34
|
-
def
|
36
|
+
def tasks_file
|
35
37
|
File.join(root, "tasks.yml")
|
36
38
|
end
|
37
39
|
|
38
|
-
def
|
40
|
+
def current_file
|
39
41
|
File.join(root, "current.yml")
|
40
42
|
end
|
41
43
|
|
42
|
-
def
|
44
|
+
def check_and_create_dir
|
43
45
|
raise "Home DIR not set!" unless ENV["HOME"]
|
44
46
|
|
45
47
|
unless File.directory?(root)
|
@@ -47,7 +49,7 @@ module Slimtimercli
|
|
47
49
|
end
|
48
50
|
end
|
49
51
|
|
50
|
-
def
|
52
|
+
def load_config
|
51
53
|
check_and_create_dir
|
52
54
|
|
53
55
|
unless File.exists?(File.join(root, "config.yml"))
|
@@ -58,89 +60,76 @@ module Slimtimercli
|
|
58
60
|
load_file("config.yml")
|
59
61
|
end
|
60
62
|
|
61
|
-
def
|
63
|
+
def save_config(config)
|
62
64
|
dump_to_file(config, "config.yml")
|
63
65
|
end
|
64
66
|
|
65
|
-
def
|
67
|
+
def load_file(file)
|
66
68
|
File.open( File.join(root, file) ) { |yf| YAML::load( yf ) }
|
67
69
|
end
|
68
70
|
|
69
|
-
def
|
71
|
+
def dump_to_file(object, file)
|
70
72
|
check_and_create_dir
|
71
73
|
File.open( File.join(root, file), 'w' ) do |out|
|
72
74
|
YAML.dump(object, out )
|
73
75
|
end
|
74
76
|
end
|
75
|
-
end
|
76
|
-
|
77
|
-
def self.create_task
|
78
|
-
name = ARGV[1]
|
79
|
-
|
80
|
-
st = Helper::login
|
81
|
-
if st.create_task(name)
|
82
|
-
Helper::dump_to_file(st.tasks, "tasks.yml")
|
83
|
-
puts "Task #{name} successfully created."
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def self.tasks(show= true)
|
88
|
-
config = Helper::load_config
|
89
|
-
st = SlimTimer.new(config["email"], config["password"],
|
90
|
-
config["api_key"])
|
91
|
-
|
92
|
-
if !File.exists?(Helper::tasks_file) ||
|
93
|
-
File.mtime(Helper::tasks_file) < (Time.now - 60 * 60 *24)
|
94
|
-
|
95
|
-
st.login
|
96
|
-
Helper::dump_to_file(st.tasks, "tasks.yml")
|
97
|
-
end
|
98
77
|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
tasks.each do |t|
|
104
|
-
puts t.name
|
105
|
-
end
|
106
|
-
end
|
107
|
-
|
108
|
-
def self.force_reload
|
109
|
-
config = Helper::load_config
|
110
|
-
st = SlimTimer.new(config["email"], config["password"],
|
111
|
-
config["api_key"])
|
112
|
-
|
113
|
-
st.login
|
114
|
-
Helper::dump_to_file(st.tasks, "tasks.yml")
|
115
|
-
tasks = Helper::load_file("tasks.yml")
|
116
|
-
|
117
|
-
tasks.each do |t|
|
118
|
-
puts t.name
|
78
|
+
def rm_current
|
79
|
+
FileUtils.rm(current_file) if
|
80
|
+
File.exists?(current_file)
|
119
81
|
end
|
120
|
-
end
|
121
82
|
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
83
|
+
def parse(args)
|
84
|
+
|
85
|
+
if !args || args.empty?
|
86
|
+
raise "Need to specify arguments, run slimtimer -h for help"
|
87
|
+
|
88
|
+
end
|
89
|
+
|
90
|
+
options = OpenStruct.new
|
91
|
+
options.force = false
|
92
|
+
|
93
|
+
opts = OptionParser.new do |opts|
|
94
|
+
|
95
|
+
opts.banner = "Usage: slimtimer [options]"
|
96
|
+
|
97
|
+
opts.on("-s TASK", "--start TASK",
|
98
|
+
"Start a TASK given by the task name") do |t|
|
99
|
+
|
100
|
+
options.run = "start"
|
101
|
+
options.task_name = t
|
102
|
+
end
|
103
|
+
|
104
|
+
opts.on("-c TASK", "--create TASK",
|
105
|
+
"Create a ne task by the given name") do |t|
|
106
|
+
options.run = "create"
|
107
|
+
options.task_name = t
|
108
|
+
end
|
109
|
+
|
110
|
+
opts.on("-e", "--end" ,"Stops time recording for the given task") do
|
111
|
+
options.run = "stop"
|
112
|
+
end
|
113
|
+
|
114
|
+
opts.on("-t", "--tasks", "Prints all available tasks") do
|
115
|
+
options.run = "tasks"
|
116
|
+
end
|
117
|
+
|
118
|
+
opts.on("-f", "--force", "Force deletion of tasks") do
|
119
|
+
options.force = true
|
120
|
+
end
|
121
|
+
|
122
|
+
opts.on("--setup", "Setup your account") do
|
123
|
+
options.run = "setup"
|
124
|
+
end
|
125
|
+
|
126
|
+
opts.on_tail("-h", "Shows this note") do
|
127
|
+
puts opts
|
128
|
+
exit
|
129
|
+
end
|
130
|
+
|
131
|
+
opts.on("--help", "Show verbose help") do
|
132
|
+
@out.puts <<-HELP
|
144
133
|
SlimTimer is a tool to record your time spend on a
|
145
134
|
task. SlimTimer CLI allows you to controll your
|
146
135
|
SlimTimer directly from where you spend most of your
|
@@ -174,53 +163,166 @@ Finally you can run
|
|
174
163
|
|
175
164
|
To show all your tasks available.
|
176
165
|
HELP
|
166
|
+
exit
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
begin
|
171
|
+
opts.parse!(args)
|
172
|
+
rescue
|
173
|
+
puts $!.message
|
174
|
+
exit
|
175
|
+
end
|
176
|
+
options
|
177
|
+
end
|
177
178
|
end
|
178
179
|
|
179
|
-
|
180
|
-
|
181
|
-
|
182
|
-
|
180
|
+
class CommandLine
|
181
|
+
|
182
|
+
# Include Helper module
|
183
|
+
include Helper
|
184
|
+
|
185
|
+
def initialize(args, output = $stdout)
|
186
|
+
@args = args
|
187
|
+
@out = output
|
188
|
+
|
189
|
+
deprecated_calls
|
190
|
+
|
191
|
+
@options = parse(args)
|
183
192
|
end
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
|
193
|
+
|
194
|
+
def create
|
195
|
+
st = login
|
196
|
+
if st.create_task(@options.task_name)
|
197
|
+
dump_to_file(st.tasks, "tasks.yml")
|
198
|
+
@out.puts "Task #{name} successfully created."
|
199
|
+
end
|
188
200
|
end
|
189
201
|
|
190
|
-
|
191
|
-
|
192
|
-
|
193
|
-
# dum curent task to file
|
194
|
-
Helper::dump_to_file(info, "current.yml")
|
195
|
-
return true
|
196
|
-
end
|
202
|
+
def tasks(show = true)
|
203
|
+
tasks = load_tasks
|
204
|
+
return tasks unless show
|
197
205
|
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
rescue
|
202
|
-
puts "You must start a task before you finish it"
|
203
|
-
return false
|
206
|
+
tasks.each do |t|
|
207
|
+
@out.puts t.name
|
208
|
+
end
|
204
209
|
end
|
210
|
+
|
211
|
+
def setup
|
212
|
+
config = load_config
|
213
|
+
|
214
|
+
@out.puts "Slimtimer Login Credentials\n"
|
215
|
+
@out.print "E-Mail: "
|
216
|
+
config["email"] = STDIN.gets.gsub("\n", "")
|
217
|
+
|
218
|
+
@out.print "Password: "
|
219
|
+
config["password"] = STDIN.gets.gsub("\n", "")
|
205
220
|
|
221
|
+
@out.print "API Key: "
|
222
|
+
config["api_key"] = STDIN.gets.gsub("\n", "")
|
206
223
|
|
207
|
-
|
208
|
-
t = tasks(false).find {|t| t.name == info["task"]}
|
224
|
+
save_config(config)
|
209
225
|
|
210
|
-
|
226
|
+
# clear the screen
|
227
|
+
system("clear")
|
228
|
+
end
|
229
|
+
|
230
|
+
def start
|
231
|
+
if File.exists?(current_file)
|
232
|
+
@out.puts "Need to stop the other task first"
|
233
|
+
return false
|
234
|
+
end
|
235
|
+
|
236
|
+
info = {"task" => @options.task_name,
|
237
|
+
"start_time" => Time.now}
|
238
|
+
|
239
|
+
#Find task in tasks yml
|
240
|
+
t = load_tasks.find {|t| t.name == info["task"]}
|
241
|
+
unless t
|
242
|
+
@out.puts "Task not found in list. Reload List?"
|
243
|
+
return false
|
244
|
+
end
|
211
245
|
|
212
|
-
|
213
|
-
|
214
|
-
|
246
|
+
dump_to_file(info, "current.yml")
|
247
|
+
return true
|
248
|
+
end
|
249
|
+
|
250
|
+
def stop
|
215
251
|
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
252
|
+
if @options.force
|
253
|
+
rm_current
|
254
|
+
@out.puts "Forced ending of task, no entry to slimtimer.com written"
|
255
|
+
return true
|
256
|
+
end
|
257
|
+
|
258
|
+
|
259
|
+
begin
|
260
|
+
info = load_file("current.yml")
|
261
|
+
rescue
|
262
|
+
puts "You must start a task before you finish it"
|
263
|
+
return false
|
264
|
+
end
|
220
265
|
|
221
|
-
|
222
|
-
|
223
|
-
|
266
|
+
#Find task in tasks yml
|
267
|
+
t = load_tasks.find {|t| t.name == info["task"]}
|
268
|
+
unless t
|
269
|
+
@out.puts "Task not found in list. Reload List?"
|
270
|
+
return false
|
271
|
+
end
|
272
|
+
raise unless t
|
273
|
+
|
274
|
+
st = login
|
275
|
+
result = st.create_time_entry(t, info["start_time"],
|
276
|
+
(Time.now - info["start_time"]).to_i)
|
277
|
+
|
278
|
+
# Delete yml file
|
279
|
+
if result
|
280
|
+
rm_current
|
281
|
+
|
282
|
+
# Output
|
283
|
+
@out.puts "Wrote new Entry for #{t.name}, duration #{result["duration_in_seconds"] / 60}m"
|
284
|
+
return true
|
285
|
+
else
|
286
|
+
@out.puts "Coult not write new entry, please try again"
|
287
|
+
return false
|
288
|
+
end
|
289
|
+
end
|
290
|
+
|
291
|
+
def run
|
292
|
+
send(@options.run.to_sym)
|
293
|
+
end
|
294
|
+
|
295
|
+
alias_method :end, :stop
|
296
|
+
|
297
|
+
private
|
298
|
+
|
299
|
+
# This method checks if the first parameter in args needs to
|
300
|
+
# be transformed to the new one
|
301
|
+
def deprecated_calls
|
302
|
+
case @args[0]
|
303
|
+
when "start": @args[0] = "-s"
|
304
|
+
when "end": @args[0] = "-e"
|
305
|
+
when "create_task": @args[0] = "-c"
|
306
|
+
when "tasks": @args[0] = "-t"
|
307
|
+
when "setup": @args[0] = "--setup"
|
308
|
+
end
|
309
|
+
end
|
310
|
+
|
311
|
+
def load_tasks(force = false)
|
312
|
+
config = load_config
|
313
|
+
st = SlimTimer.new(config["email"], config["password"],
|
314
|
+
config["api_key"])
|
315
|
+
|
316
|
+
tasks = []
|
317
|
+
if !File.exists?(tasks_file) ||
|
318
|
+
File.mtime(tasks_file) < (Time.now - 60 * 60 *24) || force
|
319
|
+
st.login
|
320
|
+
tasks = st.tasks
|
321
|
+
dump_to_file(tasks, "tasks.yml")
|
322
|
+
else
|
323
|
+
tasks = load_file("tasks.yml")
|
324
|
+
end
|
325
|
+
tasks
|
326
|
+
end
|
224
327
|
end
|
225
|
-
|
226
328
|
end
|
data/lib/slimtimercli/version.rb
CHANGED
data/spec/slimtimercli_spec.rb
CHANGED
@@ -1,5 +1,6 @@
|
|
1
|
-
require File.dirname(__FILE__) + '/spec_helper.rb'
|
1
|
+
require File.dirname(__FILE__) + '/spec_helper.rb'
|
2
2
|
|
3
|
+
include Slimtimercli::Helper
|
3
4
|
# Time to add your specs!
|
4
5
|
# http://rspec.rubyforge.org/
|
5
6
|
describe "SlimTimer" do
|
@@ -7,8 +8,11 @@ describe "SlimTimer" do
|
|
7
8
|
describe "Helper" do
|
8
9
|
|
9
10
|
it "should return the path to the config files" do
|
10
|
-
|
11
|
-
Slimtimercli::
|
11
|
+
|
12
|
+
st = Slimtimercli::CommandLine.new(["-e"])
|
13
|
+
|
14
|
+
st.config_file.should =~ /.slimtimer\/config.yml/
|
15
|
+
st.tasks_file.should =~ /.slimtimer\/tasks.yml/
|
12
16
|
end
|
13
17
|
|
14
18
|
end
|
@@ -49,44 +53,92 @@ describe "SlimTimer" do
|
|
49
53
|
describe "command line interface" do
|
50
54
|
|
51
55
|
before do
|
52
|
-
Slimtimercli::
|
56
|
+
Slimtimercli::CommandLine.
|
57
|
+
any_instance.stubs(:root).returns(File.dirname(__FILE__))
|
53
58
|
|
54
59
|
@c = File.join(File.dirname(__FILE__), "current.yml")
|
55
60
|
FileUtils.rm(@c) if File.exists?(@c)
|
56
61
|
|
57
62
|
@d = File.join(File.dirname(__FILE__), "config.yml")
|
58
63
|
FileUtils.rm(@d) if File.exists?(@d)
|
64
|
+
|
59
65
|
end
|
60
66
|
|
61
67
|
it "should start a task" do
|
62
|
-
|
63
|
-
|
64
|
-
Slimtimercli.
|
68
|
+
# Manipulate ARGV
|
69
|
+
|
70
|
+
lambda { Slimtimercli::CommandLine.new([]) }.should
|
71
|
+
raise_error(RuntimeError)
|
65
72
|
File.exists?(@c).should be_false
|
66
|
-
|
73
|
+
|
74
|
+
Slimtimercli::CommandLine.
|
75
|
+
any_instance.stubs(:load_tasks).
|
76
|
+
returns(stub("task", :find => stub("task", :name => "test")))
|
77
|
+
|
67
78
|
# Set a task
|
68
79
|
ARGV[1] = "test"
|
69
|
-
|
80
|
+
|
81
|
+
st = Slimtimercli::CommandLine.new(ARGV)
|
82
|
+
st.start
|
70
83
|
File.exists?(@c).should be_true
|
71
84
|
|
72
85
|
# no double start
|
73
|
-
|
74
|
-
|
75
|
-
|
86
|
+
st.start.should be_false
|
76
87
|
end
|
77
88
|
|
78
89
|
it "should stop a task" do
|
79
|
-
Slimtimercli.
|
80
|
-
|
81
|
-
|
90
|
+
Slimtimercli::CommandLine.
|
91
|
+
any_instance.stubs(:load_tasks).
|
92
|
+
returns(stub("task", :find => stub("task", :name => "test")))
|
93
|
+
|
94
|
+
Slimtimercli::CommandLine.any_instance.stubs(:login).
|
95
|
+
returns(stub("slimtimer",
|
96
|
+
:create_time_entry => {"duration_in_seconds" => 10}))
|
82
97
|
|
83
|
-
ARGV[1] = "test"
|
84
|
-
Slimtimercli.
|
85
|
-
|
98
|
+
ARGV[1] = "test"
|
99
|
+
st = Slimtimercli::CommandLine.new(ARGV)
|
100
|
+
st.start.should be_true
|
101
|
+
st.end.should be_true
|
102
|
+
|
103
|
+
File.exists?(@c).should be_false
|
86
104
|
end
|
87
105
|
|
88
106
|
it "should not stop a task if none is running" do
|
89
|
-
Slimtimercli.
|
107
|
+
st = Slimtimercli::CommandLine.new(["-e"])
|
108
|
+
st.end.should be_false
|
109
|
+
end
|
110
|
+
|
111
|
+
it "should not start a task that does not exist" do
|
112
|
+
Slimtimercli::CommandLine.any_instance.
|
113
|
+
stubs(:load_tasks).returns(stub("task", :find => nil))
|
114
|
+
|
115
|
+
ARGV[1] = "not exisiting task"
|
116
|
+
st = Slimtimercli::CommandLine.new(ARGV)
|
117
|
+
st.start.should be_false
|
118
|
+
|
119
|
+
end
|
120
|
+
|
121
|
+
it "should allow to force the deletion of the current task" do
|
122
|
+
st = Slimtimercli::CommandLine.new(["-e"])
|
123
|
+
st.end.should be_false
|
124
|
+
ARGV[0] = "-e"
|
125
|
+
ARGV[1] = "--force" || "-f"
|
126
|
+
st = Slimtimercli::CommandLine.new(ARGV)
|
127
|
+
st.end.should be_true
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
|
132
|
+
describe "option parser" do
|
133
|
+
|
134
|
+
it "should parse the start part correctly" do
|
135
|
+
|
136
|
+
args = ["--start", "my_task"]
|
137
|
+
options = parse(args)
|
138
|
+
|
139
|
+
options.run.should == "start"
|
140
|
+
options.task_name.should == "my_task"
|
141
|
+
|
90
142
|
end
|
91
143
|
|
92
144
|
end
|
data/spec/spec_helper.rb
CHANGED
@@ -1,10 +1,20 @@
|
|
1
1
|
begin
|
2
|
+
|
2
3
|
require 'spec'
|
4
|
+
require 'mocha'
|
5
|
+
|
3
6
|
rescue LoadError
|
4
7
|
require 'rubygems'
|
5
8
|
gem 'rspec'
|
6
|
-
require 'spec'
|
9
|
+
require 'spec'
|
10
|
+
|
11
|
+
gem 'mocha'
|
12
|
+
require 'mocha'
|
7
13
|
end
|
8
|
-
|
14
|
+
|
9
15
|
$:.unshift(File.dirname(__FILE__) + '/../lib')
|
10
|
-
require 'slimtimercli'
|
16
|
+
require 'slimtimercli'
|
17
|
+
|
18
|
+
Spec::Runner.configure do |config|
|
19
|
+
config.mock_with :mocha
|
20
|
+
end
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: slimtimercli
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Martin Grund
|
@@ -9,7 +9,7 @@ autorequire:
|
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
11
|
|
12
|
-
date: 2008-04-
|
12
|
+
date: 2008-04-07 00:00:00 +02:00
|
13
13
|
default_executable:
|
14
14
|
dependencies: []
|
15
15
|
|