doing 2.1.22 → 2.1.26

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