Class: Worklog::Storage

Inherits:
Object
  • Object
show all
Defined in:
lib/storage.rb

Overview

Handles storage of daily logs and people

Defined Under Namespace

Classes: LogNotFoundError

Constant Summary collapse

FILE_SUFFIX =
'.yaml'
LOG_PATTERN =

Regular expression to match daily log file names

/\d{4}-\d{2}-\d{2}#{FILE_SUFFIX}\z/

Instance Method Summary collapse

Constructor Details

#initialize(config) ⇒ Storage

Returns a new instance of Storage.



24
25
26
# File 'lib/storage.rb', line 24

def initialize(config)
  @config = config
end

Instance Method Details

#all_daysArray<DailyLog>

Return all logs for all available days

Returns:

  • (Array<DailyLog>)

    List of all logs



34
35
36
37
38
39
40
41
42
43
44
45
# File 'lib/storage.rb', line 34

def all_days
  return [] unless folder_exists?

  logs = []
  Dir.glob(File.join(@config.storage_path, "*#{FILE_SUFFIX}")).map do |file|
    next unless file.match?(LOG_PATTERN)

    logs << load_log(file)
  end

  logs
end

#create_default_folderObject

Create folder if not exists already.



177
178
179
180
181
182
# File 'lib/storage.rb', line 177

def create_default_folder
  # Do nothing if the storage path is not the default path
  return unless @config.default_storage_path?

  Dir.mkdir(@config.storage_path) unless Dir.exist?(@config.storage_path)
end

#create_file_skeleton(date) ⇒ Object

Create file for a new day if it does not exist

Parameters:

  • date (Date)

    The date, used as the file name.



100
101
102
# File 'lib/storage.rb', line 100

def create_file_skeleton(date)
  File.write(filepath(date), YAML.dump(DailyLog.new(date:, entries: []))) unless File.exist?(filepath(date))
end

#days_between(start_date, end_date = nil, epics_only = nil, tags_filter = nil) ⇒ Array<DailyLog>

Return days between start_date and end_date If end_date is nil, return logs from start_date to today

Parameters:

  • start_date (Date)

    The start date, inclusive

  • end_date (Date) (defaults to: nil)

    The end date, inclusive

  • epics_only (Boolean) (defaults to: nil)

    If true, only return logs with epic entries

  • tags_filter (Array<String>) (defaults to: nil)

    If provided, only return logs with entries that have at least one of the tags

Returns:



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
# File 'lib/storage.rb', line 72

def days_between(start_date, end_date = nil, epics_only = nil, tags_filter = nil)
  return [] unless folder_exists?

  logs = []
  end_date = Date.today if end_date.nil?

  return [] if start_date > end_date

  while start_date <= end_date
    if File.exist?(filepath(start_date))
      tmp_logs = load_log!(filepath(start_date))
      tmp_logs.entries.keep_if { |entry| entry.epic? } if epics_only

      if tags_filter
        # Safeguard against entries without any tags, not just empty array
        tmp_logs.entries.keep_if { |entry| entry.tags && (entry.tags & tags_filter).size > 0 }
      end

      logs << tmp_logs if tmp_logs.entries.length > 0
    end

    start_date += 1
  end
  logs
end

#filepath(date) ⇒ String

Construct filepath for a given date.

Parameters:

  • date (Date)

    The date

Returns:

  • (String)

    The filepath



187
188
189
# File 'lib/storage.rb', line 187

def filepath(date)
  File.join(@config.storage_path, "#{date}#{FILE_SUFFIX}")
end

#folder_exists?Boolean

Returns:

  • (Boolean)


28
29
30
# File 'lib/storage.rb', line 28

def folder_exists?
  Dir.exist?(@config.storage_path)
end

#load_log(file) ⇒ Object



104
105
106
107
108
109
# File 'lib/storage.rb', line 104

def load_log(file)
  load_log!(file)
rescue LogNotFoundError
  WorkLogger.error "No work log found for #{file}. Aborting."
  nil
end

#load_log!(file) ⇒ Object



111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
# File 'lib/storage.rb', line 111

def load_log!(file)
  WorkLogger.debug "Loading file #{file}"

  # Alias DailyLog to Worklog::DailyLog

  begin
    log = YAML.load_file(file, permitted_classes: [Date, Time, DailyLog, LogEntry])
    log.entries.each do |entry|
      entry.time = Time.parse(entry.time) unless entry.time.respond_to?(:strftime)
    end
    log
  rescue Errno::ENOENT
    raise LogNotFoundError
  end
end

#load_peopleArray<Person>

Load all people from the people file, or return an empty array if the file does not exist

Returns:

  • (Array<Person>)

    List of people



145
146
147
148
149
150
# File 'lib/storage.rb', line 145

def load_people
  load_people!
rescue Errno::ENOENT
  WorkLogger.info 'Unable to load people.'
  []
end

#load_people!Array<Person>

Load all people from the people file

Returns:

  • (Array<Person>)

    List of people



160
161
162
163
164
165
# File 'lib/storage.rb', line 160

def load_people!
  people_file = File.join(@config.storage_path, 'people.yaml')
  return [] unless File.exist?(people_file)

  YAML.load_file(people_file, permitted_classes: [Person])
end

#load_people_hashHash<String, Person>

Load all people from the people file and return them as a hash with handle as key

Returns:

  • (Hash<String, Person>)

    Hash of people with handle as key



154
155
156
# File 'lib/storage.rb', line 154

def load_people_hash
  load_people.to_h { |person| [person.handle, person] }
end

#load_single_log_file(file, headline = true) ⇒ Object

Load a single log file and return its entries



136
137
138
139
140
# File 'lib/storage.rb', line 136

def load_single_log_file(file, headline = true)
  daily_log = load_log!(file)
  puts "Work log for #{Rainbow(daily_log.date).gold}:" if headline
  daily_log.entries
end

#tagsSet<String>

Return all tags as a set

Returns:

  • (Set<String>)

    Set of all tags



49
50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/storage.rb', line 49

def tags
  logs = all_days
  tags = Set[]
  logs.each do |log|
    log.entries.each do |entry|
      next unless entry.tags

      entry.tags.each do |tag|
        tags << tag
      end
    end
  end
  tags
end

#write_log(file, daily_log) ⇒ Object



127
128
129
130
131
132
133
# File 'lib/storage.rb', line 127

def write_log(file, daily_log)
  WorkLogger.debug "Writing to file #{file}"

  File.open(file, 'w') do |f|
    f.puts daily_log.to_yaml
  end
end

#write_people!(people) ⇒ Object

Write people to the people file

Parameters:

  • people (Array<Person>)

    List of people



169
170
171
172
173
174
# File 'lib/storage.rb', line 169

def write_people!(people)
  people_file = File.join(@config.storage_path, 'people.yaml')
  File.open(people_file, 'w') do |f|
    f.puts people.to_yaml
  end
end