doing 2.1.24 → 2.1.25

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 (90) hide show
  1. checksums.yaml +4 -4
  2. data/.yardoc/checksums +11 -10
  3. data/.yardoc/object_types +0 -0
  4. data/.yardoc/objects/root.dat +0 -0
  5. data/CHANGELOG.md +17 -0
  6. data/Gemfile.lock +1 -1
  7. data/README.md +1 -1
  8. data/Rakefile +2 -1
  9. data/bin/doing +81 -37
  10. data/docs/doc/Array.html +70 -7
  11. data/docs/doc/BooleanTermParser/Clause.html +5 -5
  12. data/docs/doc/BooleanTermParser/Operator.html +4 -4
  13. data/docs/doc/BooleanTermParser/Query.html +8 -8
  14. data/docs/doc/BooleanTermParser/QueryParser.html +2 -2
  15. data/docs/doc/BooleanTermParser/QueryTransformer.html +2 -2
  16. data/docs/doc/BooleanTermParser.html +1 -1
  17. data/docs/doc/Doing/Color.html +4 -4
  18. data/docs/doc/Doing/Completion.html +2 -2
  19. data/docs/doc/Doing/Configuration.html +14 -16
  20. data/docs/doc/Doing/Errors/DoingNoTraceError.html +2 -2
  21. data/docs/doc/Doing/Errors/DoingRuntimeError.html +2 -2
  22. data/docs/doc/Doing/Errors/DoingStandardError.html +2 -2
  23. data/docs/doc/Doing/Errors/EmptyInput.html +2 -2
  24. data/docs/doc/Doing/Errors/NoResults.html +2 -2
  25. data/docs/doc/Doing/Errors/PluginException.html +3 -3
  26. data/docs/doc/Doing/Errors/UserCancelled.html +2 -2
  27. data/docs/doc/Doing/Errors/WrongCommand.html +2 -2
  28. data/docs/doc/Doing/Errors.html +1 -1
  29. data/docs/doc/Doing/Hooks.html +6 -6
  30. data/docs/doc/Doing/Item.html +50 -16
  31. data/docs/doc/Doing/Items.html +10 -10
  32. data/docs/doc/Doing/LogAdapter.html +24 -24
  33. data/docs/doc/Doing/Note.html +7 -7
  34. data/docs/doc/Doing/Pager.html +4 -4
  35. data/docs/doc/Doing/Plugins.html +7 -7
  36. data/docs/doc/Doing/Prompt.html +14 -14
  37. data/docs/doc/Doing/Section.html +6 -6
  38. data/docs/doc/Doing/TemplateString.html +8 -8
  39. data/docs/doc/Doing/Types.html +6 -1
  40. data/docs/doc/Doing/Util/Backup.html +10 -10
  41. data/docs/doc/Doing/Util.html +15 -15
  42. data/docs/doc/Doing/WWID.html +65 -53
  43. data/docs/doc/Doing.html +3 -3
  44. data/docs/doc/GLI/Commands/Help.html +3 -3
  45. data/docs/doc/GLI/Commands/MarkdownDocumentListener.html +17 -17
  46. data/docs/doc/GLI/Commands.html +1 -1
  47. data/docs/doc/GLI.html +1 -1
  48. data/docs/doc/Hash.html +45 -11
  49. data/docs/doc/Numeric.html +5 -5
  50. data/docs/doc/PhraseParser/Operator.html +4 -4
  51. data/docs/doc/PhraseParser/PhraseClause.html +5 -5
  52. data/docs/doc/PhraseParser/Query.html +10 -10
  53. data/docs/doc/PhraseParser/QueryParser.html +2 -2
  54. data/docs/doc/PhraseParser/QueryTransformer.html +2 -2
  55. data/docs/doc/PhraseParser/TermClause.html +5 -5
  56. data/docs/doc/PhraseParser.html +1 -1
  57. data/docs/doc/Status.html +7 -7
  58. data/docs/doc/String.html +107 -44
  59. data/docs/doc/Symbol.html +8 -8
  60. data/docs/doc/Time.html +6 -6
  61. data/docs/doc/_index.html +41 -18
  62. data/docs/doc/class_list.html +1 -1
  63. data/docs/doc/file.README.html +2 -2
  64. data/docs/doc/index.html +2 -2
  65. data/docs/doc/method_list.html +369 -313
  66. data/docs/doc/top-level-namespace.html +2 -2
  67. data/doing.rdoc +19 -11
  68. data/example_plugin.rb +2 -2
  69. data/lib/completion/_doing.zsh +12 -12
  70. data/lib/completion/doing.bash +2 -2
  71. data/lib/completion/doing.fish +9 -8
  72. data/lib/doing/changelog/changes.rb +1 -1
  73. data/lib/doing/configuration.rb +4 -6
  74. data/lib/doing/good.rb +64 -0
  75. data/lib/doing/hash.rb +4 -0
  76. data/lib/doing/hooks.rb +3 -3
  77. data/lib/doing/item.rb +14 -10
  78. data/lib/doing/plugins/import/calendar_import.rb +1 -1
  79. data/lib/doing/plugins/import/doing_import.rb +1 -1
  80. data/lib/doing/plugins/import/timing_import.rb +1 -1
  81. data/lib/doing/string.rb +1 -1
  82. data/lib/doing/template_string.rb +2 -2
  83. data/lib/doing/types.rb +1 -0
  84. data/lib/doing/util.rb +10 -10
  85. data/lib/doing/version.rb +1 -1
  86. data/lib/doing/wwid.rb +40 -18
  87. data/lib/doing.rb +1 -0
  88. data/lib/helpers/threaded_tests.rb +35 -64
  89. data/lib/helpers/threaded_tests_string.rb +50 -0
  90. metadata +4 -2
@@ -131,7 +131,7 @@ module Doing
131
131
 
132
132
  after = m['after']
133
133
 
134
- if value.nil? || value.empty?
134
+ if !value.good?
135
135
  after
136
136
  else
137
137
  pad = m['width'].to_i
@@ -183,7 +183,7 @@ module Doing
183
183
  ' '
184
184
  else
185
185
  line = l.gsub(/%/, '\%').strip.wrap(width, pad: pad, indent: indent, offset: 0, prefix: prefix, color: last_color, after: after, reset: reset, pad_first: true)
186
- line.highlight_tags!(tags_color, last_color: last_color) unless !tags_color || tags_color.nil? || tags_color.empty?
186
+ line.highlight_tags!(tags_color, last_color: last_color) unless !tags_color || !tags_color.good?
187
187
  "#{line} "
188
188
  end
189
189
  end.join("\n")
data/lib/doing/types.rb CHANGED
@@ -20,6 +20,7 @@ module Doing
20
20
  DateBeginString = Class.new(DateTime)
21
21
  DateEndString = Class.new(DateTime)
22
22
  DateRangeString = Class.new(Array)
23
+ DateRangeOptionalString = Class.new(Array)
23
24
  DateIntervalString = Class.new(DateTime)
24
25
  end
25
26
  end
data/lib/doing/util.rb CHANGED
@@ -19,7 +19,7 @@ module Doing
19
19
  ## @param cli [String] The name or path of the cli
20
20
  ##
21
21
  def exec_available(cli)
22
- return false if cli.nil?
22
+ return false unless cli.good?
23
23
 
24
24
  !TTY::Which.which(cli).nil?
25
25
  end
@@ -32,7 +32,7 @@ module Doing
32
32
  ##
33
33
  def first_available_exec(*commands)
34
34
  commands.compact.map(&:strip).reject(&:empty?).uniq
35
- .find { |cmd| exec_available(cmd.split.first) }
35
+ .find { |cmd| exec_available(cmd.split.first) }
36
36
  end
37
37
 
38
38
  def merge_default_proc(target, overwrite)
@@ -56,7 +56,7 @@ module Doing
56
56
  # @param [Hash] other_hash The other hash
57
57
  #
58
58
  def deep_merge_hashes(master_hash, other_hash)
59
- deep_merge_hashes!(master_hash.dup, other_hash)
59
+ deep_merge_hashes!(master_hash.clone, other_hash)
60
60
  end
61
61
 
62
62
  # Merges a master hash with another hash, recursively.
@@ -157,32 +157,32 @@ module Doing
157
157
  def find_default_editor(editor_for = 'default')
158
158
  # return nil unless $stdout.isatty || ENV['DOING_EDITOR_TEST']
159
159
 
160
- if ENV['DOING_EDITOR_TEST']
161
- return ENV['EDITOR']
162
- end
160
+ return ENV['EDITOR'] if ENV['DOING_EDITOR_TEST']
163
161
 
164
162
  editor_config = Doing.config.settings['editors']
165
163
 
166
164
  if editor_config.is_a?(String)
167
- Doing.logger.warn('Deprecated:', "Please update your configuration, 'editors' should be a mapping. Delete the key and run `doing config --update`.")
165
+ msg = "Please update your configuration, 'editors' should be a mapping."
166
+ msg << ' Delete the key and run `doing config --update`.'
167
+ Doing.logger.warn('Deprecated:', msg)
168
168
  return editor_config
169
169
  end
170
170
 
171
171
  if editor_config[editor_for]
172
172
  editor = editor_config[editor_for]
173
173
  # Doing.logger.debug('Editor:', "Using #{editor} from config 'editors->#{editor_for}'")
174
- return editor unless editor.nil? || editor.empty?
174
+ return editor unless editor.good?
175
175
  end
176
176
 
177
177
  if editor_for != 'editor' && editor_config['default']
178
178
  editor = editor_config['default']
179
179
  # Doing.logger.debug('Editor:', "Using #{editor} from config: 'editors->default'")
180
- return editor unless editor.nil? || editor.empty?
180
+ return editor unless editor.good?
181
181
  end
182
182
 
183
183
  editor ||= ENV['DOING_EDITOR'] || ENV['GIT_EDITOR'] || ENV['EDITOR']
184
184
 
185
- unless editor.nil? || editor.empty?
185
+ unless editor.good?
186
186
  # Doing.logger.debug('Editor:', "Found editor in environment variables: #{editor}")
187
187
  return editor
188
188
  end
data/lib/doing/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Doing
2
- VERSION = '2.1.24'
2
+ VERSION = '2.1.25'
3
3
  end
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
 
@@ -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)
@@ -2202,7 +2223,7 @@ EOS
2202
2223
 
2203
2224
  filename ||= @config['doing_file']
2204
2225
  init_doing_file(filename)
2205
- current_content = @content.dup
2226
+ current_content = @content.clone
2206
2227
  backup_file = Util::Backup.last_backup(filename, count: 1)
2207
2228
  raise DoingRuntimeError, 'No undo history to diff' if backup_file.nil?
2208
2229
 
@@ -2321,8 +2342,9 @@ EOS
2321
2342
  item
2322
2343
  else
2323
2344
  counter += 1
2345
+ old_item = item.clone
2324
2346
  item.move_to(destination, label: label, log: false)
2325
- Hooks.trigger :post_entry_updated, self, item.dup
2347
+ Hooks.trigger :post_entry_updated, self, item, old_item
2326
2348
  item
2327
2349
  end
2328
2350
  end
data/lib/doing.rb CHANGED
@@ -31,6 +31,7 @@ require_relative 'doing/template_string'
31
31
  require_relative 'doing/string'
32
32
  require_relative 'doing/time'
33
33
  require_relative 'doing/array'
34
+ require_relative 'doing/good'
34
35
  require_relative 'doing/symbol'
35
36
  require_relative 'doing/util'
36
37
  require_relative 'doing/util_backup'
@@ -2,64 +2,21 @@
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
21
  max_threads = 1000 if max_threads == 0
65
22
 
@@ -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: 4, width: 1, head: ' ', unknown: ' ', 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
@@ -140,30 +105,36 @@ class ThreadedTests
140
105
  rescue
141
106
  progress.stop
142
107
  end
108
+ ensure
109
+ FileUtils.rm(@results)
143
110
  end
144
111
 
145
112
  def run_test(s)
146
-
147
113
  bar = s[1]
148
- bar.advance(status: ": #{'running'.green}")
114
+ s[2] = ": #{'running'.green}"
115
+ bar.advance(status: s[2])
149
116
 
150
117
  if @running_tests.count.positive?
151
- prev_bar = @running_tests[-1][1]
152
- unless prev_bar.complete?
153
- prev_bar.update(head: ' ', unfinished: ' ')
154
- prev_bar.advance(status: ": #{'running'.green}")
118
+ @running_tests.each do |b|
119
+ prev_bar = b[1]
120
+ if prev_bar.complete?
121
+ prev_bar.reset
122
+ prev_bar.advance(status: b[2])
123
+ prev_bar.finish
124
+ else
125
+ prev_bar.update(head: ' ', unfinished: ' ')
126
+ prev_bar.advance(status: b[2])
127
+ end
155
128
  end
156
129
  end
157
130
 
158
131
  @running_tests.push(s)
159
-
160
-
161
- out, _err, status = Open3.capture3(ENV, 'rake', "test:#{s[0]}", stdin_data: nil)
132
+ out, _err, status = Open3.capture3(ENV, "rake test:#{s[0]} | tee #{@results}", stdin_data: nil)
162
133
  unless status.success?
163
134
  m = out.match(/(?<fail>\d+) failures, (?<err>\d+) errors/)
164
- status = ": #{m['fail'].bold.red} #{'failures'.red}, #{m['err'].bold.red} #{'errors'.red}"
135
+ s[2] = ": #{m['fail'].bold.red} #{'failures'.red}, #{m['err'].bold.red} #{'errors'.red}"
165
136
  bar.update(head: '✖'.boldred)
166
- bar.advance(head: '✖'.boldred, status: status)
137
+ bar.advance(head: '✖'.boldred, status: s[2])
167
138
 
168
139
  # errs = out.scan(/(?:Failure|Error): [\w_]+\((?:.*?)\):(?:.*?)(?=\n=======)/m)
169
140
  @error_out.push(out.highlight_errors)
@@ -175,7 +146,7 @@ class ThreadedTests
175
146
 
176
147
  time = out.match(/^Finished in (?<time>\d+\.\d+) seconds\./)
177
148
  count = out.match(/^(?<tests>\d+) tests, (?<assrt>\d+) assertions, (?<fails>\d+) failures, (?<errs>\d+) errors/)
178
- status = [
149
+ s[2] = [
179
150
  ': ',
180
151
  count['tests'].green,
181
152
  '/',
@@ -190,7 +161,7 @@ class ThreadedTests
190
161
  's'
191
162
  ].join('')
192
163
  bar.update(head: '✔'.boldgreen)
193
- bar.advance(head: '✔'.boldgreen, status: status)
164
+ bar.advance(head: '✔'.boldgreen, status: s[2])
194
165
  @test_total += count['tests'].to_i
195
166
  @assrt_total += count['assrt'].to_i
196
167
  @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
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.24
4
+ version: 2.1.25
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-22 00:00:00.000000000 Z
11
+ date: 2022-01-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: safe_yaml
@@ -555,6 +555,7 @@ files:
555
555
  - lib/doing/completion/zsh_completion.rb
556
556
  - lib/doing/configuration.rb
557
557
  - lib/doing/errors.rb
558
+ - lib/doing/good.rb
558
559
  - lib/doing/hash.rb
559
560
  - lib/doing/help_monkey_patch.rb
560
561
  - lib/doing/hooks.rb
@@ -687,6 +688,7 @@ files:
687
688
  - lib/helpers/fzf/test/test_go.rb
688
689
  - lib/helpers/fzf/uninstall
689
690
  - lib/helpers/threaded_tests.rb
691
+ - lib/helpers/threaded_tests_string.rb
690
692
  - lib/templates/doing-dayone-entry.erb
691
693
  - lib/templates/doing-dayone.erb
692
694
  - lib/templates/doing-markdown.erb