ptf 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -7,58 +7,54 @@ module Ptf
7
7
  class << self
8
8
 
9
9
  def show(id)
10
- if !Ptf::Utilities::FileSystem.id_exist?(id.to_i)
11
- puts "Task #{id} does not exist."
12
- return
10
+ if !Ptf::FileSystem.id_exist?(id.to_i)
11
+ return "Task #{id} does not exist."
13
12
  end
14
13
 
15
- metadata_file = Ptf::Utilities::FileSystem.find_file id.to_i
14
+ metadata_file = Ptf::FileSystem.find_file id.to_i
16
15
 
17
16
  if metadata_file.nil?
18
- puts "Task #{id} has been closed. Reopen it with ptf task reopen ###."
19
- return
17
+ return "Task #{id} has been closed. Reopen it with ptf task reopen ###."
20
18
  end
21
19
 
22
- info = Ptf::Data::MetadataFile.new(metadata_file)
20
+ info = Ptf::MetadataFile.create_from_file(metadata_file)
23
21
 
24
- data_file = File.join(Ptf::Utilities::FileSystem.data_dir, info.hash)
25
- puts `cat #{data_file}`
22
+ data_file = File.join(Ptf::FileSystem.data_dir, info.hash)
23
+ return File.read data_file
26
24
  end
27
25
 
28
26
  def close(id)
29
- if !Ptf::Utilities::FileSystem.id_exist?(id.to_i)
30
- puts "Task #{id} does not exist."
31
- return
27
+ if !Ptf::FileSystem.id_exist?(id.to_i)
28
+ return "Task #{id} does not exist."
32
29
  end
33
30
 
34
- metadata_file = Ptf::Utilities::FileSystem.find_file id.to_i
31
+ metadata_file = Ptf::FileSystem.find_file id.to_i
35
32
 
36
33
  if metadata_file.nil?
37
- puts "Task #{id} has been closed. Reopen it with ptf task reopen ###."
38
- return
34
+ return "Task #{id} has been closed. Reopen it with ptf task reopen ###."
39
35
  end
40
36
 
41
- info = Ptf::Data::MetadataFile.create_from_file(metadata_file)
37
+ info = Ptf::MetadataFile.create_from_file(metadata_file)
42
38
 
43
39
  info.complete_now
40
+ return "Task #{info.id} is closed."
44
41
  end
45
42
 
46
43
  def reopen(id)
47
- if !Ptf::Utilities::FileSystem.id_exist?(id.to_i)
48
- puts "Task #{id} does not exist."
49
- return
44
+ if !Ptf::FileSystem.id_exist?(id.to_i)
45
+ return "Task #{id} does not exist."
50
46
  end
51
47
 
52
- metadata_file = Ptf::Utilities::FileSystem.find_file id.to_i, false
48
+ metadata_file = Ptf::FileSystem.find_file id.to_i, false
53
49
 
54
50
  if metadata_file.nil?
55
- puts "Task #{id} is already open. Close it with ptf task close ###."
56
- return
51
+ return "Task #{id} is already open. Close it with ptf task close ###."
57
52
  end
58
53
 
59
- info = Ptf::Data::MetadataFile.create_from_file(metadata_file)
54
+ info = Ptf::MetadataFile.create_from_file(metadata_file)
60
55
 
61
56
  info.reopen
57
+ return "Task #{info.id} is reopened."
62
58
  end
63
59
 
64
60
  end
@@ -11,7 +11,7 @@ module Ptf
11
11
  end
12
12
 
13
13
  def new_id_number
14
- id_file_path = Ptf::Utilities::FileSystem.id_counter_file
14
+ id_file_path = Ptf::FileSystem.id_counter_file
15
15
  next_id = File.read(id_file_path).to_i
16
16
 
17
17
  id_file = File.new(id_file_path, "w")
@@ -29,38 +29,38 @@ module Ptf
29
29
 
30
30
  # Select a group for the task
31
31
  if group.nil?
32
- group = Ptf::Data::Group.default_group
32
+ group = Ptf::Group.default_group
33
33
  else
34
- if Ptf::Data::Group.group_exist? group
35
- group = Ptf::Data::Group.get_group group
34
+ if Ptf::Group.group_exist? group
35
+ group = Ptf::Group.get_group group
36
36
  else
37
- puts "Group #{p} does not exist. Create it with ptf group add GROUP ABBREVIATION"
38
- return
37
+ return "Group #{p} does not exist. Create it with ptf group add GROUP ABBREVIATION"
39
38
  end
40
39
  end
41
40
 
42
41
  # Verify the due date
43
42
  if !due_date.nil?
44
- due_date = Ptf::Utilities::Date.create_datetime_from_str(due_date)
43
+ due_date = Ptf::Date.create_datetime_from_str(due_date)
45
44
  if due_date.nil?
46
- puts "Improperly formatted due date '#{d}' given."
47
- return
45
+ return "Improperly formatted due date '#{d}' given."
48
46
  end
49
47
  end
50
48
 
51
49
  id = new_id_number
52
50
 
53
- info_file = Ptf::Data::MetadataFile.create_from_input(title, group, due_date, estimate, id)
51
+ info_file = Ptf::MetadataFile.create_from_input(title, group, due_date, estimate, id)
54
52
 
55
53
  task_info_hash = generate_hash info_file.file_string
56
54
 
57
55
  # Append hash to the file
58
56
  info_file.add_content(:hash, task_info_hash)
59
57
 
60
- data_file = Ptf::Data::DataFile.new(info_file)
58
+ data_file = Ptf::DataFile.new(info_file)
61
59
 
62
60
  info_file.write_to_file
63
61
  data_file.write_to_file
62
+
63
+ return "Task #{info_file.id} created successfully."
64
64
  end
65
65
 
66
66
  end
@@ -4,47 +4,131 @@ module Ptf
4
4
  module Edit
5
5
  class << self
6
6
 
7
- def verify_file(file)
8
- puts "File verification not implemented"
9
- true
7
+ def verify_file(file, metadata)
8
+ title_line, due_date_line, estimate_line = File.foreach(file).first(3)
9
+
10
+ did_succeed, updated_metadata = verify_title_line title_line, metadata
11
+ return false unless did_succeed
12
+
13
+ did_succeed, updated_metadata = verify_due due_date_line, updated_metadata
14
+ return false unless did_succeed
15
+
16
+ did_succeed, updated_metadata = verify_estimate estimate_line, updated_metadata
17
+ return false unless did_succeed
18
+
19
+ updated_metadata.write_to_file
20
+ did_succeed
21
+ end
22
+
23
+ def verify_title_line(line, metadata)
24
+ title_line_regex = /^#([A-Z]+)--(\d+)\s([ a-zA-Z0-9]+)$/
25
+
26
+ _, group, id, title = title_line_regex.match(line).to_a
27
+
28
+ is_title_valid, updated_metadata = verify_title title, metadata
29
+ [(verify_group group, metadata) && (verify_id id, metadata) && is_title_valid, updated_metadata]
30
+ end
31
+
32
+ def verify_group(str, metadata)
33
+ return false unless !str.nil? && str.is_a?(String)
34
+
35
+ Ptf::Group.group_exist?(str) && metadata.group.abbreviation == str
36
+ end
37
+
38
+ def verify_id(str, metadata)
39
+ return false unless !str.nil? && str.is_a?(String)
40
+
41
+ str.to_i == metadata.id
42
+ end
43
+
44
+ def verify_title(str, metadata)
45
+ return false unless !str.nil? && str.is_a?(String)
46
+
47
+ if str != metadata.title
48
+ metadata.set_title str
49
+ end
50
+
51
+ [true, metadata]
52
+ end
53
+
54
+ def verify_due(line, metadata)
55
+ due_line_regex = /^#Due: ?(\d\d\d\d[01]\d[0-3]\d[0-2]\d[0-5]\d[0-5]\d)?$/
56
+
57
+ base, date = due_line_regex.match(line).to_a
58
+
59
+ if !base.nil? && date.nil?
60
+ metadata.set_due_date nil
61
+ return [true, metadata]
62
+ end
63
+
64
+ begin
65
+ datetime = Ptf::Date.str_to_datetime date
66
+ rescue
67
+ return [false, metadata]
68
+ end
69
+
70
+ metadata.set_due_date datetime
71
+ [!datetime.nil?, metadata]
72
+ end
73
+
74
+ def verify_estimate(line, metadata)
75
+ estimate_line_regex = /^#Estimate: ?(\d+)?$/
76
+
77
+ base, estimate = estimate_line_regex.match(line).to_a
78
+
79
+ if !base.nil? && estimate.nil?
80
+ metadata.set_estimate nil
81
+ return [true, metadata]
82
+ elsif base.nil?
83
+ return [false, metadata]
84
+ end
85
+
86
+ estimate = estimate.to_i
87
+ if estimate != 0
88
+ metadata.set_estimate estimate
89
+ return [true, metadata]
90
+ else
91
+ return [false, metadata]
92
+ end
10
93
  end
11
94
 
12
95
  def edit(id)
13
- unless Ptf::Utilities::FileSystem.id_exist? (id)
14
- puts "The task #{id} does not exist"
15
- return
96
+ unless Ptf::FileSystem.id_exist? (id)
97
+ return "The task #{id} does not exist"
16
98
  end
17
99
 
18
- metadata_file = Ptf::Utilities::FileSystem.find_file id
100
+ metadata_file = Ptf::FileSystem.find_file id
19
101
 
20
102
  if metadata_file.nil?
21
- puts "The task #{id} has been closed. Reopen it with ptf task reopen ###."
22
- return
103
+ return "The task #{id} has been closed. Reopen it with ptf task reopen ###."
23
104
  end
24
105
 
25
106
  # Get hash from file
26
- data_file_name = Ptf::Data::MetadataFile.create_from_file(metadata_file).hash
27
- data_file = File.join(Ptf::Utilities::FileSystem.data_dir, data_file_name)
107
+ metadata = Ptf::MetadataFile.create_from_file(metadata_file)
108
+ data_file_name = metadata.hash
109
+ data_file = File.join(Ptf::FileSystem.data_dir, data_file_name)
28
110
 
29
111
  # Create a copy in tmp foldere
30
- tmp_file_path = File.join(Ptf::Utilities::FileSystem.tmp_dir, data_file_name)
112
+ tmp_file_path = File.join(Ptf::FileSystem.tmp_dir, data_file_name)
31
113
  FileUtils.copy data_file, tmp_file_path
32
114
  edit_succeeded = system("vim #{data_file}")
33
115
 
34
116
  if !edit_succeeded
35
117
  # Move tmp file back, then remove it
36
- puts "Vim edit failed. Aborting changes."
37
- return
118
+
119
+ FileUtils.copy tmp_file_path, data_file
120
+ FileUtils.remove_file tmp_file_path
121
+ return "Vim edit failed. Aborting changes."
38
122
  end
39
123
 
40
- if verify_file(data_file)
41
- puts "Edit successful!"
124
+ if verify_file(data_file, metadata)
125
+ FileUtils.remove_file tmp_file_path
126
+ return "Edit successful!"
42
127
  else
43
- puts "File verification failed. Aborting changes."
128
+ FileUtils.copy tmp_file_path, data_file
129
+ FileUtils.remove_file tmp_file_path
130
+ return "File verification failed. Aborting changes."
44
131
  end
45
-
46
- # remove tmp file
47
- FileUtils.remove_file tmp_file_path
48
132
  end
49
133
 
50
134
  end
@@ -0,0 +1,40 @@
1
+ module Ptf
2
+ class DataFile
3
+
4
+ DIR_PATH = Ptf::FileSystem.data_dir
5
+
6
+ # Initialize a new DataFile.
7
+ #
8
+ # @param metadata_file [Ptf::MetadataFile] the associated metadata file.
9
+ #
10
+ # @raise [ArgumntError] if a MetadataFile is not given.
11
+ def initialize(metadata_file)
12
+ raise ArgumentError, "Metadata file not given." unless metadata_file.is_a? Ptf::MetadataFile
13
+
14
+ @metadata_file = metadata_file
15
+ end
16
+
17
+ # Returns the full path to the data file.
18
+ #
19
+ # @return [String] the full path to the data file.
20
+ def data_file_path
21
+ File.join(DIR_PATH, @metadata_file.hash)
22
+ end
23
+
24
+ # Returns the header string for the file.
25
+ #
26
+ # @return [String] the header string for the data file.
27
+ def header_string
28
+ "##{@metadata_file.group.abbreviation}--#{@metadata_file.id} #{@metadata_file.title}\n#Due: #{@metadata_file.due_date_str}\n#Estimate: #{@metadata_file.estimate}\n\n\n"
29
+ end
30
+
31
+ # Write the header string to the data file. Overwrites any data file for the same task.
32
+ def write_to_file
33
+ File.open(data_file_path, "w") do |f|
34
+ f.write header_string
35
+ end
36
+ end
37
+
38
+ end
39
+ end
40
+
@@ -0,0 +1,61 @@
1
+ module Ptf
2
+ module Date
3
+ class << self
4
+
5
+ def datetime_to_str(datetime)
6
+ raise ArgumentError, "DateTime expected. Received #{datetime.class} instead." unless datetime.is_a? DateTime
7
+
8
+ datetime.strftime('%Y%m%d%H%M%S')
9
+ end
10
+
11
+ def create_datetime_from_str(str)
12
+
13
+ begin
14
+ dt = str_to_datetime(str)
15
+ return dt
16
+ rescue
17
+ end
18
+
19
+ time_regex = /([0-2]?\d):([0-5]\d):?([0-5]\d)?/
20
+ # Check if given time 12:21(:21)
21
+ match = time_regex.match(str).to_a
22
+
23
+ if !match.nil? && (match.length == 3 || match.length == 4)
24
+ now = DateTime.now
25
+ return DateTime.new(now.year, now.month, now.day, match[1].to_i, match[2].to_i, 0, now.zone)
26
+ end
27
+
28
+ # Check if given date 12/27(/[15|2015])
29
+ date_regex = /^([01]?\d)\/([0-3]?\d)\/?(\d\d\d\d|\d\d)?$/
30
+ match = date_regex.match(str)
31
+
32
+ if !match.nil? && (match.length == 3 || match.length == 4)
33
+ now = DateTime.now
34
+
35
+ if !match[3].nil? && match[3].length == 2
36
+ year = 2000 + match[3].to_i
37
+ elsif !match[3].nil?
38
+ year = match[3].to_i
39
+ end
40
+
41
+ return DateTime.new((match[3].nil? ? now.year : year), match[1].to_i, match[2].to_i, 12, 0, 0, now.zone)
42
+ end
43
+
44
+ nil
45
+ end
46
+
47
+ def str_to_datetime(str)
48
+ date_regex = /^(\d\d\d\d)([01]\d)([0-3]\d)([0-2]\d)([0-5]\d)([0-5]\d)?$/
49
+
50
+ regex_match = date_regex.match(str)
51
+
52
+ raise ArgumentError, "Improperly formatted datetime string, #{str}." unless regex_match.to_a.length == 7
53
+
54
+ _, year, month, day, hour, minute, second = regex_match.to_a
55
+
56
+ DateTime.new(year.to_i, month.to_i, day.to_i, hour.to_i, minute.to_i, second.to_i)
57
+ end
58
+
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,81 @@
1
+ module Ptf
2
+ module FileSystem
3
+ class << self
4
+
5
+ def file_exist?(filepath)
6
+ File.file?(filepath)
7
+ end
8
+
9
+ def config
10
+ @config = Ptf::Config.get_config if @config.nil?
11
+
12
+ @config
13
+ end
14
+
15
+ def file_permission
16
+ @config[:file_permission]
17
+ end
18
+
19
+ def base_dir
20
+ config[:base_dir]
21
+ end
22
+
23
+ def id_counter_file
24
+ File.join(base_dir, config[:task_counter_file])
25
+ end
26
+
27
+ def id_counter_starting_content
28
+ config[:id_counter_start]
29
+ end
30
+
31
+ def group_list_file
32
+ File.join(base_dir, config[:group_list_file])
33
+ end
34
+
35
+ def metadata_dir
36
+ File.join(base_dir, config[:task_metadata_dir])
37
+ end
38
+
39
+ def metadata_open_dir
40
+ File.join(metadata_dir, config[:in_progress_dir])
41
+ end
42
+
43
+ def metadata_closed_dir
44
+ File.join(metadata_dir, config[:completed_dir])
45
+ end
46
+
47
+ def data_dir
48
+ File.join(base_dir, config[:task_data_dir])
49
+ end
50
+
51
+ def tmp_dir
52
+ File.join(base_dir, config[:tmp_dir])
53
+ end
54
+
55
+ def id_exist?(id)
56
+ next_id = File.read(id_counter_file).to_i
57
+
58
+ (id < next_id && id > 0)
59
+ end
60
+
61
+ def find_file(id, open = true)
62
+ raise ArgumentError, "No task with id #{id} exists." unless id_exist?(id)
63
+
64
+ search_dir = (open ? metadata_open_dir : metadata_closed_dir)
65
+ groups = Ptf::Group.all_groups
66
+
67
+ groups.each do |g|
68
+ dir = File.join(search_dir, g.name)
69
+ possible_id_file = File.join(dir, id.to_s)
70
+
71
+ if file_exist?(possible_id_file)
72
+ return possible_id_file
73
+ end
74
+ end
75
+
76
+ nil
77
+ end
78
+
79
+ end
80
+ end
81
+ end