dayrb 2.0.2
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.
- checksums.yaml +7 -0
- data/.gitignore +11 -0
- data/LICENSE +8 -0
- data/Rakefile +118 -0
- data/VERSION +1 -0
- data/bin/day.rb +144 -0
- data/changelog.md +100 -0
- data/dayrb.gemspec +14 -0
- data/lib/day/configuration.rb +140 -0
- data/lib/day/parser.rb +168 -0
- data/lib/day/presenter.rb +223 -0
- data/lib/day/task.rb +44 -0
- data/lib/day/tasklist.rb +44 -0
- data/readme.md +53 -0
- data/spec/configuration_spec.rb +142 -0
- data/spec/parser_spec.rb +191 -0
- data/spec/spec_helper.rb +35 -0
- metadata +64 -0
data/lib/day/parser.rb
ADDED
@@ -0,0 +1,168 @@
|
|
1
|
+
# DayRB Parser Module
|
2
|
+
#
|
3
|
+
# Parses and validates ARGV.
|
4
|
+
# After validation, we can confidently assume a specified task in opts exists.
|
5
|
+
#
|
6
|
+
# MIT License; See LICENSE file; Cameron Carroll 2014
|
7
|
+
|
8
|
+
require 'abbrev'
|
9
|
+
|
10
|
+
E_NO_SUCH_TASK = "I didn't find any task by that name."
|
11
|
+
E_MUST_SPECIFY_TASK = "I need you to specify which task to delete."
|
12
|
+
|
13
|
+
# DayRB Parser Module
|
14
|
+
#
|
15
|
+
# Scans and validates ARGV inputs and builds the opts hash.
|
16
|
+
# (Performs argument validation, and checks that a specified task really exists.)
|
17
|
+
module Parser
|
18
|
+
class << self
|
19
|
+
|
20
|
+
# Parse ARGV into opts hash
|
21
|
+
#
|
22
|
+
# @param config [Configuration] Entire configuration object, needed for task lookups.
|
23
|
+
def parse_options(config)
|
24
|
+
opts = {}
|
25
|
+
@config = config
|
26
|
+
|
27
|
+
opts[:operation] = case ARGV.first
|
28
|
+
when nil
|
29
|
+
:print
|
30
|
+
when "-a", "-A"
|
31
|
+
opts[:all] = true
|
32
|
+
:print
|
33
|
+
when "clear", "c"
|
34
|
+
:clear
|
35
|
+
when "delete", "rm"
|
36
|
+
:delete
|
37
|
+
when "info", "i"
|
38
|
+
:print_info
|
39
|
+
when "help"
|
40
|
+
:print_help
|
41
|
+
when "version"
|
42
|
+
:print_version
|
43
|
+
else
|
44
|
+
handle_non_command(ARGV.first) # could either be a new task or switch to an existing one
|
45
|
+
end
|
46
|
+
|
47
|
+
opts[:task] = case opts[:operation]
|
48
|
+
when :clear, :print_info
|
49
|
+
check_for_second_argument
|
50
|
+
when :delete
|
51
|
+
demand_second_argument
|
52
|
+
when :switch
|
53
|
+
task = lookup_task(ARGV.first)
|
54
|
+
if task && @config.data['context'] == task
|
55
|
+
opts[:operation] = :leave
|
56
|
+
nil
|
57
|
+
elsif task
|
58
|
+
task
|
59
|
+
else
|
60
|
+
raise ArgumentError, E_NO_SUCH_TASK
|
61
|
+
end
|
62
|
+
when :new
|
63
|
+
ARGV.first
|
64
|
+
end
|
65
|
+
|
66
|
+
if opts[:operation] == :new
|
67
|
+
opts = handle_new_task(opts)
|
68
|
+
end
|
69
|
+
|
70
|
+
opts.delete_if { |k, v| v.nil? }
|
71
|
+
return opts
|
72
|
+
end
|
73
|
+
|
74
|
+
private
|
75
|
+
|
76
|
+
# Determine if a non-command argument corresponds to a :switch or a :new task
|
77
|
+
def handle_non_command(argument)
|
78
|
+
if argument.number? || lookup_task(argument) # then we switch to that task index or name
|
79
|
+
:switch
|
80
|
+
else # then we assume it's a new task to be created.
|
81
|
+
:new
|
82
|
+
end
|
83
|
+
end
|
84
|
+
|
85
|
+
# Check for ARGV[1] but don't raise error if it doesn't exist.
|
86
|
+
# But if we find a task name/index, we make sure it is valid.
|
87
|
+
def check_for_second_argument
|
88
|
+
if ARGV[1]
|
89
|
+
task = lookup_task(ARGV[1])
|
90
|
+
if task
|
91
|
+
task
|
92
|
+
else
|
93
|
+
raise ArgumentError, E_NO_SUCH_TASK
|
94
|
+
end
|
95
|
+
end
|
96
|
+
end
|
97
|
+
|
98
|
+
# Checks for second argument, but raises error if it doesn't exist.
|
99
|
+
def demand_second_argument
|
100
|
+
argument = check_for_second_argument
|
101
|
+
if argument
|
102
|
+
argument
|
103
|
+
else
|
104
|
+
raise ArgumentError, E_MUST_SPECIFY_TASK
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Check config data either for a task name or index.
|
109
|
+
def lookup_task(name)
|
110
|
+
@config.lookup_task(name)
|
111
|
+
end
|
112
|
+
|
113
|
+
# Gather remaining options for a new task
|
114
|
+
# Checks for a description (or a mention of EDITOR),
|
115
|
+
# valid days, and a time estimate.
|
116
|
+
def handle_new_task(opts)
|
117
|
+
ARGV[1..-1].each do |arg|
|
118
|
+
if arg =~ /\(.+\)/
|
119
|
+
next if opts[:editor]
|
120
|
+
opts[:description] = arg
|
121
|
+
elsif arg.downcase == EDITOR
|
122
|
+
opts[:editor] = true
|
123
|
+
opts[:description] = ''
|
124
|
+
tempfile = 'dayrb_description.tmp'
|
125
|
+
system("#{EDITOR} #{tempfile}")
|
126
|
+
input = ""
|
127
|
+
begin
|
128
|
+
File.open(tempfile, 'r') do |tempfile|
|
129
|
+
while (line = tempfile.gets)
|
130
|
+
opts[:description] << line.chomp
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
File.delete tempfile
|
135
|
+
rescue => err
|
136
|
+
raise ArgumentError, err
|
137
|
+
end
|
138
|
+
elsif arg.downcase.nan?
|
139
|
+
opts[:days] ||= []
|
140
|
+
key = parse_day_argument(arg)
|
141
|
+
if opts[:days].include? key
|
142
|
+
raise ArgumentError, "You specified a single day (#{key}) more than once."
|
143
|
+
else
|
144
|
+
opts[:days] << key
|
145
|
+
end
|
146
|
+
else
|
147
|
+
if opts[:estimate]
|
148
|
+
raise ArgumentError, 'You specified more than one time estimate.'
|
149
|
+
else
|
150
|
+
opts[:estimate] = arg.to_i * 60# convert to seconds for storage
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
return opts
|
156
|
+
end
|
157
|
+
|
158
|
+
# Check a possible valid-day argument against abbreviation list.
|
159
|
+
def parse_day_argument(day)
|
160
|
+
abbreviations = Abbrev.abbrev(%w{sunday monday tuesday wednesday thursday friday saturday})
|
161
|
+
if abbreviations.has_key? day
|
162
|
+
return abbreviations[day].to_sym
|
163
|
+
else
|
164
|
+
raise ArgumentError, "Couldn't parse which days to enable task."
|
165
|
+
end
|
166
|
+
end
|
167
|
+
end
|
168
|
+
end
|
@@ -0,0 +1,223 @@
|
|
1
|
+
# DayRB Presentation Module
|
2
|
+
#
|
3
|
+
# Handles printouts and error messages.
|
4
|
+
# Also adds colorization as specified in main file.
|
5
|
+
#
|
6
|
+
# MIT License; See LICENSE file; Cameron Carroll 2014
|
7
|
+
|
8
|
+
module Presenter
|
9
|
+
class << self
|
10
|
+
|
11
|
+
# Prints out task list and current context, if applicable.
|
12
|
+
#
|
13
|
+
# @param tasklist [Hash] Hash of task_name => task_object pairs
|
14
|
+
# @param context [String] Name of current task context
|
15
|
+
# @param time [String] Elapsed time since starting current task.
|
16
|
+
def print_list(tasklist, context, time)
|
17
|
+
if tasklist.empty?
|
18
|
+
print_error_empty
|
19
|
+
else
|
20
|
+
print_task_list(tasklist)
|
21
|
+
end
|
22
|
+
if context
|
23
|
+
print_current_context(context, time)
|
24
|
+
end
|
25
|
+
end
|
26
|
+
|
27
|
+
# Prints info for a specific task if provided.
|
28
|
+
# If not, prints out every description for tasks that have one.
|
29
|
+
#
|
30
|
+
# @param tasklist [Hash] Hash of task_name => task_object pairs
|
31
|
+
# @param task [String] Name of specific task to print info for.
|
32
|
+
def print_info(tasklist, task)
|
33
|
+
if task
|
34
|
+
task_object = tasklist[task]
|
35
|
+
if task_object.description
|
36
|
+
print_description task, task_object
|
37
|
+
else
|
38
|
+
puts "There was no description for #{task}."
|
39
|
+
end
|
40
|
+
else
|
41
|
+
tasklist.each do |task_name, task_object|
|
42
|
+
print_description task_name, task_object if task_object.description
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
# Prints out program help string
|
48
|
+
def print_help
|
49
|
+
puts <<-eos
|
50
|
+
Usage: day.rb <command> [<args>]
|
51
|
+
|
52
|
+
Commands:
|
53
|
+
(no command) Prints out task list for the day
|
54
|
+
(nonexisting task) Creates a new task
|
55
|
+
(existing task) Start tracking time for named task.
|
56
|
+
delete (task) Remove a task
|
57
|
+
info Print all descriptions
|
58
|
+
info (task) Print a specific description
|
59
|
+
clear Clear fulfillment for all tasks.
|
60
|
+
clear (task) Clear fulfillment for a specific task.
|
61
|
+
|
62
|
+
Refer to a task either by its name or index.
|
63
|
+
See readme.md for a more detailed overview.
|
64
|
+
eos
|
65
|
+
end
|
66
|
+
|
67
|
+
# Prints out the VERSION constant
|
68
|
+
def print_version
|
69
|
+
puts "Day.rb v#{VERSION}"
|
70
|
+
end
|
71
|
+
|
72
|
+
# Announces task has been deleted and prints its description if applicable.
|
73
|
+
#
|
74
|
+
# @param task [String] Name of task to be deleted
|
75
|
+
# @param description [String] Description of task (optional)
|
76
|
+
def announce_deletion(task, description)
|
77
|
+
puts "Deleted #{task}".color_text
|
78
|
+
puts "Description was: #{description}".color_text if description
|
79
|
+
end
|
80
|
+
|
81
|
+
# Announces that either a task or all tasks have had fulfillment cleared.
|
82
|
+
#
|
83
|
+
# @param task [String] Name of task to be cleared
|
84
|
+
def announce_clear(task)
|
85
|
+
if task
|
86
|
+
puts "Cleared fulfillment for #{task}".color_text
|
87
|
+
else
|
88
|
+
puts "Cleared fulfillment for all tasks".color_text
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
# Announces a switch to a new task...
|
93
|
+
# also prints the amount of time spent on the old one.
|
94
|
+
#
|
95
|
+
# @param task [String] Name of task to switch to
|
96
|
+
# @param old_task [String] Name of current context, before switching
|
97
|
+
# @param old_time [String] Time spent since starting old_task
|
98
|
+
def announce_switch(task, old_task, old_time)
|
99
|
+
puts "Switching to #{task}"
|
100
|
+
if old_task && old_time
|
101
|
+
puts "(Spent #{convert_time_with_suffix old_time} on #{old_task})"
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Announces that we leave current context, prints out time spent.
|
106
|
+
# Used when not starting a new task.
|
107
|
+
#
|
108
|
+
# @param old_task [String] Name of current context
|
109
|
+
# @param old_time [String] Time spent since starting old_task
|
110
|
+
def announce_leave_context(old_task, old_time)
|
111
|
+
puts "Stopping tracking for #{old_task}"
|
112
|
+
puts "(Spent #{convert_time_with_suffix old_time})"
|
113
|
+
end
|
114
|
+
|
115
|
+
# Announces the creation of a new task.
|
116
|
+
#
|
117
|
+
# @param task [String] Name of task to be added
|
118
|
+
def announce_new_task(task)
|
119
|
+
puts "Added new task, #{task}"
|
120
|
+
end
|
121
|
+
|
122
|
+
private
|
123
|
+
|
124
|
+
# Iterate through tasklist, printing index, name, description flag and fulfillment/estimate data.
|
125
|
+
#
|
126
|
+
# @param tasks [Hash] Collection of task_name => task_object pairs
|
127
|
+
def print_task_list(tasks)
|
128
|
+
ii = 0
|
129
|
+
# indexing the hash as an array
|
130
|
+
# task[0] contains key (task name)
|
131
|
+
# task[1] contains task object
|
132
|
+
tasks.each_with_index do |task, ii|
|
133
|
+
task_name = task[0]
|
134
|
+
task_object = task[1]
|
135
|
+
print ii.to_s.color_index + ': ' + task_name.color_task
|
136
|
+
print "*".color_star if task_object.description
|
137
|
+
print_fulfillment(task_object.fulfillment, task_object.time_estimate)
|
138
|
+
puts "\n"
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
# Print/format fulfillment and estimate data.
|
143
|
+
#
|
144
|
+
# @param fulfillment [Integer] Time spent on task in seconds
|
145
|
+
# @param estimate [Integer] Estimated time for task in seconds
|
146
|
+
def print_fulfillment(fulfillment, estimate)
|
147
|
+
if fulfillment
|
148
|
+
if estimate
|
149
|
+
diff = fulfillment.to_f / estimate.to_f * 100
|
150
|
+
print " [#{convert_time(fulfillment)}".color_completion + "/#{convert_time_with_suffix(estimate)}]".color_text
|
151
|
+
print " [#{'%2.1f' % diff}%]".color_completion
|
152
|
+
else
|
153
|
+
print " [#{convert_time_with_suffix(fulfillment)}]"
|
154
|
+
end
|
155
|
+
elsif estimate
|
156
|
+
print " (#{convert_time_with_suffix(estimate)} estimate)"
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
# Print task name and description.
|
161
|
+
#
|
162
|
+
# @param task_name [String] Name of task
|
163
|
+
# @param task_object [Task] Task object to print description for
|
164
|
+
def print_description(task_name, task_object)
|
165
|
+
print "Description for #{task_name}: "
|
166
|
+
puts task_object.description
|
167
|
+
end
|
168
|
+
|
169
|
+
# Print information about the current task.
|
170
|
+
#
|
171
|
+
# @param context [String] Name of current task
|
172
|
+
# @param time [Integer] Time spent on current task in seconds
|
173
|
+
def print_current_context(context, time)
|
174
|
+
puts "Current task: #{context} (#{convert_time_with_suffix(time)})"
|
175
|
+
end
|
176
|
+
|
177
|
+
# Convert seconds into a more appropriate amount.
|
178
|
+
# Hours and days also return the leftover minutes and hours, respectively.
|
179
|
+
#
|
180
|
+
# @param seconds [Integer] Time to be converted in seconds.
|
181
|
+
def convert_time(seconds)
|
182
|
+
if seconds < 60
|
183
|
+
return ('%1.0f' % seconds)
|
184
|
+
elsif seconds >= 60 && seconds < 3600
|
185
|
+
return ('%2.1f' % (seconds/60))
|
186
|
+
elsif seconds >= 3600 && seconds < 86400
|
187
|
+
hours = seconds / 3600
|
188
|
+
leftover_minutes = seconds % 3600 / 60
|
189
|
+
return ('%1.0f' % hours), ('%2.1f' % leftover_minutes)
|
190
|
+
elsif seconds >= 86400
|
191
|
+
days = seconds / 86400
|
192
|
+
leftover_hours = seconds % 86400 / 3600
|
193
|
+
return ('%1.0f' % days), ('%2.1f' % leftover_hours)
|
194
|
+
end
|
195
|
+
end
|
196
|
+
|
197
|
+
# Formats the results of convert_time into a human-readable string.
|
198
|
+
#
|
199
|
+
# @param seconds [Integer] Time to be converted in seconds.
|
200
|
+
def convert_time_with_suffix(seconds)
|
201
|
+
first_result, second_result = convert_time(seconds)
|
202
|
+
if seconds < 60
|
203
|
+
"#{first_result} seconds"
|
204
|
+
elsif seconds >= 60 && seconds < 3600
|
205
|
+
"#{first_result} minutes"
|
206
|
+
elsif seconds >= 3600 && seconds < 86400
|
207
|
+
"#{first_result} hours and #{second_result} minutes"
|
208
|
+
elsif seconds >= 86400
|
209
|
+
"#{first_result} days and #{second_result} hours"
|
210
|
+
end
|
211
|
+
end
|
212
|
+
|
213
|
+
# Print empty-tasklist error.
|
214
|
+
def print_error_empty()
|
215
|
+
puts "The task list is empty!"
|
216
|
+
end
|
217
|
+
|
218
|
+
# Print unknown error.
|
219
|
+
def print_error_unknown()
|
220
|
+
puts "Sorry, that command is not known. Try 'help'."
|
221
|
+
end
|
222
|
+
end
|
223
|
+
end
|
data/lib/day/task.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# DayRB Task Class
|
2
|
+
#
|
3
|
+
# Has essentially only one function, which is to perform valid_today? checks.
|
4
|
+
# But maybe we'll just keep it and give it more responsibility later.
|
5
|
+
#
|
6
|
+
# MIT License; See LICENSE file; Cameron Carroll 2014
|
7
|
+
|
8
|
+
class Task
|
9
|
+
|
10
|
+
attr_reader :name, :valid_days, :description, :time_estimate, :fulfillment
|
11
|
+
|
12
|
+
def initialize(name, description, valid_days, time_estimate, fulfillment)
|
13
|
+
@name = name
|
14
|
+
@valid_days = valid_days
|
15
|
+
@description = description
|
16
|
+
@time_estimate = time_estimate
|
17
|
+
@fulfillment = fulfillment
|
18
|
+
end
|
19
|
+
|
20
|
+
# Determine whether the task is valid today.
|
21
|
+
def valid_today?
|
22
|
+
if @valid_days
|
23
|
+
today = Time.new.wday #0 is sunday, 6 saturday
|
24
|
+
|
25
|
+
weekday_key = case today
|
26
|
+
when 0 then :sunday
|
27
|
+
when 1 then :monday
|
28
|
+
when 2 then :tuesday
|
29
|
+
when 3 then :wednesday
|
30
|
+
when 4 then :thursday
|
31
|
+
when 5 then :friday
|
32
|
+
when 6 then :saturday
|
33
|
+
end
|
34
|
+
|
35
|
+
if (@valid_days.include?(weekday_key) || @valid_days.empty?)
|
36
|
+
return true
|
37
|
+
else
|
38
|
+
return false
|
39
|
+
end
|
40
|
+
else
|
41
|
+
return true # valid everyday
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
data/lib/day/tasklist.rb
ADDED
@@ -0,0 +1,44 @@
|
|
1
|
+
# DayRB Tasklist Module
|
2
|
+
#
|
3
|
+
# MIT License; See LICENSE file; Cameron Carroll 2014
|
4
|
+
|
5
|
+
require_relative 'task'
|
6
|
+
|
7
|
+
# DayRB Tasklist Module
|
8
|
+
#
|
9
|
+
# Responsible for loading tasks.
|
10
|
+
# Mainly to manage a list of tasks which are valid today,
|
11
|
+
# but also allow us to use the '-a' option.
|
12
|
+
class Tasklist
|
13
|
+
attr_reader :all_tasks, :valid_tasks
|
14
|
+
|
15
|
+
def initialize(config)
|
16
|
+
@config = config
|
17
|
+
@all_tasks = load_tasks(config.data['tasks'])
|
18
|
+
today = Time.new.strftime("%A").downcase.to_sym
|
19
|
+
@valid_tasks = @all_tasks.select do |task_name, task_object|
|
20
|
+
if task_object.valid_days
|
21
|
+
task_object.valid_days.include? today
|
22
|
+
else
|
23
|
+
true
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
private
|
29
|
+
|
30
|
+
# Build array of task objects from their DB records.
|
31
|
+
#
|
32
|
+
# @param tasks [Hash] Collection of task_name => task_hash pairs
|
33
|
+
def load_tasks(tasks)
|
34
|
+
task_objects = {}
|
35
|
+
unless tasks.empty?
|
36
|
+
tasks.each do |task_name, task|
|
37
|
+
task_objects[task_name] = Task.new(task_name, task['description'], task['valid_days'],
|
38
|
+
task['estimate'], task['fulfillment'])
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
return task_objects
|
43
|
+
end
|
44
|
+
end
|
data/readme.md
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
day.rb
|
2
|
+
======
|
3
|
+
(Version 2.0.1 -- August 2014)
|
4
|
+
|
5
|
+
A command-line to-do & time-tracking application.
|
6
|
+
|
7
|
+
* Define & describe tasks, and set time estimates for yourself.
|
8
|
+
* Check in or out of tasks to track time spent.
|
9
|
+
|
10
|
+
Requirements:
|
11
|
+
-------------
|
12
|
+
* Ruby (Tested with 2.1.2)
|
13
|
+
|
14
|
+
Installation:
|
15
|
+
-------------
|
16
|
+
|
17
|
+
### Method 1: Download a Release (One File)
|
18
|
+
|
19
|
+
* Head on over to the [Releases Page](https://github.com/sanarothe/day/releases)
|
20
|
+
* Download the latest "one-file distributable" version of day.rb
|
21
|
+
* Stick it in your favorite bin folder. (~/bin)
|
22
|
+
* Chmod it to be executable (chmod +x ~/bin/day.rb)
|
23
|
+
|
24
|
+
### Method 2: Clone the Repository (Entire Folder)
|
25
|
+
|
26
|
+
* Clone the repository to your favorite apps folder. (git clone https://github.com/sanarothe/day.git ~/apps)
|
27
|
+
* Symlink day.rb into your favorite bin folder. (ln -s ~/apps/day/day.rb ~/bin/day)
|
28
|
+
* Chmod it to be executable (chmod +x ~/bin/day)
|
29
|
+
|
30
|
+
Usage Overview:
|
31
|
+
---------------
|
32
|
+
|
33
|
+
Usage: day.rb <command> [<args>]
|
34
|
+
|
35
|
+
Commands:
|
36
|
+
(no command) Prints out task list for the day
|
37
|
+
(nonexisting task) Creates a new task
|
38
|
+
(existing task) Start tracking time for named task
|
39
|
+
delete (task) Remove a task
|
40
|
+
info Print all descriptions
|
41
|
+
info (task) Print a specific description
|
42
|
+
clear Clear fulfillment for all tasks.
|
43
|
+
clear (task) Clear fulfillment for a specific task.
|
44
|
+
|
45
|
+
(From 'day.rb help')
|
46
|
+
|
47
|
+
* Use the '-a' flag (with no command) to print out tasks that aren't enabled for the day
|
48
|
+
* Jump directly from task to task
|
49
|
+
* Stores data by default in ~/.config/day/ -- Edit the constant at top of script to change this.
|
50
|
+
|
51
|
+
Copyright 2014 - Cameron Carroll
|
52
|
+
|
53
|
+
License: MIT
|
@@ -0,0 +1,142 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
require 'fileutils'
|
3
|
+
describe Configuration do
|
4
|
+
|
5
|
+
describe "#initialize" do
|
6
|
+
before :each do
|
7
|
+
bootstrap
|
8
|
+
end
|
9
|
+
|
10
|
+
it "accepts a file path and creates a DB file." do
|
11
|
+
expect(File.exists?(FULL_FILE_PATH)).to be(true)
|
12
|
+
end
|
13
|
+
|
14
|
+
it "bootstraps the DB" do
|
15
|
+
expect(@config.data['tasks'].class).to be(Hash)
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe "#new_task" do
|
20
|
+
before :each do
|
21
|
+
bootstrap
|
22
|
+
end
|
23
|
+
|
24
|
+
it "adds a task to the database" do
|
25
|
+
test_name = 'test_task_name'
|
26
|
+
opts = {:task => test_name, :description => 'some description'}
|
27
|
+
expect(@config.data['tasks'][test_name]).to be(nil)
|
28
|
+
@config.new_task(opts)
|
29
|
+
@config.reload
|
30
|
+
expect(@config.data['tasks'][test_name]).to be_truthy
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
describe "#switch_to" do
|
35
|
+
before :each do
|
36
|
+
bootstrap
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should enter a new context (no current)" do
|
40
|
+
expect(@config.data['context']).to eq(nil)
|
41
|
+
@config.switch_to("test")
|
42
|
+
expect(@config.data['context']).to eq("test")
|
43
|
+
end
|
44
|
+
|
45
|
+
it "should enter a new context (given a current one)" do
|
46
|
+
bootstrap_task("test2")
|
47
|
+
@config.switch_to("test")
|
48
|
+
expect(@config.data['context']).to eq("test")
|
49
|
+
@config.switch_to("test2")
|
50
|
+
expect(@config.data['context']).to eq("test2")
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
describe "#delete" do
|
55
|
+
before :each do
|
56
|
+
bootstrap
|
57
|
+
end
|
58
|
+
|
59
|
+
it "should remove a task from data" do
|
60
|
+
expect(@config.data['tasks']['test']).to be_truthy
|
61
|
+
@config.delete("test")
|
62
|
+
expect(@config.data['tasks']['test']).not_to be_truthy
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
describe "#clear_context" do
|
67
|
+
before :each do
|
68
|
+
bootstrap
|
69
|
+
end
|
70
|
+
|
71
|
+
it "should clear context given a current one" do
|
72
|
+
@config.switch_to("test")
|
73
|
+
expect(@config.data['context']).to eq("test")
|
74
|
+
@config.reload
|
75
|
+
@config.clear_context
|
76
|
+
expect(@config.data['context']).to eq(nil)
|
77
|
+
end
|
78
|
+
|
79
|
+
it "should add time to the fulfillment" do
|
80
|
+
@config.switch_to("test")
|
81
|
+
@config.reload
|
82
|
+
@config.clear_context
|
83
|
+
expect(@config.data['tasks']['test']['fulfillment']).to be_truthy
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
describe "#clear_fulfillment" do
|
88
|
+
before :each do
|
89
|
+
bootstrap
|
90
|
+
end
|
91
|
+
|
92
|
+
it "should clear fulfillment for a specified task" do
|
93
|
+
@config.switch_to("test")
|
94
|
+
@config.reload
|
95
|
+
@config.clear_context
|
96
|
+
@config.reload
|
97
|
+
expect(@config.data['tasks']['test']['fulfillment']).to be_truthy
|
98
|
+
@config.clear_fulfillment("test")
|
99
|
+
@config.reload
|
100
|
+
expect(@config.data['tasks']['test']['fulfillment']).not_to be_truthy
|
101
|
+
end
|
102
|
+
|
103
|
+
it "should clear fulfillment for all tasks otherwise" do
|
104
|
+
@config.switch_to("test")
|
105
|
+
@config.reload
|
106
|
+
@config.clear_context
|
107
|
+
@config.reload
|
108
|
+
expect(@config.data['tasks']['test']['fulfillment']).to be_truthy
|
109
|
+
@config.clear_fulfillment(nil)
|
110
|
+
@config.reload
|
111
|
+
expect(@config.data['tasks']['test']['fulfillment']).not_to be_truthy
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
115
|
+
describe "#lookup_task" do
|
116
|
+
before :each do
|
117
|
+
bootstrap
|
118
|
+
end
|
119
|
+
|
120
|
+
it "should return a task name given a corresponding name" do
|
121
|
+
input = "test"
|
122
|
+
expect(@config.lookup_task(input)).to eq(input)
|
123
|
+
end
|
124
|
+
|
125
|
+
it "should return a task name given a corresponding index" do
|
126
|
+
input = "0"
|
127
|
+
expected = "test"
|
128
|
+
expect(@config.lookup_task(input)).to eq(expected)
|
129
|
+
end
|
130
|
+
|
131
|
+
it "should return nil given a non-task name" do
|
132
|
+
input = "non-task"
|
133
|
+
expect(@config.lookup_task(input)).to eq(nil)
|
134
|
+
end
|
135
|
+
|
136
|
+
it "should return nil given an out-of-bound index" do
|
137
|
+
input = "1"
|
138
|
+
expect(@config.lookup_task(input)).to eq(nil)
|
139
|
+
end
|
140
|
+
end
|
141
|
+
|
142
|
+
end
|