timr 0.3.0 → 0.4.0

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.
Files changed (106) hide show
  1. checksums.yaml +4 -4
  2. data/.ackrc +9 -0
  3. data/.editorconfig +1 -0
  4. data/.env.example +7 -0
  5. data/.github/CONTRIBUTING.md +32 -0
  6. data/.github/ISSUE_TEMPLATE.md +13 -0
  7. data/.gitignore +8 -2
  8. data/.rdoc_options +21 -0
  9. data/.travis.yml +10 -7
  10. data/Gemfile +8 -0
  11. data/README.md +216 -3
  12. data/bin/.gitignore +2 -0
  13. data/bin/README.md +17 -0
  14. data/bin/build.sh +14 -0
  15. data/bin/build_api.sh +14 -0
  16. data/bin/build_coverage.sh +23 -0
  17. data/bin/build_info.sh +27 -0
  18. data/bin/build_man.sh +41 -0
  19. data/bin/clean.sh +14 -0
  20. data/bin/dev_setup.sh +19 -0
  21. data/bin/install.sh +49 -0
  22. data/bin/publish +38 -0
  23. data/bin/release.sh +35 -0
  24. data/bin/test.sh +19 -0
  25. data/bin/timr +20 -40
  26. data/bin/timr_bash_completion.sh +337 -0
  27. data/bin/uninstall.sh +24 -0
  28. data/lib/timr.rb +36 -8
  29. data/lib/timr/command/basic_command.rb +170 -0
  30. data/lib/timr/command/continue_command.rb +86 -0
  31. data/lib/timr/command/help_command.rb +137 -0
  32. data/lib/timr/command/log_command.rb +297 -0
  33. data/lib/timr/command/pause_command.rb +89 -0
  34. data/lib/timr/command/pop_command.rb +176 -0
  35. data/lib/timr/command/push_command.rb +141 -0
  36. data/lib/timr/command/report_command.rb +689 -0
  37. data/lib/timr/command/start_command.rb +172 -0
  38. data/lib/timr/command/status_command.rb +198 -0
  39. data/lib/timr/command/stop_command.rb +127 -0
  40. data/lib/timr/command/task_command.rb +318 -0
  41. data/lib/timr/command/track_command.rb +381 -0
  42. data/lib/timr/command/version_command.rb +18 -0
  43. data/lib/timr/duration.rb +159 -0
  44. data/lib/timr/exception/timr_error.rb +113 -0
  45. data/lib/timr/ext/time.rb +12 -0
  46. data/lib/timr/helper/datetime_helper.rb +128 -0
  47. data/lib/timr/helper/terminal_helper.rb +58 -0
  48. data/lib/timr/helper/translation_helper.rb +45 -0
  49. data/lib/timr/model/basic_model.rb +287 -0
  50. data/lib/timr/model/config.rb +48 -0
  51. data/lib/timr/model/foreign_id_db.rb +84 -0
  52. data/lib/timr/model/stack.rb +161 -0
  53. data/lib/timr/model/task.rb +1039 -0
  54. data/lib/timr/model/track.rb +589 -0
  55. data/lib/timr/progressbar.rb +41 -0
  56. data/lib/timr/simple_opt_parser.rb +230 -0
  57. data/lib/timr/status.rb +70 -0
  58. data/lib/timr/table.rb +88 -0
  59. data/lib/timr/timr.rb +500 -558
  60. data/lib/timr/version.rb +4 -15
  61. data/man/.gitignore +2 -0
  62. data/man/_footer +3 -0
  63. data/man/timr-continue.1 +48 -0
  64. data/man/timr-continue.1.ronn +39 -0
  65. data/man/timr-ftime.7 +77 -0
  66. data/man/timr-ftime.7.ronn +57 -0
  67. data/man/timr-log.1 +109 -0
  68. data/man/timr-log.1.ronn +87 -0
  69. data/man/timr-pause.1 +56 -0
  70. data/man/timr-pause.1.ronn +45 -0
  71. data/man/timr-pop.1 +66 -0
  72. data/man/timr-pop.1.ronn +53 -0
  73. data/man/timr-push.1 +25 -0
  74. data/man/timr-push.1.ronn +20 -0
  75. data/man/timr-report.1 +228 -0
  76. data/man/timr-report.1.ronn +193 -0
  77. data/man/timr-start.1 +100 -0
  78. data/man/timr-start.1.ronn +82 -0
  79. data/man/timr-status.1 +53 -0
  80. data/man/timr-status.1.ronn +42 -0
  81. data/man/timr-stop.1 +75 -0
  82. data/man/timr-stop.1.ronn +60 -0
  83. data/man/timr-task.1 +147 -0
  84. data/man/timr-task.1.ronn +115 -0
  85. data/man/timr-track.1 +109 -0
  86. data/man/timr-track.1.ronn +89 -0
  87. data/man/timr.1 +119 -0
  88. data/man/timr.1.ronn +68 -0
  89. data/timr.gemspec +18 -3
  90. data/timr.sublime-project +20 -1
  91. metadata +142 -23
  92. data/Makefile +0 -12
  93. data/Makefile.common +0 -56
  94. data/lib/timr/stack.rb +0 -81
  95. data/lib/timr/task.rb +0 -258
  96. data/lib/timr/track.rb +0 -167
  97. data/lib/timr/window.rb +0 -259
  98. data/lib/timr/window_help.rb +0 -41
  99. data/lib/timr/window_tasks.rb +0 -30
  100. data/lib/timr/window_test.rb +0 -20
  101. data/lib/timr/window_timeline.rb +0 -33
  102. data/tests/tc_stack.rb +0 -121
  103. data/tests/tc_task.rb +0 -190
  104. data/tests/tc_track.rb +0 -144
  105. data/tests/tc_window.rb +0 -428
  106. data/tests/ts_all.rb +0 -6
@@ -0,0 +1,18 @@
1
+
2
+ module TheFox
3
+ module Timr
4
+ module Command
5
+
6
+ class VersionCommand < BasicCommand
7
+
8
+ # See BasicCommand#run.
9
+ def run
10
+ puts "#{NAME} #{VERSION} (#{DATE})"
11
+ puts "#{HOMEPAGE}"
12
+ end
13
+
14
+ end # class VersionCommand
15
+
16
+ end # module Command
17
+ end # module Timr
18
+ end # module TheFox
@@ -0,0 +1,159 @@
1
+
2
+ require 'chronic_duration'
3
+
4
+ module TheFox
5
+ module Timr
6
+
7
+ # Uses seconds as basis.
8
+ class Duration
9
+
10
+ include Error
11
+
12
+ # Basis Data (Integer)
13
+ #
14
+ # A Duration is stored as seconds.
15
+ attr_reader :seconds
16
+
17
+ def initialize(seconds = 0)
18
+ @seconds = seconds.to_i
19
+
20
+ @smh_seconds = nil
21
+ @smh_minutes = nil
22
+ @smh_hours = nil
23
+ end
24
+
25
+ # Seconds, Minutes, Hours as Array
26
+ def to_smh
27
+ @smh_seconds = @seconds
28
+
29
+ @smh_hours = @smh_seconds / 3600
30
+
31
+ @smh_seconds -= @smh_hours * 3600
32
+ @smh_minutes = @smh_seconds / 60
33
+
34
+ @smh_seconds -= @smh_minutes * 60
35
+
36
+ [@smh_seconds, @smh_minutes, @smh_hours]
37
+ end
38
+
39
+ # Converts seconds to `nh nm ns` format. Where `n` is a number.
40
+ def to_human
41
+ dur_opt = {
42
+ :format => :short,
43
+ :limit_to_hours => true,
44
+ :keep_zero => false,
45
+ :units => 2,
46
+ }
47
+ h = ChronicDuration.output(@seconds, dur_opt)
48
+
49
+ h ? h : '---'
50
+ end
51
+
52
+ # Man-days, Man-hours
53
+ #
54
+ # Man Unit:
55
+ #
56
+ # - 8 hours are 1 man-day.
57
+ # - 5 man-days are 1 man-week, and so on.
58
+ def to_man_days
59
+ if @seconds < 28800 # 8 * 3600 = 1 man-day
60
+ to_human
61
+ elsif @seconds < 144000 # 5 * 28800 = 1 man-week
62
+ seconds = @seconds
63
+
64
+ man_days = seconds / 28800
65
+
66
+ seconds -= man_days * 28800
67
+ man_hours = seconds / 3600
68
+
69
+ '%dd %dh' % [man_days, man_hours]
70
+ else
71
+ seconds = @seconds
72
+
73
+ man_weeks = seconds / 144000
74
+
75
+ seconds -= man_weeks * 144000
76
+ man_days = seconds / 28800
77
+
78
+ seconds -= man_days * 28800
79
+ man_hours = seconds / 3600
80
+
81
+ '%dw %dd %dh' % [man_weeks, man_days, man_hours]
82
+ end
83
+ end
84
+
85
+ # Adds two Durations.
86
+ def +(duration)
87
+ case duration
88
+ when Integer
89
+ Duration.new(@seconds + duration)
90
+ when Duration
91
+ Duration.new(@seconds + duration.seconds)
92
+ when nil
93
+ Duration.new(@seconds)
94
+ else
95
+ raise DurationError, "Wrong type #{duration.class} for '+' function."
96
+ end
97
+ end
98
+
99
+ # Subtract two Durations.
100
+ def -(duration)
101
+ case duration
102
+ when Integer
103
+ diff = @seconds - duration
104
+ when Duration
105
+ diff = @seconds - duration.seconds
106
+ else
107
+ raise DurationError, "Wrong type #{duration.class} for '+' function."
108
+ end
109
+
110
+ if diff < 0
111
+ diff = 0
112
+ end
113
+ Duration.new(diff)
114
+ end
115
+
116
+ # Lesser
117
+ def <(obj)
118
+ case obj
119
+ when Integer
120
+ @seconds < obj
121
+ when Duration
122
+ @seconds < obj.to_i
123
+ end
124
+ end
125
+
126
+ # Greater
127
+ def >(obj)
128
+ case obj
129
+ when Integer
130
+ @seconds > obj
131
+ when Duration
132
+ @seconds > obj.to_i
133
+ end
134
+ end
135
+
136
+ # String
137
+ def to_s
138
+ @seconds.to_s
139
+ end
140
+
141
+ # Use this instead of `Duration.seconds`.
142
+ def to_i
143
+ @seconds
144
+ end
145
+
146
+ # All methods in this block are static.
147
+ class << self
148
+
149
+ # Parse a String using [ChronicDuration](https://rubygems.org/gems/chronic_duration) and create a new Duration instance.
150
+ def parse(str)
151
+ Duration.new(ChronicDuration.parse(str))
152
+ end
153
+
154
+ end
155
+
156
+ end # class Duration
157
+
158
+ end # module Timr
159
+ end # module TheFox
@@ -0,0 +1,113 @@
1
+
2
+ module TheFox
3
+ module Timr
4
+
5
+ # # Errors Inheritance Tree
6
+ #
7
+ # TimrError is the basic class for all Timr Error classes. It subclasses from [Rubys StandardError](http://ruby-doc.org/core-2.4.1/Exception.html).
8
+ #
9
+ # - TimrError
10
+ # - ModelError
11
+ # - IdError
12
+ # - ForeignIdError
13
+ # - TaskError
14
+ # - TrackError
15
+ # - StackError
16
+ # - DateTimeHelperError
17
+ # - TerminalHelperError
18
+ # - CommandError
19
+ # - ContinueCommandError
20
+ # - LogCommandError
21
+ # - PauseCommandError
22
+ # - PopCommandError
23
+ # - PushCommandError
24
+ # - ReportCommandError
25
+ # - StartCommandError
26
+ # - StatusCommandError
27
+ # - StopCommandError
28
+ # - TaskCommandError
29
+ # - TrackCommandError
30
+ # - HelpCommandError
31
+ # - DurationError
32
+ # - ThisShouldNeverHappenError
33
+ module Error
34
+
35
+ class TimrError < StandardError
36
+ end
37
+
38
+ class ModelError < TimrError
39
+ end
40
+
41
+ class IdError < ModelError
42
+ end
43
+
44
+ class ForeignIdError < ModelError
45
+ end
46
+
47
+ class TaskError < ModelError
48
+ end
49
+
50
+ class TrackError < ModelError
51
+ end
52
+
53
+ class StackError < ModelError
54
+ end
55
+
56
+ # Use by TheFox::Timr::Helper::DateTimeHelper.
57
+ class DateTimeHelperError < TimrError
58
+ end
59
+
60
+ # Use by TheFox::Timr::Helper::TerminalHelper.
61
+ class TerminalHelperError < TimrError
62
+ end
63
+
64
+ class CommandError < TimrError
65
+ end
66
+
67
+ class ContinueCommandError < CommandError
68
+ end
69
+
70
+ class LogCommandError < CommandError
71
+ end
72
+
73
+ class PauseCommandError < CommandError
74
+ end
75
+
76
+ class PopCommandError < CommandError
77
+ end
78
+
79
+ class PushCommandError < CommandError
80
+ end
81
+
82
+ class ReportCommandError < CommandError
83
+ end
84
+
85
+ class StartCommandError < CommandError
86
+ end
87
+
88
+ class StatusCommandError < CommandError
89
+ end
90
+
91
+ class StopCommandError < CommandError
92
+ end
93
+
94
+ class TaskCommandError < CommandError
95
+ end
96
+
97
+ class TrackCommandError < CommandError
98
+ end
99
+
100
+ class HelpCommandError < CommandError
101
+ end
102
+
103
+ class DurationError < TimrError
104
+ end
105
+
106
+ # This should really never happen. But you never know. ;)
107
+ class ThisShouldNeverHappenError < TimrError
108
+ end
109
+
110
+ end # module Error
111
+
112
+ end # module Timr
113
+ end # module TheFox
@@ -0,0 +1,12 @@
1
+
2
+ # Extend core [Time](http://ruby-doc.org/stdlib-2.4.0/libdoc/time/rdoc/Time.html) class.
3
+ class Time
4
+
5
+ # See [How do I get elapsed time in milliseconds in Ruby?](http://stackoverflow.com/questions/1414951/how-do-i-get-elapsed-time-in-milliseconds-in-ruby)
6
+ #
7
+ # Not really used. Only to measure the execution from start to end. See `bin/timr`.
8
+ def to_ms
9
+ (self.to_f * 1000.0).to_i
10
+ end
11
+
12
+ end
@@ -0,0 +1,128 @@
1
+
2
+ require 'date'
3
+ require 'time'
4
+
5
+ module TheFox
6
+ module Timr
7
+ module Helper
8
+
9
+ # This class should *NOT* replace [Time](http://ruby-doc.org/core-2.4.1/Time.html), [Date](http://ruby-doc.org/stdlib-2.4.1/libdoc/date/rdoc/Date.html) or [DateTime](http://ruby-doc.org/stdlib-2.4.1/libdoc/date/rdoc/DateTime.html).
10
+ class DateTimeHelper
11
+
12
+ # All methods in this block are static.
13
+ class << self
14
+
15
+ include TheFox::Timr::Error
16
+
17
+ # Convert String to Date.
18
+ def convert_date(date)
19
+ case date
20
+ when String
21
+ Time.parse(date).utc.to_date
22
+ when nil
23
+ Time.now.utc.to_date
24
+ end
25
+ end
26
+
27
+ # Convert String to Time.
28
+ def convert_time(time)
29
+ case time
30
+ when String
31
+ Time.parse(time).utc
32
+ when nil
33
+ Time.now.utc
34
+ end
35
+ end
36
+
37
+ # Parse an argv Array.
38
+ #
39
+ # Create a `from` and `to` for a day.
40
+ def parse_day_argv(argv)
41
+ day = argv.shift
42
+ from = Time.parse("#{day} 00:00:00")
43
+ to = Time.parse("#{day} 23:59:59")
44
+ [from, to]
45
+ end
46
+
47
+ # Parse an argv Array.
48
+ #
49
+ # Create a `from` and `to` for a month.
50
+ def parse_month_argv(argv)
51
+ parts = argv.shift.split('-').map{ |s| s.to_i }
52
+ if parts.count == 1
53
+ y = Date.today.year
54
+ m = parts.first
55
+ else
56
+ y, m = parts
57
+ end
58
+ if y < 2000 # shit
59
+ y += 2000
60
+ end
61
+
62
+ start_date = Date.new(y, m, 1)
63
+ end_date = Date.new(y, m, -1)
64
+
65
+ from = Time.parse("#{start_date.strftime('%F')} 00:00:00")
66
+ to = Time.parse("#{end_date.strftime('%F')} 23:59:59")
67
+ [from, to]
68
+ end
69
+
70
+ # Parse an argv Array.
71
+ #
72
+ # Create a `from` and `to` for a year.
73
+ def parse_year_argv(argv)
74
+ y = argv.shift
75
+ if y
76
+ y = y.to_i
77
+ else
78
+ y = Date.today.year
79
+ end
80
+ if y < 2000 # shit
81
+ y += 2000
82
+ end
83
+
84
+ start_date = Date.new(y, 1, 1)
85
+ end_date = Date.new(y, 12, -1)
86
+
87
+ from = Time.parse("#{start_date.strftime('%F')} 00:00:00")
88
+ to = Time.parse("#{end_date.strftime('%F')} 23:59:59")
89
+ [from, to]
90
+ end
91
+
92
+ # Create a Time instance from a Hash.
93
+ #
94
+ # Options:
95
+ #
96
+ # - `:date` String
97
+ # - `:time` String
98
+ def get_datetime_from_options(options = Hash.new)
99
+ date_opt = options.fetch(:date, nil)
100
+ time_opt = options.fetch(:time, nil)
101
+
102
+ if date_opt && !time_opt
103
+ raise DateTimeHelperError, 'You also need to set a time when giving a date.'
104
+ end
105
+
106
+ datetime_a = []
107
+ if date_opt
108
+ datetime_a << date_opt
109
+ end
110
+ if time_opt
111
+ datetime_a << time_opt
112
+ end
113
+
114
+ if datetime_a.count > 0
115
+ datetime_s = datetime_a.join(' ')
116
+ Time.parse(datetime_s).utc
117
+ else
118
+ Time.now.utc
119
+ end
120
+ end
121
+
122
+ end
123
+
124
+ end # class DateTimeHelper
125
+
126
+ end # module Helper
127
+ end # module Timr
128
+ end # module TheFox
@@ -0,0 +1,58 @@
1
+
2
+ module TheFox
3
+ module Timr
4
+ module Helper
5
+
6
+ # This class helps with Terminal operations.
7
+ class TerminalHelper
8
+
9
+ # All methods in this block are static.
10
+ class << self
11
+
12
+ include TheFox::Timr::Error
13
+
14
+ # Run external editor via EDITOR environment variable.
15
+ def run_external_editor(text = nil)
16
+ case text
17
+ when Array
18
+ text = text.join("\n")
19
+ end
20
+
21
+ if !ENV['EDITOR'] || ENV['EDITOR'].length == 0
22
+ raise TerminalHelperError, 'EDITOR environment variable not set.'
23
+ end
24
+
25
+ tmpfile = Tempfile.new('timr_message')
26
+ if text
27
+ tmpfile.write(text)
28
+ end
29
+ tmpfile.close
30
+
31
+ system_s = '%s %s' % [ENV['EDITOR'], tmpfile.path]
32
+ system(system_s)
33
+
34
+ tmpfile.open
35
+ tmpfile_lines = tmpfile.read
36
+ tmpfile.close
37
+
38
+ tmpfile_lines
39
+ .split("\n")
40
+ .select{ |row| row[0] != '#' }
41
+ .join("\n")
42
+ end
43
+
44
+ # Print help to external editor.
45
+ def external_editor_help(edit_text)
46
+ edit_text << '# This is a comment.'
47
+ edit_text << '# The first line should be a sentence. Sentence have dots at the end.'
48
+ edit_text << '# The second line should be empty, if you provide a more detailed'
49
+ edit_text << '# description from on the third line. Like on Git.'
50
+ end
51
+
52
+ end
53
+
54
+ end # class TerminalHelper
55
+
56
+ end # module Helper
57
+ end # module Timr
58
+ end # module TheFox