Module: Devlog

Defined in:
lib/devlog.rb,
lib/devlog_settings.rb

Overview

The devlog module with all the mumbo

Defined Under Namespace

Modules: SevendaysTotal Classes: Day, Parsing, Settings, Sevendays, Tajm, Zezzion

Constant Summary collapse

LIBPATH =

:stopdoc:

::File.expand_path(::File.dirname(__FILE__)) + ::File::SEPARATOR
PATH =
::File.dirname(LIBPATH) + ::File::SEPARATOR
VERSION =
File.open(File.join(File.dirname(__FILE__), %w[.. VERSION]), 'r').read
DATETIME_FORMAT =

Parsing datetime

'%d.%m.%Y %H:%M:%S'.freeze
DEVLOG_FILE =

The default is the current folder with devlog.markdown in it.

'devlog.markdown'.freeze

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.display_versionObject



62
63
64
# File 'lib/devlog.rb', line 62

def self.display_version
  "\n#{'Devlog'.green} v#{Devlog.version}\n"
end

.libpath(*args) ⇒ Object

Returns the library path for the module. If any arguments are given, they will be joined to the end of the libray path using File.join.



36
37
38
# File 'lib/devlog.rb', line 36

def self.libpath(*args)
  args.empty? ? LIBPATH : ::File.join(LIBPATH, args.flatten)
end

.log(txt) ⇒ Object

Write simple console log



67
68
69
# File 'lib/devlog.rb', line 67

def self.log(txt)
  puts "#{txt}"
end

.path(*args) ⇒ Object

Returns the lpath for the module. If any arguments are given, they will be joined to the end of the path using File.join.



44
45
46
# File 'lib/devlog.rb', line 44

def self.path(*args)
  args.empty? ? PATH : ::File.join(PATH, args.flatten)
end

.require_all_libs_relative_to(fname, dir = nil) ⇒ Object

Utility method used to require all files ending in .rb that lie in the directory below this file that has the same name as the filename passed in. Optionally, a specific directory name can be passed in such that the filename does not have to be equivalent to the directory.



53
54
55
56
57
58
59
60
# File 'lib/devlog.rb', line 53

def self.require_all_libs_relative_to(fname, dir = nil)
  dir ||= ::File.basename(fname, '.*')
  search_me = ::File.expand_path(
    ::File.join(::File.dirname(fname), dir, '**', '*.rb')
  )

  Dir.glob(search_me).sort.each { |rb| require rb }
end

.versionObject

:startdoc: Returns the version string for the library.



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

def self.version
  VERSION
end

Instance Method Details

#devlog_file_settingObject

Calculate a devlog_file path.



43
44
45
46
47
48
49
50
51
# File 'lib/devlog_settings.rb', line 43

def devlog_file_setting
  return DEVLOG_FILE unless settings
  devlog_file_setting = settings['devlog_file']
  if devlog_file_setting && File.exist?(File.join(Dir.pwd, devlog_file_setting))
    devlog_file_setting
  else
    DEVLOG_FILE
  end
end

#devlog_session_entry(session_type = 'Coding', begin_end = 'BEGIN') ⇒ Object

Helper for the time entries



194
195
196
# File 'lib/devlog.rb', line 194

def devlog_session_entry(session_type = 'Coding', begin_end = 'BEGIN')
  "\n##{Time.now.strftime(DATETIME_FORMAT)} #{session_type}Session::#{begin_end}\n"
end

#devlog_timezone_settingObject



53
54
55
56
57
58
59
60
61
# File 'lib/devlog_settings.rb', line 53

def devlog_timezone_setting
  return 'Amsterdam' unless settings
  devlog_timezone_setting = settings['timezone']
  if devlog_timezone_setting.present?
    devlog_timezone_setting
  else
    'Amsterdam'
  end
end

#export_devlog_now(devlog_file = 'devlog.markdown') ⇒ Object



258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
# File 'lib/devlog.rb', line 258

def export_devlog_now(devlog_file = 'devlog.markdown')
  devlog_export_file = File.join(File.dirname(devlog_file), 'devlog_book.markdown')
  # `sed -n '1!G;h;$p' #{devlog_file} > #{devlog_export_file}` #not what we want! , we want just the sessions upside down, but text intact
  # so need to parse all sessions and print them out in reverse!

  sessionEnd = ''
  sessionMidd = ''
  sessionBegin = ''
  in_session = false

  # The ends are the begins, the begins are the ends

  File.new(devlog_export_file, 'wb')

  File.open(devlog_file, 'r').each do |line|
    if line =~ /-NOCHARGE/
      in_session = false #do not export nocharge sessions
    elsif line =~ /\A#/ && (line =~ /CodingSession::END/ || line =~ /ComSession::END/ )
      in_session = true
      sessionEnd = line
    elsif line =~ /\A#/ && ( line =~ /CodingSession::BEGIN/ || line =~ /ComSession::BEGIN/ )
      if in_session
        in_session = false
        sessionBegin = line
        s = sessionBegin + sessionMidd + sessionEnd
        # system "echo '#{s}' | cat - #{devlog_export_file} > #{devlog_export_file}.tmp && mv #{devlog_export_file}.tmp #{devlog_export_file}"
        prepend_string(devlog_export_file, s)
        sessionEnd = ''
        sessionMidd = ''
        sessionBegin = ''
      end
    else
      sessionMidd << line
    end
  end

  devlog_export_file
end

#is_session_open(devlog_file = 'devlog.markdown') ⇒ Object

If the first non empty line is not and END entry then session is open (or malformed file)



240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
# File 'lib/devlog.rb', line 240

def is_session_open(devlog_file = 'devlog.markdown')
  is_open = true
  File.open(devlog_file, 'r') do |f|
    loop do
      break if not line = f.gets # exit on end of file, read line
      if (line.strip.size>0) # non empty line
        if (line =~ /Session::END/)
          is_open = false
          break
        else
          break
        end
      end
    end
  end
  is_open
end

#load_settings(file) ⇒ Object



26
27
28
29
30
31
32
33
# File 'lib/devlog_settings.rb', line 26

def load_settings(file)
  begin
    yaml = YAML.load_file(file)
  rescue
    yaml = nil
  end
  @settings = yaml ? Settings[yaml] : Settings.new
end

#parse_datetime(line) ⇒ Object



73
74
75
76
77
78
# File 'lib/devlog.rb', line 73

def parse_datetime(line)
  parts = line[1..-1].split
  DateTime.strptime("#{parts[0]} #{parts[1]}", DATETIME_FORMAT)
rescue StandardError
  abort "\nError\nCan not parse line with invalid date:\n\n#{line}".to_s.blue
end

#parse_devlog_now(devlog = nil) ⇒ Object



80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
# File 'lib/devlog.rb', line 80

def parse_devlog_now(devlog = nil)
  t = Parsing.new
  t.devlog_file = devlog

  return t unless devlog
  return t unless File.exist?(devlog)

  timeEnd = nil
  timeBegin = nil
  timeEnd_line_number = nil
  timeBegin_line_number = nil
  in_session = false
  temp_zezzion = nil

  line_number = 0
  File.open(devlog, 'r').each do |line|
    line_number += 1

    if line =~ /-NOCHARGE/
      in_session = false # do not count nocharge sessions, this is a secret feature
    elsif line =~ /\A#/ && line =~ /CodingSession::END/
      in_session = true
      timeEnd = parse_datetime(line)
      timeEnd_line_number = line_number

      # zezzion
      temp_zezzion = Zezzion.new
      temp_zezzion.zzend = timeEnd
      temp_zezzion.zzend_line_number = timeEnd_line_number

    elsif line =~ /\A#/ && line =~ /CodingSession::BEGIN/
      if in_session
        in_session = false
        timeBegin = parse_datetime(line)
        timeBegin_line_number = line_number

        # cs_time += (timeEnd - timeBegin).to_f * 24 #hours *60 #minutes *60 #seconds
        delta = (timeEnd - timeBegin).to_f * 24 #hours *60 #minutes *60 #seconds
        t.coding_session_time += delta

        # zezzion
        temp_zezzion.coding_session_time += delta
        temp_zezzion.zzbegin = timeBegin
        temp_zezzion.zzbegin_line_number = timeBegin_line_number
        t.add_zezzion temp_zezzion
        temp_zezzion = nil

      end
    elsif line =~ /\A#/ && line =~ /ComSession::END/
      in_session = true
      timeEnd = parse_datetime(line)
      timeEnd_line_number = line_number

      # zezzion
      temp_zezzion = Zezzion.new(Zezzion::COM)
      temp_zezzion.zzend = timeEnd
      temp_zezzion.zzend_line_number = timeEnd_line_number

    elsif line =~ /\A#/ && line =~ /ComSession::BEGIN/
      if in_session
        in_session = false
        timeBegin = parse_datetime(line)
        timeBegin_line_number = line_number

        delta = (timeEnd - timeBegin).to_f * 24
        t.com_session_time += delta

        # zezzion
        temp_zezzion.coding_session_time += delta
        temp_zezzion.zzbegin = timeBegin
        temp_zezzion.zzbegin_line_number = timeBegin_line_number
        t.add_zezzion temp_zezzion
        temp_zezzion = nil

      end
    elsif line =~ /\A\+[0-9]+[h]/
      delta = line.to_f
      t.com_session_time += delta

      # zezzion
      if temp_zezzion
        temp_zezzion.com_session_time += delta
      else
        puts "error adding temp_zezzion com_session_time at line: #{line}"
      end
    elsif line =~ /\A\+[0-9]+[m]/
      delta = (line.to_f / 60)
      t.com_session_time += delta

      # zezzion
      if temp_zezzion
        temp_zezzion.com_session_time += delta
      else
        puts "error adding temp_zezzion com_session_time at line: #{line}"
      end
    elsif line =~ /\A\-[0-9]+[h]/
      delta = (line.to_f)
      t.payed_time += delta

      # zezzion
      if temp_zezzion
        temp_zezzion.payed_time += delta
      else
        puts "error adding temp_zezzion delta time at line: #{line}"
      end
    end
  end
  # return the Parsing object
  t
end

#prepend_string(path, string = "\n") ⇒ Object



204
205
206
207
208
209
210
211
212
213
# File 'lib/devlog.rb', line 204

def prepend_string(path, string = "\n")
  Tempfile.open File.basename(path) do |tempfile|
    tempfile << string
    File.open(path, 'r+') do |file|
      tempfile << file.read
      file.pos = tempfile.pos = 0
      file << tempfile.read
    end
  end
end

#save_info(devlog_file = 'devlog.markdown', info_file = 'info.markdown') ⇒ Object



226
227
228
229
230
231
232
233
# File 'lib/devlog.rb', line 226

def save_info(devlog_file = 'devlog.markdown', info_file = 'info.markdown')
  info = parse_devlog_now(devlog_file)
  if info.has_info?
    File.open(File.join(File.dirname(devlog_file), info_file), 'w') {|f| f.write(info.to_info_string(true)) }
  else
    puts "No info present.".red
  end
end

#save_to_readme(devlog_file = 'devlog.markdown') ⇒ Object



235
236
237
# File 'lib/devlog.rb', line 235

def save_to_readme(devlog_file = 'devlog.markdown')
  `cp #{devlog_file} #{File.join(File.dirname(devlog_file), 'README.markdown')}`
end

#settingsObject



35
36
37
# File 'lib/devlog_settings.rb', line 35

def settings
  @settings ||= Settings.new
end

#start_coding_session(devlog_file = 'devlog.markdown') ⇒ Object

insert a new session



216
217
218
# File 'lib/devlog.rb', line 216

def start_coding_session(devlog_file = 'devlog.markdown')
  prepend_string(devlog_file, devlog_session_entry('Coding', 'BEGIN'))
end

#stop_coding_session(devlog_file = 'devlog.markdown') ⇒ Object

close the current session, if any



221
222
223
224
# File 'lib/devlog.rb', line 221

def stop_coding_session(devlog_file = 'devlog.markdown')
  prepend_string(devlog_file, devlog_session_entry('Coding', 'END'))
  save_info(devlog_file)
end

#weekly_pdf(tajm, weeks_from_now = 0, devlog_file = 'devlog.markdown') ⇒ Object



297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/devlog.rb', line 297

def weekly_pdf(tajm, weeks_from_now = 0, devlog_file = 'devlog.markdown')
  require 'erb'
  devlog_file = settings.devlog_file_setting || devlog_file
  template = settings.has?(:weekly_timesheet_template) ? settings.weekly_timesheet_template : File.join(Devlog.path, 'templates', 'weekly_timesheet.erb.html')
  convert_command = settings.has?(:convert_to_pdf_command) ? settings.convert_to_pdf_command : 'wkhtmltopdf'
  puts "Using weekly template: #{template} #{settings.has?(:weekly_timesheet_template)}".green

  zezzions = tajm.zezzions_for_week(weeks_from_now, DateTime.current)

  if zezzions.any?
    file_id = zezzions.last.zzbegin.strftime("%Y-%m-%d")
    pdf = File.join(File.dirname(devlog_file), "sevendays-#{file_id}.pdf")
    html = File.join(File.dirname(devlog_file), "sevendays-#{file_id}.html")
    @sevendays = Sevendays.new(zezzions)

    renderer = ERB.new(File.read(template))

    File.open(html,'w') {|f| f.write(renderer.result()) }

    `#{convert_command} #{html} #{pdf}`
  else
    'No sessions to render.'.red
  end
end