doing 2.1.11 → 2.1.15

Sign up to get free protection for your applications and to get access to all the features.
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