doing 2.1.14 → 2.1.18

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.
Files changed (91) hide show
  1. checksums.yaml +4 -4
  2. data/.irbrc +1 -0
  3. data/.yardoc/checksums +14 -12
  4. data/.yardoc/object_types +0 -0
  5. data/.yardoc/objects/root.dat +0 -0
  6. data/CHANGELOG.md +66 -0
  7. data/Gemfile.lock +3 -2
  8. data/README.md +56 -19
  9. data/bin/doing +134 -47
  10. data/docs/doc/Array.html +117 -3
  11. data/docs/doc/BooleanTermParser/Clause.html +1 -1
  12. data/docs/doc/BooleanTermParser/Operator.html +1 -1
  13. data/docs/doc/BooleanTermParser/Query.html +1 -1
  14. data/docs/doc/BooleanTermParser/QueryParser.html +1 -1
  15. data/docs/doc/BooleanTermParser/QueryTransformer.html +1 -1
  16. data/docs/doc/BooleanTermParser.html +1 -1
  17. data/docs/doc/Doing/Color.html +6 -2
  18. data/docs/doc/Doing/Completion.html +1 -1
  19. data/docs/doc/Doing/Configuration.html +8 -4
  20. data/docs/doc/Doing/Errors/DoingNoTraceError.html +1 -1
  21. data/docs/doc/Doing/Errors/DoingRuntimeError.html +1 -1
  22. data/docs/doc/Doing/Errors/DoingStandardError.html +1 -1
  23. data/docs/doc/Doing/Errors/EmptyInput.html +1 -1
  24. data/docs/doc/Doing/Errors/NoResults.html +1 -1
  25. data/docs/doc/Doing/Errors/PluginException.html +1 -1
  26. data/docs/doc/Doing/Errors/UserCancelled.html +1 -1
  27. data/docs/doc/Doing/Errors/WrongCommand.html +1 -1
  28. data/docs/doc/Doing/Errors.html +1 -1
  29. data/docs/doc/Doing/Hooks.html +1 -1
  30. data/docs/doc/Doing/Item.html +224 -2
  31. data/docs/doc/Doing/Items.html +2 -2
  32. data/docs/doc/Doing/LogAdapter.html +1 -1
  33. data/docs/doc/Doing/Note.html +2 -2
  34. data/docs/doc/Doing/Pager.html +1 -1
  35. data/docs/doc/Doing/Plugins.html +1 -1
  36. data/docs/doc/Doing/Prompt.html +69 -1
  37. data/docs/doc/Doing/Section.html +1 -1
  38. data/docs/doc/Doing/TemplateString.html +2 -2
  39. data/docs/doc/Doing/Util/Backup.html +1 -1
  40. data/docs/doc/Doing/Util.html +1 -1
  41. data/docs/doc/Doing/WWID.html +71 -67
  42. data/docs/doc/Doing.html +3 -3
  43. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +1 -1
  44. data/docs/doc/GLI/Commands.html +1 -1
  45. data/docs/doc/GLI.html +1 -1
  46. data/docs/doc/Hash.html +1 -1
  47. data/docs/doc/Numeric.html +279 -0
  48. data/docs/doc/PhraseParser/Operator.html +1 -1
  49. data/docs/doc/PhraseParser/PhraseClause.html +1 -1
  50. data/docs/doc/PhraseParser/Query.html +1 -1
  51. data/docs/doc/PhraseParser/QueryParser.html +1 -1
  52. data/docs/doc/PhraseParser/QueryTransformer.html +1 -1
  53. data/docs/doc/PhraseParser/TermClause.html +1 -1
  54. data/docs/doc/PhraseParser.html +1 -1
  55. data/docs/doc/Status.html +1 -1
  56. data/docs/doc/String.html +997 -118
  57. data/docs/doc/Symbol.html +1 -1
  58. data/docs/doc/Time.html +1 -1
  59. data/docs/doc/_index.html +14 -9
  60. data/docs/doc/class_list.html +1 -1
  61. data/docs/doc/file.README.html +41 -15
  62. data/docs/doc/index.html +41 -15
  63. data/docs/doc/method_list.html +448 -312
  64. data/docs/doc/top-level-namespace.html +2 -2
  65. data/docs/index.md +56 -19
  66. data/doing.gemspec +1 -0
  67. data/doing.rdoc +36 -6
  68. data/example_plugin.rb +2 -4
  69. data/lib/completion/_doing.zsh +8 -8
  70. data/lib/completion/doing.bash +12 -12
  71. data/lib/completion/doing.fish +8 -3
  72. data/lib/doing/array_chronify.rb +57 -0
  73. data/lib/doing/colors.rb +4 -0
  74. data/lib/doing/configuration.rb +6 -2
  75. data/lib/doing/item.rb +83 -0
  76. data/lib/doing/log_adapter.rb +3 -3
  77. data/lib/doing/numeric_chronify.rb +40 -0
  78. data/lib/doing/plugins/export/dayone_export.rb +1 -1
  79. data/lib/doing/plugins/export/json_export.rb +2 -2
  80. data/lib/doing/plugins/export/template_export.rb +49 -90
  81. data/lib/doing/prompt.rb +52 -0
  82. data/lib/doing/string.rb +137 -33
  83. data/lib/doing/string_chronify.rb +112 -14
  84. data/lib/doing/template_string.rb +1 -1
  85. data/lib/doing/time.rb +4 -4
  86. data/lib/doing/util_backup.rb +1 -1
  87. data/lib/doing/version.rb +1 -1
  88. data/lib/doing/wwid.rb +107 -101
  89. data/lib/doing.rb +35 -31
  90. data/lib/examples/plugins/say_export.rb +1 -4
  91. metadata +26 -2
data/lib/doing/wwid.rb CHANGED
@@ -185,34 +185,11 @@ module Doing
185
185
 
186
186
  date = nil
187
187
  iso_rx = /\d{4}-\d\d-\d\d \d\d:\d\d/
188
- watch_tags = [
189
- 'start(?:ed)?',
190
- 'beg[ia]n',
191
- 'done',
192
- 'finished',
193
- 'completed?',
194
- 'waiting',
195
- 'defer(?:red)?'
196
- ]
197
- if @config['date_tags']
198
- date_tags = @config['date_tags']
199
- date_tags = date_tags.split(/ *, */) if date_tags.is_a?(String)
200
- date_tags.map! do |tag|
201
- tag.sub(/^@/, '').gsub(/\((?!\?:)(.*?)\)/, '(?:\1)').strip
202
- end
203
- watch_tags.concat(date_tags).uniq!
204
- end
205
-
206
- done_rx = /(?<=^| )@(?<tag>#{watch_tags.join('|')})\((?<date>.*?)\)/i
207
188
  date_rx = /^(?:\s*- )?(?<date>.*?) \| (?=\S)/
208
189
 
209
- title.gsub!(done_rx) do
210
- m = Regexp.last_match
211
- t = m['tag']
212
- d = m['date']
213
- parsed_date = d =~ date_rx ? Time.parse(d) : d.chronify(guess: :begin)
214
- parsed_date.nil? ? m[0] : "@#{t}(#{parsed_date.strftime('%F %R')})"
215
- end
190
+ raise EmptyInput, 'No content' if title.sub(/^.*?\| */, '').strip.empty?
191
+
192
+ title.expand_date_tags(@config['date_tags'])
216
193
 
217
194
  if title =~ date_rx
218
195
  m = title.match(date_rx)
@@ -369,7 +346,8 @@ module Doing
369
346
  items.each_with_index do |i, x|
370
347
  next if i.title =~ / @done/
371
348
 
372
- items[x].title = "#{i.title} @done(#{opt[:back].strftime('%F %R')})"
349
+ finish_date = verify_duration(i.date, opt[:back], title: i.title)
350
+ items[x].tag('done', value: finish_date.strftime('%F %R'))
373
351
  break
374
352
  end
375
353
  end
@@ -820,17 +798,18 @@ module Doing
820
798
  end
821
799
 
822
800
  def delete_items(items, force: false)
823
- res = force ? true : Prompt.yn("Delete #{items.size} #{items.size == 1 ? 'item' : 'items'}?", default_response: 'y')
824
- if res
825
- items.each do |i|
826
- deleted = @content.delete_item(i, single: items.count == 1)
827
- Hooks.trigger :post_entry_removed, self, deleted
828
- end
829
- write(@doing_file)
830
- end
801
+ items.slice(0, 5).each { |i| puts i.to_pretty } unless force
802
+ puts softpurple("+ #{items.size - 5} additional #{'item'.to_p(items.size - 5)}") if items.size > 5 && !force
803
+
804
+ res = force ? true : Prompt.yn("Delete #{items.size} #{'item'.to_p(items.size)}?", default_response: 'y')
805
+ return unless res
806
+
807
+ items.each { |i| Hooks.trigger :post_entry_removed, self, @content.delete_item(i, single: items.count == 1) }
808
+ write(@doing_file)
831
809
  end
832
810
 
833
811
  def edit_items(items)
812
+ items.sort_by! { |i| i.date }
834
813
  editable_items = []
835
814
 
836
815
  items.each do |i|
@@ -839,16 +818,16 @@ module Doing
839
818
  editable += "\n#{old_note}" unless old_note.nil?
840
819
  editable_items << editable
841
820
  end
842
- divider = "\n-----------\n"
821
+ divider = "-----------"
843
822
  notice =<<~EONOTICE
844
823
  # - You may delete entries, but leave all divider lines (---) in place.
845
824
  # - Start and @done dates replaced with a time string (yesterday 3pm) will
846
825
  # be parsed automatically. Do not delete the pipe (|) between start date
847
826
  # and entry title.
848
827
  EONOTICE
849
- input = "#{editable_items.map(&:strip).join(divider)}\n\n#{notice}"
828
+ input = "#{editable_items.map(&:strip).join("\n#{divider}\n")}\n\n#{notice}"
850
829
 
851
- new_items = fork_editor(input).split(/#{divider}/)
830
+ new_items = fork_editor(input).split(/^#{divider}/).map(&:strip)
852
831
 
853
832
  new_items.each_with_index do |new_item, i|
854
833
  input_lines = new_item.split(/[\n\r]+/).delete_if(&:ignore?)
@@ -857,7 +836,7 @@ module Doing
857
836
  if first_line.nil? || first_line =~ /^#{divider.strip}$/ || first_line.strip.empty?
858
837
  deleted = @content.delete_item(items[i], single: new_items.count == 1)
859
838
  Hooks.trigger :post_entry_removed, self, deleted
860
- Doing.logger.count(:deleted)
839
+ Doing.logger.info('Deleted:', deleted.title)
861
840
  else
862
841
  date, title, note = format_input(new_item)
863
842
 
@@ -985,8 +964,14 @@ module Doing
985
964
  type = action =~ /^add/ ? 'add' : 'remove'
986
965
  raise InvalidArgument, "'add tag' and 'remove tag' can not be used together" if opt[:tag]
987
966
 
988
- print "#{yellow("Tag to #{type}: ")}#{reset}"
989
- tag = $stdin.gets
967
+ tags = type == 'add' ? all_tags(@content) : all_tags(items)
968
+
969
+ puts "#{yellow}Separate multiple tags with spaces, hit tab to complete known tags#{type == 'add' ? ', include values with tag(value)' : ''}"
970
+ puts "#{boldgreen}Available tags: #{boldwhite}#{tags.sort.map(&:add_at).join(', ')}" if type == 'remove'
971
+ tag = Prompt.read_line(prompt: "Tags to #{type}", completions: tags)
972
+
973
+ # print "#{yellow("Tag to #{type}: ")}#{reset}"
974
+ # tag = $stdin.gets
990
975
  next if tag =~ /^ *$/
991
976
 
992
977
  opt[:tag] = tag.strip.sub(/^@/, '')
@@ -1001,15 +986,16 @@ module Doing
1001
986
  '--no-sort',
1002
987
  '--info=hidden'
1003
988
  ])
1004
- next if tag =~ /^ *$/
989
+ next if output_format =~ /^ *$/
1005
990
 
1006
991
  raise UserCancelled unless output_format
1007
992
 
1008
993
  opt[:output] = output_format.strip
1009
994
  res = opt[:force] ? false : Prompt.yn('Save to file?', default_response: 'n')
1010
995
  if res
1011
- print "#{yellow('File path/name: ')}#{reset}"
1012
- filename = $stdin.gets.strip
996
+ # print "#{yellow('File path/name: ')}#{reset}"
997
+ # filename = $stdin.gets.strip
998
+ filename = Prompt.read_line(prompt: 'File path/name')
1013
999
  next if filename.empty?
1014
1000
 
1015
1001
  opt[:save_to] = filename
@@ -1089,6 +1075,7 @@ module Doing
1089
1075
  tag = opt[:tag]
1090
1076
  items.map! do |i|
1091
1077
  i.tag(tag, date: false, remove: opt[:remove], single: single)
1078
+ i.expand_date_tags(@config['date_tags'])
1092
1079
  Hooks.trigger :post_entry_updated, self, i
1093
1080
  end
1094
1081
  end
@@ -1116,10 +1103,10 @@ module Doing
1116
1103
  i
1117
1104
  end
1118
1105
 
1119
- @content = Items.new
1120
- @content.concat(items)
1121
- @content.add_section(Section.new('Export'), log: false)
1122
- options = { section: 'Export' }
1106
+ export_items = Items.new
1107
+ export_items.concat(items)
1108
+ export_items.add_section(Section.new('Export'), log: false)
1109
+ options = { section: 'All' }
1123
1110
 
1124
1111
  if opt[:output] =~ /doing/
1125
1112
  options[:output] = 'template'
@@ -1129,7 +1116,7 @@ module Doing
1129
1116
  options[:template] = opt[:template] || nil
1130
1117
  end
1131
1118
 
1132
- output = list_section(options) # hooked
1119
+ output = list_section(options, items: export_items) # hooked
1133
1120
 
1134
1121
  if opt[:save_to]
1135
1122
  file = File.expand_path(opt[:save_to])
@@ -1148,6 +1135,26 @@ module Doing
1148
1135
  end
1149
1136
  end
1150
1137
 
1138
+ def verify_duration(date, finish_date, title: nil)
1139
+ max_elapsed = @config.dig('interaction', 'confirm_longer_than') || 0
1140
+ max_elapsed = max_elapsed.chronify_qty if max_elapsed.is_a?(String)
1141
+ elapsed = finish_date - date
1142
+
1143
+ if max_elapsed.positive? && (elapsed > max_elapsed)
1144
+ puts boldwhite(title) if title
1145
+ human = elapsed.time_string(format: :natural)
1146
+ res = Prompt.yn(yellow("Did this entry actually take #{human}"), default_response: true)
1147
+ unless res
1148
+ new_elapsed = Prompt.enter_text('How long did it take?').chronify_qty
1149
+ raise InvalidTimeExpression, 'Unrecognized time span entry' unless new_elapsed.positive?
1150
+
1151
+ finish_date = date + new_elapsed if new_elapsed
1152
+ end
1153
+ end
1154
+
1155
+ finish_date
1156
+ end
1157
+
1151
1158
  ##
1152
1159
  ## Tag the last entry or X entries
1153
1160
  ##
@@ -1186,6 +1193,19 @@ module Doing
1186
1193
 
1187
1194
  raise NoResults, 'no items matched your search' if items.empty?
1188
1195
 
1196
+ if opt[:tags].empty? && !opt[:autotag]
1197
+ completions = opt[:remove] ? all_tags(items) : all_tags(@content)
1198
+ if opt[:remove]
1199
+ puts "#{yellow}Available tags: #{boldwhite}#{completions.map(&:add_at).join(', ')}"
1200
+ else
1201
+ puts "#{yellow}Use tab to complete known tags"
1202
+ end
1203
+ opt[:tags] = Doing::Prompt.read_line(prompt: "Enter tag(s) to #{opt[:remove] ? 'remove' : 'add'}",
1204
+ completions: completions,
1205
+ default_response: '').to_tags
1206
+ raise UserCancelled, 'No tags provided' if opt[:tags].empty?
1207
+ end
1208
+
1189
1209
  items.each do |item|
1190
1210
  added = []
1191
1211
  removed = []
@@ -1209,21 +1229,8 @@ module Doing
1209
1229
  else
1210
1230
  next_entry.date - 60
1211
1231
  end
1212
- elsif opt[:took]
1213
- if item.date + opt[:took] > Time.now
1214
- item.date = Time.now - opt[:took]
1215
- done_date = Time.now
1216
- else
1217
- done_date = item.date + opt[:took]
1218
- end
1219
- elsif opt[:back]
1220
- done_date = if opt[:back].is_a? Integer
1221
- item.date + opt[:back]
1222
- else
1223
- item.date + (opt[:back] - item.date)
1224
- end
1225
1232
  else
1226
- done_date = Time.now
1233
+ done_date = item.calculate_end_date(opt)
1227
1234
  end
1228
1235
 
1229
1236
  opt[:tags].each do |tag|
@@ -1234,7 +1241,28 @@ module Doing
1234
1241
  next
1235
1242
  end
1236
1243
 
1244
+
1237
1245
  tag = tag.strip
1246
+
1247
+ if tag =~ /^done$/
1248
+ max_elapsed = @config.dig('interaction', 'confirm_longer_than') || 0
1249
+ max_elapsed = max_elapsed.chronify_qty if max_elapsed.is_a?(String)
1250
+ elapsed = done_date - item.date
1251
+
1252
+ if max_elapsed.positive? && (elapsed > max_elapsed) && !opt[:took]
1253
+ puts boldwhite(item.title)
1254
+ human = elapsed.time_string(format: :natural)
1255
+ res = Prompt.yn(yellow("Did this actually take #{human}"), default_response: true)
1256
+ unless res
1257
+ new_elapsed = Prompt.enter_text('How long did it take?').chronify_qty
1258
+ raise InvalidTimeExpression, 'Unrecognized time span entry' unless new_elapsed > 0
1259
+
1260
+ opt[:took] = new_elapsed
1261
+ done_date = item.calculate_end_date(opt) if opt[:took]
1262
+ end
1263
+ end
1264
+ end
1265
+
1238
1266
  if opt[:remove] || opt[:rename] || opt[:value]
1239
1267
  rename_to = nil
1240
1268
  if opt[:value]
@@ -1272,6 +1300,7 @@ module Doing
1272
1300
  logger.warn('Skipped:', 'Archiving is skipped when operating on all entries')
1273
1301
  end
1274
1302
 
1303
+ item.expand_date_tags(@config['date_tags'])
1275
1304
  Hooks.trigger :post_entry_updated, self, item
1276
1305
  end
1277
1306
 
@@ -1621,6 +1650,7 @@ module Doing
1621
1650
 
1622
1651
  opt[:output] ||= 'template'
1623
1652
  opt[:wrap_width] ||= @config['templates']['default']['wrap_width'] || 0
1653
+
1624
1654
  output(items, title, is_single, opt)
1625
1655
  end
1626
1656
 
@@ -2005,7 +2035,7 @@ module Doing
2005
2035
  EOS
2006
2036
  sorted_tags_data.reverse.each do |k, v|
2007
2037
  if v > 0
2008
- output += "<tr><td style='text-align:left;'>#{k}</td><td style='text-align:left;'>#{'%02d:%02d:%02d' % format_time(v)}</td></tr>\n"
2038
+ output += "<tr><td style='text-align:left;'>#{k}</td><td style='text-align:left;'>#{v.time_string(format: :clock)}</td></tr>\n"
2009
2039
  end
2010
2040
  end
2011
2041
  tail = <<EOS
@@ -2016,7 +2046,7 @@ EOS
2016
2046
  <tfoot>
2017
2047
  <tr>
2018
2048
  <td style="text-align:left;"><strong>Total</strong></td>
2019
- <td style="text-align:left;">#{'%02d:%02d:%02d' % format_time(total)}</td>
2049
+ <td style="text-align:left;">#{total.time_string(format: :clock)}</td>
2020
2050
  </tr>
2021
2051
  </tfoot>
2022
2052
  </table>
@@ -2031,7 +2061,7 @@ EOS
2031
2061
  EOS
2032
2062
  sorted_tags_data.reverse.each do |k, v|
2033
2063
  if v > 0
2034
- output += "| #{' ' * (pad - k.length)}#{k} | #{'%02d:%02d:%02d' % format_time(v)} |\n"
2064
+ output += "| #{' ' * (pad - k.length)}#{k} | #{v.time_string(format: :clock)} |\n"
2035
2065
  end
2036
2066
  end
2037
2067
  tail = "[Tag Totals]"
@@ -2039,11 +2069,10 @@ EOS
2039
2069
  when :json
2040
2070
  output = []
2041
2071
  sorted_tags_data.reverse.each do |k, v|
2042
- d, h, m = format_time(v)
2043
2072
  output << {
2044
2073
  'tag' => k,
2045
2074
  'seconds' => v,
2046
- 'formatted' => format('%<d>02d:%<h>02d:%<m>02d', d: d, h: h, m: m)
2075
+ 'formatted' => v.time_string(format: :clock)
2047
2076
  }
2048
2077
  end
2049
2078
  output
@@ -2054,8 +2083,7 @@ EOS
2054
2083
  (max - k.length).times do
2055
2084
  spacer += ' '
2056
2085
  end
2057
- _d, h, m = format_time(v, human: true)
2058
- output.push("┃ #{spacer}#{k}:#{format('%<h> 4dh %<m>02dm', h: h, m: m)} ┃")
2086
+ output.push("┃ #{spacer}#{k}:#{v.time_string(format: :hm)} ┃")
2059
2087
  end
2060
2088
 
2061
2089
  header = '┏━━ Tag Totals '
@@ -2068,14 +2096,14 @@ EOS
2068
2096
  (max + 12).times { divider += '━' }
2069
2097
  divider += '┫'
2070
2098
  output = output.empty? ? '' : "\n#{header}\n#{output.join("\n")}"
2071
- d, h, m = format_time(total, human: true)
2072
2099
  output += "\n#{divider}"
2073
2100
  spacer = ''
2074
2101
  (max - 6).times do
2075
2102
  spacer += ' '
2076
2103
  end
2104
+ total_time = total.time_string(format: :hm)
2077
2105
  total = "┃ #{spacer}total: "
2078
- total += format('%<h> 4dh %<m>02dm', h: h, m: m)
2106
+ total += total_time
2079
2107
  total += ' ┃'
2080
2108
  output += "\n#{total}"
2081
2109
  output += "\n#{footer}"
@@ -2087,13 +2115,11 @@ EOS
2087
2115
  (max - k.length).times do
2088
2116
  spacer += ' '
2089
2117
  end
2090
- d, h, m = format_time(v)
2091
- output.push("#{k}:#{spacer}#{format('%<d>02d:%<h>02d:%<m>02d', d: d, h: h, m: m)}")
2118
+ output.push("#{k}:#{spacer}#{v.time_string(format: :clock)}")
2092
2119
  end
2093
2120
 
2094
2121
  output = output.empty? ? '' : "\n--- Tag Totals ---\n#{output.join("\n")}"
2095
- d, h, m = format_time(total)
2096
- output += "\n\nTotal tracked: #{format('%<d>02d:%<h>02d:%<m>02d', d: d, h: h, m: m)}\n"
2122
+ output += "\n\nTotal tracked: #{total.time_string(format: :clock)}\n"
2097
2123
  output
2098
2124
  end
2099
2125
  end
@@ -2118,39 +2144,19 @@ EOS
2118
2144
  record_tag_times(item, seconds) if record
2119
2145
  return seconds.positive? ? seconds : false unless formatted
2120
2146
 
2121
- return seconds.positive? ? format('%02d:%02d:%02d', *format_time(seconds)) : false
2147
+ return seconds.positive? ? seconds.time_string(format: :clock) : false
2122
2148
  end
2123
2149
 
2124
2150
  false
2125
2151
  end
2126
2152
 
2127
2153
  ##
2128
- ## Format human readable time from seconds
2154
+ ## Load configuration files and updated the @config
2155
+ ## attribute with a Doing::Configuration object
2129
2156
  ##
2130
- ## @param seconds [Integer] Seconds
2157
+ ## @param filename [String] (optional) path to
2158
+ ## alternative config file
2131
2159
  ##
2132
- def format_time(seconds, human: false)
2133
- return [0, 0, 0] if seconds.nil?
2134
-
2135
- if seconds.instance_of?(String) && seconds =~ /(\d+):(\d+):(\d+)/
2136
- h = Regexp.last_match(1)
2137
- m = Regexp.last_match(2)
2138
- s = Regexp.last_match(3)
2139
- seconds = (h.to_i * 60 * 60) + (m.to_i * 60) + s.to_i
2140
- end
2141
- minutes = (seconds / 60).to_i
2142
- hours = (minutes / 60).to_i
2143
- if human
2144
- minutes = (minutes % 60).to_i
2145
- [0, hours, minutes]
2146
- else
2147
- days = (hours / 24).to_i
2148
- hours = (hours % 24).to_i
2149
- minutes = (minutes % 60).to_i
2150
- [days, hours, minutes]
2151
- end
2152
- end
2153
-
2154
2160
  def configure(filename = nil)
2155
2161
  if filename
2156
2162
  Doing.config_with(filename, { ignore_local: true })
data/lib/doing.rb CHANGED
@@ -9,43 +9,47 @@ require 'csv'
9
9
  require 'tempfile'
10
10
  require 'zlib'
11
11
  require 'base64'
12
+ require 'plist'
13
+ require 'readline'
14
+ require 'haml'
15
+ require 'json'
16
+ require 'logger'
17
+ require 'safe_yaml/load'
12
18
 
13
19
  require 'chronic'
14
20
  require 'tty-link'
15
21
  require 'tty-which'
16
22
  require 'tty-markdown'
17
23
  require 'tty-reader'
18
- require 'plist'
19
- # require 'amatch'
20
- require 'haml'
21
- require 'json'
22
- require 'logger'
23
- require 'safe_yaml/load'
24
- require 'doing/hash'
25
- require 'doing/colors'
26
- require 'doing/template_string'
27
- require 'doing/string'
28
- require 'doing/string_chronify'
29
- require 'doing/time'
30
- require 'doing/array'
31
- require 'doing/symbol'
32
- require 'doing/util'
33
- require 'doing/util_backup'
34
- require 'doing/configuration'
35
- require 'doing/section'
36
- require 'doing/items'
37
- require 'doing/note'
38
- require 'doing/item'
39
- require 'doing/wwid'
40
- require 'doing/log_adapter'
41
- require 'doing/prompt'
42
- require 'doing/errors'
43
- require 'doing/hooks'
44
- require 'doing/plugin_manager'
45
- require 'doing/pager'
46
- require 'doing/completion'
47
- require 'doing/boolean_term_parser'
48
- require 'doing/phrase_parser'
24
+ require 'tty-screen'
25
+
26
+ require_relative 'doing/hash'
27
+ require_relative 'doing/colors'
28
+ require_relative 'doing/template_string'
29
+ require_relative 'doing/string'
30
+ require_relative 'doing/time'
31
+ require_relative 'doing/array'
32
+ require_relative 'doing/symbol'
33
+ require_relative 'doing/util'
34
+ require_relative 'doing/util_backup'
35
+ require_relative 'doing/configuration'
36
+ require_relative 'doing/section'
37
+ require_relative 'doing/items'
38
+ require_relative 'doing/note'
39
+ require_relative 'doing/item'
40
+ require_relative 'doing/wwid'
41
+ require_relative 'doing/log_adapter'
42
+ require_relative 'doing/prompt'
43
+ require_relative 'doing/errors'
44
+ require_relative 'doing/hooks'
45
+ require_relative 'doing/plugin_manager'
46
+ require_relative 'doing/pager'
47
+ require_relative 'doing/completion'
48
+ require_relative 'doing/boolean_term_parser'
49
+ require_relative 'doing/phrase_parser'
50
+ require_relative 'doing/array_chronify'
51
+ require_relative 'doing/numeric_chronify'
52
+ require_relative 'doing/string_chronify'
49
53
  # require 'doing/markdown_document_listener'
50
54
 
51
55
  # Main doing module
@@ -149,11 +149,8 @@ module Doing
149
149
  finished_at = i.end_date
150
150
  took += finished_at.strftime('%A %B %e at %I:%M%p')
151
151
 
152
- d, h, m = wwid.format_time(interval)
153
152
  took += ' and it took'
154
- took += " #{d.to_i} days" if d.to_i.positive?
155
- took += " #{h.to_i} hours" if h.to_i.positive?
156
- took += " #{m.to_i} minutes" if m.to_i.positive?
153
+ took += interval.time_string(format: :natural)
157
154
  end
158
155
  end
159
156
 
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: doing
3
3
  version: !ruby/object:Gem::Version
4
- version: 2.1.14
4
+ version: 2.1.18
5
5
  platform: ruby
6
6
  authors:
7
7
  - Brett Terpstra
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-01-15 00:00:00.000000000 Z
11
+ date: 2022-01-18 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: safe_yaml
@@ -366,6 +366,26 @@ dependencies:
366
366
  - - ">="
367
367
  - !ruby/object:Gem::Version
368
368
  version: 0.9.0
369
+ - !ruby/object:Gem::Dependency
370
+ name: tty-screen
371
+ requirement: !ruby/object:Gem::Requirement
372
+ requirements:
373
+ - - "~>"
374
+ - !ruby/object:Gem::Version
375
+ version: '0.8'
376
+ - - ">="
377
+ - !ruby/object:Gem::Version
378
+ version: 0.8.1
379
+ type: :runtime
380
+ prerelease: false
381
+ version_requirements: !ruby/object:Gem::Requirement
382
+ requirements:
383
+ - - "~>"
384
+ - !ruby/object:Gem::Version
385
+ version: '0.8'
386
+ - - ">="
387
+ - !ruby/object:Gem::Version
388
+ version: 0.8.1
369
389
  - !ruby/object:Gem::Dependency
370
390
  name: parslet
371
391
  requirement: !ruby/object:Gem::Requirement
@@ -416,6 +436,7 @@ extensions: []
416
436
  extra_rdoc_files:
417
437
  - README.md
418
438
  files:
439
+ - ".irbrc"
419
440
  - ".yardoc/checksums"
420
441
  - ".yardoc/complete"
421
442
  - ".yardoc/object_types"
@@ -477,6 +498,7 @@ files:
477
498
  - docs/doc/GLI/Commands.html
478
499
  - docs/doc/GLI/Commands/MarkdownDocumentListener.html
479
500
  - docs/doc/Hash.html
501
+ - docs/doc/Numeric.html
480
502
  - docs/doc/PhraseParser.html
481
503
  - docs/doc/PhraseParser/Operator.html
482
504
  - docs/doc/PhraseParser/PhraseClause.html
@@ -515,6 +537,7 @@ files:
515
537
  - lib/completion/doing.fish
516
538
  - lib/doing.rb
517
539
  - lib/doing/array.rb
540
+ - lib/doing/array_chronify.rb
518
541
  - lib/doing/boolean_term_parser.rb
519
542
  - lib/doing/cli_status.rb
520
543
  - lib/doing/colors.rb
@@ -532,6 +555,7 @@ files:
532
555
  - lib/doing/log_adapter.rb
533
556
  - lib/doing/markdown_document_listener.rb
534
557
  - lib/doing/note.rb
558
+ - lib/doing/numeric_chronify.rb
535
559
  - lib/doing/pager.rb
536
560
  - lib/doing/phrase_parser.rb
537
561
  - lib/doing/plugin_manager.rb