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.



20
21
22
# File 'lib/storage.rb', line 20

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



30
31
32
33
34
35
36
37
38
39
40
41
# File 'lib/storage.rb', line 30

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.



173
174
175
176
177
178
# File 'lib/storage.rb', line 173

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.



96
97
98
# File 'lib/storage.rb', line 96

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:



68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
# File 'lib/storage.rb', line 68

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



183
184
185
# File 'lib/storage.rb', line 183

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

#folder_exists?Boolean

Returns:

  • (Boolean)


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

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

#load_log(file) ⇒ Object



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

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

#load_log!(file) ⇒ Object



107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
# File 'lib/storage.rb', line 107

def load_log!(file)
  WorkLogger.debug "Loading file #{file}"
  begin
    yaml_content = File.read(file)
    cleaned_yaml = yaml_content.gsub(%r{!ruby/object:[^\s]+}, '')
    log = DailyLog.from_hash(YAML.safe_load(cleaned_yaml, permitted_classes: [Date, Time], symbolize_names: true))

    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



141
142
143
144
145
146
# File 'lib/storage.rb', line 141

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



156
157
158
159
160
161
# File 'lib/storage.rb', line 156

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



150
151
152
# File 'lib/storage.rb', line 150

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



132
133
134
135
136
# File 'lib/storage.rb', line 132

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



45
46
47
48
49
50
51
52
53
54
55
56
57
58
# File 'lib/storage.rb', line 45

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



123
124
125
126
127
128
129
# File 'lib/storage.rb', line 123

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



165
166
167
168
169
170
# File 'lib/storage.rb', line 165

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