achoo 0.3 → 0.4.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/CHANGES +12 -0
- data/README.rdoc +26 -30
- data/Rakefile +3 -0
- data/bin/achoo +2 -2
- data/lib/achoo.rb +1 -139
- data/lib/achoo/achievo.rb +13 -0
- data/lib/achoo/achievo/form.rb +22 -0
- data/lib/achoo/achievo/hour_administration_form.rb +91 -0
- data/lib/achoo/achievo/hour_registration_form.rb +230 -0
- data/lib/achoo/achievo/hour_registration_form_ranged.rb +49 -0
- data/lib/achoo/achievo/lock_month_form.rb +44 -0
- data/lib/achoo/achievo/login_form.rb +27 -0
- data/lib/achoo/achievo/table.rb +30 -0
- data/lib/achoo/app.rb +153 -0
- data/lib/achoo/awake.rb +86 -100
- data/lib/achoo/extensions.rb +24 -0
- data/lib/achoo/ical.rb +47 -40
- data/lib/achoo/rc_loader.rb +42 -42
- data/lib/achoo/system.rb +8 -3
- data/lib/achoo/system/cstruct.rb +67 -0
- data/lib/achoo/system/log_entry.rb +24 -0
- data/lib/achoo/system/pm_suspend.rb +17 -20
- data/lib/achoo/system/utmp_record.rb +64 -0
- data/lib/achoo/system/wtmp.rb +14 -10
- data/lib/achoo/temporal.rb +8 -0
- data/lib/achoo/temporal/open_timespan.rb +16 -0
- data/lib/achoo/temporal/timespan.rb +122 -0
- data/lib/achoo/term.rb +58 -56
- data/lib/achoo/term/menu.rb +2 -2
- data/lib/achoo/term/table.rb +59 -60
- data/lib/achoo/ui.rb +13 -9
- data/lib/achoo/ui/commands.rb +60 -38
- data/lib/achoo/ui/common.rb +10 -7
- data/lib/achoo/ui/date_chooser.rb +69 -65
- data/lib/achoo/ui/date_choosers.rb +15 -14
- data/lib/achoo/ui/exception_handling.rb +14 -12
- data/lib/achoo/ui/month_chooser.rb +37 -24
- data/lib/achoo/ui/optionally_ranged_date_chooser.rb +29 -25
- data/lib/achoo/ui/register_hours.rb +116 -114
- data/lib/achoo/vcs.rb +32 -30
- data/lib/achoo/vcs/git.rb +18 -14
- data/lib/achoo/vcs/subversion.rb +25 -23
- metadata +30 -24
- data/lib/achoo/binary.rb +0 -7
- data/lib/achoo/binary/cstruct.rb +0 -60
- data/lib/achoo/binary/utmp_record.rb +0 -59
- data/lib/achoo/form.rb +0 -18
- data/lib/achoo/hour_administration_form.rb +0 -131
- data/lib/achoo/hour_registration_form.rb +0 -227
- data/lib/achoo/hour_registration_form_ranged.rb +0 -45
- data/lib/achoo/lock_month_form.rb +0 -40
- data/lib/achoo/open_timespan.rb +0 -13
- data/lib/achoo/timespan.rb +0 -119
data/lib/achoo/ui.rb
CHANGED
@@ -1,10 +1,14 @@
|
|
1
|
-
|
1
|
+
require 'achoo'
|
2
2
|
|
3
|
-
Achoo
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
3
|
+
module Achoo
|
4
|
+
module UI
|
5
|
+
autoload :Commands, 'achoo/ui/commands'
|
6
|
+
autoload :Common, 'achoo/ui/common'
|
7
|
+
autoload :DateChooser, 'achoo/ui/date_chooser'
|
8
|
+
autoload :DateChoosers, 'achoo/ui/date_choosers'
|
9
|
+
autoload :ExceptionHandling, 'achoo/ui/exception_handling'
|
10
|
+
autoload :MonthChooser, 'achoo/ui/month_chooser'
|
11
|
+
autoload :OptionallyRangedDateChooser, 'achoo/ui/optionally_ranged_date_chooser'
|
12
|
+
autoload :RegisterHours, 'achoo/ui/register_hours'
|
13
|
+
end
|
14
|
+
end
|
data/lib/achoo/ui/commands.rb
CHANGED
@@ -1,51 +1,73 @@
|
|
1
|
-
require 'achoo/
|
2
|
-
require 'achoo/
|
1
|
+
require 'achoo/achievo'
|
2
|
+
require 'achoo/term'
|
3
3
|
require 'achoo/ui'
|
4
4
|
|
5
|
-
module Achoo
|
5
|
+
module Achoo
|
6
|
+
module UI
|
7
|
+
module Commands
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
+
include DateChoosers
|
10
|
+
include Common
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
12
|
+
def show_registered_hours_for_day(agent)
|
13
|
+
date = date_chooser
|
14
|
+
form = Achievo::HourAdministrationForm.new(agent)
|
15
|
+
form.show_registered_hours_for_day(date)
|
16
|
+
end
|
15
17
|
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
18
|
+
def show_registered_hours_for_week(agent)
|
19
|
+
date = date_chooser
|
20
|
+
form = Achievo::HourAdministrationForm.new(agent)
|
21
|
+
form.show_registered_hours_for_week(date)
|
22
|
+
end
|
21
23
|
|
22
24
|
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
25
|
+
def show_flexi_time(agent)
|
26
|
+
date = date_chooser
|
27
|
+
form = Achievo::HourAdministrationForm.new(agent)
|
28
|
+
balance = form.flexi_time(date)
|
29
|
+
puts "Flexi time balance: #{Term::underline(balance)}"
|
30
|
+
end
|
29
31
|
|
30
32
|
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
33
|
+
def lock_month(agent)
|
34
|
+
month = month_chooser
|
35
|
+
form = Achievo::LockMonthForm.new(agent)
|
36
|
+
form.lock_month(month)
|
37
|
+
form.print_values
|
38
|
+
if confirm
|
39
|
+
form.submit
|
40
|
+
else
|
41
|
+
puts "Cancelled"
|
42
|
+
end
|
43
|
+
end
|
42
44
|
|
43
45
|
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
46
|
+
def show_holiday_report(agent)
|
47
|
+
page = agent.get(RC[:holiday_report_url])
|
48
|
+
page.body.match(/<b>(\d+,\d+)<\/b>/)
|
49
|
+
puts "Balance: #{Term::underline($1)}"
|
50
|
+
end
|
50
51
|
|
52
|
+
|
53
|
+
def view_report(agent)
|
54
|
+
choices = RC[:reports].keys
|
55
|
+
answer = Term.choose('Report', choices)
|
56
|
+
key = choices[answer.to_i - 1]
|
57
|
+
|
58
|
+
puts "Fetching data ..."
|
59
|
+
page = agent.get(RC[:url] + RC[:reports][key])
|
60
|
+
|
61
|
+
table = Achievo::Table.new(page.search('#rl_1 tr'))
|
62
|
+
table.select_columns do |c|
|
63
|
+
['Date', 'Project', 'Phase', 'Remark', 'Time'].include?(c[0])
|
64
|
+
end
|
65
|
+
|
66
|
+
Term::Table.new(table.first,
|
67
|
+
table[2...table.length-1],
|
68
|
+
table.last).print
|
69
|
+
end
|
70
|
+
|
71
|
+
end
|
72
|
+
end
|
51
73
|
end
|
data/lib/achoo/ui/common.rb
CHANGED
@@ -1,15 +1,18 @@
|
|
1
1
|
require 'achoo/term'
|
2
|
+
require 'achoo/ui'
|
2
3
|
|
3
|
-
|
4
|
+
module Achoo
|
5
|
+
module UI
|
6
|
+
module Common
|
4
7
|
|
5
|
-
|
8
|
+
def confirm
|
9
|
+
answer = Term::ask "Submit? [Y/n]"
|
10
|
+
answer.downcase!
|
11
|
+
return answer == 'y' || answer == ''
|
12
|
+
end
|
6
13
|
|
7
|
-
|
8
|
-
answer = Achoo::Term::ask "Submit? [Y/n]"
|
9
|
-
answer.downcase!
|
10
|
-
return answer == 'y' || answer == ''
|
14
|
+
end
|
11
15
|
end
|
12
|
-
|
13
16
|
end
|
14
17
|
|
15
18
|
|
@@ -1,75 +1,79 @@
|
|
1
1
|
require 'achoo/term'
|
2
|
+
require 'achoo/ui'
|
2
3
|
|
3
|
-
|
4
|
+
module Achoo
|
5
|
+
module UI
|
4
6
|
|
5
|
-
class
|
7
|
+
class DateChooser
|
6
8
|
|
7
|
-
|
8
|
-
|
9
|
+
PROMPT = "Date ([today] | ?)"
|
10
|
+
FORMAT = " today | (+|-)n | [[[YY]YY]-[M]M]-[D]D"
|
9
11
|
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
12
|
+
def choose
|
13
|
+
loop do
|
14
|
+
answer = Term::ask PROMPT
|
15
|
+
begin
|
16
|
+
date = handle_answer(answer)
|
17
|
+
return date if date
|
18
|
+
rescue ArgumentError => e
|
19
|
+
puts e
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def parse_date(date_str, base=Date.today)
|
25
|
+
raise ArgumentError.new('Invalid date') if date_str.nil?
|
26
|
+
|
27
|
+
# Today (default)
|
28
|
+
if date_str == 'today' || date_str.empty?
|
29
|
+
return Date.today
|
30
|
+
end
|
31
|
+
|
32
|
+
# Base offset
|
33
|
+
case date_str.chars.first
|
34
|
+
when '-'
|
35
|
+
return base - Integer(date_str[1..-1])
|
36
|
+
when '+'
|
37
|
+
return base + Integer(date_str[1..-1])
|
38
|
+
end
|
39
|
+
|
40
|
+
#
|
41
|
+
date = date_str.split('-').collect {|d| d.to_i}
|
42
|
+
case date.length
|
43
|
+
when 1
|
44
|
+
return Date.civil(base.year, base.month, *date)
|
45
|
+
when 2
|
46
|
+
return Date.civil(base.year, *date)
|
47
|
+
when 3
|
48
|
+
date[0] += 2000 if date[0] < 100
|
49
|
+
return Date.civil(*date)
|
50
|
+
end
|
51
|
+
|
52
|
+
raise ArgumentError.new('Invalid date')
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def handle_answer(answer)
|
58
|
+
if answer == '?'
|
59
|
+
print_help_message
|
60
|
+
return false
|
61
|
+
else
|
62
|
+
return parse_date(answer)
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def print_help_message
|
67
|
+
puts "Accepted formats:"
|
68
|
+
puts date_format_help_string
|
69
|
+
puts
|
70
|
+
system 'cal -3m'
|
71
|
+
end
|
72
|
+
|
73
|
+
def date_format_help_string
|
74
|
+
FORMAT
|
18
75
|
end
|
19
|
-
end
|
20
|
-
end
|
21
|
-
|
22
|
-
def parse_date(date_str, base=Date.today)
|
23
|
-
raise ArgumentError.new('Invalid date') if date_str.nil?
|
24
|
-
|
25
|
-
# Today (default)
|
26
|
-
if date_str == 'today' || date_str.empty?
|
27
|
-
return Date.today
|
28
|
-
end
|
29
|
-
|
30
|
-
# Base offset
|
31
|
-
case date_str.chars.first
|
32
|
-
when '-'
|
33
|
-
return base - Integer(date_str[1..-1])
|
34
|
-
when '+'
|
35
|
-
return base + Integer(date_str[1..-1])
|
36
|
-
end
|
37
|
-
|
38
|
-
#
|
39
|
-
date = date_str.split('-').collect {|d| d.to_i}
|
40
|
-
case date.length
|
41
|
-
when 1
|
42
|
-
return Date.civil(base.year, base.month, *date)
|
43
|
-
when 2
|
44
|
-
return Date.civil(base.year, *date)
|
45
|
-
when 3
|
46
|
-
date[0] += 2000 if date[0] < 100
|
47
|
-
return Date.civil(*date)
|
48
|
-
end
|
49
|
-
|
50
|
-
raise ArgumentError.new('Invalid date')
|
51
|
-
end
|
52
|
-
|
53
|
-
private
|
54
76
|
|
55
|
-
def handle_answer(answer)
|
56
|
-
if answer == '?'
|
57
|
-
print_help_message
|
58
|
-
return false
|
59
|
-
else
|
60
|
-
return parse_date(answer)
|
61
77
|
end
|
62
78
|
end
|
63
|
-
|
64
|
-
def print_help_message
|
65
|
-
puts "Accepted formats:"
|
66
|
-
puts date_format_help_string
|
67
|
-
puts
|
68
|
-
system 'cal -3m'
|
69
|
-
end
|
70
|
-
|
71
|
-
def date_format_help_string
|
72
|
-
FORMAT
|
73
|
-
end
|
74
|
-
|
75
79
|
end
|
@@ -1,21 +1,22 @@
|
|
1
|
-
require 'achoo/ui
|
2
|
-
require 'achoo/ui/optionally_ranged_date_chooser'
|
3
|
-
require 'achoo/ui/month_chooser'
|
1
|
+
require 'achoo/ui'
|
4
2
|
|
5
|
-
|
3
|
+
module Achoo
|
4
|
+
module UI
|
6
5
|
|
7
|
-
module
|
6
|
+
module DateChoosers
|
8
7
|
|
9
|
-
|
10
|
-
|
11
|
-
|
8
|
+
def date_chooser
|
9
|
+
DateChooser.new.choose
|
10
|
+
end
|
12
11
|
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
def optionally_ranged_date_chooser
|
13
|
+
OptionallyRangedDateChooser.new.choose
|
14
|
+
end
|
16
15
|
|
17
|
-
|
18
|
-
|
19
|
-
|
16
|
+
def month_chooser
|
17
|
+
MonthChooser.new.choose
|
18
|
+
end
|
20
19
|
|
20
|
+
end
|
21
|
+
end
|
21
22
|
end
|
@@ -1,20 +1,22 @@
|
|
1
1
|
require 'achoo/term'
|
2
|
+
require 'achoo/ui'
|
2
3
|
|
3
|
-
|
4
|
+
module Achoo
|
5
|
+
module UI
|
6
|
+
module ExceptionHandling
|
4
7
|
|
5
|
-
|
8
|
+
def handle_exception(user_message, e)
|
9
|
+
Term::warn(user_message) + get_exception_reason(e)
|
10
|
+
end
|
6
11
|
|
7
|
-
|
8
|
-
|
9
|
-
|
12
|
+
def handle_fatal_exception(user_message, e)
|
13
|
+
abort Term::fatal(user_message) + get_exception_reason(e)
|
14
|
+
end
|
10
15
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
16
|
+
def get_exception_reason(e)
|
17
|
+
"\nReason: \n\t" + e.message.gsub("\n", "\n\t") + "\n---\n\t" + e.backtrace.join("\n\t")
|
18
|
+
end
|
15
19
|
|
16
|
-
|
17
|
-
"\nReason: \n\t" + e.message.gsub("\n", "\n\t") + "\n---\n\t" + e.backtrace.join("\n\t")
|
20
|
+
end
|
18
21
|
end
|
19
|
-
|
20
22
|
end
|
@@ -1,27 +1,40 @@
|
|
1
1
|
require 'achoo/term'
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
2
|
+
require 'achoo/ui'
|
3
|
+
|
4
|
+
module Achoo
|
5
|
+
module UI
|
6
|
+
class MonthChooser
|
7
|
+
|
8
|
+
def choose
|
9
|
+
loop do
|
10
|
+
answer = Term::ask "Period ([#{one_month_ago}] | YYYYMM)"
|
11
|
+
begin
|
12
|
+
return handle_answer(answer)
|
13
|
+
rescue ArgumentError => e
|
14
|
+
puts e
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
def handle_answer(answer)
|
20
|
+
period = !answer || answer.empty? ? one_month_ago : answer
|
21
|
+
period =~ /\A \d{4} (?: 0\d | 1[0-2]) \z/x \
|
22
|
+
or raise ArgumentError.new('Invalid month')
|
23
|
+
period
|
24
|
+
end
|
25
|
+
|
26
|
+
def one_month_ago
|
27
|
+
now = Time.now
|
28
|
+
year = now.year
|
29
|
+
|
30
|
+
# Use -2 + 1 to shift range from 0-11 to 1-12
|
31
|
+
month = (now.month - 2)%12 + 1
|
32
|
+
year -= 1 if month > now.month
|
33
|
+
|
34
|
+
sprintf "%d%02d", year, month
|
35
|
+
end
|
36
|
+
|
37
|
+
end
|
24
38
|
end
|
25
|
-
|
26
|
-
end
|
39
|
+
end
|
27
40
|
|
@@ -1,33 +1,37 @@
|
|
1
1
|
require 'achoo/ui/date_chooser'
|
2
2
|
|
3
|
-
|
3
|
+
module Achoo
|
4
|
+
module UI
|
5
|
+
class OptionallyRangedDateChooser < DateChooser
|
4
6
|
|
5
|
-
|
6
|
-
|
7
|
-
|
8
|
-
|
9
|
-
|
10
|
-
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
7
|
+
def parse_date_range(date_range_str)
|
8
|
+
start_date_str, finish_date_str = *date_range_str.split('->')
|
9
|
+
start_date = parse_date(start_date_str.strip)
|
10
|
+
finish_date = parse_date(finish_date_str.strip, start_date)
|
11
|
+
|
12
|
+
if start_date >= finish_date
|
13
|
+
raise ArgumentError.new('Invalid date range')
|
14
|
+
end
|
15
|
+
|
16
|
+
[start_date, finish_date]
|
17
|
+
end
|
16
18
|
|
17
|
-
|
19
|
+
private
|
20
|
+
|
21
|
+
def handle_answer(answer)
|
22
|
+
if answer.include? '->'
|
23
|
+
return parse_date_range(answer)
|
24
|
+
else
|
25
|
+
return super
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def date_format_help_string
|
30
|
+
return " DATE [-> DATE]\n" \
|
31
|
+
<< " DATE:\n" \
|
32
|
+
<< FORMAT
|
33
|
+
end
|
18
34
|
|
19
|
-
def handle_answer(answer)
|
20
|
-
if answer.include? '->'
|
21
|
-
return parse_date_range(answer)
|
22
|
-
else
|
23
|
-
return super
|
24
35
|
end
|
25
36
|
end
|
26
|
-
|
27
|
-
def date_format_help_string
|
28
|
-
return " DATE [-> DATE]\n" \
|
29
|
-
<< " DATE:\n" \
|
30
|
-
<< FORMAT
|
31
|
-
end
|
32
|
-
|
33
37
|
end
|