doing 2.1.22 → 2.1.26

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 (147) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +17 -14
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/CHANGELOG.md +323 -111
  6. data/Gemfile.lock +1 -1
  7. data/README.md +1 -1
  8. data/Rakefile +2 -1
  9. data/bin/commands/add_section.rb +13 -0
  10. data/bin/commands/again.rb +99 -0
  11. data/bin/commands/archive.rb +96 -0
  12. data/bin/commands/cancel.rb +102 -0
  13. data/bin/commands/changes.rb +42 -0
  14. data/bin/commands/choose.rb +9 -0
  15. data/bin/commands/colors.rb +19 -0
  16. data/bin/commands/commands.rb +87 -0
  17. data/bin/commands/commands_accepting.rb +25 -0
  18. data/bin/commands/completion.rb +24 -0
  19. data/bin/commands/config.rb +245 -0
  20. data/bin/commands/done.rb +249 -0
  21. data/bin/commands/finish.rb +149 -0
  22. data/bin/commands/flag.rb +126 -0
  23. data/bin/commands/grep.rb +124 -0
  24. data/bin/commands/import.rb +101 -0
  25. data/bin/commands/install_fzf.rb +17 -0
  26. data/bin/commands/last.rb +114 -0
  27. data/bin/commands/meanwhile.rb +86 -0
  28. data/bin/commands/note.rb +130 -0
  29. data/bin/commands/now.rb +151 -0
  30. data/bin/commands/on.rb +66 -0
  31. data/bin/commands/open.rb +53 -0
  32. data/bin/commands/plugins.rb +23 -0
  33. data/bin/commands/recent.rb +78 -0
  34. data/bin/commands/redo.rb +22 -0
  35. data/bin/commands/reset.rb +106 -0
  36. data/bin/commands/rotate.rb +73 -0
  37. data/bin/commands/sections.rb +11 -0
  38. data/bin/commands/select.rb +123 -0
  39. data/bin/commands/show.rb +231 -0
  40. data/bin/commands/since.rb +64 -0
  41. data/bin/commands/tag.rb +179 -0
  42. data/bin/commands/tag_dir.rb +29 -0
  43. data/bin/commands/tags.rb +93 -0
  44. data/bin/commands/template.rb +61 -0
  45. data/bin/commands/today.rb +65 -0
  46. data/bin/commands/undo.rb +49 -0
  47. data/bin/commands/view.rb +238 -0
  48. data/bin/commands/views.rb +11 -0
  49. data/bin/commands/yesterday.rb +73 -0
  50. data/bin/doing +54 -3505
  51. data/docs/doc/Array.html +79 -11
  52. data/docs/doc/BooleanTermParser/Clause.html +5 -5
  53. data/docs/doc/BooleanTermParser/Operator.html +4 -4
  54. data/docs/doc/BooleanTermParser/Query.html +8 -8
  55. data/docs/doc/BooleanTermParser/QueryParser.html +2 -2
  56. data/docs/doc/BooleanTermParser/QueryTransformer.html +2 -2
  57. data/docs/doc/BooleanTermParser.html +1 -1
  58. data/docs/doc/Doing/Color.html +4 -4
  59. data/docs/doc/Doing/Completion.html +2 -2
  60. data/docs/doc/Doing/Configuration.html +17 -18
  61. data/docs/doc/Doing/Errors/DoingNoTraceError.html +2 -2
  62. data/docs/doc/Doing/Errors/DoingRuntimeError.html +2 -2
  63. data/docs/doc/Doing/Errors/DoingStandardError.html +2 -2
  64. data/docs/doc/Doing/Errors/EmptyInput.html +2 -2
  65. data/docs/doc/Doing/Errors/NoResults.html +2 -2
  66. data/docs/doc/Doing/Errors/PluginException.html +3 -3
  67. data/docs/doc/Doing/Errors/UserCancelled.html +2 -2
  68. data/docs/doc/Doing/Errors/WrongCommand.html +2 -2
  69. data/docs/doc/Doing/Errors.html +1 -1
  70. data/docs/doc/Doing/Hooks.html +6 -6
  71. data/docs/doc/Doing/Item.html +50 -16
  72. data/docs/doc/Doing/Items.html +10 -10
  73. data/docs/doc/Doing/LogAdapter.html +24 -24
  74. data/docs/doc/Doing/Note.html +7 -7
  75. data/docs/doc/Doing/Pager.html +4 -4
  76. data/docs/doc/Doing/Plugins.html +7 -7
  77. data/docs/doc/Doing/Prompt.html +59 -14
  78. data/docs/doc/Doing/Section.html +6 -6
  79. data/docs/doc/Doing/TemplateString.html +8 -8
  80. data/docs/doc/Doing/Types.html +206 -0
  81. data/docs/doc/Doing/Util/Backup.html +10 -10
  82. data/docs/doc/Doing/Util.html +16 -19
  83. data/docs/doc/Doing/WWID.html +65 -53
  84. data/docs/doc/Doing.html +3 -3
  85. data/docs/doc/FalseClass.html +201 -0
  86. data/docs/doc/GLI/Commands/Help.html +185 -0
  87. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +17 -17
  88. data/docs/doc/GLI/Commands.html +5 -3
  89. data/docs/doc/GLI.html +4 -2
  90. data/docs/doc/Hash.html +47 -21
  91. data/docs/doc/Numeric.html +5 -5
  92. data/docs/doc/Object.html +203 -0
  93. data/docs/doc/PhraseParser/Operator.html +4 -4
  94. data/docs/doc/PhraseParser/PhraseClause.html +5 -5
  95. data/docs/doc/PhraseParser/Query.html +10 -10
  96. data/docs/doc/PhraseParser/QueryParser.html +2 -2
  97. data/docs/doc/PhraseParser/QueryTransformer.html +2 -2
  98. data/docs/doc/PhraseParser/TermClause.html +5 -5
  99. data/docs/doc/PhraseParser.html +1 -1
  100. data/docs/doc/Status.html +7 -7
  101. data/docs/doc/String.html +144 -51
  102. data/docs/doc/Symbol.html +8 -8
  103. data/docs/doc/Time.html +6 -6
  104. data/docs/doc/TrueClass.html +201 -0
  105. data/docs/doc/_index.html +46 -16
  106. data/docs/doc/class_list.html +1 -1
  107. data/docs/doc/file.README.html +2 -2
  108. data/docs/doc/index.html +2 -2
  109. data/docs/doc/method_list.html +292 -212
  110. data/docs/doc/top-level-namespace.html +2 -2
  111. data/docs/index.md +1 -1
  112. data/doing.rdoc +178 -16
  113. data/example_plugin.rb +2 -2
  114. data/lib/completion/_doing.zsh +27 -27
  115. data/lib/completion/doing.bash +31 -20
  116. data/lib/completion/doing.fish +33 -11
  117. data/lib/doing/array.rb +2 -2
  118. data/lib/doing/changelog/change.rb +115 -0
  119. data/lib/doing/changelog/changes.rb +73 -0
  120. data/lib/doing/changelog/entry.rb +21 -0
  121. data/lib/doing/changelog/version.rb +97 -0
  122. data/lib/doing/changelog.rb +6 -0
  123. data/lib/doing/completion/fish_completion.rb +2 -1
  124. data/lib/doing/configuration.rb +20 -13
  125. data/lib/doing/good.rb +64 -0
  126. data/lib/doing/hash.rb +7 -2
  127. data/lib/doing/help_monkey_patch.rb +31 -0
  128. data/lib/doing/hooks.rb +8 -4
  129. data/lib/doing/item.rb +24 -35
  130. data/lib/doing/pager.rb +1 -0
  131. data/lib/doing/plugins/export/template_export.rb +1 -1
  132. data/lib/doing/plugins/import/calendar_import.rb +1 -1
  133. data/lib/doing/plugins/import/doing_import.rb +1 -1
  134. data/lib/doing/plugins/import/timing_import.rb +1 -1
  135. data/lib/doing/prompt.rb +8 -0
  136. data/lib/doing/string.rb +20 -11
  137. data/lib/doing/string_chronify.rb +1 -1
  138. data/lib/doing/template_string.rb +2 -2
  139. data/lib/doing/types.rb +3 -0
  140. data/lib/doing/util.rb +12 -11
  141. data/lib/doing/version.rb +1 -1
  142. data/lib/doing/wwid.rb +62 -37
  143. data/lib/doing.rb +2 -0
  144. data/lib/examples/commands/wiki.rb +6 -7
  145. data/lib/helpers/threaded_tests.rb +61 -71
  146. data/lib/helpers/threaded_tests_string.rb +50 -0
  147. metadata +56 -2
data/lib/doing/wwid.rb CHANGED
@@ -338,6 +338,7 @@ module Doing
338
338
  ## @option opt :note [Array] item note (will be converted if value is String)
339
339
  ## @option opt :back [Date] backdate
340
340
  ## @option opt :timed [Boolean] new item is timed entry, marks previous entry as @done
341
+ ## @option opt :done [Date] If set, adds a @done tag to new entry
341
342
  ##
342
343
  def add_item(title, section = nil, opt)
343
344
  opt ||= {}
@@ -360,9 +361,18 @@ module Doing
360
361
 
361
362
  title.compress!
362
363
  entry = Item.new(opt[:back], title.strip, section)
364
+
365
+ if opt[:done] && entry.should_finish?
366
+ if entry.should_time?
367
+ entry.tag('done', value: opt[:done])
368
+ else
369
+ entry.tag('done')
370
+ end
371
+ end
372
+
363
373
  entry.note = note
364
374
 
365
- items = @content.dup
375
+ items = @content.clone
366
376
  if opt[:timed]
367
377
  items.reverse!
368
378
  items.each_with_index do |i, x|
@@ -380,7 +390,8 @@ module Doing
380
390
  # logger.count(:added, level: :debug)
381
391
  logger.info('New entry:', %(added "#{entry.date.relative_date}: #{entry.title}" to #{section}))
382
392
 
383
- Hooks.trigger :post_entry_added, self, entry.dup
393
+ Hooks.trigger :post_entry_added, self, entry
394
+ entry
384
395
  end
385
396
 
386
397
  ##
@@ -474,6 +485,7 @@ module Doing
474
485
  #
475
486
  def repeat_item(item, opt)
476
487
  opt ||= {}
488
+ old_item = item.clone
477
489
  if item.should_finish?
478
490
  if item.should_time?
479
491
  finish_date = verify_duration(item.date, Time.now, title: item.title)
@@ -481,7 +493,7 @@ module Doing
481
493
  else
482
494
  item.title.tag!('done')
483
495
  end
484
- Hooks.trigger :post_entry_updated, self, item
496
+ Hooks.trigger :post_entry_updated, self, item, old_item
485
497
  end
486
498
 
487
499
  # Remove @done tag
@@ -651,7 +663,7 @@ module Doing
651
663
 
652
664
  if items.nil? || items.empty?
653
665
  section = opt[:section] ? guess_section(opt[:section]) : 'All'
654
- items = section =~ /^all$/i ? @content.dup : @content.in_section(section)
666
+ items = section =~ /^all$/i ? @content.clone : @content.in_section(section)
655
667
  end
656
668
 
657
669
  opt[:time_filter] = [nil, nil]
@@ -847,7 +859,7 @@ module Doing
847
859
  note.map!(&:strip)
848
860
  note.delete_if(&:ignore?)
849
861
  item = items[i]
850
- old_item = item.dup
862
+ old_item = item.clone
851
863
  item.date = date || items[i].date
852
864
  item.title = title
853
865
  item.note = note
@@ -855,7 +867,7 @@ module Doing
855
867
  Doing.logger.count(:skipped, level: :debug)
856
868
  else
857
869
  Doing.logger.count(:updated)
858
- Hooks.trigger :post_entry_updated, self, item
870
+ Hooks.trigger :post_entry_updated, self, item, old_item
859
871
  end
860
872
  end
861
873
  end
@@ -1045,9 +1057,10 @@ module Doing
1045
1057
  else
1046
1058
  opt[:resume]
1047
1059
  end
1060
+ old_item = item.clone
1048
1061
  new_entry = reset_item(item, date: date, resume: res)
1049
1062
  @content.update_item(item, new_entry)
1050
- Hooks.trigger :post_entry_updated, self, new_entry
1063
+ Hooks.trigger :post_entry_updated, self, new_entry, old_item
1051
1064
  end
1052
1065
  write(@doing_file)
1053
1066
 
@@ -1062,8 +1075,9 @@ module Doing
1062
1075
  if opt[:flag]
1063
1076
  tag = @config['marker_tag'] || 'flagged'
1064
1077
  items.map! do |i|
1078
+ old_item = i.clone
1065
1079
  i.tag(tag, date: false, remove: opt[:remove], single: single)
1066
- Hooks.trigger :post_entry_updated, self, i
1080
+ Hooks.trigger :post_entry_updated, self, i, old_item
1067
1081
  end
1068
1082
  end
1069
1083
 
@@ -1071,9 +1085,10 @@ module Doing
1071
1085
  tag = 'done'
1072
1086
  items.map! do |i|
1073
1087
  if i.should_finish?
1088
+ old_item = i.clone
1074
1089
  should_date = !opt[:cancel] && i.should_time?
1075
1090
  i.tag(tag, date: should_date, remove: opt[:remove], single: single)
1076
- Hooks.trigger :post_entry_updated, self, i
1091
+ Hooks.trigger :post_entry_updated, self, i, old_item
1077
1092
  end
1078
1093
  end
1079
1094
  end
@@ -1087,8 +1102,9 @@ module Doing
1087
1102
  else
1088
1103
  logger.count(:added_tags)
1089
1104
  logger.write(items.count == 1 ? :info : :debug, 'Tagged:', new_title)
1105
+ old_item = i.clone
1090
1106
  i.title = new_title
1091
- Hooks.trigger :post_entry_updated, self, i
1107
+ Hooks.trigger :post_entry_updated, self, i, old_item
1092
1108
  end
1093
1109
  end
1094
1110
  end
@@ -1096,17 +1112,19 @@ module Doing
1096
1112
  if opt[:tag]
1097
1113
  tag = opt[:tag]
1098
1114
  items.map! do |i|
1115
+ old_item = i.clone
1099
1116
  i.tag(tag, date: false, remove: opt[:remove], single: single)
1100
1117
  i.expand_date_tags(@config['date_tags'])
1101
- Hooks.trigger :post_entry_updated, self, i
1118
+ Hooks.trigger :post_entry_updated, self, i, old_item
1102
1119
  end
1103
1120
  end
1104
1121
 
1105
1122
  if opt[:archive] || opt[:move]
1106
1123
  section = opt[:archive] ? 'Archive' : guess_section(opt[:move])
1107
1124
  items.map! do |i|
1125
+ old_item = i.clone
1108
1126
  i.move_to(section, label: true)
1109
- Hooks.trigger :post_entry_updated, self, i
1127
+ Hooks.trigger :post_entry_updated, self, i, old_item
1110
1128
  end
1111
1129
  end
1112
1130
 
@@ -1228,6 +1246,7 @@ module Doing
1228
1246
  end
1229
1247
 
1230
1248
  items.each do |item|
1249
+ old_item = item.clone
1231
1250
  added = []
1232
1251
  removed = []
1233
1252
 
@@ -1265,7 +1284,7 @@ module Doing
1265
1284
 
1266
1285
  tag = tag.strip
1267
1286
 
1268
- if tag =~ /^done$/
1287
+ if tag =~ /^done$/ && opt[:date] && item.should_time?
1269
1288
  max_elapsed = @config.dig('interaction', 'confirm_longer_than') || 0
1270
1289
  max_elapsed = max_elapsed.chronify_qty if max_elapsed.is_a?(String)
1271
1290
  elapsed = done_date - item.date
@@ -1322,7 +1341,7 @@ module Doing
1322
1341
  end
1323
1342
 
1324
1343
  item.expand_date_tags(@config['date_tags'])
1325
- Hooks.trigger :post_entry_updated, self, item
1344
+ Hooks.trigger :post_entry_updated, self, item, old_item
1326
1345
  end
1327
1346
 
1328
1347
  write(@doing_file)
@@ -1361,6 +1380,7 @@ module Doing
1361
1380
  return
1362
1381
  end
1363
1382
 
1383
+ old_item = item.clone
1364
1384
  content = ["#{item.date.strftime('%F %R')} | #{item.title.dup}"]
1365
1385
  content << item.note.strip_lines.join("\n") unless item.note.empty?
1366
1386
  new_item = fork_editor(content.join("\n"))
@@ -1376,7 +1396,7 @@ module Doing
1376
1396
  item.title = title
1377
1397
  item.note.add(note, replace: true)
1378
1398
  logger.info('Edited:', item.title)
1379
- Hooks.trigger :post_entry_updated, self, item.dup
1399
+ Hooks.trigger :post_entry_updated, self, item, old_item
1380
1400
 
1381
1401
  write(@doing_file)
1382
1402
  end
@@ -1413,6 +1433,7 @@ module Doing
1413
1433
  found_items = 0
1414
1434
 
1415
1435
  @content.each_with_index do |item, i|
1436
+ old_item = i.clone
1416
1437
  next unless item.section == opt[:section] || opt[:section] =~ /all/i
1417
1438
 
1418
1439
  next unless item.title =~ /@#{tag}/
@@ -1431,7 +1452,7 @@ module Doing
1431
1452
  logger.count(:completed)
1432
1453
  logger.info('Completed:', item.title)
1433
1454
  end
1434
- Hooks.trigger :post_entry_updated, self, item
1455
+ Hooks.trigger :post_entry_updated, self, item, old_item
1435
1456
  end
1436
1457
 
1437
1458
 
@@ -1492,7 +1513,7 @@ module Doing
1492
1513
 
1493
1514
  unless ((!tags.empty? && !item.tags?(tags, bool)) || (opt[:search] && !item.search(opt[:search].to_s)) || (opt[:before] && item.date >= cutoff))
1494
1515
  new_item = @content.delete(item)
1495
- Hooks.trigger :post_entry_removed, self, item.dup
1516
+ Hooks.trigger :post_entry_removed, self, item.clone
1496
1517
  raise DoingRuntimeError, "Error deleting item: #{item}" if new_item.nil?
1497
1518
 
1498
1519
  new_content.add_section(new_item.section, log: false)
@@ -1719,7 +1740,7 @@ module Doing
1719
1740
  opt[:totals] ||= false
1720
1741
  opt[:sort_tags] ||= false
1721
1742
 
1722
- cfg = @config['templates']['today'].deep_merge(@config['templates']['default'], { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
1743
+ cfg = @config['templates'][opt[:config_template]].deep_merge(@config['templates']['default'], { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
1723
1744
  'wrap_width' => @config['wrap_width'] || 0,
1724
1745
  'date_format' => @config['default_date_format'],
1725
1746
  'order' => @config['order'] || 'asc',
@@ -1728,6 +1749,8 @@ module Doing
1728
1749
  'interval_format' => @config['interval_format']
1729
1750
  }, { extend_existing_arrays: true, sort_merged_arrays: true })
1730
1751
 
1752
+ template = opt[:template] || cfg['template']
1753
+
1731
1754
  opt[:duration] ||= cfg['duration'] || false
1732
1755
  opt[:interval_format] ||= cfg['interval_format'] || 'text'
1733
1756
 
@@ -1743,13 +1766,13 @@ module Doing
1743
1766
  output: output,
1744
1767
  section: opt[:section],
1745
1768
  sort_tags: opt[:sort_tags],
1746
- template: cfg['template'],
1769
+ template: template,
1747
1770
  times: times,
1748
1771
  today: true,
1749
1772
  totals: opt[:totals],
1750
1773
  wrap_width: cfg['wrap_width'],
1751
1774
  tags_color: cfg['tags_color'],
1752
- config_template: 'today'
1775
+ config_template: opt[:config_template]
1753
1776
  }
1754
1777
  list_section(options)
1755
1778
  end
@@ -1781,7 +1804,8 @@ module Doing
1781
1804
  totals: opt[:totals],
1782
1805
  duration: opt[:duration],
1783
1806
  sort_tags: opt[:sort_tags],
1784
- config_template: 'default'
1807
+ template: opt[:template],
1808
+ config_template: opt[:config_template]
1785
1809
  })
1786
1810
  end
1787
1811
 
@@ -1816,7 +1840,8 @@ module Doing
1816
1840
  times: times,
1817
1841
  totals: opt[:totals],
1818
1842
  yesterday: true,
1819
- config_template: 'today'
1843
+ config_template: opt[:config_template] || 'today',
1844
+ template: opt[:template]
1820
1845
  }
1821
1846
 
1822
1847
  list_section(options)
@@ -1835,7 +1860,7 @@ module Doing
1835
1860
  opt[:totals] ||= false
1836
1861
  opt[:sort_tags] ||= false
1837
1862
 
1838
- cfg = @config['templates']['recent'].deep_merge(@config['templates']['default'], { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
1863
+ cfg = @config['templates'][opt[:config_template]].deep_merge(@config['templates']['default'], { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
1839
1864
  'wrap_width' => @config['wrap_width'] || 0,
1840
1865
  'date_format' => @config['default_date_format'],
1841
1866
  'order' => @config['order'] || 'asc',
@@ -1853,10 +1878,9 @@ module Doing
1853
1878
  opt[:wrap_width] = cfg['wrap_width']
1854
1879
  opt[:count] = count
1855
1880
  opt[:format] = cfg['date_format']
1856
- opt[:template] = cfg['template']
1881
+ opt[:template] = opt[:template] || cfg['template']
1857
1882
  opt[:order] = 'asc'
1858
1883
  opt[:times] = times
1859
- opt[:config_template] = 'recent'
1860
1884
 
1861
1885
  list_section(opt)
1862
1886
  end
@@ -1869,7 +1893,7 @@ module Doing
1869
1893
  ##
1870
1894
  def last(times: true, section: nil, options: {})
1871
1895
  section = section.nil? || section =~ /all/i ? 'All' : guess_section(section)
1872
- cfg = @config['templates']['last'].deep_merge(@config['templates']['default'], { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
1896
+ cfg = @config['templates'][options[:config_template]].deep_merge(@config['templates']['default'], { extend_existing_arrays: true, sort_merged_arrays: true }).deep_merge({
1873
1897
  'wrap_width' => @config['wrap_width'] || 0,
1874
1898
  'date_format' => @config['default_date_format'],
1875
1899
  'order' => @config['order'] || 'asc',
@@ -1881,19 +1905,19 @@ module Doing
1881
1905
  options[:interval_format] ||= cfg['interval_format'] || 'text'
1882
1906
 
1883
1907
  opts = {
1884
- section: section,
1885
- wrap_width: cfg['wrap_width'],
1908
+ case: options[:case],
1909
+ config_template: 'last',
1886
1910
  count: 1,
1887
- format: cfg['date_format'],
1888
- template: cfg['template'],
1889
- times: times,
1911
+ delete: options[:delete],
1890
1912
  duration: options[:duration],
1913
+ format: cfg['date_format'],
1891
1914
  interval_format: options[:interval_format],
1892
- case: options[:case],
1893
1915
  not: options[:negate],
1894
- config_template: 'last',
1895
- delete: options[:delete],
1896
- val: options[:val]
1916
+ section: section,
1917
+ template: options[:template] || cfg['template'],
1918
+ times: times,
1919
+ val: options[:val],
1920
+ wrap_width: cfg['wrap_width']
1897
1921
  }
1898
1922
 
1899
1923
  if options[:tag]
@@ -2199,7 +2223,7 @@ EOS
2199
2223
 
2200
2224
  filename ||= @config['doing_file']
2201
2225
  init_doing_file(filename)
2202
- current_content = @content.dup
2226
+ current_content = @content.clone
2203
2227
  backup_file = Util::Backup.last_backup(filename, count: 1)
2204
2228
  raise DoingRuntimeError, 'No undo history to diff' if backup_file.nil?
2205
2229
 
@@ -2318,8 +2342,9 @@ EOS
2318
2342
  item
2319
2343
  else
2320
2344
  counter += 1
2345
+ old_item = item.clone
2321
2346
  item.move_to(destination, label: label, log: false)
2322
- Hooks.trigger :post_entry_updated, self, item.dup
2347
+ Hooks.trigger :post_entry_updated, self, item, old_item
2323
2348
  item
2324
2349
  end
2325
2350
  end
data/lib/doing.rb CHANGED
@@ -23,6 +23,7 @@ require 'tty-markdown'
23
23
  require 'tty-reader'
24
24
  require 'tty-screen'
25
25
 
26
+ require_relative 'doing/changelog'
26
27
  require_relative 'doing/hash'
27
28
  require_relative 'doing/types'
28
29
  require_relative 'doing/colors'
@@ -30,6 +31,7 @@ require_relative 'doing/template_string'
30
31
  require_relative 'doing/string'
31
32
  require_relative 'doing/time'
32
33
  require_relative 'doing/array'
34
+ require_relative 'doing/good'
33
35
  require_relative 'doing/symbol'
34
36
  require_relative 'doing/util'
35
37
  require_relative 'doing/util_backup'
@@ -36,8 +36,7 @@ command :wiki do |c|
36
36
  c.switch [:only_timed], default_value: false, negatable: false
37
37
 
38
38
  c.action do |global, options, args|
39
- wwid = global[:wwid]
40
- tags = wwid.tag_groups([], opt: options)
39
+ tags = @wwid.tag_groups([], opt: options)
41
40
 
42
41
  wiki = Doing::Plugins.plugins.dig(:export, 'wiki', :class)
43
42
 
@@ -46,7 +45,7 @@ command :wiki do |c|
46
45
 
47
46
  raise RuntimeError, 'Missing plugin "wiki"' unless wiki
48
47
 
49
- out = wiki.render(wwid, items, variables: export_options)
48
+ out = wiki.render(@wwid, items, variables: export_options)
50
49
 
51
50
  if out
52
51
  FileUtils.mkdir_p('doing_wiki')
@@ -56,13 +55,13 @@ command :wiki do |c|
56
55
  end
57
56
  end
58
57
 
59
- template = if wwid.config['export_templates']['wiki_index'] && File.exist?(File.expand_path(wwid.config['export_templates']['wiki_index']))
60
- IO.read(File.expand_path(wwid.config['export_templates']['wiki_index']))
58
+ template = if @settings['export_templates']['wiki_index'] && File.exist?(File.expand_path(@settings['export_templates']['wiki_index']))
59
+ IO.read(File.expand_path(@settings['export_templates']['wiki_index']))
61
60
  else
62
61
  wiki.template('wiki_index')
63
62
  end
64
- style = if wwid.config['export_templates']['wiki_css'] && File.exist?(File.expand_path(wwid.config['export_templates']['wiki_css']))
65
- IO.read(File.expand_path(wwid.config['export_templates']['wiki_css']))
63
+ style = if @settings['export_templates']['wiki_css'] && File.exist?(File.expand_path(@settings['export_templates']['wiki_css']))
64
+ IO.read(File.expand_path(@settings['export_templates']['wiki_css']))
66
65
  else
67
66
  wiki.template('wiki_css')
68
67
  end
@@ -2,66 +2,23 @@
2
2
 
3
3
  require 'tty-spinner'
4
4
  require 'tty-progressbar'
5
- require './lib/doing'
6
5
  require 'open3'
7
6
  require 'shellwords'
7
+ require 'fileutils'
8
8
 
9
- class ::String
10
- include Doing::Color
11
-
12
- def highlight_errors
13
- cols = `tput cols`.strip.to_i
14
-
15
- string = dup
16
-
17
- errs = string.scan(/(?<==\n)(?:Failure|Error):.*?(?=\n=+)/m)
18
-
19
- errs.map! do |error|
20
- err = error.dup
21
-
22
- err.gsub!(%r{^(/.*?/)([^/:]+):(\d+):in (.*?)$}) do
23
- m = Regexp.last_match
24
- "#{m[1].white}#{m[2].bold.white}:#{m[3].yellow}:in #{m[4].cyan}"
25
- end
26
- err.gsub!(/(Failure|Error): (.*?)\((.*?)\):\n (.*?)(?=\n)/m) do
27
- m = Regexp.last_match
28
- [
29
- m[1].bold.boldbgred.white,
30
- m[3].bold.boldbgcyan.white,
31
- m[2].bold.boldbgyellow.black,
32
- " #{m[4]} ".bold.boldbgwhite.black.reset
33
- ].join(':'.boldblack.boldbgblack.reset)
34
- end
35
- err.gsub!(/(<.*?>) (was expected to) (.*?)\n( *<.*?>)./m) do
36
- m = Regexp.last_match
37
- "#{m[1].bold.green} #{m[2].white} #{m[3].boldwhite.boldbgred.reset}\n#{m[4].bold.white}"
38
- end
39
- err.gsub!(/(Finished in) ([\d.]+) (seconds)/) do
40
- m = Regexp.last_match
41
- "#{m[1].green} #{m[2].bold.white} #{m[3].green}"
42
- end
43
- err.gsub!(/(\d+) (failures)/) do
44
- m = Regexp.last_match
45
- "#{m[1].bold.red} #{m[2].red}"
46
- end
47
- err.gsub!(/100% passed/) do |m|
48
- m.bold.green
49
- end
50
-
51
- err
52
- end
53
-
54
- errs.join("\n#{('=' * cols).blue}\n")
55
- end
56
- end
9
+ $LOAD_PATH.unshift File.join(__dir__, '..')
10
+ require 'doing'
11
+ require 'helpers/threaded_tests_string'
57
12
 
58
13
  class ThreadedTests
59
14
  include Doing::Color
15
+ include ThreadedTestString
60
16
 
61
17
  def run(pattern: '*', max_threads: 8, max_tests: 0)
62
18
  start_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
19
+ @results = File.expand_path('results.log')
63
20
 
64
- max_threads = 1000 if max_threads == 0
21
+ max_threads = 1000 if max_threads.to_i == 0
65
22
 
66
23
  c = Doing::Color
67
24
  c.coloring = true
@@ -70,8 +27,8 @@ class ThreadedTests
70
27
 
71
28
  tests = Dir.glob(pattern)
72
29
 
73
- if max_tests > 0
74
- tests = tests.slice(0, max_tests - 1)
30
+ if max_tests.to_i > 0
31
+ tests = tests.slice(0, max_tests.to_i - 1)
75
32
  end
76
33
 
77
34
  puts "#{tests.count} test files".boldcyan
@@ -90,13 +47,21 @@ class ThreadedTests
90
47
  ].join('')
91
48
  progress = TTY::ProgressBar::Multi.new(banner,
92
49
  width: 12,
50
+ clear: true,
93
51
  hide_cursor: true)
94
52
  @children = []
95
53
  tests.each do |t|
96
54
  test_name = File.basename(t, '.rb').sub(/doing_(.*?)_test/, '\1')
97
55
  new_sp = progress.register("[#{':bar'.cyan}] #{test_name.bold.white}:status",
98
- total: 2, width: 1, head: '.', hide_cursor: true, clear: true)
99
- @children.push([test_name, new_sp, nil])
56
+ total: tests.count + 8,
57
+ width: 1,
58
+ head: ' ',
59
+ unknown: ' ',
60
+ hide_cursor: true,
61
+ clear: true)
62
+ status = ': waiting'.dark.yellow.reset
63
+ @children.push([test_name, new_sp, status])
64
+ # new_sp.advance(status: ': waiting'.dark.yellow.reset)
100
65
  end
101
66
 
102
67
  @elapsed = 0.0
@@ -105,6 +70,7 @@ class ThreadedTests
105
70
  @error_out = []
106
71
  # progress.start
107
72
  @threads = []
73
+ @running_tests = []
108
74
 
109
75
  begin
110
76
  while @children.count.positive?
@@ -123,34 +89,60 @@ class ThreadedTests
123
89
  finish_time = Process.clock_gettime(Process::CLOCK_MONOTONIC)
124
90
 
125
91
  progress.finish
92
+ rescue
93
+ progress.stop
94
+ ensure
95
+ msg = @running_tests.map { |t| t[1].format.uncolor.sub(/^\[:bar\] (.*?):status/, "#{c.bold}#{c.white}\\1#{c.reset}#{t[2]}") }.join("\n")
96
+
97
+ Doing::Prompt.clear_screen(msg)
126
98
 
127
99
  output = []
128
- if @error_out.count.positive?
129
- output << c.boldred("#{@error_out.count} Issues")
130
- else
131
- output << c.green('Success')
132
- end
100
+ output << if @error_out.count.positive?
101
+ c.boldred("#{@error_out.count} Issues")
102
+ else
103
+ c.green('Success')
104
+ end
133
105
  output << c.green("#{@test_total} tests")
134
106
  output << c.cyan("#{@assrt_total} assertions")
135
107
  output << c.yellow("#{(finish_time - start_time).round(3)}s")
136
108
  puts output.join(', ')
137
109
 
138
- puts @error_out.join("\n----\n".boldwhite) if @error_out.count.positive?
139
- rescue
140
- progress.stop
110
+ if @error_out.count.positive?
111
+ res = Doing::Prompt.yn('Display error report?', default_response: false)
112
+ Doing::Pager.paginate = true
113
+ Doing::Pager.page(@error_out.join("\n----\n".boldwhite)) if res
114
+ end
141
115
  end
142
116
  end
143
117
 
144
118
  def run_test(s)
145
119
  bar = s[1]
146
- bar.advance(status: ": #{'running'.green}")
120
+ s[2] = ": #{'running'.green}"
121
+ bar.advance(status: s[2])
122
+
123
+ if @running_tests.count.positive?
124
+ @running_tests.each do |b|
125
+ prev_bar = b[1]
126
+ if prev_bar.complete?
127
+ prev_bar.reset
128
+ prev_bar.advance(status: b[2])
129
+ prev_bar.finish
130
+ else
131
+ prev_bar.update(head: ' ', unfinished: ' ')
132
+ prev_bar.advance(status: b[2])
133
+ end
134
+ end
135
+ end
147
136
 
137
+ @running_tests.push(s)
148
138
  out, _err, status = Open3.capture3(ENV, 'rake', "test:#{s[0]}", stdin_data: nil)
149
- unless status.success?
150
- m = out.match(/(?<fail>\d+) failures, (?<err>\d+) errors/)
151
- status = ": #{m['fail'].bold.red} #{'failures'.red}, #{m['err'].bold.red} #{'errors'.red}"
139
+ time = out.match(/^Finished in (?<time>\d+\.\d+) seconds\./)
140
+ count = out.match(/^(?<tests>\d+) tests, (?<assrt>\d+) assertions, (?<fails>\d+) failures, (?<errs>\d+) errors/)
141
+
142
+ unless status.success? && !count['fails'].to_i.positive? && !count['errs'].to_i.positive?
143
+ s[2] = ": #{count['fails'].bold.red} #{'failures'.red}, #{count['errs'].bold.red} #{'errors'.red}"
152
144
  bar.update(head: '✖'.boldred)
153
- bar.advance(head: '✖'.boldred, status: status)
145
+ bar.advance(head: '✖'.boldred, status: s[2])
154
146
 
155
147
  # errs = out.scan(/(?:Failure|Error): [\w_]+\((?:.*?)\):(?:.*?)(?=\n=======)/m)
156
148
  @error_out.push(out.highlight_errors)
@@ -160,9 +152,7 @@ class ThreadedTests
160
152
  Thread.exit
161
153
  end
162
154
 
163
- time = out.match(/^Finished in (?<time>\d+\.\d+) seconds\./)
164
- count = out.match(/^(?<tests>\d+) tests, (?<assrt>\d+) assertions, (?<fails>\d+) failures, (?<errs>\d+) errors/)
165
- status = [
155
+ s[2] = [
166
156
  ': ',
167
157
  count['tests'].green,
168
158
  '/',
@@ -177,7 +167,7 @@ class ThreadedTests
177
167
  's'
178
168
  ].join('')
179
169
  bar.update(head: '✔'.boldgreen)
180
- bar.advance(head: '✔'.boldgreen, status: status)
170
+ bar.advance(head: '✔'.boldgreen, status: s[2])
181
171
  @test_total += count['tests'].to_i
182
172
  @assrt_total += count['assrt'].to_i
183
173
  @elapsed += time['time'].to_f
@@ -0,0 +1,50 @@
1
+ module ThreadedTestString
2
+ class ::String
3
+ include Doing::Color
4
+
5
+ def highlight_errors
6
+ cols = `tput cols`.strip.to_i
7
+
8
+ string = dup
9
+
10
+ errs = string.scan(/(?<==\n)(?:Failure|Error):.*?(?=\n=+)/m)
11
+
12
+ errs.map! do |error|
13
+ err = error.dup
14
+
15
+ err.gsub!(%r{^(/.*?/)([^/:]+):(\d+):in (.*?)$}) do
16
+ m = Regexp.last_match
17
+ "#{m[1].white}#{m[2].bold.white}:#{m[3].yellow}:in #{m[4].cyan}"
18
+ end
19
+ err.gsub!(/(Failure|Error): (.*?)\((.*?)\):\n (.*?)(?=\n)/m) do
20
+ m = Regexp.last_match
21
+ [
22
+ m[1].bold.boldbgred.white,
23
+ m[3].bold.boldbgcyan.white,
24
+ m[2].bold.boldbgyellow.black,
25
+ " #{m[4]} ".bold.boldbgwhite.black.reset
26
+ ].join(':'.boldblack.boldbgblack.reset)
27
+ end
28
+ err.gsub!(/(<.*?>) (was expected to) (.*?)\n( *<.*?>)./m) do
29
+ m = Regexp.last_match
30
+ "#{m[1].bold.green} #{m[2].white} #{m[3].boldwhite.boldbgred.reset}\n#{m[4].bold.white}"
31
+ end
32
+ err.gsub!(/(Finished in) ([\d.]+) (seconds)/) do
33
+ m = Regexp.last_match
34
+ "#{m[1].green} #{m[2].bold.white} #{m[3].green}"
35
+ end
36
+ err.gsub!(/(\d+) (failures)/) do
37
+ m = Regexp.last_match
38
+ "#{m[1].bold.red} #{m[2].red}"
39
+ end
40
+ err.gsub!(/100% passed/) do |m|
41
+ m.bold.green
42
+ end
43
+
44
+ err
45
+ end
46
+
47
+ errs.join("\n#{('=' * cols).blue}\n")
48
+ end
49
+ end
50
+ end