slimtimercli 0.1.1

Sign up to get free protection for your applications and to get access to all the features.
data/History.txt ADDED
@@ -0,0 +1,4 @@
1
+ == 0.1.1 2008-04-03
2
+
3
+ * Initial Release of the gem
4
+ * started adding tests
data/License.txt ADDED
@@ -0,0 +1,20 @@
1
+ Copyright (c) 2008 FIXME full name
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining
4
+ a copy of this software and associated documentation files (the
5
+ "Software"), to deal in the Software without restriction, including
6
+ without limitation the rights to use, copy, modify, merge, publish,
7
+ distribute, sublicense, and/or sell copies of the Software, and to
8
+ permit persons to whom the Software is furnished to do so, subject to
9
+ the following conditions:
10
+
11
+ The above copyright notice and this permission notice shall be
12
+ included in all copies or substantial portions of the Software.
13
+
14
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
15
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
16
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
17
+ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
18
+ LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
19
+ OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
20
+ WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
data/Manifest.txt ADDED
@@ -0,0 +1,21 @@
1
+ History.txt
2
+ License.txt
3
+ Manifest.txt
4
+ README.txt
5
+ Rakefile
6
+ bin/slimtimer
7
+ config/hoe.rb
8
+ config/requirements.rb
9
+ lib/slimtimercli.rb
10
+ lib/slimtimercli/entities.rb
11
+ lib/slimtimercli/slim_timer.rb
12
+ lib/slimtimercli/version.rb
13
+ log/debug.log
14
+ setup.rb
15
+ spec/slimtimercli_spec.rb
16
+ spec/spec.opts
17
+ spec/spec_helper.rb
18
+ tasks/deployment.rake
19
+ tasks/environment.rake
20
+ tasks/rspec.rake
21
+ tasks/website.rake
data/README.txt ADDED
@@ -0,0 +1,37 @@
1
+ = slimtimercli
2
+
3
+ == DESCRIPTION:
4
+
5
+ SlimTimer is a tool to record your time spend on a
6
+ task. SlimTimer CLI allows you to controll your
7
+ SlimTimer directly from where you spend most of your
8
+ time - on the command line. To use SlimTimer proceed
9
+ with the following steps:
10
+
11
+ The first time you need to setup SlimTimer CLI with
12
+
13
+ slimtimer setup
14
+
15
+ Now it will ask for your email and password and API key
16
+ to use with your account. These information will be stored
17
+ in ~/.slimtimer/config.yml
18
+
19
+ To create a task run
20
+
21
+ slimtimer create_task my_shiny_task
22
+
23
+ To spend some time on the task you have to make the timer run
24
+
25
+ slimtimer start my_shiny_task
26
+
27
+ When you finished working on a task, you can call
28
+
29
+ slimtimer end
30
+
31
+ This will write the time spend back to SlimTimer.com.
32
+ Finally you can run
33
+
34
+ slimtimer tasks
35
+
36
+ To show all your tasks available.
37
+
data/Rakefile ADDED
@@ -0,0 +1,4 @@
1
+ require 'config/requirements'
2
+ require 'config/hoe' # setup Hoe + all gem configuration
3
+
4
+ Dir['tasks/**/*.rake'].each { |rake| load rake }
data/bin/slimtimer ADDED
@@ -0,0 +1,12 @@
1
+ #!/usr/bin/env ruby
2
+ require 'rubygems'
3
+
4
+ gem 'slimtimercli'
5
+ require 'slimtimercli'
6
+
7
+ # Run
8
+ if ARGV.size == 0
9
+ Slimtimercli.__send__(:help)
10
+ else
11
+ Slimtimercli.__send__(ARGV[0].to_sym)
12
+ end
data/config/hoe.rb ADDED
@@ -0,0 +1,70 @@
1
+ require 'slimtimercli/version'
2
+
3
+ AUTHOR = 'Martin Grund' # can also be an array of Authors
4
+ EMAIL = "grundprinzip@gmail.com"
5
+ DESCRIPTION = "Command line interface to SlimTimer"
6
+ GEM_NAME = 'slimtimercli' # what ppl will type to install your gem
7
+ RUBYFORGE_PROJECT = 'rug-b' # The unix name for your project
8
+ HOMEPATH = "http://blog.grundprinzip.de"
9
+ DOWNLOAD_PATH = "http://rubyforge.org/projects/#{RUBYFORGE_PROJECT}"
10
+
11
+ @config_file = "~/.rubyforge/user-config.yml"
12
+ @config = nil
13
+ RUBYFORGE_USERNAME = "unknown"
14
+ def rubyforge_username
15
+ unless @config
16
+ begin
17
+ @config = YAML.load(File.read(File.expand_path(@config_file)))
18
+ rescue
19
+ puts <<-EOS
20
+ ERROR: No rubyforge config file found: #{@config_file}
21
+ Run 'rubyforge setup' to prepare your env for access to Rubyforge
22
+ - See http://newgem.rubyforge.org/rubyforge.html for more details
23
+ EOS
24
+ exit
25
+ end
26
+ end
27
+ RUBYFORGE_USERNAME.replace @config["username"]
28
+ end
29
+
30
+
31
+ REV = nil
32
+ # UNCOMMENT IF REQUIRED:
33
+ # REV = `svn info`.each {|line| if line =~ /^Revision:/ then k,v = line.split(': '); break v.chomp; else next; end} rescue nil
34
+ VERS = Slimtimercli::VERSION::STRING + (REV ? ".#{REV}" : "")
35
+ RDOC_OPTS = ['--quiet', '--title', 'slimtimercli documentation',
36
+ "--opname", "index.html",
37
+ "--line-numbers",
38
+ "--main", "README",
39
+ "--inline-source"]
40
+
41
+ class Hoe
42
+ def extra_deps
43
+ @extra_deps.reject! { |x| Array(x).first == 'hoe' }
44
+ @extra_deps
45
+ end
46
+ end
47
+
48
+ # Generate all the Rake tasks
49
+ # Run 'rake -T' to see list of generated tasks (from gem root directory)
50
+ $hoe = Hoe.new(GEM_NAME, VERS) do |p|
51
+ p.developer(AUTHOR, EMAIL)
52
+ p.description = DESCRIPTION
53
+ p.summary = DESCRIPTION
54
+ p.url = HOMEPATH
55
+ p.rubyforge_name = RUBYFORGE_PROJECT if RUBYFORGE_PROJECT
56
+ p.test_globs = ["test/**/test_*.rb"]
57
+ p.clean_globs |= ['**/.*.sw?', '*.gem', '.config', '**/.DS_Store'] #An array of file patterns to delete on clean.
58
+
59
+ # == Optional
60
+ p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
61
+ #p.extra_deps = [] # An array of rubygem dependencies [name, version], e.g. [ ['active_support', '>= 1.3.1'] ]
62
+
63
+ #p.spec_extras = {} # A hash of extra values to set in the gemspec.
64
+
65
+ end
66
+
67
+ CHANGES = $hoe.paragraphs_of('History.txt', 0..1).join("\\n\\n")
68
+ PATH = (RUBYFORGE_PROJECT == GEM_NAME) ? RUBYFORGE_PROJECT : "#{RUBYFORGE_PROJECT}/#{GEM_NAME}"
69
+ $hoe.remote_rdoc_dir = File.join(PATH.gsub(/^#{RUBYFORGE_PROJECT}\/?/,''), 'rdoc')
70
+ $hoe.rsync_args = '-av --delete --ignore-errors'
@@ -0,0 +1,15 @@
1
+ require 'fileutils'
2
+ include FileUtils
3
+
4
+ require 'rubygems'
5
+ %w[rake hoe newgem rubigen].each do |req_gem|
6
+ begin
7
+ require req_gem
8
+ rescue LoadError
9
+ puts "This Rakefile requires the '#{req_gem}' RubyGem."
10
+ puts "Installation: gem install #{req_gem} -y"
11
+ exit
12
+ end
13
+ end
14
+
15
+ $:.unshift(File.join(File.dirname(__FILE__), %w[.. lib]))
@@ -0,0 +1,71 @@
1
+ class TimeEntry
2
+ attr_accessor :id, :start_time, :end_time,
3
+ :duration_in_seconds, :tags, :in_progress, :updated_at,
4
+ :created_at, :task
5
+
6
+ def self._load(hsh)
7
+ te = TimeEntry.new
8
+ hsh.each {|k,v|
9
+ te.__send__("#{k}=".to_sym, v) if te.respond_to?("#{k}=".to_sym)
10
+ }
11
+ end
12
+
13
+ def _serialize
14
+ {"time_entry" => {
15
+ "start_time" => @start_time,
16
+ "duration_in_seconds" => @duration_in_seconds,
17
+ "task_id" => @task.id}}
18
+ end
19
+
20
+ end
21
+
22
+ class Task
23
+ attr_accessor :name, :tags, :role, :owners, :hours,
24
+ :id
25
+
26
+ def self._load(hsh)
27
+ Task.new.__send__(:_load, hsh)
28
+ end
29
+
30
+ def _serialize
31
+ {"task" => instance_variables.map{ |i|
32
+ {i.to_s.gsub("@", "") => instance_variable_get(i)}
33
+ }.inject({}){|m,v| m.merge v}}
34
+ end
35
+
36
+ private
37
+
38
+ def _load(hsh)
39
+ hsh.each do |k,v|
40
+ self.instance_variable_set("@#{k}", v) if self.respond_to?(k.to_sym) &&
41
+ !v.kind_of?(Array)
42
+ end
43
+
44
+ @owners = hsh["owners"].map{|o| User._load(o)}
45
+ @coworkers = hsh["coworkers"].map{|o| User._load(o)}
46
+
47
+ self
48
+ end
49
+
50
+ end
51
+
52
+ class User
53
+ attr_accessor :email, :password, :user_id, :name
54
+
55
+ def initialize(e=nil, p=nil)
56
+ @email = e
57
+ @password = p
58
+ end
59
+
60
+ def self._load(hsh)
61
+ u = User.new
62
+ hsh.each do |k,v|
63
+ u.send("#{k}=".to_sym, v) if u.respond_to?("#{k}=".to_sym)
64
+ end
65
+ u
66
+ end
67
+
68
+ def _serialize
69
+ {"user" => {"email" => email, "password" => password}}
70
+ end
71
+ end
@@ -0,0 +1,139 @@
1
+ class SlimTimer
2
+
3
+ DATE_FORMAT = "%Y-%m-%d %H-%M-%S"
4
+
5
+ @@host = "slimtimer.com"
6
+ @@port = 80
7
+ #@@api_key = ""
8
+
9
+ attr_accessor :tasks, :time_entries
10
+
11
+ def initialize(user, pass, api)
12
+ @user = user; @pass = pass
13
+ @api_key = api
14
+ end
15
+
16
+ # Performs the login to the system, and stores
17
+ # the user id and the access token in the local
18
+ # class for reusse
19
+ def login
20
+ data = post_request("/users/token", User.new(@user, @pass)._serialize)
21
+ @token = data["access_token"]
22
+ @user_id = data["user_id"]
23
+ end
24
+
25
+ # Lists all tasks for the user logged in the system
26
+ # ==== Parameters
27
+ # show_completed<String>:: yes | no | only Include completed tasks (yes/no)
28
+ # or show only completed tasks Default: yes
29
+ # role<String>:: owner,coworker,reporter Include tasks where the user's role
30
+ # is one of the roles given (comma delimited) Default:
31
+ # owner,coworker
32
+ def tasks(show_completed = "yes", role="owner,coworker")
33
+ list = get_request("/users/#{@user_id}/tasks",
34
+ {"show_completed" => show_completed,
35
+ "role" => role})
36
+
37
+ list.map{ |t|
38
+ Task._load(t)
39
+ }
40
+
41
+ end
42
+
43
+ # Create a new task for this user
44
+ # ==== Parameters
45
+ # name<String>:: name for the new task
46
+ # tags<String>:: comma separated list of tags for the task
47
+ def create_task(name, tags= "", coworker_emails = "", reporter_emails = "")
48
+
49
+ t = Task.new
50
+ t.name = name
51
+ t.tags = tags
52
+
53
+ t._serialize
54
+
55
+
56
+ Task._load(post_request("/users/#{@user_id}/tasks", t._serialize))
57
+ end
58
+
59
+ def find_task_by_name(name)
60
+ tasks("no").find {|t| t.name == name}
61
+ end
62
+
63
+ def delete_task(name)
64
+ t = find_task_by_name(name)
65
+ delete_request("/users/#{@user_id}/tasks/#{t.id}")
66
+ end
67
+
68
+ # List all time entries for the user logged in
69
+ # ==== Parameters
70
+ # range_start<Time>:: start of the range
71
+ # range_end<Time>:: end of the range
72
+ def time_entries(range_start = nil, range_end = nil)
73
+ options = {}
74
+
75
+ options = {"range_start" =>
76
+ range_start.strftime(DATE_FORMAT)} if range_start
77
+ options = {"range_end" =>
78
+ range_end.strftime(DATE_FORMAT)} if range_end
79
+
80
+ # do the actual request
81
+ get_request("/users/#{@user_id}/time_entries", options)
82
+ end
83
+
84
+ def create_time_entry(task, start_time = Time.now, duration = 0)
85
+ te = TimeEntry.new
86
+ te.task = task; te.start_time = start_time
87
+ te.duration_in_seconds = duration
88
+
89
+ post_request("/users/#{@user_id}/time_entries", te._serialize)
90
+ end
91
+
92
+ protected
93
+
94
+ def handle_error(object)
95
+ if object.kind_of?(ActiveRecord::Errors)
96
+ raise "ActiveRecord::Errors " + object.map{|k,v| k + " " + v}.join("\n")
97
+ else
98
+ object
99
+ end
100
+ end
101
+
102
+ def get_request(path, params = {})
103
+ post_request(path, {"_method" => "get"}.merge(params))
104
+ end
105
+
106
+ def put_request(path, params = {})
107
+ post_request(path, {"_method" => "put"}.merge(params))
108
+ end
109
+
110
+ def delete_request(path, params = {})
111
+ post_request(path, {"_method" => "delete"}.merge(params))
112
+ end
113
+
114
+ def post_request(path, params = {})
115
+ request(Net::HTTP::Post.new(path, default_header), params)
116
+ end
117
+
118
+ def request(method, params = {})
119
+
120
+ puts "Start Request" if $DEBUG
121
+ # merge api key
122
+ params = {"api_key" => @api_key}.merge(params)
123
+ # If token there merge it
124
+ params = {"access_token" => @token}.merge(params) if @token
125
+ res, body = Net::HTTP.start(@@host,@@port) {|http|
126
+ p params if $DEBUG
127
+ method.body = params.to_yaml
128
+ http.request(method)
129
+ }
130
+ puts "Finished Request" if $DEBUG
131
+ handle_error(YAML.load(body))
132
+ end
133
+
134
+ def default_header
135
+ {"Accept" => "application/x-yaml",
136
+ "Content-Type" => "application/x-yaml"}
137
+ end
138
+
139
+ end
@@ -0,0 +1,9 @@
1
+ module Slimtimercli #:nodoc:
2
+ module VERSION #:nodoc:
3
+ MAJOR = 0
4
+ MINOR = 1
5
+ TINY = 1
6
+
7
+ STRING = [MAJOR, MINOR, TINY].join('.')
8
+ end
9
+ end
@@ -0,0 +1,215 @@
1
+ $:.unshift(File.dirname(__FILE__)) unless
2
+ $:.include?(File.dirname(__FILE__)) || $:.include?(File.expand_path(File.dirname(__FILE__)))
3
+
4
+ require 'fileutils'
5
+ require 'net/http'
6
+ require 'rubygems'
7
+ require 'active_record'
8
+ require 'active_support'
9
+ require 'yaml'
10
+
11
+ require "slimtimercli/entities"
12
+ require "slimtimercli/slim_timer"
13
+ require "slimtimercli/version"
14
+
15
+ module Slimtimercli
16
+ module Helper
17
+ def self.login
18
+ config = Helper::load_config
19
+ st = SlimTimer.new(config["email"], config["password"],
20
+ config["api_key"])
21
+ st.login
22
+
23
+ st
24
+ end
25
+
26
+ def self.root
27
+ File.join(ENV["HOME"], ".slimtimer")
28
+ end
29
+
30
+ def self.config_file
31
+ File.join(root, "config.yml")
32
+ end
33
+
34
+ def self.tasks_file
35
+ File.join(root, "tasks.yml")
36
+ end
37
+
38
+ def self.current_file
39
+ File.join(root, "current.yml")
40
+ end
41
+
42
+ def self.check_and_create_dir
43
+ raise "Home DIR not set!" unless ENV["HOME"]
44
+
45
+ unless File.directory?(root)
46
+ FileUtils.mkdir(root)
47
+ end
48
+ end
49
+
50
+ def self.load_config
51
+ check_and_create_dir
52
+
53
+ unless File.exists?(File.join(root, "config.yml"))
54
+ File.open( File.join(root, "config.yml"), 'w' ) do |out|
55
+ YAML.dump({}, out )
56
+ end
57
+ end
58
+ load_file("config.yml")
59
+ end
60
+
61
+ def self.save_config(config)
62
+ dump_to_file(config, "config.yml")
63
+ end
64
+
65
+ def self.load_file(file)
66
+ File.open( File.join(root, file) ) { |yf| YAML::load( yf ) }
67
+ end
68
+
69
+ def self.dump_to_file(object, file)
70
+ check_and_create_dir
71
+ File.open( File.join(root, file), 'w' ) do |out|
72
+ YAML.dump(object, out )
73
+ end
74
+ 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
+
99
+ tasks = Helper::load_file("tasks.yml")
100
+
101
+ return tasks unless show
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
119
+ end
120
+ end
121
+
122
+ # This method stores the credentials in the necessary directoyr
123
+ def self.setup
124
+ config = Helper::load_config
125
+
126
+ puts "Slimtimer Login Credentials\n"
127
+ print "E-Mail: "
128
+ config["email"] = STDIN.gets.gsub("\n", "")
129
+
130
+ print "Password: "
131
+ config["password"] = STDIN.gets.gsub("\n", "")
132
+
133
+ print "API Key: "
134
+ config["api_key"] = STDIN.gets.gsub("\n", "")
135
+
136
+ Helper::save_config(config)
137
+
138
+ # clear the screen
139
+ system("clear")
140
+ end
141
+
142
+ def self.help
143
+ puts <<-HELP
144
+ SlimTimer is a tool to record your time spend on a
145
+ task. SlimTimer CLI allows you to controll your
146
+ SlimTimer directly from where you spend most of your
147
+ time - on the command line. To use SlimTimer proceed
148
+ with the following steps:
149
+
150
+ The first time you need to setup SlimTimer CLI with
151
+
152
+ slimtimer setup
153
+
154
+ Now it will ask for your email and password and API key
155
+ to use with your account. These information will be stored
156
+ in ~/.slimtimer/config.yml
157
+
158
+ To create a task run
159
+
160
+ slimtimer create_task my_shiny_task
161
+
162
+ To spend some time on the task you have to make the timer run
163
+
164
+ slimtimer start my_shiny_task
165
+
166
+ When you finished working on a task, you can call
167
+
168
+ slimtimer end
169
+
170
+ This will write the time spend back to SlimTimer.com.
171
+ Finally you can run
172
+
173
+ slimtimer tasks
174
+
175
+ To show all your tasks available.
176
+ HELP
177
+ end
178
+
179
+ def self.start
180
+ info = {"task" => ARGV[1],
181
+ "start_time" => Time.now}
182
+
183
+ # dum curent task to file
184
+ Helper::dump_to_file(info, "current.yml")
185
+ end
186
+
187
+ def self.end
188
+ begin
189
+ info = Helper::load_file("current.yml")
190
+ rescue
191
+ puts "You must start a task before you finish it"
192
+ return
193
+ end
194
+
195
+
196
+ #Find task in tasks yml
197
+ t = tasks(false).find {|t| t.name == info["task"]}
198
+
199
+ raise "Task not found in list. Reload List?" unless t
200
+
201
+ st = Helper::login
202
+ result = st.create_time_entry(t, info["start_time"],
203
+ (Time.now - info["start_time"]).to_i)
204
+
205
+ # Delete yml file
206
+ if result
207
+ FileUtils.rm(Helper::current_file)
208
+ end
209
+
210
+ # Output
211
+ puts "Wrote new Entry for #{t.name}, duration #{result["duration_in_seconds"] / 60}m"
212
+
213
+ end
214
+
215
+ end
data/log/debug.log ADDED
File without changes