ruby-rescuetime 0.0.1
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/MIT-LICENSE +20 -0
- data/README.rdoc +16 -0
- data/Rakefile +37 -0
- data/bin/ruby-rescuetime +6 -0
- data/lib/rescuetime.rb +16 -0
- data/lib/rescuetime/application.rb +152 -0
- data/lib/rescuetime/commands.rb +50 -0
- data/lib/rescuetime/config.rb +83 -0
- data/lib/rescuetime/debug.rb +18 -0
- data/lib/rescuetime/extension.rb +29 -0
- data/lib/rescuetime/extensions/chromium.rb +32 -0
- data/lib/rescuetime/extensions/gedit.rb +13 -0
- data/lib/rescuetime/loop.rb +97 -0
- data/lib/rescuetime/uploader.rb +79 -0
- data/lib/rescuetime/version.rb +3 -0
- data/lib/tasks/ruby-rescuetime_tasks.rake +4 -0
- data/test/application_test.rb +12 -0
- data/test/dummy/Rakefile +7 -0
- data/test/dummy/app/assets/javascripts/application.js +9 -0
- data/test/dummy/app/assets/stylesheets/application.css +7 -0
- data/test/dummy/app/controllers/application_controller.rb +3 -0
- data/test/dummy/app/helpers/application_helper.rb +2 -0
- data/test/dummy/app/views/layouts/application.html.erb +14 -0
- data/test/dummy/config.ru +4 -0
- data/test/dummy/config/application.rb +45 -0
- data/test/dummy/config/boot.rb +10 -0
- data/test/dummy/config/database.yml +25 -0
- data/test/dummy/config/environment.rb +5 -0
- data/test/dummy/config/environments/development.rb +30 -0
- data/test/dummy/config/environments/production.rb +60 -0
- data/test/dummy/config/environments/test.rb +39 -0
- data/test/dummy/config/initializers/backtrace_silencers.rb +7 -0
- data/test/dummy/config/initializers/inflections.rb +10 -0
- data/test/dummy/config/initializers/mime_types.rb +5 -0
- data/test/dummy/config/initializers/secret_token.rb +7 -0
- data/test/dummy/config/initializers/session_store.rb +8 -0
- data/test/dummy/config/initializers/wrap_parameters.rb +14 -0
- data/test/dummy/config/locales/en.yml +5 -0
- data/test/dummy/config/routes.rb +58 -0
- data/test/dummy/db/test.sqlite3 +0 -0
- data/test/dummy/log/development.log +0 -0
- data/test/dummy/log/test.log +0 -0
- data/test/dummy/public/404.html +26 -0
- data/test/dummy/public/422.html +26 -0
- data/test/dummy/public/500.html +26 -0
- data/test/dummy/public/favicon.ico +0 -0
- data/test/dummy/script/rails +6 -0
- data/test/loop_test.rb +16 -0
- data/test/rescuetime_test.rb +8 -0
- data/test/test_helper.rb +10 -0
- metadata +180 -0
data/MIT-LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright 2012 YOURNAME
|
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/README.rdoc
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
= RubyRescuetime
|
2
|
+
|
3
|
+
== Ruby port of: https://launchpad.net/rescuetime-linux-uploader
|
4
|
+
So, it's basically a inofficial uploader for:
|
5
|
+
https://www.rescuetime.com/
|
6
|
+
|
7
|
+
_It's probably running only on Ubuntu machines. (Feel free to test)_
|
8
|
+
|
9
|
+
== Installation:
|
10
|
+
gem install ruby-rescuetime
|
11
|
+
|
12
|
+
== Usage:
|
13
|
+
ruby-rescuetime --help
|
14
|
+
|
15
|
+
This project rocks and uses MIT-LICENSE.
|
16
|
+
|
data/Rakefile
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
#!/usr/bin/env rake
|
2
|
+
begin
|
3
|
+
require 'bundler/setup'
|
4
|
+
rescue LoadError
|
5
|
+
puts 'You must `gem install bundler` and `bundle install` to run rake tasks'
|
6
|
+
end
|
7
|
+
begin
|
8
|
+
require 'rdoc/task'
|
9
|
+
rescue LoadError
|
10
|
+
require 'rdoc/rdoc'
|
11
|
+
require 'rake/rdoctask'
|
12
|
+
RDoc::Task = Rake::RDocTask
|
13
|
+
end
|
14
|
+
|
15
|
+
RDoc::Task.new(:rdoc) do |rdoc|
|
16
|
+
rdoc.rdoc_dir = 'rdoc'
|
17
|
+
rdoc.title = 'RubyRescuetime'
|
18
|
+
rdoc.options << '--line-numbers'
|
19
|
+
rdoc.rdoc_files.include('README.rdoc')
|
20
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
|
25
|
+
Bundler::GemHelper.install_tasks
|
26
|
+
|
27
|
+
require 'rake/testtask'
|
28
|
+
|
29
|
+
Rake::TestTask.new(:test) do |t|
|
30
|
+
t.libs << 'lib'
|
31
|
+
t.libs << 'test'
|
32
|
+
t.pattern = 'test/**/*_test.rb'
|
33
|
+
t.verbose = false
|
34
|
+
end
|
35
|
+
|
36
|
+
|
37
|
+
task :default => :test
|
data/bin/ruby-rescuetime
ADDED
data/lib/rescuetime.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
module Rescuetime
|
2
|
+
require 'rescuetime/debug'
|
3
|
+
require 'rescuetime/extension'
|
4
|
+
|
5
|
+
require 'rescuetime/application'
|
6
|
+
require 'rescuetime/config'
|
7
|
+
require 'rescuetime/loop'
|
8
|
+
require 'rescuetime/uploader'
|
9
|
+
|
10
|
+
# Load Extensions
|
11
|
+
Dir["#{File.dirname(__FILE__)}/rescuetime/extensions/**/*.rb"].each { |f| require f }
|
12
|
+
|
13
|
+
# Load Extensions defined in users home directory
|
14
|
+
Dir["#{Dir.home}/.ruby-rescuetime/extensions/**/*.rb"].each { |f| require f }
|
15
|
+
end
|
16
|
+
|
@@ -0,0 +1,152 @@
|
|
1
|
+
module Rescuetime
|
2
|
+
class Application
|
3
|
+
include Rescuetime::Debug
|
4
|
+
|
5
|
+
def self.current_application_name
|
6
|
+
cmd = <<-CMD
|
7
|
+
xprop -id `xprop -root |
|
8
|
+
awk '/_NET_ACTIVE_WINDOW/ {print $5; exit;}'` |
|
9
|
+
awk -F = '/WM_CLASS/ {print $2; exit;}'|
|
10
|
+
awk '{print $2}' |
|
11
|
+
sed 's/^"//g' |
|
12
|
+
sed 's/"$//g'
|
13
|
+
CMD
|
14
|
+
`#{cmd}`.strip
|
15
|
+
end
|
16
|
+
|
17
|
+
def self.current_window_title
|
18
|
+
cmd = <<-CMD
|
19
|
+
xprop -id `xprop -root |
|
20
|
+
awk '/_NET_ACTIVE_WINDOW/ {print $5; exit;}'` |
|
21
|
+
awk -F = '/^WM_NAME/ {print $2; exit;}' |
|
22
|
+
sed -e's/^ *"//g' |
|
23
|
+
sed -e's/\\"$//g'
|
24
|
+
CMD
|
25
|
+
`#{cmd}`.strip
|
26
|
+
end
|
27
|
+
|
28
|
+
attr_reader :name, :title, :created_at, :finished_at
|
29
|
+
#protected_class_method :new
|
30
|
+
|
31
|
+
# TODO
|
32
|
+
def self.create(options = {})
|
33
|
+
name = options[:name] || self.current_application_name
|
34
|
+
klass = Rescuetime::Extension.get(name) || self
|
35
|
+
klass.new(options)
|
36
|
+
end
|
37
|
+
|
38
|
+
|
39
|
+
|
40
|
+
# Constructor: Call with {:debug => true} to get debug messages
|
41
|
+
def initialize(options = {})
|
42
|
+
@debug = options[:debug]
|
43
|
+
@name = options[:name] || current_application_name
|
44
|
+
@title = options[:title] || current_window_title
|
45
|
+
|
46
|
+
@created_at = Time.now
|
47
|
+
@finished_at = nil
|
48
|
+
@active = true
|
49
|
+
end
|
50
|
+
|
51
|
+
def name
|
52
|
+
@name.gsub("\000", "").gsub("'", "`")
|
53
|
+
end
|
54
|
+
|
55
|
+
def title
|
56
|
+
@title.gsub("\000", "").gsub("'", "`")
|
57
|
+
end
|
58
|
+
|
59
|
+
# Returns: Time of where app where detected to not be active anymore, or
|
60
|
+
# Time now if not finished yet
|
61
|
+
def finished_at
|
62
|
+
(@finished_at || Time.now).to_s[0..-7] # HACK: to remove offset (e.g. + 01:00)
|
63
|
+
end
|
64
|
+
|
65
|
+
def created_at
|
66
|
+
(@created_at || Time.now).to_s[0..-7] # HACK: to remove offset (e.g. + 01:00)
|
67
|
+
end
|
68
|
+
|
69
|
+
# Returns: boolean, if application is still active window
|
70
|
+
def active?
|
71
|
+
return @active unless @active
|
72
|
+
|
73
|
+
@active = @name == current_application_name &&
|
74
|
+
@title == current_window_title
|
75
|
+
finish! unless @active
|
76
|
+
|
77
|
+
return @active
|
78
|
+
end
|
79
|
+
|
80
|
+
def finished?
|
81
|
+
!active?
|
82
|
+
end
|
83
|
+
|
84
|
+
# Returns difference between StartTime and now if still active, or
|
85
|
+
# StartTime and FinishedTime if not ative anymore
|
86
|
+
def active_time
|
87
|
+
(active?) ? (Time.now - @created_at) : (@finished_at - @created_at)
|
88
|
+
end
|
89
|
+
|
90
|
+
def to_s
|
91
|
+
"#{name}:#{title}:#{extended_info}"
|
92
|
+
end
|
93
|
+
|
94
|
+
def extended_info
|
95
|
+
(@extended_info || "").gsub("\000", "").gsub("'", "`")
|
96
|
+
end
|
97
|
+
|
98
|
+
def os_username
|
99
|
+
@os_username ||= `uname -n`.strip + "\\" + `id -un`.strip
|
100
|
+
end
|
101
|
+
|
102
|
+
# TODO
|
103
|
+
def to_upload_data
|
104
|
+
return "" if name.empty?
|
105
|
+
|
106
|
+
out = "- os_username: '#{os_username}'\n"
|
107
|
+
out += " app_name: '#{name}'\n"
|
108
|
+
out += " window_title: '#{title}'\n"
|
109
|
+
out += " extended_info: '#{extended_info}'\n"
|
110
|
+
out += " start_time: #{created_at}\n"
|
111
|
+
out += " end_time: #{finished_at}\n"
|
112
|
+
|
113
|
+
return out
|
114
|
+
end
|
115
|
+
|
116
|
+
|
117
|
+
|
118
|
+
private
|
119
|
+
def finish!
|
120
|
+
@active = false
|
121
|
+
@finished_at = Time.now
|
122
|
+
end
|
123
|
+
|
124
|
+
def current_application_name
|
125
|
+
application_name(self.class.current_application_name)
|
126
|
+
end
|
127
|
+
|
128
|
+
def current_window_title
|
129
|
+
window_title(self.class.current_window_title)
|
130
|
+
end
|
131
|
+
|
132
|
+
# To be overwritten
|
133
|
+
def application_name(name)
|
134
|
+
name
|
135
|
+
end
|
136
|
+
|
137
|
+
# To be overwritten
|
138
|
+
def window_title(title)
|
139
|
+
title
|
140
|
+
end
|
141
|
+
end
|
142
|
+
end
|
143
|
+
|
144
|
+
|
145
|
+
|
146
|
+
#- os_username: 'werbeboten-HP-Pavilion-g6-Notebook-PC\werbeboten'
|
147
|
+
# app_name: 'werbeboten@werbeboten-HP-Pavilion-g6-Notebook-PC: ~/Dev/Rails3/BuecherdeParser'
|
148
|
+
# window_title: 'werbeboten@werbeboten-HP-Pavilion-g6-Notebook-PC: ~/Dev/Rails3/BuecherdeParser'
|
149
|
+
# extended_info: ''
|
150
|
+
# start_time: 2012-02-10 11:56:52
|
151
|
+
# end_time: 2012-02-10 11:56:57
|
152
|
+
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require 'rescuetime'
|
2
|
+
require 'optparse'
|
3
|
+
|
4
|
+
# This hash will hold all of the options
|
5
|
+
# parsed from the command-line by OptionParser.
|
6
|
+
options = {}
|
7
|
+
|
8
|
+
optparse = OptionParser.new do|opts|
|
9
|
+
# Set a banner, displayed at the top of the help screen.
|
10
|
+
opts.banner = "Usage: ruby-rescuetime [options]"
|
11
|
+
|
12
|
+
# Define the options, and what they do
|
13
|
+
opts.on( '-d', '--debug', 'View debug messages' ) do
|
14
|
+
options[:debug] = true
|
15
|
+
end
|
16
|
+
|
17
|
+
opts.on( '-u', '--email EMAIL', 'Your email login used.' ) do |email|
|
18
|
+
options[:email] = email
|
19
|
+
end
|
20
|
+
|
21
|
+
opts.on( '-p', '--password PASSWORD', 'Your password used.' ) do |password|
|
22
|
+
options[:password] = password
|
23
|
+
end
|
24
|
+
|
25
|
+
options[:config] = File.join(Dir.home, ".ruby-rescuetime", "config.yml")
|
26
|
+
opts.on( '-c', '--config FILE', 'Path to your config-file. (Default: ~/.ruby-rescuetime/config.yml)' ) do |config|
|
27
|
+
options[:config] = config
|
28
|
+
end
|
29
|
+
|
30
|
+
options[:path] = File.join(Dir.home, ".ruby-rescuetime")
|
31
|
+
opts.on('--path PATH', 'Path to your config directory. (Default: ~/.ruby-rescuetime/)' ) do |path|
|
32
|
+
options[:path] = path
|
33
|
+
end
|
34
|
+
|
35
|
+
# This displays the help screen, all programs are assumed to have this option.
|
36
|
+
opts.on( '-h', '--help', 'Display this screen' ) do
|
37
|
+
puts opts
|
38
|
+
exit
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
# Parse the command-line. Remember there are two forms
|
43
|
+
# of the parse method. The 'parse' method simply parses
|
44
|
+
# ARGV, while the 'parse!' method parses ARGV and removes
|
45
|
+
# any options found there, as well as any parameters for
|
46
|
+
# the options. What's left is the list of files to resize.
|
47
|
+
optparse.parse!
|
48
|
+
|
49
|
+
Rescuetime::Loop.new(options)
|
50
|
+
|
@@ -0,0 +1,83 @@
|
|
1
|
+
module Rescuetime
|
2
|
+
class Config
|
3
|
+
include Rescuetime::Debug
|
4
|
+
require 'fileutils'
|
5
|
+
require 'yaml'
|
6
|
+
|
7
|
+
DEFAULT_PATH = File.join(Dir.home, ".ruby-rescuetime")
|
8
|
+
DEFAULT_FILE = "config.yml"
|
9
|
+
|
10
|
+
DEFAULT_CONFIG = {
|
11
|
+
:email => "foo@example.com",
|
12
|
+
:password => ""
|
13
|
+
}
|
14
|
+
|
15
|
+
# Constructor
|
16
|
+
def initialize(options = {})
|
17
|
+
options = {
|
18
|
+
:debug => false,
|
19
|
+
:email => nil,
|
20
|
+
:password => nil,
|
21
|
+
:config => File.join(DEFAULT_PATH, DEFAULT_FILE),
|
22
|
+
:path => nil
|
23
|
+
}.merge(options)
|
24
|
+
|
25
|
+
@debug = options[:debug]
|
26
|
+
@config_path = options[:config] || File.join(options[:path] || DEFAULT_PATH, DEFAULT_FILE)
|
27
|
+
config = read_config(@config_path)
|
28
|
+
|
29
|
+
@config = {
|
30
|
+
:email => options[:email] || config[:email],
|
31
|
+
:password => options[:password] || config[:password],
|
32
|
+
:path => DEFAULT_PATH || config[:path]
|
33
|
+
}
|
34
|
+
update if @config != config
|
35
|
+
end
|
36
|
+
|
37
|
+
def email
|
38
|
+
@config[:email]
|
39
|
+
end
|
40
|
+
|
41
|
+
def password
|
42
|
+
@config[:password]
|
43
|
+
end
|
44
|
+
|
45
|
+
# Path where to store data
|
46
|
+
def path
|
47
|
+
@config[:path]
|
48
|
+
end
|
49
|
+
|
50
|
+
def location
|
51
|
+
@config_path
|
52
|
+
end
|
53
|
+
|
54
|
+
# Write current config to disc
|
55
|
+
def update
|
56
|
+
update_config(@config, @config_path)
|
57
|
+
end
|
58
|
+
|
59
|
+
|
60
|
+
|
61
|
+
private
|
62
|
+
def read_config(path)
|
63
|
+
create_config_file(path) unless File.exist?(path)
|
64
|
+
YAML::load(File.open(path))
|
65
|
+
end
|
66
|
+
|
67
|
+
def create_config_file(path)
|
68
|
+
write_config_file(DEFAULT_CONFIG, path)
|
69
|
+
end
|
70
|
+
|
71
|
+
def update_config(config, path)
|
72
|
+
write_config_file(config, path)
|
73
|
+
end
|
74
|
+
|
75
|
+
def write_config_file(config, path)
|
76
|
+
FileUtils.mkdir_p(File.dirname(path))
|
77
|
+
File.open(path, 'w') do |f|
|
78
|
+
f.write(YAML::dump(config))
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Rescuetime
|
2
|
+
module Debug
|
3
|
+
# Debug-mode turned on?
|
4
|
+
def debug?
|
5
|
+
@debug == true
|
6
|
+
end
|
7
|
+
|
8
|
+
private
|
9
|
+
# Debug-Wrapper
|
10
|
+
def debug(msg = nil, &block)
|
11
|
+
return unless debug?
|
12
|
+
|
13
|
+
puts msg if msg
|
14
|
+
yield if block_given?
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Rescuetime
|
2
|
+
module Extension
|
3
|
+
@extensions = {}
|
4
|
+
|
5
|
+
def self.included(klass)
|
6
|
+
# TODO: raise "No APPLICATION constant defined."
|
7
|
+
|
8
|
+
app = klass::APPLICATION.to_s
|
9
|
+
if @extensions[app]
|
10
|
+
warn <<-WARN
|
11
|
+
Extension for given APPLICATION (#{app}) allready exists.
|
12
|
+
Class: #{klass}
|
13
|
+
Trace: #{caller.first.inspect}
|
14
|
+
WARN
|
15
|
+
end
|
16
|
+
|
17
|
+
@extensions[app] = klass
|
18
|
+
end
|
19
|
+
|
20
|
+
def self.extensions
|
21
|
+
@extensions
|
22
|
+
end
|
23
|
+
|
24
|
+
def self.get(key)
|
25
|
+
@extensions[key.to_s]
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
@@ -0,0 +1,32 @@
|
|
1
|
+
class Rescuetime::Chromium < Rescuetime::Application
|
2
|
+
APPLICATION = "Chromium-browser"
|
3
|
+
include Rescuetime::Extension
|
4
|
+
include Rescuetime::Debug
|
5
|
+
|
6
|
+
def window_title(given_title)
|
7
|
+
title = given_title.gsub(/- Chromium$/, '').strip
|
8
|
+
t = title.downcase
|
9
|
+
if t["google mail"]
|
10
|
+
return "http://www.mail.google.com"
|
11
|
+
elsif t["twitter"]
|
12
|
+
return "http://www.twitter.com"
|
13
|
+
elsif t["facebook"]
|
14
|
+
return "http://www.facebook.com"
|
15
|
+
else
|
16
|
+
return t
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
alias :old_name :name
|
21
|
+
def name
|
22
|
+
["google mail", "twitter", "facebook"].each do |e|
|
23
|
+
return "#{e} - chromium" if title[e]
|
24
|
+
end
|
25
|
+
"#{title} - chromium"
|
26
|
+
end
|
27
|
+
|
28
|
+
# def extended_info
|
29
|
+
# title
|
30
|
+
# end
|
31
|
+
end
|
32
|
+
|