doing 2.1.11 → 2.1.15

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 (92) hide show
  1. checksums.yaml +4 -4
  2. data/.irbrc +1 -0
  3. data/.yardoc/checksums +15 -13
  4. data/.yardoc/object_types +0 -0
  5. data/.yardoc/objects/root.dat +0 -0
  6. data/CHANGELOG.md +44 -1
  7. data/Gemfile.lock +9 -2
  8. data/README.md +56 -19
  9. data/bin/doing +215 -76
  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 +1 -1
  18. data/docs/doc/Doing/Completion.html +1 -1
  19. data/docs/doc/Doing/Configuration.html +7 -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 +337 -14
  31. data/docs/doc/Doing/Items.html +66 -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 +35 -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 +84 -1
  40. data/docs/doc/Doing/Util.html +1 -1
  41. data/docs/doc/Doing/WWID.html +180 -35
  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 +767 -115
  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 +407 -279
  64. data/docs/doc/top-level-namespace.html +2 -2
  65. data/docs/index.md +56 -19
  66. data/doing.gemspec +2 -0
  67. data/doing.rdoc +244 -45
  68. data/example_plugin.rb +2 -4
  69. data/lib/completion/_doing.zsh +31 -27
  70. data/lib/completion/doing.bash +50 -39
  71. data/lib/completion/doing.fish +35 -6
  72. data/lib/doing/array_chronify.rb +57 -0
  73. data/lib/doing/configuration.rb +4 -1
  74. data/lib/doing/item.rb +176 -0
  75. data/lib/doing/log_adapter.rb +1 -1
  76. data/lib/doing/numeric_chronify.rb +40 -0
  77. data/lib/doing/plugins/export/dayone_export.rb +1 -1
  78. data/lib/doing/plugins/export/json_export.rb +2 -2
  79. data/lib/doing/plugins/export/template_export.rb +47 -90
  80. data/lib/doing/plugins/import/calendar_import.rb +13 -1
  81. data/lib/doing/plugins/import/doing_import.rb +12 -1
  82. data/lib/doing/plugins/import/timing_import.rb +13 -1
  83. data/lib/doing/prompt.rb +13 -1
  84. data/lib/doing/string.rb +97 -33
  85. data/lib/doing/string_chronify.rb +83 -13
  86. data/lib/doing/time.rb +6 -6
  87. data/lib/doing/util_backup.rb +1 -1
  88. data/lib/doing/version.rb +1 -1
  89. data/lib/doing/wwid.rb +88 -93
  90. data/lib/doing.rb +31 -27
  91. data/lib/examples/plugins/say_export.rb +1 -4
  92. metadata +46 -2
data/lib/doing/wwid.rb CHANGED
@@ -185,34 +185,9 @@ 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
+ title.expand_date_tags(@config['date_tags'])
216
191
 
217
192
  if title =~ date_rx
218
193
  m = title.match(date_rx)
@@ -369,7 +344,8 @@ module Doing
369
344
  items.each_with_index do |i, x|
370
345
  next if i.title =~ / @done/
371
346
 
372
- items[x].title = "#{i.title} @done(#{opt[:back].strftime('%F %R')})"
347
+ finish_date = verify_duration(i.date, opt[:back], title: i.title)
348
+ items[x].tag('done', value: finish_date.strftime('%F %R'))
373
349
  break
374
350
  end
375
351
  end
@@ -384,10 +360,13 @@ module Doing
384
360
  end
385
361
 
386
362
  ##
387
- ## Remove items from a list that already exist in @content
363
+ ## Remove items from an array that already exist in
364
+ ## @content based on start and end times
388
365
  ##
389
- ## @param items [Array] The items to deduplicate
390
- ## @param no_overlap [Boolean] Remove items with overlapping time spans
366
+ ## @param items [Array] The items to
367
+ ## deduplicate
368
+ ## @param no_overlap [Boolean] Remove items with
369
+ ## overlapping time spans
391
370
  ##
392
371
  def dedup(items, no_overlap: false)
393
372
  items.delete_if do |item|
@@ -640,6 +619,7 @@ module Doing
640
619
  ## @option opt [Boolean] :yesterday (false) limit to entries from yesterday
641
620
  ## @option opt [Number] :count (0) max entries to return
642
621
  ## @option opt [String] :age (new) 'old' or 'new'
622
+ ## @option opt [Array] :val (nil) Array of tag value queries
643
623
  ##
644
624
  def filter_items(items = Items.new, opt: {})
645
625
  time_rx = /^(\d{1,2}+(:\d{1,2}+)?( *(am|pm))?|midnight|noon)$/
@@ -701,6 +681,16 @@ module Doing
701
681
  keep = false if finished
702
682
  end
703
683
 
684
+ if keep && opt[:val]&.count&.positive?
685
+ bool = opt[:bool].normalize_bool if opt[:bool]
686
+ bool ||= :and
687
+ bool = :and if bool == :pattern
688
+
689
+ val_match = opt[:val].nil? || opt[:val].empty? ? true : item.tag_values?(opt[:val], bool)
690
+ keep = false unless val_match
691
+ keep = opt[:not] ? !keep : keep
692
+ end
693
+
704
694
  if keep && opt[:tag]
705
695
  opt[:tag_bool] = opt[:bool].normalize_bool if opt[:bool]
706
696
  opt[:tag_bool] ||= :and
@@ -883,11 +873,11 @@ module Doing
883
873
  opt[:search] = search
884
874
  end
885
875
 
886
- opt[:query] = opt[:search] if opt[:search] && !opt[:query]
887
- opt[:query] = "!#{opt[:query]}" if opt[:not]
876
+ # opt[:query] = opt[:search] if opt[:search] && !opt[:query]
877
+ opt[:query] = "!#{opt[:query]}" if opt[:query] && opt[:not]
888
878
  opt[:multiple] = true
889
879
  opt[:show_if_single] = true
890
- filter_options = %i[after before case date_filter from fuzzy not search section].each_with_object({}) {
880
+ filter_options = %i[after before case date_filter from fuzzy not search section val].each_with_object({}) {
891
881
  |k, hsh| hsh[k] = opt[k]
892
882
  }
893
883
  items = filter_items(Items.new, opt: filter_options)
@@ -987,7 +977,7 @@ module Doing
987
977
  '--no-sort',
988
978
  '--info=hidden'
989
979
  ])
990
- next if tag =~ /^ *$/
980
+ next if output_format =~ /^ *$/
991
981
 
992
982
  raise UserCancelled unless output_format
993
983
 
@@ -1075,6 +1065,7 @@ module Doing
1075
1065
  tag = opt[:tag]
1076
1066
  items.map! do |i|
1077
1067
  i.tag(tag, date: false, remove: opt[:remove], single: single)
1068
+ i.expand_date_tags(@config['date_tags'])
1078
1069
  Hooks.trigger :post_entry_updated, self, i
1079
1070
  end
1080
1071
  end
@@ -1134,6 +1125,26 @@ module Doing
1134
1125
  end
1135
1126
  end
1136
1127
 
1128
+ def verify_duration(date, finish_date, title: nil)
1129
+ max_elapsed = @config.dig('interaction', 'confirm_longer_than') || 0
1130
+ max_elapsed = max_elapsed.chronify_qty if max_elapsed.is_a?(String)
1131
+ elapsed = finish_date - date
1132
+
1133
+ if max_elapsed.positive? && (elapsed > max_elapsed)
1134
+ puts boldwhite(title) if title
1135
+ human = elapsed.time_string(format: :natural)
1136
+ res = Prompt.yn(yellow("Did this entry actually take #{human}"), default_response: true)
1137
+ unless res
1138
+ new_elapsed = Prompt.enter_text('How long did it take?').chronify_qty
1139
+ raise InvalidTimeExpression, 'Unrecognized time span entry' unless new_elapsed.positive?
1140
+
1141
+ finish_date = date + new_elapsed if new_elapsed
1142
+ end
1143
+ end
1144
+
1145
+ finish_date
1146
+ end
1147
+
1137
1148
  ##
1138
1149
  ## Tag the last entry or X entries
1139
1150
  ##
@@ -1195,21 +1206,8 @@ module Doing
1195
1206
  else
1196
1207
  next_entry.date - 60
1197
1208
  end
1198
- elsif opt[:took]
1199
- if item.date + opt[:took] > Time.now
1200
- item.date = Time.now - opt[:took]
1201
- done_date = Time.now
1202
- else
1203
- done_date = item.date + opt[:took]
1204
- end
1205
- elsif opt[:back]
1206
- done_date = if opt[:back].is_a? Integer
1207
- item.date + opt[:back]
1208
- else
1209
- item.date + (opt[:back] - item.date)
1210
- end
1211
1209
  else
1212
- done_date = Time.now
1210
+ done_date = item.calculate_end_date(opt)
1213
1211
  end
1214
1212
 
1215
1213
  opt[:tags].each do |tag|
@@ -1220,15 +1218,39 @@ module Doing
1220
1218
  next
1221
1219
  end
1222
1220
 
1221
+
1223
1222
  tag = tag.strip
1224
- if opt[:remove] || opt[:rename]
1223
+
1224
+ if tag =~ /^done$/
1225
+ max_elapsed = @config.dig('interaction', 'confirm_longer_than') || 0
1226
+ max_elapsed = max_elapsed.chronify_qty if max_elapsed.is_a?(String)
1227
+ elapsed = done_date - item.date
1228
+
1229
+ if max_elapsed.positive? && (elapsed > max_elapsed) && !opt[:took]
1230
+ puts boldwhite(item.title)
1231
+ human = elapsed.time_string(format: :natural)
1232
+ res = Prompt.yn(yellow("Did this actually take #{human}"), default_response: true)
1233
+ unless res
1234
+ new_elapsed = Prompt.enter_text('How long did it take?').chronify_qty
1235
+ raise InvalidTimeExpression, 'Unrecognized time span entry' unless new_elapsed > 0
1236
+
1237
+ opt[:took] = new_elapsed
1238
+ done_date = item.calculate_end_date(opt) if opt[:took]
1239
+ end
1240
+ end
1241
+ end
1242
+
1243
+ if opt[:remove] || opt[:rename] || opt[:value]
1225
1244
  rename_to = nil
1226
- if opt[:rename]
1245
+ if opt[:value]
1246
+ rename_to = tag
1247
+ elsif opt[:rename]
1227
1248
  rename_to = tag
1228
1249
  tag = opt[:rename]
1229
1250
  end
1230
1251
  old_title = item.title.dup
1231
- item.title.tag!(tag, remove: opt[:remove], rename_to: rename_to, regex: opt[:regex])
1252
+ force = opt[:value].nil? ? false : true
1253
+ item.title.tag!(tag, remove: opt[:remove], rename_to: rename_to, regex: opt[:regex], value: opt[:value], force: force)
1232
1254
  if old_title != item.title
1233
1255
  removed << tag
1234
1256
  added << rename_to if rename_to
@@ -1255,6 +1277,7 @@ module Doing
1255
1277
  logger.warn('Skipped:', 'Archiving is skipped when operating on all entries')
1256
1278
  end
1257
1279
 
1280
+ item.expand_date_tags(@config['date_tags'])
1258
1281
  Hooks.trigger :post_entry_updated, self, item
1259
1282
  end
1260
1283
 
@@ -1823,7 +1846,8 @@ module Doing
1823
1846
  case: options[:case],
1824
1847
  not: options[:negate],
1825
1848
  config_template: 'last',
1826
- delete: options[:delete]
1849
+ delete: options[:delete],
1850
+ val: options[:val]
1827
1851
  }
1828
1852
 
1829
1853
  if options[:tag]
@@ -1987,7 +2011,7 @@ module Doing
1987
2011
  EOS
1988
2012
  sorted_tags_data.reverse.each do |k, v|
1989
2013
  if v > 0
1990
- output += "<tr><td style='text-align:left;'>#{k}</td><td style='text-align:left;'>#{'%02d:%02d:%02d' % format_time(v)}</td></tr>\n"
2014
+ output += "<tr><td style='text-align:left;'>#{k}</td><td style='text-align:left;'>#{v.time_string(format: :clock)}</td></tr>\n"
1991
2015
  end
1992
2016
  end
1993
2017
  tail = <<EOS
@@ -1998,7 +2022,7 @@ EOS
1998
2022
  <tfoot>
1999
2023
  <tr>
2000
2024
  <td style="text-align:left;"><strong>Total</strong></td>
2001
- <td style="text-align:left;">#{'%02d:%02d:%02d' % format_time(total)}</td>
2025
+ <td style="text-align:left;">#{total.time_string(format: :clock)}</td>
2002
2026
  </tr>
2003
2027
  </tfoot>
2004
2028
  </table>
@@ -2013,7 +2037,7 @@ EOS
2013
2037
  EOS
2014
2038
  sorted_tags_data.reverse.each do |k, v|
2015
2039
  if v > 0
2016
- output += "| #{' ' * (pad - k.length)}#{k} | #{'%02d:%02d:%02d' % format_time(v)} |\n"
2040
+ output += "| #{' ' * (pad - k.length)}#{k} | #{v.time_string(format: :clock)} |\n"
2017
2041
  end
2018
2042
  end
2019
2043
  tail = "[Tag Totals]"
@@ -2021,11 +2045,10 @@ EOS
2021
2045
  when :json
2022
2046
  output = []
2023
2047
  sorted_tags_data.reverse.each do |k, v|
2024
- d, h, m = format_time(v)
2025
2048
  output << {
2026
2049
  'tag' => k,
2027
2050
  'seconds' => v,
2028
- 'formatted' => format('%<d>02d:%<h>02d:%<m>02d', d: d, h: h, m: m)
2051
+ 'formatted' => v.time_string(format: :clock)
2029
2052
  }
2030
2053
  end
2031
2054
  output
@@ -2036,8 +2059,7 @@ EOS
2036
2059
  (max - k.length).times do
2037
2060
  spacer += ' '
2038
2061
  end
2039
- _d, h, m = format_time(v, human: true)
2040
- output.push("┃ #{spacer}#{k}:#{format('%<h> 4dh %<m>02dm', h: h, m: m)} ┃")
2062
+ output.push("┃ #{spacer}#{k}:#{v.time_string(format: :hm)} ┃")
2041
2063
  end
2042
2064
 
2043
2065
  header = '┏━━ Tag Totals '
@@ -2050,14 +2072,14 @@ EOS
2050
2072
  (max + 12).times { divider += '━' }
2051
2073
  divider += '┫'
2052
2074
  output = output.empty? ? '' : "\n#{header}\n#{output.join("\n")}"
2053
- d, h, m = format_time(total, human: true)
2054
2075
  output += "\n#{divider}"
2055
2076
  spacer = ''
2056
2077
  (max - 6).times do
2057
2078
  spacer += ' '
2058
2079
  end
2080
+ total_time = total.time_string(format: :hm)
2059
2081
  total = "┃ #{spacer}total: "
2060
- total += format('%<h> 4dh %<m>02dm', h: h, m: m)
2082
+ total += total_time
2061
2083
  total += ' ┃'
2062
2084
  output += "\n#{total}"
2063
2085
  output += "\n#{footer}"
@@ -2069,13 +2091,11 @@ EOS
2069
2091
  (max - k.length).times do
2070
2092
  spacer += ' '
2071
2093
  end
2072
- d, h, m = format_time(v)
2073
- output.push("#{k}:#{spacer}#{format('%<d>02d:%<h>02d:%<m>02d', d: d, h: h, m: m)}")
2094
+ output.push("#{k}:#{spacer}#{v.time_string(format: :clock)}")
2074
2095
  end
2075
2096
 
2076
2097
  output = output.empty? ? '' : "\n--- Tag Totals ---\n#{output.join("\n")}"
2077
- d, h, m = format_time(total)
2078
- output += "\n\nTotal tracked: #{format('%<d>02d:%<h>02d:%<m>02d', d: d, h: h, m: m)}\n"
2098
+ output += "\n\nTotal tracked: #{total.time_string(format: :clock)}\n"
2079
2099
  output
2080
2100
  end
2081
2101
  end
@@ -2100,39 +2120,12 @@ EOS
2100
2120
  record_tag_times(item, seconds) if record
2101
2121
  return seconds.positive? ? seconds : false unless formatted
2102
2122
 
2103
- return seconds.positive? ? format('%02d:%02d:%02d', *format_time(seconds)) : false
2123
+ return seconds.positive? ? seconds.time_string(format: :clock) : false
2104
2124
  end
2105
2125
 
2106
2126
  false
2107
2127
  end
2108
2128
 
2109
- ##
2110
- ## Format human readable time from seconds
2111
- ##
2112
- ## @param seconds [Integer] Seconds
2113
- ##
2114
- def format_time(seconds, human: false)
2115
- return [0, 0, 0] if seconds.nil?
2116
-
2117
- if seconds.instance_of?(String) && seconds =~ /(\d+):(\d+):(\d+)/
2118
- h = Regexp.last_match(1)
2119
- m = Regexp.last_match(2)
2120
- s = Regexp.last_match(3)
2121
- seconds = (h.to_i * 60 * 60) + (m.to_i * 60) + s.to_i
2122
- end
2123
- minutes = (seconds / 60).to_i
2124
- hours = (minutes / 60).to_i
2125
- if human
2126
- minutes = (minutes % 60).to_i
2127
- [0, hours, minutes]
2128
- else
2129
- days = (hours / 24).to_i
2130
- hours = (hours % 24).to_i
2131
- minutes = (minutes % 60).to_i
2132
- [days, hours, minutes]
2133
- end
2134
- end
2135
-
2136
2129
  def configure(filename = nil)
2137
2130
  if filename
2138
2131
  Doing.config_with(filename, { ignore_local: true })
@@ -2212,6 +2205,8 @@ EOS
2212
2205
  break
2213
2206
  end
2214
2207
 
2208
+ logger.debug('Output:', "#{items.count} #{items.count == 1 ? 'item' : 'items'} shown")
2209
+
2215
2210
  out
2216
2211
  end
2217
2212
 
data/lib/doing.rb CHANGED
@@ -9,42 +9,46 @@ require 'csv'
9
9
  require 'tempfile'
10
10
  require 'zlib'
11
11
  require 'base64'
12
+ require 'plist'
12
13
 
13
14
  require 'chronic'
14
15
  require 'tty-link'
15
16
  require 'tty-which'
16
17
  require 'tty-markdown'
17
- require 'plist'
18
- # require 'amatch'
18
+ require 'tty-reader'
19
+ require 'tty-screen'
19
20
  require 'haml'
20
21
  require 'json'
21
22
  require 'logger'
22
23
  require 'safe_yaml/load'
23
- require 'doing/hash'
24
- require 'doing/colors'
25
- require 'doing/template_string'
26
- require 'doing/string'
27
- require 'doing/string_chronify'
28
- require 'doing/time'
29
- require 'doing/array'
30
- require 'doing/symbol'
31
- require 'doing/util'
32
- require 'doing/util_backup'
33
- require 'doing/configuration'
34
- require 'doing/section'
35
- require 'doing/items'
36
- require 'doing/note'
37
- require 'doing/item'
38
- require 'doing/wwid'
39
- require 'doing/log_adapter'
40
- require 'doing/prompt'
41
- require 'doing/errors'
42
- require 'doing/hooks'
43
- require 'doing/plugin_manager'
44
- require 'doing/pager'
45
- require 'doing/completion'
46
- require 'doing/boolean_term_parser'
47
- require 'doing/phrase_parser'
24
+
25
+ require_relative 'doing/hash'
26
+ require_relative 'doing/colors'
27
+ require_relative 'doing/template_string'
28
+ require_relative 'doing/string'
29
+ require_relative 'doing/time'
30
+ require_relative 'doing/array'
31
+ require_relative 'doing/symbol'
32
+ require_relative 'doing/util'
33
+ require_relative 'doing/util_backup'
34
+ require_relative 'doing/configuration'
35
+ require_relative 'doing/section'
36
+ require_relative 'doing/items'
37
+ require_relative 'doing/note'
38
+ require_relative 'doing/item'
39
+ require_relative 'doing/wwid'
40
+ require_relative 'doing/log_adapter'
41
+ require_relative 'doing/prompt'
42
+ require_relative 'doing/errors'
43
+ require_relative 'doing/hooks'
44
+ require_relative 'doing/plugin_manager'
45
+ require_relative 'doing/pager'
46
+ require_relative 'doing/completion'
47
+ require_relative 'doing/boolean_term_parser'
48
+ require_relative 'doing/phrase_parser'
49
+ require_relative 'doing/array_chronify'
50
+ require_relative 'doing/numeric_chronify'
51
+ require_relative 'doing/string_chronify'
48
52
  # require 'doing/markdown_document_listener'
49
53
 
50
54
  # 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.11
4
+ version: 2.1.15
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-12 00:00:00.000000000 Z
11
+ date: 2022-01-17 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: safe_yaml
@@ -346,6 +346,46 @@ dependencies:
346
346
  - - ">="
347
347
  - !ruby/object:Gem::Version
348
348
  version: 0.7.0
349
+ - !ruby/object:Gem::Dependency
350
+ name: tty-reader
351
+ requirement: !ruby/object:Gem::Requirement
352
+ requirements:
353
+ - - "~>"
354
+ - !ruby/object:Gem::Version
355
+ version: '0.9'
356
+ - - ">="
357
+ - !ruby/object:Gem::Version
358
+ version: 0.9.0
359
+ type: :runtime
360
+ prerelease: false
361
+ version_requirements: !ruby/object:Gem::Requirement
362
+ requirements:
363
+ - - "~>"
364
+ - !ruby/object:Gem::Version
365
+ version: '0.9'
366
+ - - ">="
367
+ - !ruby/object:Gem::Version
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
349
389
  - !ruby/object:Gem::Dependency
350
390
  name: parslet
351
391
  requirement: !ruby/object:Gem::Requirement
@@ -396,6 +436,7 @@ extensions: []
396
436
  extra_rdoc_files:
397
437
  - README.md
398
438
  files:
439
+ - ".irbrc"
399
440
  - ".yardoc/checksums"
400
441
  - ".yardoc/complete"
401
442
  - ".yardoc/object_types"
@@ -457,6 +498,7 @@ files:
457
498
  - docs/doc/GLI/Commands.html
458
499
  - docs/doc/GLI/Commands/MarkdownDocumentListener.html
459
500
  - docs/doc/Hash.html
501
+ - docs/doc/Numeric.html
460
502
  - docs/doc/PhraseParser.html
461
503
  - docs/doc/PhraseParser/Operator.html
462
504
  - docs/doc/PhraseParser/PhraseClause.html
@@ -495,6 +537,7 @@ files:
495
537
  - lib/completion/doing.fish
496
538
  - lib/doing.rb
497
539
  - lib/doing/array.rb
540
+ - lib/doing/array_chronify.rb
498
541
  - lib/doing/boolean_term_parser.rb
499
542
  - lib/doing/cli_status.rb
500
543
  - lib/doing/colors.rb
@@ -512,6 +555,7 @@ files:
512
555
  - lib/doing/log_adapter.rb
513
556
  - lib/doing/markdown_document_listener.rb
514
557
  - lib/doing/note.rb
558
+ - lib/doing/numeric_chronify.rb
515
559
  - lib/doing/pager.rb
516
560
  - lib/doing/phrase_parser.rb
517
561
  - lib/doing/plugin_manager.rb